Add option to apply only attributes from IMC group.

This commit is contained in:
Ottermandias 2024-09-16 22:54:06 +02:00
parent ac1ea124d9
commit 00fbb2686b
8 changed files with 63 additions and 40 deletions

View file

@ -6,9 +6,9 @@ namespace Penumbra.Meta;
public class ImcChecker
{
private static readonly Dictionary<ImcIdentifier, int> VariantCounts = [];
private static MetaFileManager? _dataManager;
private static readonly Dictionary<ImcIdentifier, int> VariantCounts = [];
private static MetaFileManager? _dataManager;
private static readonly ConcurrentDictionary<ImcIdentifier, CachedEntry> GlobalCachedDefaultEntries = [];
public static int GetVariantCount(ImcIdentifier identifier)
{
@ -26,23 +26,20 @@ public class ImcChecker
public readonly record struct CachedEntry(ImcEntry Entry, bool FileExists, bool VariantExists);
private readonly Dictionary<ImcIdentifier, CachedEntry> _cachedDefaultEntries = new();
private readonly MetaFileManager _metaFileManager;
public ImcChecker(MetaFileManager metaFileManager)
{
_metaFileManager = metaFileManager;
_dataManager = metaFileManager;
}
=> _dataManager = metaFileManager;
public CachedEntry GetDefaultEntry(ImcIdentifier identifier, bool storeCache)
public static CachedEntry GetDefaultEntry(ImcIdentifier identifier, bool storeCache)
{
if (_cachedDefaultEntries.TryGetValue(identifier, out var entry))
if (GlobalCachedDefaultEntries.TryGetValue(identifier, out var entry))
return entry;
if (_dataManager == null)
return new CachedEntry(default, false, false);
try
{
var e = ImcFile.GetDefault(_metaFileManager, identifier.GamePath(), identifier.EquipSlot, identifier.Variant, out var entryExists);
var e = ImcFile.GetDefault(_dataManager, identifier.GamePath(), identifier.EquipSlot, identifier.Variant, out var entryExists);
entry = new CachedEntry(e, true, entryExists);
}
catch (Exception)
@ -51,7 +48,7 @@ public class ImcChecker
}
if (storeCache)
_cachedDefaultEntries.Add(identifier, entry);
GlobalCachedDefaultEntries.TryAdd(identifier, entry);
return entry;
}

View file

@ -10,8 +10,7 @@ namespace Penumbra.Mods.Editor;
public class ModMetaEditor(
ModGroupEditor groupEditor,
MetaFileManager metaFileManager,
ImcChecker imcChecker) : MetaDictionary, IService
MetaFileManager metaFileManager) : MetaDictionary, IService
{
public sealed class OtherOptionData : HashSet<string>
{
@ -67,14 +66,14 @@ public class ModMetaEditor(
Changes = false;
}
public static bool DeleteDefaultValues(MetaFileManager metaFileManager, ImcChecker imcChecker, MetaDictionary dict)
public static bool DeleteDefaultValues(MetaFileManager metaFileManager, MetaDictionary dict)
{
var clone = dict.Clone();
dict.Clear();
var count = 0;
foreach (var (key, value) in clone.Imc)
{
var defaultEntry = imcChecker.GetDefaultEntry(key, false);
var defaultEntry = ImcChecker.GetDefaultEntry(key, false);
if (!defaultEntry.Entry.Equals(value))
{
dict.TryAdd(key, value);
@ -164,7 +163,7 @@ public class ModMetaEditor(
}
public void DeleteDefaultValues()
=> Changes = DeleteDefaultValues(metaFileManager, imcChecker, this);
=> Changes = DeleteDefaultValues(metaFileManager, this);
public void Apply(IModDataContainer container)
{

View file

@ -35,6 +35,7 @@ public class ImcModGroup(Mod mod) : IModGroup
public ImcIdentifier Identifier;
public ImcEntry DefaultEntry;
public bool AllVariants;
public bool OnlyAttributes;
public FullPath? FindBestMatch(Utf8GamePath gamePath)
@ -97,28 +98,36 @@ public class ImcModGroup(Mod mod) : IModGroup
public IModGroupEditDrawer EditDrawer(ModGroupEditDrawer editDrawer)
=> new ImcModGroupEditDrawer(editDrawer, this);
public ImcEntry GetEntry(ushort mask)
=> DefaultEntry with { AttributeMask = mask };
private ImcEntry GetEntry(Variant variant, ushort mask)
{
if (!OnlyAttributes)
return DefaultEntry with { AttributeMask = mask };
var defaultEntry = ImcChecker.GetDefaultEntry(Identifier with { Variant = variant }, true);
if (defaultEntry.VariantExists)
return defaultEntry.Entry with { AttributeMask = mask };
return DefaultEntry with { AttributeMask = mask };
}
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, MetaDictionary manipulations)
{
if (IsDisabled(setting))
return;
var mask = GetCurrentMask(setting);
var entry = GetEntry(mask);
var mask = GetCurrentMask(setting);
if (AllVariants)
{
var count = ImcChecker.GetVariantCount(Identifier);
if (count == 0)
manipulations.TryAdd(Identifier, entry);
manipulations.TryAdd(Identifier, GetEntry(Identifier.Variant, mask));
else
for (var i = 0; i <= count; ++i)
manipulations.TryAdd(Identifier with { Variant = (Variant)i }, entry);
manipulations.TryAdd(Identifier with { Variant = (Variant)i }, GetEntry((Variant)i, mask));
}
else
{
manipulations.TryAdd(Identifier, entry);
manipulations.TryAdd(Identifier, GetEntry(Identifier.Variant, mask));
}
}
@ -138,6 +147,8 @@ public class ImcModGroup(Mod mod) : IModGroup
serializer.Serialize(jWriter, DefaultEntry);
jWriter.WritePropertyName(nameof(AllVariants));
jWriter.WriteValue(AllVariants);
jWriter.WritePropertyName(nameof(OnlyAttributes));
jWriter.WriteValue(OnlyAttributes);
jWriter.WritePropertyName("Options");
jWriter.WriteStartArray();
foreach (var option in OptionData)
@ -170,8 +181,9 @@ public class ImcModGroup(Mod mod) : IModGroup
var identifier = ImcIdentifier.FromJson(json[nameof(Identifier)] as JObject);
var ret = new ImcModGroup(mod)
{
DefaultEntry = json[nameof(DefaultEntry)]?.ToObject<ImcEntry>() ?? new ImcEntry(),
AllVariants = json[nameof(AllVariants)]?.ToObject<bool>() ?? false,
DefaultEntry = json[nameof(DefaultEntry)]?.ToObject<ImcEntry>() ?? new ImcEntry(),
AllVariants = json[nameof(AllVariants)]?.ToObject<bool>() ?? false,
OnlyAttributes = json[nameof(OnlyAttributes)]?.ToObject<bool>() ?? false,
};
if (!ModSaveGroup.ReadJsonBase(json, ret))
return null;

View file

@ -89,6 +89,16 @@ public sealed class ImcModGroupEditor(CommunicatorService communicator, SaveServ
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
}
public void ChangeOnlyAttributes(ImcModGroup group, bool onlyAttributes, SaveType saveType = SaveType.Queue)
{
if (group.OnlyAttributes == onlyAttributes)
return;
group.OnlyAttributes = onlyAttributes;
SaveService.Save(saveType, new ModSaveGroup(group, Config.ReplaceNonAsciiOnImport));
Communicator.ModOptionChanged.Invoke(ModOptionChangeType.OptionMetaChanged, group.Mod, group, null, null, -1);
}
public void ChangeCanBeDisabled(ImcModGroup group, bool canBeDisabled, SaveType saveType = SaveType.Queue)
{
if (group.CanBeDisabled == canBeDisabled)

View file

@ -25,8 +25,7 @@ public partial class ModCreator(
Configuration config,
ModDataEditor dataEditor,
MetaFileManager metaFileManager,
GamePathParser gamePathParser,
ImcChecker imcChecker) : IService
GamePathParser gamePathParser) : IService
{
public readonly Configuration Config = config;
@ -86,7 +85,7 @@ public partial class ModCreator(
{
foreach (var container in mod.AllDataContainers)
{
if (ModMetaEditor.DeleteDefaultValues(metaFileManager, imcChecker, container.Manipulations))
if (ModMetaEditor.DeleteDefaultValues(metaFileManager, container.Manipulations))
saveService.ImmediateSaveSync(new ModSaveGroup(container, Config.ReplaceNonAsciiOnImport));
}
}
@ -235,7 +234,7 @@ public partial class ModCreator(
DeleteDeleteList(deleteList, delete);
var changes = oldSize < option.Manipulations.Count;
if (deleteDefault && !Config.KeepDefaultMetaChanges)
changes |= ModMetaEditor.DeleteDefaultValues(metaFileManager, imcChecker, option.Manipulations);
changes |= ModMetaEditor.DeleteDefaultValues(metaFileManager, option.Manipulations);
return (changes, deleteList);
}

View file

@ -30,7 +30,7 @@ public sealed class ImcMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile
}
private void UpdateEntry()
=> (Entry, _fileExists, _) = MetaFiles.ImcChecker.GetDefaultEntry(Identifier, true);
=> (Entry, _fileExists, _) = ImcChecker.GetDefaultEntry(Identifier, true);
protected override void DrawNew()
{
@ -54,7 +54,7 @@ public sealed class ImcMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile
DrawMetaButtons(identifier, entry);
DrawIdentifier(identifier);
var defaultEntry = MetaFiles.ImcChecker.GetDefaultEntry(identifier, true).Entry;
var defaultEntry = ImcChecker.GetDefaultEntry(identifier, true).Entry;
if (DrawEntry(defaultEntry, ref entry, true))
Editor.Changes |= Editor.Update(identifier, entry);
}

View file

@ -24,13 +24,11 @@ public class AddGroupDrawer : IUiService
private bool _imcFileExists;
private bool _entryExists;
private bool _entryInvalid;
private readonly ImcChecker _imcChecker;
private readonly ModManager _modManager;
public AddGroupDrawer(ModManager modManager, ImcChecker imcChecker)
public AddGroupDrawer(ModManager modManager)
{
_modManager = modManager;
_imcChecker = imcChecker;
UpdateEntry();
}
@ -142,7 +140,7 @@ public class AddGroupDrawer : IUiService
private void UpdateEntry()
{
(_defaultEntry, _imcFileExists, _entryExists) = _imcChecker.GetDefaultEntry(_imcIdentifier, false);
(_defaultEntry, _imcFileExists, _entryExists) = ImcChecker.GetDefaultEntry(_imcIdentifier, false);
_entryInvalid = !_imcIdentifier.Validate() || _defaultEntry.MaterialId == 0 || !_entryExists;
}
}

View file

@ -6,6 +6,7 @@ using OtterGui.Text;
using OtterGui.Text.Widget;
using OtterGuiInternal.Utility;
using Penumbra.GameData.Structs;
using Penumbra.Meta;
using Penumbra.Mods.Groups;
using Penumbra.Mods.Manager.OptionEditor;
using Penumbra.Mods.SubMods;
@ -18,18 +19,25 @@ public readonly struct ImcModGroupEditDrawer(ModGroupEditDrawer editor, ImcModGr
public void Draw()
{
var identifier = group.Identifier;
var defaultEntry = editor.ImcChecker.GetDefaultEntry(identifier, true).Entry;
var defaultEntry = ImcChecker.GetDefaultEntry(identifier, true).Entry;
var entry = group.DefaultEntry;
var changes = false;
var width = editor.AvailableWidth.X - ImUtf8.ItemInnerSpacing.X - ImUtf8.CalcTextSize("All Variants"u8).X;
var width = editor.AvailableWidth.X - 3 * ImUtf8.ItemInnerSpacing.X - ImUtf8.ItemSpacing.X - ImUtf8.CalcTextSize("All Variants"u8).X - ImUtf8.CalcTextSize("Only Attributes"u8).X - 2 * ImUtf8.FrameHeight;
ImUtf8.TextFramed(identifier.ToString(), 0, new Vector2(width, 0), borderColor: ImGui.GetColorU32(ImGuiCol.Border));
ImUtf8.SameLineInner();
var allVariants = group.AllVariants;
if (ImUtf8.Checkbox("All Variants"u8, ref allVariants))
editor.ModManager.OptionEditor.ImcEditor.ChangeAllVariants(group, allVariants);
ImUtf8.HoverTooltip("Make this group overwrite all corresponding variants for this identifier, not just the one specified."u8);
ImGui.SameLine();
var onlyAttributes = group.OnlyAttributes;
if (ImUtf8.Checkbox("Only Attributes"u8, ref onlyAttributes))
editor.ModManager.OptionEditor.ImcEditor.ChangeOnlyAttributes(group, onlyAttributes);
ImUtf8.HoverTooltip("Only overwrite the attribute flags and take all the other values from the game's default entry instead of the one configured here.\n\nMainly useful if used with All Variants to keep the material IDs for each variant."u8);
using (ImUtf8.Group())
{
ImUtf8.TextFrameAligned("Material ID"u8);