Some cleanup.

This commit is contained in:
Ottermandias 2024-04-25 17:58:32 +02:00
parent cd76c31d8c
commit 72db023804
12 changed files with 163 additions and 154 deletions

View file

@ -51,7 +51,7 @@ public readonly struct ModSaveGroup : ISavable
if (_groupIdx >= 0)
_group!.WriteJson(j, serializer);
else
IModDataContainer.WriteModData(j, serializer, _defaultMod!, _basePath);
SubModHelpers.WriteModContainer(j, serializer, _defaultMod!, _basePath);
j.WriteEndObject();
}
}

View file

@ -54,7 +54,7 @@ public sealed class MultiModGroup(Mod mod) : IModGroup, ITexToolsGroup
return OptionData.Count - 1;
}
public static MultiModGroup? Load(Mod mod, JObject json, int groupIdx)
public static MultiModGroup? Load(Mod mod, JObject json)
{
var ret = new MultiModGroup(mod)
{
@ -140,10 +140,10 @@ public sealed class MultiModGroup(Mod mod) : IModGroup, ITexToolsGroup
jWriter.WriteStartArray();
foreach (var option in OptionData)
{
IModOption.WriteModOption(jWriter, option);
SubModHelpers.WriteModOption(jWriter, option);
jWriter.WritePropertyName(nameof(option.Priority));
jWriter.WriteValue(option.Priority.Value);
IModDataContainer.WriteModData(jWriter, serializer, option, basePath ?? Mod.ModPath);
SubModHelpers.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
}
jWriter.WriteEndArray();

View file

@ -52,7 +52,7 @@ public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
public bool IsOption
=> OptionData.Count > 1;
public static SingleModGroup? Load(Mod mod, JObject json, int groupIdx)
public static SingleModGroup? Load(Mod mod, JObject json)
{
var options = json["Options"];
var ret = new SingleModGroup(mod)
@ -144,8 +144,8 @@ public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
jWriter.WriteStartArray();
foreach (var option in OptionData)
{
IModOption.WriteModOption(jWriter, option);
IModDataContainer.WriteModData(jWriter, serializer, option, basePath ?? Mod.ModPath);
SubModHelpers.WriteModOption(jWriter, option);
SubModHelpers.WriteModContainer(jWriter, serializer, option, basePath ?? Mod.ModPath);
}
jWriter.WriteEndArray();

View file

@ -251,7 +251,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
Description = option.Description,
};
if (option is IModDataContainer data)
IModDataContainer.Clone(data, newOption);
SubModHelpers.Clone(data, newOption);
s.OptionData.Add(newOption);
break;
}
@ -265,7 +265,7 @@ public class ModOptionEditor(CommunicatorService communicator, SaveService saveS
Priority = option is MultiSubMod s ? s.Priority : ModPriority.Default,
};
if (option is IModDataContainer data)
IModDataContainer.Clone(data, newOption);
SubModHelpers.Clone(data, newOption);
m.OptionData.Add(newOption);
break;
}

View file

@ -78,7 +78,7 @@ public sealed class Mod : IMod
group.AddData(config, dictRedirections, setManips);
}
Default.AddDataTo(dictRedirections, setManips);
Default.AddTo(dictRedirections, setManips);
return new AppliedModData(dictRedirections, setManips);
}

View file

