Remove ISubMod.

This commit is contained in:
Ottermandias 2024-04-19 18:28:25 +02:00
parent 8fc7de64d9
commit 9f4c6767f8
23 changed files with 123 additions and 184 deletions

View file

@ -152,7 +152,7 @@ public partial class TexToolsImporter
}
// Iterate through all pages
var options = new List<ISubMod>();
var options = new List<SubMod>();
var groupPriority = ModPriority.Default;
var groupNames = new HashSet<string>();
foreach (var page in modList.ModPackPages)

View file

@ -29,7 +29,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
Worker = Task.Run(() => CheckDuplicates(filesTmp, _cancellationTokenSource.Token), _cancellationTokenSource.Token);
}
public void DeleteDuplicates(ModFileCollection files, Mod mod, ISubMod option, bool useModManager)
public void DeleteDuplicates(ModFileCollection files, Mod mod, SubMod option, bool useModManager)
{
if (!Worker.IsCompleted || _duplicates.Count == 0)
return;
@ -72,7 +72,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
return;
void HandleSubMod(ISubMod subMod, int groupIdx, int optionIdx)
void HandleSubMod(SubMod subMod, int groupIdx, int optionIdx)
{
var changes = false;
var dict = subMod.Files.ToDictionary(kvp => kvp.Key,
@ -86,8 +86,7 @@ public class DuplicateManager(ModManager modManager, SaveService saveService, Co
}
else
{
var sub = (SubMod)subMod;
sub.FileData = dict;
subMod.FileData = dict;
saveService.ImmediateSaveSync(new ModSaveGroup(mod, groupIdx, config.ReplaceNonAsciiOnImport));
}
}

View file

@ -5,7 +5,7 @@ namespace Penumbra.Mods.Editor;
public class FileRegistry : IEquatable<FileRegistry>
{
public readonly List<(ISubMod, Utf8GamePath)> SubModUsage = [];
public readonly List<(SubMod, Utf8GamePath)> SubModUsage = [];
public FullPath File { get; private init; }
public Utf8RelPath RelPath { get; private init; }
public long FileSize { get; private init; }

View file

@ -6,8 +6,8 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods.Editor;
public record struct AppliedModData(
IReadOnlyCollection<KeyValuePair<Utf8GamePath, FullPath>> FileRedirections,
IReadOnlyCollection<MetaManipulation> Manipulations)
Dictionary<Utf8GamePath, FullPath> FileRedirections,
HashSet<MetaManipulation> Manipulations)
{
public static readonly AppliedModData Empty = new([], []);
}
@ -19,13 +19,9 @@ public interface IMod
public int Index { get; }
public ModPriority Priority { get; }
public AppliedModData GetData(ModSettings? settings = null);
public ISubMod Default { get; }
public IReadOnlyList<IModGroup> Groups { get; }
public IEnumerable<SubMod> AllSubMods { get; }
public AppliedModData GetData(ModSettings? settings = null);
// Cache
public int TotalManipulations { get; }

View file

@ -29,7 +29,7 @@ public class ModEditor(
public int OptionIdx { get; private set; }
public IModGroup? Group { get; private set; }
public ISubMod? Option { get; private set; }
public SubMod? Option { get; private set; }
public void LoadMod(Mod mod)
=> LoadMod(mod, -1, 0);
@ -104,7 +104,7 @@ public class ModEditor(
=> Clear();
/// <summary> Apply a option action to all available option in a mod, including the default option. </summary>
public static void ApplyToAllOptions(Mod mod, Action<ISubMod, int, int> action)
public static void ApplyToAllOptions(Mod mod, Action<SubMod, int, int> action)
{
action(mod.Default, -1, 0);
foreach (var (group, groupIdx) in mod.Groups.WithIndex())

View file

@ -38,13 +38,13 @@ public class ModFileCollection : IDisposable
public bool Ready { get; private set; } = true;
public void UpdateAll(Mod mod, ISubMod option)
public void UpdateAll(Mod mod, SubMod option)
{
UpdateFiles(mod, new CancellationToken());
UpdatePaths(mod, option, false, new CancellationToken());
}
public void UpdatePaths(Mod mod, ISubMod option)
public void UpdatePaths(Mod mod, SubMod option)
=> UpdatePaths(mod, option, true, new CancellationToken());
public void Clear()
@ -59,7 +59,7 @@ public class ModFileCollection : IDisposable
public void ClearMissingFiles()
=> _missing.Clear();
public void RemoveUsedPath(ISubMod option, FileRegistry? file, Utf8GamePath gamePath)
public void RemoveUsedPath(SubMod option, FileRegistry? file, Utf8GamePath gamePath)
{
_usedPaths.Remove(gamePath);
if (file != null)
@ -69,10 +69,10 @@ public class ModFileCollection : IDisposable
}
}
public void RemoveUsedPath(ISubMod option, FullPath file, Utf8GamePath gamePath)
public void RemoveUsedPath(SubMod option, FullPath file, Utf8GamePath gamePath)
=> RemoveUsedPath(option, _available.FirstOrDefault(f => f.File.Equals(file)), gamePath);
public void AddUsedPath(ISubMod option, FileRegistry? file, Utf8GamePath gamePath)
public void AddUsedPath(SubMod option, FileRegistry? file, Utf8GamePath gamePath)
{
_usedPaths.Add(gamePath);
if (file == null)
@ -82,7 +82,7 @@ public class ModFileCollection : IDisposable
file.SubModUsage.Add((option, gamePath));
}
public void AddUsedPath(ISubMod option, FullPath file, Utf8GamePath gamePath)
public void AddUsedPath(SubMod option, FullPath file, Utf8GamePath gamePath)
=> AddUsedPath(option, _available.FirstOrDefault(f => f.File.Equals(file)), gamePath);
public void ChangeUsedPath(FileRegistry file, int pathIdx, Utf8GamePath gamePath)
@ -154,7 +154,7 @@ public class ModFileCollection : IDisposable
_usedPaths.Clear();
}
private void UpdatePaths(Mod mod, ISubMod option, bool clearRegistries, CancellationToken tok)
private void UpdatePaths(Mod mod, SubMod option, bool clearRegistries, CancellationToken tok)
{
tok.ThrowIfCancellationRequested();
ClearPaths(clearRegistries, tok);

View file

@ -30,16 +30,16 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
return num;
}
public void Revert(Mod mod, ISubMod option)
public void Revert(Mod mod, SubMod option)
{
files.UpdateAll(mod, option);
Changes = false;
}
/// <summary> Remove all path redirections where the pointed-to file does not exist. </summary>
public void RemoveMissingPaths(Mod mod, ISubMod option)
public void RemoveMissingPaths(Mod mod, SubMod option)
{
void HandleSubMod(ISubMod subMod, int groupIdx, int optionIdx)
void HandleSubMod(SubMod subMod, int groupIdx, int optionIdx)
{
var newDict = subMod.Files.Where(kvp => CheckAgainstMissing(mod, subMod, kvp.Value, kvp.Key, subMod == option))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
@ -61,7 +61,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
/// If path is empty, it will be deleted instead.
/// If pathIdx is equal to the total number of paths, path will be added, otherwise replaced.
/// </summary>
public bool SetGamePath(ISubMod option, int fileIdx, int pathIdx, Utf8GamePath path)
public bool SetGamePath(SubMod option, int fileIdx, int pathIdx, Utf8GamePath path)
{
if (!CanAddGamePath(path) || fileIdx < 0 || fileIdx > files.Available.Count)
return false;
@ -84,7 +84,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
/// Transform a set of files to the appropriate game paths with the given number of folders skipped,
/// and add them to the given option.
/// </summary>
public int AddPathsToSelected(ISubMod option, IEnumerable<FileRegistry> files1, int skipFolders = 0)
public int AddPathsToSelected(SubMod option, IEnumerable<FileRegistry> files1, int skipFolders = 0)
{
var failed = 0;
foreach (var file in files1)
@ -111,7 +111,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
/// <summary> Remove all paths in the current option from the given files. </summary>
public void RemovePathsFromSelected(ISubMod option, IEnumerable<FileRegistry> files1)
public void RemovePathsFromSelected(SubMod option, IEnumerable<FileRegistry> files1)
{
foreach (var file in files1)
{
@ -129,7 +129,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
/// <summary> Delete all given files from your filesystem </summary>
public void DeleteFiles(Mod mod, ISubMod option, IEnumerable<FileRegistry> files1)
public void DeleteFiles(Mod mod, SubMod option, IEnumerable<FileRegistry> files1)
{
var deletions = 0;
foreach (var file in files1)
@ -155,7 +155,7 @@ public class ModFileEditor(ModFileCollection files, ModManager modManager, Commu
}
private bool CheckAgainstMissing(Mod mod, ISubMod option, FullPath file, Utf8GamePath key, bool removeUsed)
private bool CheckAgainstMissing(Mod mod, SubMod option, FullPath file, Utf8GamePath key, bool removeUsed)
{
if (!files.Missing.Contains(file))
return true;

View file

@ -151,7 +151,7 @@ public class ModMerger : IDisposable
MergeIntoOption(MergeFromMod!.AllSubMods.Reverse(), option, true);
}
private void MergeIntoOption(IEnumerable<ISubMod> mergeOptions, SubMod option, bool fromFileToFile)
private void MergeIntoOption(IEnumerable<SubMod> mergeOptions, SubMod option, bool fromFileToFile)
{
var redirections = option.FileData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var swaps = option.FileSwapData.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

View file

@ -103,7 +103,7 @@ public class ModMetaEditor(ModManager modManager)
Changes = true;
}
public void Load(Mod mod, ISubMod currentOption)
public void Load(Mod mod, SubMod currentOption)
{
OtherImcCount = 0;
OtherEqpCount = 0;

View file

@ -11,7 +11,7 @@ public class ModSwapEditor(ModManager modManager)
public IReadOnlyDictionary<Utf8GamePath, FullPath> Swaps
=> _swaps;
public void Revert(ISubMod option)
public void Revert(SubMod option)
{
_swaps.SetTo(option.FileSwaps);
Changes = false;

View file

@ -5,6 +5,7 @@ using Penumbra.GameData.Structs;
using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes;
using Penumbra.Meta;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Subclasses;
@ -15,14 +16,13 @@ public class ItemSwapContainer
private readonly MetaFileManager _manager;
private readonly ObjectIdentification _identifier;
private Dictionary<Utf8GamePath, FullPath> _modRedirections = [];
private HashSet<MetaManipulation> _modManipulations = [];
private AppliedModData _appliedModData = AppliedModData.Empty;
public IReadOnlyDictionary<Utf8GamePath, FullPath> ModRedirections
=> _modRedirections;
=> _appliedModData.FileRedirections;
public IReadOnlySet<MetaManipulation> ModManipulations
=> _modManipulations;
=> _appliedModData.Manipulations;
public readonly List<Swap> Swaps = [];
@ -97,12 +97,11 @@ public class ItemSwapContainer
Clear();
if (mod == null || mod.Index < 0)
{
_modRedirections = [];
_modManipulations = [];
_appliedModData = AppliedModData.Empty;
}
else
{
(_modRedirections, _modManipulations) = ModSettings.GetResolveData(mod, settings);
_appliedModData = ModSettings.GetResolveData(mod, settings);
}
}
@ -120,7 +119,7 @@ public class ItemSwapContainer
private Func<MetaManipulation, MetaManipulation> MetaResolver(ModCollection? collection)
{
var set = collection?.MetaCache?.Manipulations.ToHashSet() ?? _modManipulations;
var set = collection?.MetaCache?.Manipulations.ToHashSet() ?? _appliedModData.Manipulations;
return m => set.TryGetValue(m, out var a) ? a : m;
}

View file

@ -262,15 +262,12 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
}
/// <summary> Add an existing option to a given group with default priority. </summary>
public void AddOption(Mod mod, int groupIdx, ISubMod option)
public void AddOption(Mod mod, int groupIdx, SubMod option)
=> AddOption(mod, groupIdx, option, ModPriority.Default);
/// <summary> Add an existing option to a given group with a given priority. </summary>
public void AddOption(Mod mod, int groupIdx, ISubMod option, ModPriority priority)
public void AddOption(Mod mod, int groupIdx, SubMod option, ModPriority priority)
{
if (option is not SubMod o)
return;
var group = mod.Groups[groupIdx];
switch (group)
{
@ -280,12 +277,12 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
+ $"since only up to {IModGroup.MaxMultiOptions} options are supported in one group.");
return;
case SingleModGroup s:
o.SetPosition(groupIdx, s.Count);
s.OptionData.Add(o);
option.SetPosition(groupIdx, s.Count);
s.OptionData.Add(option);
break;
case MultiModGroup m:
o.SetPosition(groupIdx, m.Count);
m.PrioritizedOptions.Add((o, priority));
option.SetPosition(groupIdx, m.Count);
m.PrioritizedOptions.Add((option, priority));
break;
}

View file

@ -32,6 +32,9 @@ public sealed class Mod : IMod
public ModPriority Priority
=> ModPriority.Default;
IReadOnlyList<IModGroup> IMod.Groups
=> Groups;
internal Mod(DirectoryInfo modPath)
{
ModPath = modPath;
@ -74,18 +77,12 @@ public sealed class Mod : IMod
group.AddData(config, dictRedirections, setManips);
}
((ISubMod)Default).AddData(dictRedirections, setManips);
Default.AddData(dictRedirections, setManips);
return new AppliedModData(dictRedirections, setManips);
}
ISubMod IMod.Default
=> Default;
IReadOnlyList<IModGroup> IMod.Groups
=> Groups;
public IEnumerable<SubMod> AllSubMods
=> Groups.SelectMany(o => o).OfType<SubMod>().Prepend(Default);
=> Groups.SelectMany(o => o).Prepend(Default);
public List<FullPath> FindUnusedFiles()
{

View file

@ -235,7 +235,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config,
/// <summary> Create a file for an option group from given data. </summary>
public void CreateOptionGroup(DirectoryInfo baseFolder, GroupType type, string name,
ModPriority priority, int index, Setting defaultSettings, string desc, IEnumerable<ISubMod> subMods)
ModPriority priority, int index, Setting defaultSettings, string desc, IEnumerable<SubMod> subMods)
{
switch (type)
{
@ -248,7 +248,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config,
Priority = priority,
DefaultSettings = defaultSettings,
};
group.PrioritizedOptions.AddRange(subMods.OfType<SubMod>().Select((s, idx) => (s, new ModPriority(idx))));
group.PrioritizedOptions.AddRange(subMods.Select((s, idx) => (s, new ModPriority(idx))));
_saveService.ImmediateSaveSync(new ModSaveGroup(baseFolder, group, index, Config.ReplaceNonAsciiOnImport));
break;
}
@ -269,7 +269,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config,
}
/// <summary> Create the data for a given sub mod from its data and the folder it is based on. </summary>
public ISubMod CreateSubMod(DirectoryInfo baseFolder, DirectoryInfo optionFolder, OptionList option)
public SubMod CreateSubMod(DirectoryInfo baseFolder, DirectoryInfo optionFolder, OptionList option)
{
var list = optionFolder.EnumerateNonHiddenFiles()
.Select(f => (Utf8GamePath.FromFile(f, optionFolder, out var gamePath, true), gamePath, new FullPath(f)))
@ -288,7 +288,7 @@ public partial class ModCreator(SaveService _saveService, Configuration config,
}
/// <summary> Create an empty sub mod for single groups with None options. </summary>
internal static ISubMod CreateEmptySubMod(string name)
internal static SubMod CreateEmptySubMod(string name)
=> new SubMod(null!) // Mod is irrelevant here, only used for saving.
{
Name = name,

View file

@ -6,7 +6,7 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods.Subclasses;
public interface IModGroup : IReadOnlyCollection<ISubMod>
public interface IModGroup : IReadOnlyCollection<SubMod>
{
public const int MaxMultiOptions = 63;
@ -18,7 +18,7 @@ public interface IModGroup : IReadOnlyCollection<ISubMod>
public ModPriority OptionPriority(Index optionIdx);
public ISubMod this[Index idx] { get; }
public SubMod this[Index idx] { get; }
public bool IsOption { get; }
@ -37,7 +37,7 @@ public readonly struct ModSaveGroup : ISavable
private readonly DirectoryInfo _basePath;
private readonly IModGroup? _group;
private readonly int _groupIdx;
private readonly ISubMod? _defaultMod;
private readonly SubMod? _defaultMod;
private readonly bool _onlyAscii;
public ModSaveGroup(Mod mod, int groupIdx, bool onlyAscii)
@ -59,7 +59,7 @@ public readonly struct ModSaveGroup : ISavable
_onlyAscii = onlyAscii;
}
public ModSaveGroup(DirectoryInfo basePath, ISubMod @default, bool onlyAscii)
public ModSaveGroup(DirectoryInfo basePath, SubMod @default, bool onlyAscii)
{
_basePath = basePath;
_groupIdx = -1;
@ -91,7 +91,7 @@ public readonly struct ModSaveGroup : ISavable
j.WriteStartArray();
for (var idx = 0; idx < _group.Count; ++idx)
{
ISubMod.WriteSubMod(j, serializer, _group[idx], _basePath, _group.Type switch
SubMod.WriteSubMod(j, serializer, _group[idx], _basePath, _group.Type switch
{
GroupType.Multi => _group.OptionPriority(idx),
_ => null,
@ -103,7 +103,7 @@ public readonly struct ModSaveGroup : ISavable
}
else
{
ISubMod.WriteSubMod(j, serializer, _defaultMod!, _basePath, null);
SubMod.WriteSubMod(j, serializer, _defaultMod!, _basePath, null);
}
}
}

View file

@ -1,67 +0,0 @@
using Newtonsoft.Json;
using Penumbra.Meta.Manipulations;
using Penumbra.String.Classes;
namespace Penumbra.Mods.Subclasses;
public interface ISubMod
{
public string Name { get; }
public string FullName { get; }
public string Description { get; }
public IReadOnlyDictionary<Utf8GamePath, FullPath> Files { get; }
public IReadOnlyDictionary<Utf8GamePath, FullPath> FileSwaps { get; }
public IReadOnlySet<MetaManipulation> Manipulations { get; }
public void AddData(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
{
foreach (var (path, file) in Files)
redirections.TryAdd(path, file);
foreach (var (path, file) in FileSwaps)
redirections.TryAdd(path, file);
manipulations.UnionWith(Manipulations);
}
public bool IsDefault { get; }
public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, ISubMod mod, DirectoryInfo basePath, ModPriority? priority)
{
j.WriteStartObject();
j.WritePropertyName(nameof(Name));
j.WriteValue(mod.Name);
j.WritePropertyName(nameof(Description));
j.WriteValue(mod.Description);
if (priority != null)
{
j.WritePropertyName(nameof(IModGroup.Priority));
j.WriteValue(priority.Value.Value);
}
j.WritePropertyName(nameof(mod.Files));
j.WriteStartObject();
foreach (var (gamePath, file) in mod.Files)
{
if (file.ToRelPath(basePath, out var relPath))
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(relPath.ToString());
}
}
j.WriteEndObject();
j.WritePropertyName(nameof(mod.FileSwaps));
j.WriteStartObject();
foreach (var (gamePath, file) in mod.FileSwaps)
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(file.ToString());
}
j.WriteEndObject();
j.WritePropertyName(nameof(mod.Manipulations));
serializer.Serialize(j, mod.Manipulations);
j.WriteEndObject();
}
}

View file

@ -2,6 +2,7 @@ using OtterGui;
using OtterGui.Filesystem;
using Penumbra.Api.Enums;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Manager;
using Penumbra.String.Classes;
@ -34,44 +35,14 @@ public class ModSettings
};
// Return everything required to resolve things for a single mod with given settings (which can be null, in which case the default is used.
public static (Dictionary<Utf8GamePath, FullPath>, HashSet<MetaManipulation>) GetResolveData(Mod mod, ModSettings? settings)
public static AppliedModData GetResolveData(Mod mod, ModSettings? settings)
{
if (settings == null)
settings = DefaultSettings(mod);
else
settings.Settings.FixSize(mod);
var dict = new Dictionary<Utf8GamePath, FullPath>();
var set = new HashSet<MetaManipulation>();
foreach (var (group, index) in mod.Groups.WithIndex().OrderByDescending(g => g.Value.Priority))
{
if (group.Type is GroupType.Single)
{
if (group.Count > 0)
AddOption(group[settings.Settings[index].AsIndex]);
}
else
{
foreach (var (option, optionIdx) in group.WithIndex().OrderByDescending(o => group.OptionPriority(o.Index)))
{
if (settings.Settings[index].HasFlag(optionIdx))
AddOption(option);
}
}
}
AddOption(mod.Default);
return (dict, set);
void AddOption(ISubMod option)
{
foreach (var (path, file) in option.Files.Concat(option.FileSwaps))
dict.TryAdd(path, file);
foreach (var manip in option.Manipulations)
set.Add(manip);
}
return mod.GetData(settings);
}
// Automatically react to changes in a mods available options.

View file

@ -24,7 +24,7 @@ public sealed class MultiModGroup : IModGroup
public ModPriority OptionPriority(Index idx)
=> PrioritizedOptions[idx].Priority;
public ISubMod this[Index idx]
public SubMod this[Index idx]
=> PrioritizedOptions[idx].Mod;
public bool IsOption
@ -36,7 +36,7 @@ public sealed class MultiModGroup : IModGroup
public readonly List<(SubMod Mod, ModPriority Priority)> PrioritizedOptions = [];
public IEnumerator<ISubMod> GetEnumerator()
public IEnumerator<SubMod> GetEnumerator()
=> PrioritizedOptions.Select(o => o.Mod).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
@ -117,7 +117,7 @@ public sealed class MultiModGroup : IModGroup
foreach (var (option, index) in PrioritizedOptions.WithIndex().OrderByDescending(o => o.Value.Priority))
{
if (setting.HasFlag(index))
((ISubMod)option.Mod).AddData(redirections, manipulations);
option.Mod.AddData(redirections, manipulations);
}
}

View file

@ -24,7 +24,7 @@ public sealed class SingleModGroup : IModGroup
public ModPriority OptionPriority(Index _)
=> Priority;
public ISubMod this[Index idx]
public SubMod this[Index idx]
=> OptionData[idx];
public bool IsOption
@ -34,7 +34,7 @@ public sealed class SingleModGroup : IModGroup
public int Count
=> OptionData.Count;
public IEnumerator<ISubMod> GetEnumerator()
public IEnumerator<SubMod> GetEnumerator()
=> OptionData.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()

View file

@ -1,3 +1,4 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Editor;
@ -15,7 +16,7 @@ namespace Penumbra.Mods.Subclasses;
/// Nothing is checked for existence or validity when loading.
/// Objects are also not checked for uniqueness, the first appearance of a game path or meta path decides.
/// </summary>
public sealed class SubMod : ISubMod
public sealed class SubMod
{
public string Name { get; set; } = "Default";
@ -31,6 +32,16 @@ public sealed class SubMod : ISubMod
public bool IsDefault
=> GroupIdx < 0;
public void AddData(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
{
foreach (var (path, file) in Files)
redirections.TryAdd(path, file);
foreach (var (path, file) in FileSwaps)
redirections.TryAdd(path, file);
manipulations.UnionWith(Manipulations);
}
public Dictionary<Utf8GamePath, FullPath> FileData = [];
public Dictionary<Utf8GamePath, FullPath> FileSwapData = [];
public HashSet<MetaManipulation> ManipulationData = [];
@ -60,8 +71,8 @@ public sealed class SubMod : ISubMod
ManipulationData.Clear();
// Every option has a name, but priorities are only relevant for multi group options.
Name = json[nameof(ISubMod.Name)]?.ToObject<string>() ?? string.Empty;
Description = json[nameof(ISubMod.Description)]?.ToObject<string>() ?? string.Empty;
Name = json[nameof(Name)]?.ToObject<string>() ?? string.Empty;
Description = json[nameof(Description)]?.ToObject<string>() ?? string.Empty;
priority = json[nameof(IModGroup.Priority)]?.ToObject<ModPriority>() ?? ModPriority.Default;
var files = (JObject?)json[nameof(Files)];
@ -104,4 +115,43 @@ public sealed class SubMod : ISubMod
}
}
}
public static void WriteSubMod(JsonWriter j, JsonSerializer serializer, SubMod mod, DirectoryInfo basePath, ModPriority? priority)
{
j.WriteStartObject();
j.WritePropertyName(nameof(Name));
j.WriteValue(mod.Name);
j.WritePropertyName(nameof(Description));
j.WriteValue(mod.Description);
if (priority != null)
{
j.WritePropertyName(nameof(IModGroup.Priority));
j.WriteValue(priority.Value.Value);
}
j.WritePropertyName(nameof(mod.Files));
j.WriteStartObject();
foreach (var (gamePath, file) in mod.Files)
{
if (file.ToRelPath(basePath, out var relPath))
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(relPath.ToString());
}
}
j.WriteEndObject();
j.WritePropertyName(nameof(mod.FileSwaps));
j.WriteStartObject();
foreach (var (gamePath, file) in mod.FileSwaps)
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(file.ToString());
}
j.WriteEndObject();
j.WritePropertyName(nameof(mod.Manipulations));
serializer.Serialize(j, mod.Manipulations);
j.WriteEndObject();
}
}

View file

@ -39,12 +39,9 @@ public class TemporaryMod : IMod
dict.TryAdd(gamePath, file);
}
return new AppliedModData(dict, Default.Manipulations);
return new AppliedModData(dict, Default.ManipulationData);
}
ISubMod IMod.Default
=> Default;
public IReadOnlyList<IModGroup> Groups
=> Array.Empty<IModGroup>();

View file

@ -192,7 +192,7 @@ public partial class ModEditWindow
ImGuiUtil.RightAlign(rightText);
}
private void PrintGamePath(int i, int j, FileRegistry registry, ISubMod subMod, Utf8GamePath gamePath)
private void PrintGamePath(int i, int j, FileRegistry registry, SubMod subMod, Utf8GamePath gamePath)
{
using var id = ImRaii.PushId(j);
ImGui.TableNextColumn();
@ -228,7 +228,7 @@ public partial class ModEditWindow
}
}
private void PrintNewGamePath(int i, FileRegistry registry, ISubMod subMod)
private void PrintNewGamePath(int i, FileRegistry registry, SubMod subMod)
{
var tmp = _fileIdx == i && _pathIdx == -1 ? _gamePathEdit : string.Empty;
var pos = ImGui.GetCursorPosX() - ImGui.GetFrameHeight();

View file

@ -227,7 +227,7 @@ public partial class ModEditWindow
return fileRegistry;
}
private static (DirectoryInfo, int) GetPreferredPath(Mod mod, ISubMod subMod, bool replaceNonAscii)
private static (DirectoryInfo, int) GetPreferredPath(Mod mod, SubMod subMod, bool replaceNonAscii)
{
var path = mod.ModPath;
var subDirs = 0;