Add the option to omit mch offhands from changed items.

This commit is contained in:
Ottermandias 2024-05-21 18:24:21 +02:00
parent bb56faa288
commit e85b84dafe
13 changed files with 192 additions and 117 deletions

View file

@ -6,6 +6,7 @@ using Penumbra.Communication;
using Penumbra.Mods.Editor; using Penumbra.Mods.Editor;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Mods.Manager; using Penumbra.Mods.Manager;
using Penumbra.Util;
namespace Penumbra.Collections.Cache; namespace Penumbra.Collections.Cache;
@ -439,9 +440,12 @@ public sealed class CollectionCache : IDisposable
foreach (var (manip, mod) in Meta) foreach (var (manip, mod) in Meta)
{ {
ModCacheManager.ComputeChangedItems(identifier, items, manip); identifier.MetaChangedItems(items, manip);
AddItems(mod); AddItems(mod);
} }
if (_manager.Config.HideMachinistOffhandFromChangedItems)
_changedItems.RemoveMachinistOffhands();
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -25,6 +25,7 @@ public class CollectionCacheManager : IDisposable
private readonly ModStorage _modStorage; private readonly ModStorage _modStorage;
private readonly CollectionStorage _storage; private readonly CollectionStorage _storage;
private readonly ActiveCollections _active; private readonly ActiveCollections _active;
internal readonly Configuration Config;
internal readonly ResolvedFileChanged ResolvedFileChanged; internal readonly ResolvedFileChanged ResolvedFileChanged;
internal readonly MetaFileManager MetaFileManager; internal readonly MetaFileManager MetaFileManager;
internal readonly ResourceLoader ResourceLoader; internal readonly ResourceLoader ResourceLoader;
@ -40,7 +41,8 @@ public class CollectionCacheManager : IDisposable
=> _storage.Where(c => c.HasCache); => _storage.Where(c => c.HasCache);
public CollectionCacheManager(FrameworkManager framework, CommunicatorService communicator, TempModManager tempMods, ModStorage modStorage, public CollectionCacheManager(FrameworkManager framework, CommunicatorService communicator, TempModManager tempMods, ModStorage modStorage,
MetaFileManager metaFileManager, ActiveCollections active, CollectionStorage storage, ResourceLoader resourceLoader) MetaFileManager metaFileManager, ActiveCollections active, CollectionStorage storage, ResourceLoader resourceLoader,
Configuration config)
{ {
_framework = framework; _framework = framework;
_communicator = communicator; _communicator = communicator;
@ -50,6 +52,7 @@ public class CollectionCacheManager : IDisposable
_active = active; _active = active;
_storage = storage; _storage = storage;
ResourceLoader = resourceLoader; ResourceLoader = resourceLoader;
Config = config;
ResolvedFileChanged = _communicator.ResolvedFileChanged; ResolvedFileChanged = _communicator.ResolvedFileChanged;
if (!_active.Individuals.IsLoaded) if (!_active.Individuals.IsLoaded)
@ -260,7 +263,8 @@ public class CollectionCacheManager : IDisposable
} }
/// <summary> Prepare Changes by removing mods from caches with collections or add or reload mods. </summary> /// <summary> Prepare Changes by removing mods from caches with collections or add or reload mods. </summary>
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container, int movedToIdx) private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
int movedToIdx)
{ {
if (type is ModOptionChangeType.PrepareChange) if (type is ModOptionChangeType.PrepareChange)
{ {

View file

@ -51,6 +51,7 @@ public class Configuration : IPluginConfiguration, ISavable
public bool ReplaceNonAsciiOnImport { get; set; } = false; public bool ReplaceNonAsciiOnImport { get; set; } = false;
public bool HidePrioritiesInSelector { get; set; } = false; public bool HidePrioritiesInSelector { get; set; } = false;
public bool HideRedrawBar { get; set; } = false; public bool HideRedrawBar { get; set; } = false;
public bool HideMachinistOffhandFromChangedItems { get; set; } = true;
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio; public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
public int OptionGroupCollapsibleMin { get; set; } = 5; public int OptionGroupCollapsibleMin { get; set; } = 5;

View file

@ -1,5 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
@ -40,6 +41,7 @@ public interface IModGroup
public int GetIndex(); public int GetIndex();
public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations); public void AddData(Setting setting, Dictionary<Utf8GamePath, FullPath> redirections, HashSet<MetaManipulation> manipulations);
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems);
/// <summary> Ensure that a value is valid for a group. </summary> /// <summary> Ensure that a value is valid for a group. </summary>
public Setting FixSetting(Setting setting); public Setting FixSetting(Setting setting);

View file

@ -3,12 +3,14 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods.Groups; namespace Penumbra.Mods.Groups;
@ -119,6 +121,9 @@ public class ImcModGroup(Mod mod) : IModGroup
manipulations.Add(imc); manipulations.Add(imc);
} }
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems)
=> identifier.MetaChangedItems(changedItems, GetManip(0));
public Setting FixSetting(Setting setting) public Setting FixSetting(Setting setting)
=> new(setting.Value & (((1ul << OptionData.Count) - 1) | (CanBeDisabled ? 1ul << DisabledIndex : 0))); => new(setting.Value & (((1ul << OptionData.Count) - 1) | (CanBeDisabled ? 1ul << DisabledIndex : 0)));