@ -115,7 +115,7 @@ public partial class ModCreator(
try
{
var jObject = File.Exists(defaultFile) ? JObject.Parse(File.ReadAllText(defaultFile)) : new JObject();
IModDataContainer.Load(jObject, mod.Default, mod.ModPath);
SubModHelpers.LoadDataContainer(jObject, mod.Default, mod.ModPath);
}
catch (Exception e)
{
@ -162,7 +162,7 @@ public partial class ModCreator(
deleteList.AddRange(localDeleteList);
}
IModDataContainer.DeleteDeleteList(deleteList, delete);
DeleteDeleteList(deleteList, delete);
if (!changes)
return;
@ -221,7 +221,7 @@ public partial class ModCreator(
}
}
IModDataContainer.DeleteDeleteList(deleteList, delete);
DeleteDeleteList(deleteList, delete);
return (oldSize < option.Manipulations.Count, deleteList);
}
@ -392,10 +392,8 @@ public partial class ModCreator(
Penumbra.Log.Debug($"Writing the first {IModGroup.MaxMultiOptions} options to {Path.GetFileName(oldPath)} after split.");
using (var oldFile = File.CreateText(oldPath))
{
using var j = new JsonTextWriter(oldFile)
{
Formatting = Formatting.Indented,
};
using var j = new JsonTextWriter(oldFile);
j.Formatting = Formatting.Indented;
json.WriteTo(j);
}
@ -403,10 +401,8 @@ public partial class ModCreator(
$"Writing the remaining {options.Count - IModGroup.MaxMultiOptions} options to {Path.GetFileName(newPath)} after split.");
using (var newFile = File.CreateText(newPath))
{
using var j = new JsonTextWriter(newFile)
{
Formatting = Formatting.Indented,
};
using var j = new JsonTextWriter(newFile);
j.Formatting = Formatting.Indented;
clone.WriteTo(j);
}
@ -436,8 +432,8 @@ public partial class ModCreator(
var json = JObject.Parse(File.ReadAllText(file.FullName));
switch (json[nameof(Type)]?.ToObject<GroupType>() ?? GroupType.Single)
{
case GroupType.Multi: return MultiModGroup.Load(mod, json, groupIdx);
case GroupType.Single: return SingleModGroup.Load(mod, json, groupIdx);
case GroupType.Multi: return MultiModGroup.Load(mod, json);
case GroupType.Single: return SingleModGroup.Load(mod, json);
}
}
catch (Exception e)
@ -446,5 +442,23 @@ public partial class ModCreator(
}
return null;
}
internal static void DeleteDeleteList(IEnumerable<string> deleteList, bool delete)
{
if (!delete)
return;
foreach (var file in deleteList)
{
try
{
File.Delete(file);
}
catch (Exception e)
{
Penumbra.Log.Error($"Could not delete incorporated meta file {file}:\n{e}");
}
}
}
}

View file

@ -22,9 +22,9 @@ public class DefaultSubMod(IMod mod) : IModDataContainer
IModGroup? IModDataContainer.Group
=> null;
public void AddDataTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> IModDataContainer.AddDataTo(this, redirections, manipulations);
public void AddTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> SubModHelpers.AddContainerTo(this, redirections, manipulations);
public (int GroupIndex, int DataIndex) GetDataIndices()
=> (-1, 0);
}
}

View file

@ -1,5 +1,3 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Editor;
using Penumbra.Mods.Groups;
@ -7,6 +5,7 @@ using Penumbra.String.Classes;
namespace Penumbra.Mods.SubMods;
public interface IModDataContainer
{
public IMod Mod { get; }
@ -16,116 +15,24 @@ public interface IModDataContainer
public Dictionary<Utf8GamePath, FullPath> FileSwaps { get; set; }
public HashSet<MetaManipulation> Manipulations { get; set; }
public static void AddDataTo(IModDataContainer container, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
{
foreach (var (path, file) in container.Files)
redirections.TryAdd(path, file);
foreach (var (path, file) in container.FileSwaps)
redirections.TryAdd(path, file);
manipulations.UnionWith(container.Manipulations);
}
public string GetName()
=> this switch
{
IModOption o => o.FullName,
IModOption o => o.FullName,
DefaultSubMod => DefaultSubMod.FullName,
_ => $"Container {GetDataIndices().DataIndex + 1}",
_ => $"Container {GetDataIndices().DataIndex + 1}",
};
public string GetFullName()
=> this switch
{
IModOption o => o.FullName,
DefaultSubMod => DefaultSubMod.FullName,
IModOption o => o.FullName,
DefaultSubMod => DefaultSubMod.FullName,
_ when Group != null => $"{Group.Name}: Container {GetDataIndices().DataIndex + 1}",
_ => $"Container {GetDataIndices().DataIndex + 1}",
_ => $"Container {GetDataIndices().DataIndex + 1}",
};
public static void Clone(IModDataContainer from, IModDataContainer to)
{
to.Files = new Dictionary<Utf8GamePath, FullPath>(from.Files);
to.FileSwaps = new Dictionary<Utf8GamePath, FullPath>(from.FileSwaps);
to.Manipulations = [.. from.Manipulations];
}
public (int GroupIndex, int DataIndex) GetDataIndices();
public static void Load(JToken json, IModDataContainer data, DirectoryInfo basePath)
{
data.Files.Clear();
data.FileSwaps.Clear();
data.Manipulations.Clear();
var files = (JObject?)json[nameof(Files)];
if (files != null)
foreach (var property in files.Properties())
{
if (Utf8GamePath.FromString(property.Name, out var p, true))
data.Files.TryAdd(p, new FullPath(basePath, property.Value.ToObject<Utf8RelPath>()));
}
var swaps = (JObject?)json[nameof(FileSwaps)];
if (swaps != null)
foreach (var property in swaps.Properties())
{
if (Utf8GamePath.FromString(property.Name, out var p, true))
data.FileSwaps.TryAdd(p, new FullPath(property.Value.ToObject<string>()!));
}
var manips = json[nameof(Manipulations)];
if (manips != null)
foreach (var s in manips.Children().Select(c => c.ToObject<MetaManipulation>())
.Where(m => m.Validate()))
data.Manipulations.Add(s);
}
public static void WriteModData(JsonWriter j, JsonSerializer serializer, IModDataContainer data, DirectoryInfo basePath)
{
j.WritePropertyName(nameof(data.Files));
j.WriteStartObject();
foreach (var (gamePath, file) in data.Files)
{
if (file.ToRelPath(basePath, out var relPath))
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(relPath.ToString());
}
}
j.WriteEndObject();
j.WritePropertyName(nameof(data.FileSwaps));
j.WriteStartObject();
foreach (var (gamePath, file) in data.FileSwaps)
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(file.ToString());
}
j.WriteEndObject();
j.WritePropertyName(nameof(data.Manipulations));
serializer.Serialize(j, data.Manipulations);
j.WriteEndObject();
}
internal static void DeleteDeleteList(IEnumerable<string> deleteList, bool delete)
{
if (!delete)
return;
foreach (var file in deleteList)
{
try
{
File.Delete(file);
}
catch (Exception e)
{
Penumbra.Log.Error($"Could not delete incorporated meta file {file}:\n{e}");
}
}
}
}
public interface IModDataOption : IModOption, IModDataContainer;