View file

@ -4,10 +4,12 @@ using Newtonsoft.Json.Linq;
using OtterGui; using OtterGui;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods.Groups; namespace Penumbra.Mods.Groups;
@ -114,6 +116,12 @@ public sealed class MultiModGroup(Mod mod) : IModGroup, ITexToolsGroup
} }
} }
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems)
{
foreach (var container in DataContainers)
identifier.AddChangedItems(container, changedItems);
}
public void WriteJson(JsonTextWriter jWriter, JsonSerializer serializer, DirectoryInfo? basePath = null) public void WriteJson(JsonTextWriter jWriter, JsonSerializer serializer, DirectoryInfo? basePath = null)
{ {
ModSaveGroup.WriteJsonBase(jWriter, this); ModSaveGroup.WriteJsonBase(jWriter, this);

View file

@ -2,10 +2,12 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using OtterGui; using OtterGui;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.GameData.Data;
using Penumbra.Meta.Manipulations; using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Settings; using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using Penumbra.Util;
namespace Penumbra.Mods.Groups; namespace Penumbra.Mods.Groups;
@ -99,6 +101,12 @@ public sealed class SingleModGroup(Mod mod) : IModGroup, ITexToolsGroup
OptionData[setting.AsIndex].AddDataTo(redirections, manipulations); OptionData[setting.AsIndex].AddDataTo(redirections, manipulations);
} }
public void AddChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems)
{
foreach (var container in DataContainers)
identifier.AddChangedItems(container, changedItems);
}
public Setting FixSetting(Setting setting) public Setting FixSetting(Setting setting)
=> OptionData.Count == 0 ? Setting.Zero : new Setting(Math.Min(setting.Value, (ulong)(OptionData.Count - 1))); => OptionData.Count == 0 ? Setting.Zero : new Setting(Math.Min(setting.Value, (ulong)(OptionData.Count - 1)));

View file

@ -1,26 +1,27 @@
using Penumbra.Communication; using Penumbra.Communication;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Groups; using Penumbra.Mods.Groups;
using Penumbra.Mods.Manager.OptionEditor; using Penumbra.Mods.Manager.OptionEditor;
using Penumbra.Mods.SubMods; using Penumbra.Mods.SubMods;
using Penumbra.Services; using Penumbra.Services;
using Penumbra.Util;
namespace Penumbra.Mods.Manager; namespace Penumbra.Mods.Manager;
public class ModCacheManager : IDisposable public class ModCacheManager : IDisposable
{ {
private readonly Configuration _config;
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly ObjectIdentification _identifier; private readonly ObjectIdentification _identifier;
private readonly ModStorage _modManager; private readonly ModStorage _modManager;
private bool _updatingItems = false; private bool _updatingItems = false;
public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage) public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage, Configuration config)
{ {
_communicator = communicator; _communicator = communicator;
_identifier = identifier; _identifier = identifier;
_modManager = modStorage; _modManager = modStorage;
_config = config;
_communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ModCacheManager); _communicator.ModOptionChanged.Subscribe(OnModOptionChange, ModOptionChanged.Priority.ModCacheManager);
_communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager); _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager);
@ -38,75 +39,8 @@ public class ModCacheManager : IDisposable
_communicator.ModDiscoveryFinished.Unsubscribe(OnModDiscoveryFinished); _communicator.ModDiscoveryFinished.Unsubscribe(OnModDiscoveryFinished);
} }
/// <summary> Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. </summary> private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
public static void ComputeChangedItems(ObjectIdentification identifier, IDictionary<string, object?> changedItems, MetaManipulation manip) int fromIdx)
{
switch (manip.ManipulationType)
{
case MetaManipulation.Type.Imc:
switch (manip.Imc.ObjectType)
{
case ObjectType.Equipment:
case ObjectType.Accessory:
identifier.Identify(changedItems,
GamePaths.Equipment.Mtrl.Path(manip.Imc.PrimaryId, GenderRace.MidlanderMale, manip.Imc.EquipSlot, manip.Imc.Variant,
"a"));
break;
case ObjectType.Weapon:
identifier.Identify(changedItems,
GamePaths.Weapon.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a"));
break;
case ObjectType.DemiHuman:
identifier.Identify(changedItems,
GamePaths.DemiHuman.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.EquipSlot, manip.Imc.Variant,
"a"));
break;
case ObjectType.Monster:
identifier.Identify(changedItems,
GamePaths.Monster.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a"));
break;
}
break;
case MetaManipulation.Type.Eqdp:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Eqdp.SetId, Names.CombinedRace(manip.Eqdp.Gender, manip.Eqdp.Race), manip.Eqdp.Slot));
break;
case MetaManipulation.Type.Eqp:
identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(manip.Eqp.SetId, GenderRace.MidlanderMale, manip.Eqp.Slot));
break;
case MetaManipulation.Type.Est:
switch (manip.Est.Slot)
{
case EstManipulation.EstType.Hair:
changedItems.TryAdd($"Customization: {manip.Est.Race} {manip.Est.Gender} Hair (Hair) {manip.Est.SetId}", null);
break;
case EstManipulation.EstType.Face:
changedItems.TryAdd($"Customization: {manip.Est.Race} {manip.Est.Gender} Face (Face) {manip.Est.SetId}", null);
break;
case EstManipulation.EstType.Body:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Est.SetId, Names.CombinedRace(manip.Est.Gender, manip.Est.Race),
EquipSlot.Body));
break;
case EstManipulation.EstType.Head:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Est.SetId, Names.CombinedRace(manip.Est.Gender, manip.Est.Race),
EquipSlot.Head));
break;
}
break;
case MetaManipulation.Type.Gmp:
identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(manip.Gmp.SetId, GenderRace.MidlanderMale, EquipSlot.Head));
break;
case MetaManipulation.Type.Rsp:
changedItems.TryAdd($"{manip.Rsp.SubRace.ToName()} {manip.Rsp.Attribute.ToFullString()}", null);
break;
}
}
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container, int fromIdx)
{ {
switch (type) switch (type)
{ {
@ -194,16 +128,14 @@ public class ModCacheManager : IDisposable
private void UpdateChangedItems(Mod mod) private void UpdateChangedItems(Mod mod)
{ {
var changedItems = (SortedList<string, object?>)mod.ChangedItems; mod.ChangedItems.Clear();
changedItems.Clear();
foreach (var gamePath in mod.AllDataContainers.SelectMany(m => m.Files.Keys.Concat(m.FileSwaps.Keys)))
_identifier.Identify(changedItems, gamePath.ToString());
foreach (var manip in mod.AllDataContainers.SelectMany(m => m.Manipulations)) _identifier.AddChangedItems(mod.Default, mod.ChangedItems);
ComputeChangedItems(_identifier, changedItems, manip); foreach (var group in mod.Groups)
group.AddChangedItems(_identifier, mod.ChangedItems);
foreach(var imcGroup in mod.Groups.OfType<ImcModGroup>()) if (_config.HideMachinistOffhandFromChangedItems)
ComputeChangedItems(_identifier, changedItems, imcGroup.GetManip(0)); mod.ChangedItems.RemoveMachinistOffhands();
mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant())); mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant()));
} }