View file

@ -1,27 +1,10 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Penumbra.Mods.SubMods;
public interface IModOption
{
public string Name { get; set; }
public string FullName { get; }
public string Name { get; set; }
public string FullName { get; }
public string Description { get; set; }
public static void Load(JToken json, IModOption option)
{
option.Name = json[nameof(Name)]?.ToObject<string>() ?? string.Empty;
option.Description = json[nameof(Description)]?.ToObject<string>() ?? string.Empty;
}
public (int GroupIndex, int OptionIndex) GetOptionIndices();
public static void WriteModOption(JsonWriter j, IModOption option)
{
j.WritePropertyName(nameof(Name));
j.WriteValue(option.Name);
j.WritePropertyName(nameof(Description));
j.WriteValue(option.Description);
}
}

View file

@ -35,8 +35,8 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : IModDataOption
public MultiSubMod(Mod mod, MultiModGroup group, JToken json)
: this(mod, group)
{
IModOption.Load(json, this);
IModDataContainer.Load(json, this, mod.ModPath);
SubModHelpers.LoadOptionData(json, this);
SubModHelpers.LoadDataContainer(json, this, mod.ModPath);
Priority = json[nameof(IModGroup.Priority)]?.ToObject<ModPriority>() ?? ModPriority.Default;
}
@ -48,7 +48,7 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : IModDataOption
Description = Description,
Priority = Priority,
};
IModDataContainer.Clone(this, ret);
SubModHelpers.Clone(this, ret);
return ret;
}
@ -60,12 +60,12 @@ public class MultiSubMod(Mod mod, MultiModGroup group) : IModDataOption
Name = Name,
Description = Description,
};
IModDataContainer.Clone(this, ret);
SubModHelpers.Clone(this, ret);
return ret;
}
public void AddDataTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> IModDataContainer.AddDataTo(this, redirections, manipulations);
=> SubModHelpers.AddContainerTo(this, redirections, manipulations);
public static MultiSubMod CreateForSaving(string name, string description, ModPriority priority)
=> new(null!, null!)

View file

@ -33,8 +33,8 @@ public class SingleSubMod(Mod mod, SingleModGroup group) : IModDataOption
public SingleSubMod(Mod mod, SingleModGroup group, JToken json)
: this(mod, group)
{
IModOption.Load(json, this);
IModDataContainer.Load(json, this, mod.ModPath);
SubModHelpers.LoadOptionData(json, this);
SubModHelpers.LoadDataContainer(json, this, mod.ModPath);
}
public SingleSubMod Clone(Mod mod, SingleModGroup group)
@ -44,7 +44,7 @@ public class SingleSubMod(Mod mod, SingleModGroup group) : IModDataOption
Name = Name,
Description = Description,
};
IModDataContainer.Clone(this, ret);
SubModHelpers.Clone(this, ret);
return ret;
}
@ -57,13 +57,13 @@ public class SingleSubMod(Mod mod, SingleModGroup group) : IModDataOption
Description = Description,
Priority = priority,
};
IModDataContainer.Clone(this, ret);
SubModHelpers.Clone(this, ret);
return ret;
}
public void AddDataTo(Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations)
=> IModDataContainer.AddDataTo(this, redirections, manipulations);
=> SubModHelpers.AddContainerTo(this, redirections, manipulations);
public (int GroupIndex, int DataIndex) GetDataIndices()
=> (Group.GetIndex(), GetDataIndex());