View file

@ -5,12 +5,8 @@ using Penumbra.Mods.Editor;
namespace Penumbra.Mods.Manager; namespace Penumbra.Mods.Manager;
public class ModImportManager : IDisposable public class ModImportManager(ModManager modManager, Configuration config, ModEditor modEditor) : IDisposable
{ {
private readonly ModManager _modManager;
private readonly Configuration _config;
private readonly ModEditor _modEditor;
private readonly ConcurrentQueue<string[]> _modsToUnpack = new(); private readonly ConcurrentQueue<string[]> _modsToUnpack = new();
/// <summary> Mods need to be added thread-safely outside of iteration. </summary> /// <summary> Mods need to be added thread-safely outside of iteration. </summary>
@ -26,13 +22,6 @@ public class ModImportManager : IDisposable
=> _modsToAdd; => _modsToAdd;
public ModImportManager(ModManager modManager, Configuration config, ModEditor modEditor)
{
_modManager = modManager;
_config = config;
_modEditor = modEditor;
}
public void TryUnpacking() public void TryUnpacking()
{ {
if (Importing || !_modsToUnpack.TryDequeue(out var newMods)) if (Importing || !_modsToUnpack.TryDequeue(out var newMods))
@ -51,7 +40,7 @@ public class ModImportManager : IDisposable
if (files.Length == 0) if (files.Length == 0)
return; return;
_import = new TexToolsImporter(files.Length, files, AddNewMod, _config, _modEditor, _modManager, _modEditor.Compactor); _import = new TexToolsImporter(files.Length, files, AddNewMod, config, modEditor, modManager, modEditor.Compactor);
} }
public bool Importing public bool Importing
@ -87,8 +76,8 @@ public class ModImportManager : IDisposable
return false; return false;
} }
_modManager.AddMod(directory); modManager.AddMod(directory);
mod = _modManager.LastOrDefault(); mod = modManager.LastOrDefault();
return mod != null && mod.ModPath == directory; return mod != null && mod.ModPath == directory;
} }

View file

@ -99,7 +99,7 @@ public sealed class Mod : IMod
} }
// Cache // Cache
public readonly IReadOnlyDictionary<string, object?> ChangedItems = new SortedList<string, object?>(); public readonly SortedList<string, object?> ChangedItems = new();
public string LowerChangedItemsString { get; internal set; } = string.Empty; public string LowerChangedItemsString { get; internal set; } = string.Empty;
public string AllTagsLower { get; internal set; } = string.Empty; public string AllTagsLower { get; internal set; } = string.Empty;

View file

@ -123,8 +123,7 @@ public sealed class ModGroupEditDrawer(
ModManager modManager, ModManager modManager,
Configuration config, Configuration config,
FilenameService filenames, FilenameService filenames,
DescriptionEditPopup descriptionPopup, DescriptionEditPopup descriptionPopup) : IUiService
MetaFileManager metaManager) : IUiService
{ {
private static ReadOnlySpan<byte> DragDropLabel private static ReadOnlySpan<byte> DragDropLabel
=> "##DragOption"u8; => "##DragOption"u8;

View file

@ -428,6 +428,14 @@ public class SettingsTab : ITab
_config.Ephemeral.Save(); _config.Ephemeral.Save();
} }
}); });
Checkbox("Omit Machinist Offhands in Changed Items",
"Omits all Aetherotransformers (machinist offhands) in the changed items tabs because any change on them changes all of them at the moment.\n\n"
+ "Changing this triggers a rediscovery of your mods so all changed items can be updated.",
_config.HideMachinistOffhandFromChangedItems, v =>
{
_config.HideMachinistOffhandFromChangedItems = v;
_modManager.DiscoverMods();
});
Checkbox("Hide Priority Numbers in Mod Selector", Checkbox("Hide Priority Numbers in Mod Selector",
"Hides the bracketed non-zero priority numbers displayed in the mod selector when there is enough space for them.", "Hides the bracketed non-zero priority numbers displayed in the mod selector when there is enough space for them.",
_config.HidePrioritiesInSelector, v => _config.HidePrioritiesInSelector = v); _config.HidePrioritiesInSelector, v => _config.HidePrioritiesInSelector = v);

View file

@ -0,0 +1,115 @@
using OtterGui.Classes;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Meta.Manipulations;
using Penumbra.Mods.Editor;
using Penumbra.Mods.SubMods;
namespace Penumbra.Util;
public static class IdentifierExtensions
{
/// <summary> Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. </summary>
public static void MetaChangedItems(this ObjectIdentification identifier, IDictionary<string, object?> changedItems,
MetaManipulation manip)
{
switch (manip.ManipulationType)
{
case MetaManipulation.Type.Imc:
switch (manip.Imc.ObjectType)
{
case ObjectType.Equipment:
case ObjectType.Accessory:
identifier.Identify(changedItems,
GamePaths.Equipment.Mtrl.Path(manip.Imc.PrimaryId, GenderRace.MidlanderMale, manip.Imc.EquipSlot, manip.Imc.Variant,
"a"));
break;
case ObjectType.Weapon:
identifier.Identify(changedItems,
GamePaths.Weapon.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a"));
break;
case ObjectType.DemiHuman:
identifier.Identify(changedItems,
GamePaths.DemiHuman.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.EquipSlot, manip.Imc.Variant,
"a"));
break;
case ObjectType.Monster:
identifier.Identify(changedItems,
GamePaths.Monster.Mtrl.Path(manip.Imc.PrimaryId, manip.Imc.SecondaryId, manip.Imc.Variant, "a"));
break;
}
break;
case MetaManipulation.Type.Eqdp:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Eqdp.SetId, Names.CombinedRace(manip.Eqdp.Gender, manip.Eqdp.Race), manip.Eqdp.Slot));
break;
case MetaManipulation.Type.Eqp:
identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(manip.Eqp.SetId, GenderRace.MidlanderMale, manip.Eqp.Slot));
break;
case MetaManipulation.Type.Est:
switch (manip.Est.Slot)
{
case EstManipulation.EstType.Hair:
changedItems.TryAdd($"Customization: {manip.Est.Race} {manip.Est.Gender} Hair (Hair) {manip.Est.SetId}", null);
break;
case EstManipulation.EstType.Face:
changedItems.TryAdd($"Customization: {manip.Est.Race} {manip.Est.Gender} Face (Face) {manip.Est.SetId}", null);
break;
case EstManipulation.EstType.Body:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Est.SetId, Names.CombinedRace(manip.Est.Gender, manip.Est.Race),
EquipSlot.Body));
break;
case EstManipulation.EstType.Head:
identifier.Identify(changedItems,
GamePaths.Equipment.Mdl.Path(manip.Est.SetId, Names.CombinedRace(manip.Est.Gender, manip.Est.Race),
EquipSlot.Head));
break;
}
break;
case MetaManipulation.Type.Gmp:
identifier.Identify(changedItems, GamePaths.Equipment.Mdl.Path(manip.Gmp.SetId, GenderRace.MidlanderMale, EquipSlot.Head));
break;
case MetaManipulation.Type.Rsp:
changedItems.TryAdd($"{manip.Rsp.SubRace.ToName()} {manip.Rsp.Attribute.ToFullString()}", null);
break;
}
}
public static void AddChangedItems(this ObjectIdentification identifier, IModDataContainer container,
IDictionary<string, object?> changedItems)
{
foreach (var gamePath in container.Files.Keys.Concat(container.FileSwaps.Keys))
identifier.Identify(changedItems, gamePath.ToString());
foreach (var manip in container.Manipulations)
MetaChangedItems(identifier, changedItems, manip);
}
public static void RemoveMachinistOffhands(this SortedList<string, object?> changedItems)
{
for (var i = 0; i < changedItems.Count; i++)
{
{
var value = changedItems.Values[i];
if (value is EquipItem { Type: FullEquipType.GunOff })
changedItems.RemoveAt(i--);
}
}
}
public static void RemoveMachinistOffhands(this SortedList<string, (SingleArray<IMod>, object?)> changedItems)
{
for (var i = 0; i < changedItems.Count; i++)
{
{
var value = changedItems.Values[i].Item2;
if (value is EquipItem { Type: FullEquipType.GunOff })
changedItems.RemoveAt(i--);
}
}
}
}