View file

@ -0,0 +1,105 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.ItemSwap;
using Penumbra.String.Classes;
namespace Penumbra.Mods.SubMods;
public static class SubModHelpers
{
/// <summary> Add all unique meta manipulations, file redirections and then file swaps from a ModDataContainer to the given sets. Skip any keys that are already contained. </summary>
public static void AddContainerTo(IModDataContainer container, Dictionary<Utf8GamePath, FullPath> redirections,
HashSet<MetaManipulation> manipulations)
{
foreach (var (path, file) in container.Files)
redirections.TryAdd(path, file);
foreach (var (path, file) in container.FileSwaps)
redirections.TryAdd(path, file);
manipulations.UnionWith(container.Manipulations);
}
/// <summary> Replace all data of <paramref name="to"/> with the data of <paramref name="from"/>. </summary>
public static void Clone(IModDataContainer from, IModDataContainer to)
{
to.Files = new Dictionary<Utf8GamePath, FullPath>(from.Files);
to.FileSwaps = new Dictionary<Utf8GamePath, FullPath>(from.FileSwaps);
to.Manipulations = [.. from.Manipulations];
}
/// <summary> Load all file redirections, file swaps and meta manipulations from a JToken of that option into a data container. </summary>
public static void LoadDataContainer(JToken json, IModDataContainer data, DirectoryInfo basePath)
{
data.Files.Clear();
data.FileSwaps.Clear();
data.Manipulations.Clear();
var files = (JObject?)json[nameof(data.Files)];
if (files != null)
foreach (var property in files.Properties())
{
if (Utf8GamePath.FromString(property.Name, out var p, true))
data.Files.TryAdd(p, new FullPath(basePath, property.Value.ToObject<Utf8RelPath>()));
}
var swaps = (JObject?)json[nameof(data.FileSwaps)];
if (swaps != null)
foreach (var property in swaps.Properties())
{
if (Utf8GamePath.FromString(property.Name, out var p, true))
data.FileSwaps.TryAdd(p, new FullPath(property.Value.ToObject<string>()!));
}
var manips = json[nameof(data.Manipulations)];
if (manips != null)
foreach (var s in manips.Children().Select(c => c.ToObject<MetaManipulation>())
.Where(m => m.Validate()))
data.Manipulations.Add(s);
}
/// <summary> Load the relevant data for a selectable option from a JToken of that option. </summary>
public static void LoadOptionData(JToken json, IModOption option)
{
option.Name = json[nameof(option.Name)]?.ToObject<string>() ?? string.Empty;
option.Description = json[nameof(option.Description)]?.ToObject<string>() ?? string.Empty;
}
/// <summary> Write file redirections, file swaps and meta manipulations from a data container on a JsonWriter. </summary>
public static void WriteModContainer(JsonWriter j, JsonSerializer serializer, IModDataContainer data, DirectoryInfo basePath)
{
j.WritePropertyName(nameof(data.Files));
j.WriteStartObject();
foreach (var (gamePath, file) in data.Files)
{
if (file.ToRelPath(basePath, out var relPath))
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(relPath.ToString());
}
}
j.WriteEndObject();
j.WritePropertyName(nameof(data.FileSwaps));
j.WriteStartObject();
foreach (var (gamePath, file) in data.FileSwaps)
{
j.WritePropertyName(gamePath.ToString());
j.WriteValue(file.ToString());
}
j.WriteEndObject();
j.WritePropertyName(nameof(data.Manipulations));
serializer.Serialize(j, data.Manipulations);
j.WriteEndObject();
}
/// <summary> Write the data for a selectable mod option on a JsonWriter. </summary>
public static void WriteModOption(JsonWriter j, IModOption option)
{
j.WritePropertyName(nameof(option.Name));
j.WriteValue(option.Name);
j.WritePropertyName(nameof(option.Description));
j.WriteValue(option.Description);
}
}