diff --git a/Penumbra.GameData b/Penumbra.GameData index 98bd4e99..263bfb49 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 98bd4e9946ded20cb5d54182883e73f344fe2d26 +Subproject commit 263bfb49c998700197a18ad99fa1daadc8736f5d diff --git a/Penumbra/Collections/Cache/EqdpCache.cs b/Penumbra/Collections/Cache/EqdpCache.cs index db40fcb6..1b9c8156 100644 --- a/Penumbra/Collections/Cache/EqdpCache.cs +++ b/Penumbra/Collections/Cache/EqdpCache.cs @@ -5,6 +5,7 @@ using System.Linq; using OtterGui; using OtterGui.Filesystem; using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; using Penumbra.Interop.Services; using Penumbra.Interop.Structs; using Penumbra.Meta; @@ -48,7 +49,7 @@ public readonly struct EqdpCache : IDisposable foreach (var file in _eqdpFiles.OfType()) { var relevant = CharacterUtility.RelevantIndices[file.Index.Value]; - file.Reset(_eqdpManipulations.Where(m => m.FileIndex() == relevant).Select(m => (int)m.SetId)); + file.Reset(_eqdpManipulations.Where(m => m.FileIndex() == relevant).Select(m => (SetId) m.SetId)); } _eqdpManipulations.Clear(); diff --git a/Penumbra/Collections/Cache/EqpCache.cs b/Penumbra/Collections/Cache/EqpCache.cs index 5fe40426..4e87a34a 100644 --- a/Penumbra/Collections/Cache/EqpCache.cs +++ b/Penumbra/Collections/Cache/EqpCache.cs @@ -32,7 +32,7 @@ public struct EqpCache : IDisposable if (_eqpFile == null) return; - _eqpFile.Reset(_eqpManipulations.Select(m => (int)m.SetId)); + _eqpFile.Reset(_eqpManipulations.Select(m => m.SetId)); _eqpManipulations.Clear(); } diff --git a/Penumbra/Collections/Cache/GmpCache.cs b/Penumbra/Collections/Cache/GmpCache.cs index 4e485036..1c25b9e5 100644 --- a/Penumbra/Collections/Cache/GmpCache.cs +++ b/Penumbra/Collections/Cache/GmpCache.cs @@ -29,7 +29,7 @@ public struct GmpCache : IDisposable if( _gmpFile == null ) return; - _gmpFile.Reset( _gmpManipulations.Select( m => ( int )m.SetId ) ); + _gmpFile.Reset( _gmpManipulations.Select( m => m.SetId ) ); _gmpManipulations.Clear(); } diff --git a/Penumbra/Collections/Cache/ImcCache.cs b/Penumbra/Collections/Cache/ImcCache.cs index 3d097b7b..28680d11 100644 --- a/Penumbra/Collections/Cache/ImcCache.cs +++ b/Penumbra/Collections/Cache/ImcCache.cs @@ -99,7 +99,7 @@ public readonly struct ImcCache : IDisposable return true; } - var def = ImcFile.GetDefault(manager, file.Path, m.EquipSlot, m.Variant, out _); + var def = ImcFile.GetDefault(manager, file.Path, m.EquipSlot, m.Variant.Id, out _); var manip = m.Copy(def); if (!manip.Apply(file)) return false; diff --git a/Penumbra/Collections/Manager/IndividualCollections.Access.cs b/Penumbra/Collections/Manager/IndividualCollections.Access.cs index 93c555b3..b1b0698a 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Access.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Access.cs @@ -59,7 +59,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (!_config.UseOwnerNameForCharacterCollection) return false; - identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld, + identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); return CheckWorlds(identifier, out collection); } diff --git a/Penumbra/Collections/Manager/IndividualCollections.cs b/Penumbra/Collections/Manager/IndividualCollections.cs index 065d6a79..c4d9c516 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.cs @@ -135,7 +135,7 @@ public sealed partial class IndividualCollections _ => throw new NotImplementedException(), }; return table.Where(kvp => kvp.Value == name) - .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld, identifier.Kind, + .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id, identifier.Kind, kvp.Key)).ToArray(); } diff --git a/Penumbra/Import/TexToolsMeta.Deserialization.cs b/Penumbra/Import/TexToolsMeta.Deserialization.cs index 92d2aa5a..49501d91 100644 --- a/Penumbra/Import/TexToolsMeta.Deserialization.cs +++ b/Penumbra/Import/TexToolsMeta.Deserialization.cs @@ -118,7 +118,7 @@ public partial class TexToolsMeta var partIdx = ImcFile.PartIndex(manip.EquipSlot); // Gets turned to unknown for things without equip, and unknown turns to 0. foreach (var value in values) { - if (_keepDefault || !value.Equals(def.GetEntry(partIdx, i))) + if (_keepDefault || !value.Equals(def.GetEntry(partIdx, (Variant) i))) { var imc = new ImcManipulation(manip.ObjectType, manip.BodySlot, manip.PrimaryId, manip.SecondaryId, i, manip.EquipSlot, value); diff --git a/Penumbra/Import/TexToolsMeta.Export.cs b/Penumbra/Import/TexToolsMeta.Export.cs index bee31cb2..7f455ab0 100644 --- a/Penumbra/Import/TexToolsMeta.Export.cs +++ b/Penumbra/Import/TexToolsMeta.Export.cs @@ -152,7 +152,7 @@ public partial class TexToolsMeta for( var i = 0; i <= baseFile.Count; ++i ) { - var entry = baseFile.GetEntry( partIdx, i ); + var entry = baseFile.GetEntry( partIdx, (Variant)i ); b.Write( entry.MaterialId ); b.Write( entry.DecalId ); b.Write( entry.AttributeAndSound ); @@ -184,7 +184,7 @@ public partial class TexToolsMeta foreach( var manip in manips ) { b.Write( ( ushort )Names.CombinedRace( manip.Est.Gender, manip.Est.Race ) ); - b.Write( manip.Est.SetId ); + b.Write( manip.Est.SetId.Id ); b.Write( manip.Est.Entry ); } diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index 8220c629..67d9e96d 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -244,7 +244,7 @@ public unsafe class CollectionResolver if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == null) return null; - var id = _actors.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld, + var id = _actors.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); return CheckYourself(id, owner) diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.cs b/Penumbra/Interop/ResourceTree/ResolveContext.cs index 54940f3c..90ee1a16 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.cs @@ -225,10 +225,10 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide { "chara" => SafeGet(path, 1) switch { - "accessory" => IsMatchEquipment(path[2..], $"a{Equipment.Set.Value:D4}"), - "equipment" => IsMatchEquipment(path[2..], $"e{Equipment.Set.Value:D4}"), + "accessory" => IsMatchEquipment(path[2..], $"a{Equipment.Set.Id:D4}"), + "equipment" => IsMatchEquipment(path[2..], $"e{Equipment.Set.Id:D4}"), "monster" => SafeGet(path, 2) == $"m{Skeleton:D4}", - "weapon" => IsMatchEquipment(path[2..], $"w{Equipment.Set.Value:D4}"), + "weapon" => IsMatchEquipment(path[2..], $"w{Equipment.Set.Id:D4}"), _ => null, }, _ => null, @@ -238,7 +238,7 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide => SafeGet(path, 0) == equipmentDir ? SafeGet(path, 1) switch { - "material" => SafeGet(path, 2) == $"v{Equipment.Variant:D4}", + "material" => SafeGet(path, 2) == $"v{Equipment.Variant.Id:D4}", _ => null, } : false; diff --git a/Penumbra/Meta/Files/EqdpFile.cs b/Penumbra/Meta/Files/EqdpFile.cs index 14275467..6d1b5476 100644 --- a/Penumbra/Meta/Files/EqdpFile.cs +++ b/Penumbra/Meta/Files/EqdpFile.cs @@ -40,21 +40,21 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile public int Count => (Length - DataOffset) / EqdpEntrySize; - public EqdpEntry this[int idx] + public EqdpEntry this[SetId id] { get { - if (idx >= Count || idx < 0) + if (id.Id >= Count) throw new IndexOutOfRangeException(); - return (EqdpEntry)(*(ushort*)(Data + DataOffset + EqdpEntrySize * idx)); + return (EqdpEntry)(*(ushort*)(Data + DataOffset + EqdpEntrySize * id.Id)); } set { - if (idx >= Count || idx < 0) + if (id.Id >= Count) throw new IndexOutOfRangeException(); - *(ushort*)(Data + DataOffset + EqdpEntrySize * idx) = (ushort)value; + *(ushort*)(Data + DataOffset + EqdpEntrySize * id.Id) = (ushort)value; } } @@ -81,7 +81,7 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile MemoryUtility.MemSet(myDataPtr, 0, Length - (int)((byte*)myDataPtr - Data)); } - public void Reset(IEnumerable entries) + public void Reset(IEnumerable entries) { foreach (var entry in entries) this[entry] = GetDefault(entry); @@ -103,18 +103,18 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile Reset(); } - public EqdpEntry GetDefault(int setIdx) - => GetDefault(Manager, Index, setIdx); + public EqdpEntry GetDefault(SetId setId) + => GetDefault(Manager, Index, setId); - public static EqdpEntry GetDefault(MetaFileManager manager, CharacterUtility.InternalIndex idx, int setIdx) - => GetDefault((byte*)manager.CharacterUtility.DefaultResource(idx).Address, setIdx); + public static EqdpEntry GetDefault(MetaFileManager manager, CharacterUtility.InternalIndex idx, SetId setId) + => GetDefault((byte*)manager.CharacterUtility.DefaultResource(idx).Address, setId); - public static EqdpEntry GetDefault(byte* data, int setIdx) + public static EqdpEntry GetDefault(byte* data, SetId setId) { var blockSize = *(ushort*)(data + IdentifierSize); var totalBlockCount = *(ushort*)(data + IdentifierSize + 2); - var blockIdx = setIdx / blockSize; + var blockIdx = setId.Id / blockSize; if (blockIdx >= totalBlockCount) return 0; @@ -123,9 +123,9 @@ public sealed unsafe class ExpandedEqdpFile : MetaBaseFile return 0; var blockData = (ushort*)(data + IdentifierSize + PreambleSize + totalBlockCount * 2 + block * 2); - return (EqdpEntry)(*(blockData + setIdx % blockSize)); + return (EqdpEntry)(*(blockData + setId.Id % blockSize)); } - public static EqdpEntry GetDefault(MetaFileManager manager, GenderRace raceCode, bool accessory, int setIdx) - => GetDefault(manager, CharacterUtility.ReverseIndices[(int)CharacterUtilityData.EqdpIdx(raceCode, accessory)], setIdx); + public static EqdpEntry GetDefault(MetaFileManager manager, GenderRace raceCode, bool accessory, SetId setId) + => GetDefault(manager, CharacterUtility.ReverseIndices[(int)CharacterUtilityData.EqdpIdx(raceCode, accessory)], setId); } diff --git a/Penumbra/Meta/Files/EqpGmpFile.cs b/Penumbra/Meta/Files/EqpGmpFile.cs index e21e18c7..71563ef9 100644 --- a/Penumbra/Meta/Files/EqpGmpFile.cs +++ b/Penumbra/Meta/Files/EqpGmpFile.cs @@ -28,26 +28,26 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile public ulong ControlBlock => *(ulong*)Data; - protected ulong GetInternal(int idx) + protected ulong GetInternal(SetId idx) { - return idx switch + return idx.Id switch { >= Count => throw new IndexOutOfRangeException(), <= 1 => *((ulong*)Data + 1), - _ => *((ulong*)Data + idx), + _ => *((ulong*)Data + idx.Id), }; } - protected void SetInternal(int idx, ulong value) + protected void SetInternal(SetId idx, ulong value) { - idx = idx switch + idx = idx.Id switch { >= Count => throw new IndexOutOfRangeException(), <= 0 => 1, _ => idx, }; - *((ulong*)Data + idx) = value; + *((ulong*)Data + idx.Id) = value; } protected virtual void SetEmptyBlock(int idx) @@ -85,13 +85,13 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile Reset(); } - protected static ulong GetDefaultInternal(MetaFileManager manager, CharacterUtility.InternalIndex fileIndex, int setIdx, ulong def) + protected static ulong GetDefaultInternal(MetaFileManager manager, CharacterUtility.InternalIndex fileIndex, SetId setId, ulong def) { var data = (byte*)manager.CharacterUtility.DefaultResource(fileIndex).Address; - if (setIdx == 0) - setIdx = 1; + if (setId == 0) + setId = 1; - var blockIdx = setIdx / BlockSize; + var blockIdx = setId.Id / BlockSize; if (blockIdx >= NumBlocks) return def; @@ -101,7 +101,7 @@ public unsafe class ExpandedEqpGmpBase : MetaBaseFile return def; var count = BitOperations.PopCount(control & (blockBit - 1)); - var idx = setIdx % BlockSize; + var idx = setId.Id % BlockSize; var ptr = (ulong*)data + BlockSize * count + idx; return *ptr; } @@ -116,14 +116,14 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable : base(manager, false) { } - public EqpEntry this[int idx] + public EqpEntry this[SetId idx] { get => (EqpEntry)GetInternal(idx); set => SetInternal(idx, (ulong)value); } - public static EqpEntry GetDefault(MetaFileManager manager, int setIdx) + public static EqpEntry GetDefault(MetaFileManager manager, SetId setIdx) => (EqpEntry)GetDefaultInternal(manager, InternalIndex, setIdx, (ulong)Eqp.DefaultEntry); protected override unsafe void SetEmptyBlock(int idx) @@ -134,7 +134,7 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable *ptr = (ulong)Eqp.DefaultEntry; } - public void Reset(IEnumerable entries) + public void Reset(IEnumerable entries) { foreach (var entry in entries) this[entry] = GetDefault(Manager, entry); @@ -142,7 +142,7 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable public IEnumerator GetEnumerator() { - for (var idx = 1; idx < Count; ++idx) + for (ushort idx = 1; idx < Count; ++idx) yield return this[idx]; } @@ -159,16 +159,16 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable : base(manager, true) { } - public GmpEntry this[int idx] + public GmpEntry this[SetId idx] { get => (GmpEntry)GetInternal(idx); set => SetInternal(idx, (ulong)value); } - public static GmpEntry GetDefault(MetaFileManager manager, int setIdx) + public static GmpEntry GetDefault(MetaFileManager manager, SetId setIdx) => (GmpEntry)GetDefaultInternal(manager, InternalIndex, setIdx, (ulong)GmpEntry.Default); - public void Reset(IEnumerable entries) + public void Reset(IEnumerable entries) { foreach (var entry in entries) this[entry] = GetDefault(Manager, entry); @@ -176,7 +176,7 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable public IEnumerator GetEnumerator() { - for (var idx = 1; idx < Count; ++idx) + for (ushort idx = 1; idx < Count; ++idx) yield return this[idx]; } diff --git a/Penumbra/Meta/Files/EstFile.cs b/Penumbra/Meta/Files/EstFile.cs index 72fae443..81749d46 100644 --- a/Penumbra/Meta/Files/EstFile.cs +++ b/Penumbra/Meta/Files/EstFile.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; using Penumbra.Interop.Services; using Penumbra.Interop.Structs; using Penumbra.Meta.Manipulations; @@ -168,21 +169,21 @@ public sealed unsafe class EstFile : MetaBaseFile public ushort GetDefault(GenderRace genderRace, ushort setId) => GetDefault(Manager, Index, genderRace, setId); - public static ushort GetDefault(MetaFileManager manager, CharacterUtility.InternalIndex index, GenderRace genderRace, ushort setId) + public static ushort GetDefault(MetaFileManager manager, CharacterUtility.InternalIndex index, GenderRace genderRace, SetId setId) { var data = (byte*)manager.CharacterUtility.DefaultResource(index).Address; var count = *(int*)data; var span = new ReadOnlySpan(data + 4, count); - var (idx, found) = FindEntry(span, genderRace, setId); + var (idx, found) = FindEntry(span, genderRace, setId.Id); if (!found) return 0; return *(ushort*)(data + 4 + count * EntryDescSize + idx * EntrySize); } - public static ushort GetDefault(MetaFileManager manager, MetaIndex metaIndex, GenderRace genderRace, ushort setId) + public static ushort GetDefault(MetaFileManager manager, MetaIndex metaIndex, GenderRace genderRace, SetId setId) => GetDefault(manager, CharacterUtility.ReverseIndices[(int)metaIndex], genderRace, setId); - public static ushort GetDefault(MetaFileManager manager, EstManipulation.EstType estType, GenderRace genderRace, ushort setId) + public static ushort GetDefault(MetaFileManager manager, EstManipulation.EstType estType, GenderRace genderRace, SetId setId) => GetDefault(manager, (MetaIndex)estType, genderRace, setId); } diff --git a/Penumbra/Meta/Files/ImcFile.cs b/Penumbra/Meta/Files/ImcFile.cs index d47bf387..8c957bcc 100644 --- a/Penumbra/Meta/Files/ImcFile.cs +++ b/Penumbra/Meta/Files/ImcFile.cs @@ -4,7 +4,6 @@ using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Interop.Structs; using Penumbra.Meta.Manipulations; -using Penumbra.Services; using Penumbra.String.Classes; using Penumbra.String.Functions; @@ -50,19 +49,19 @@ public unsafe class ImcFile : MetaBaseFile private static ushort PartMask(byte* data) => *(ushort*)(data + 2); - private static ImcEntry* VariantPtr(byte* data, int partIdx, int variantIdx) + private static ImcEntry* VariantPtr(byte* data, int partIdx, Variant variantIdx) { var flag = 1 << partIdx; - if ((PartMask(data) & flag) == 0 || variantIdx > CountInternal(data)) + if ((PartMask(data) & flag) == 0 || variantIdx.Id > CountInternal(data)) return null; var numParts = BitOperations.PopCount(PartMask(data)); var ptr = (ImcEntry*)(data + PreambleSize); - ptr += variantIdx * numParts + partIdx; + ptr += variantIdx.Id * numParts + partIdx; return ptr; } - public ImcEntry GetEntry(int partIdx, int variantIdx) + public ImcEntry GetEntry(int partIdx, Variant variantIdx) { var ptr = VariantPtr(Data, partIdx, variantIdx); return ptr == null ? new ImcEntry() : *ptr; @@ -106,12 +105,12 @@ public unsafe class ImcFile : MetaBaseFile return true; } - public bool SetEntry(int partIdx, int variantIdx, ImcEntry entry) + public bool SetEntry(int partIdx, Variant variantIdx, ImcEntry entry) { if (partIdx >= NumParts) return false; - EnsureVariantCount(variantIdx); + EnsureVariantCount(variantIdx.Id); var variantPtr = VariantPtr(Data, partIdx, variantIdx); if (variantPtr == null) @@ -154,10 +153,10 @@ public unsafe class ImcFile : MetaBaseFile } } - public static ImcEntry GetDefault(MetaFileManager manager, Utf8GamePath path, EquipSlot slot, int variantIdx, out bool exists) + public static ImcEntry GetDefault(MetaFileManager manager, Utf8GamePath path, EquipSlot slot, Variant variantIdx, out bool exists) => GetDefault(manager, path.ToString(), slot, variantIdx, out exists); - public static ImcEntry GetDefault(MetaFileManager manager, string path, EquipSlot slot, int variantIdx, out bool exists) + public static ImcEntry GetDefault(MetaFileManager manager, string path, EquipSlot slot, Variant variantIdx, out bool exists) { var file = manager.GameData.GetFile(path); exists = false; diff --git a/Penumbra/Meta/Manipulations/EqdpManipulation.cs b/Penumbra/Meta/Manipulations/EqdpManipulation.cs index 526abdd4..8524ab8c 100644 --- a/Penumbra/Meta/Manipulations/EqdpManipulation.cs +++ b/Penumbra/Meta/Manipulations/EqdpManipulation.cs @@ -20,13 +20,13 @@ public readonly struct EqdpManipulation : IMetaManipulation [JsonConverter(typeof(StringEnumConverter))] public ModelRace Race { get; private init; } - public ushort SetId { get; private init; } + public SetId SetId { get; private init; } [JsonConverter(typeof(StringEnumConverter))] public EquipSlot Slot { get; private init; } [JsonConstructor] - public EqdpManipulation(EqdpEntry entry, EquipSlot slot, Gender gender, ModelRace race, ushort setId) + public EqdpManipulation(EqdpEntry entry, EquipSlot slot, Gender gender, ModelRace race, SetId setId) { Gender = gender; Race = race; @@ -74,7 +74,7 @@ public readonly struct EqdpManipulation : IMetaManipulation if (g != 0) return g; - var set = SetId.CompareTo(other.SetId); + var set = SetId.Id.CompareTo(other.SetId.Id); return set != 0 ? set : Slot.CompareTo(other.Slot); } diff --git a/Penumbra/Meta/Manipulations/EqpManipulation.cs b/Penumbra/Meta/Manipulations/EqpManipulation.cs index b7a17c19..91949ae4 100644 --- a/Penumbra/Meta/Manipulations/EqpManipulation.cs +++ b/Penumbra/Meta/Manipulations/EqpManipulation.cs @@ -17,13 +17,13 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation > [JsonConverter( typeof( ForceNumericFlagEnumConverter ) )] public EqpEntry Entry { get; private init; } - public ushort SetId { get; private init; } + public SetId SetId { get; private init; } [JsonConverter( typeof( StringEnumConverter ) )] public EquipSlot Slot { get; private init; } [JsonConstructor] - public EqpManipulation( EqpEntry entry, EquipSlot slot, ushort setId ) + public EqpManipulation( EqpEntry entry, EquipSlot slot, SetId setId ) { Slot = slot; SetId = setId; @@ -48,7 +48,7 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation > public int CompareTo( EqpManipulation other ) { - var set = SetId.CompareTo( other.SetId ); + var set = SetId.Id.CompareTo( other.SetId.Id ); return set != 0 ? set : Slot.CompareTo( other.Slot ); } diff --git a/Penumbra/Meta/Manipulations/EstManipulation.cs b/Penumbra/Meta/Manipulations/EstManipulation.cs index 497c9219..3496c56c 100644 --- a/Penumbra/Meta/Manipulations/EstManipulation.cs +++ b/Penumbra/Meta/Manipulations/EstManipulation.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; using Penumbra.Interop.Structs; using Penumbra.Meta.Files; @@ -37,13 +38,13 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > [JsonConverter( typeof( StringEnumConverter ) )] public ModelRace Race { get; private init; } - public ushort SetId { get; private init; } + public SetId SetId { get; private init; } [JsonConverter( typeof( StringEnumConverter ) )] public EstType Slot { get; private init; } [JsonConstructor] - public EstManipulation( Gender gender, ModelRace race, EstType slot, ushort setId, ushort entry ) + public EstManipulation( Gender gender, ModelRace race, EstType slot, SetId setId, ushort entry ) { Entry = entry; Gender = gender; @@ -86,7 +87,7 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > } var s = Slot.CompareTo( other.Slot ); - return s != 0 ? s : SetId.CompareTo( other.SetId ); + return s != 0 ? s : SetId.Id.CompareTo( other.SetId.Id ); } public MetaIndex FileIndex() @@ -94,7 +95,7 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation > public bool Apply( EstFile file ) { - return file.SetEntry( Names.CombinedRace( Gender, Race ), SetId, Entry ) switch + return file.SetEntry( Names.CombinedRace( Gender, Race ), SetId.Id, Entry ) switch { EstFile.EstEntryChange.Unchanged => false, EstFile.EstEntryChange.Changed => true, diff --git a/Penumbra/Meta/Manipulations/GmpManipulation.cs b/Penumbra/Meta/Manipulations/GmpManipulation.cs index 38669d12..6ce954fb 100644 --- a/Penumbra/Meta/Manipulations/GmpManipulation.cs +++ b/Penumbra/Meta/Manipulations/GmpManipulation.cs @@ -10,10 +10,10 @@ namespace Penumbra.Meta.Manipulations; public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation > { public GmpEntry Entry { get; private init; } - public ushort SetId { get; private init; } + public SetId SetId { get; private init; } [JsonConstructor] - public GmpManipulation( GmpEntry entry, ushort setId ) + public GmpManipulation( GmpEntry entry, SetId setId ) { Entry = entry; SetId = setId; @@ -35,7 +35,7 @@ public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation > => SetId.GetHashCode(); public int CompareTo( GmpManipulation other ) - => SetId.CompareTo( other.SetId ); + => SetId.Id.CompareTo( other.SetId.Id ); public MetaIndex FileIndex() => MetaIndex.Gmp; diff --git a/Penumbra/Meta/Manipulations/ImcManipulation.cs b/Penumbra/Meta/Manipulations/ImcManipulation.cs index d933f73a..51ecd0fb 100644 --- a/Penumbra/Meta/Manipulations/ImcManipulation.cs +++ b/Penumbra/Meta/Manipulations/ImcManipulation.cs @@ -1,5 +1,4 @@ using System; -using System.Reflection.Metadata; using System.Runtime.InteropServices; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -12,28 +11,28 @@ using Penumbra.String.Classes; namespace Penumbra.Meta.Manipulations; -[StructLayout( LayoutKind.Sequential, Pack = 1 )] -public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public readonly struct ImcManipulation : IMetaManipulation { - public ImcEntry Entry { get; private init; } - public ushort PrimaryId { get; private init; } - public ushort SecondaryId { get; private init; } - public byte Variant { get; private init; } + public ImcEntry Entry { get; private init; } + public SetId PrimaryId { get; private init; } + public SetId SecondaryId { get; private init; } + public Variant Variant { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public ObjectType ObjectType { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public EquipSlot EquipSlot { get; private init; } - [JsonConverter( typeof( StringEnumConverter ) )] + [JsonConverter(typeof(StringEnumConverter))] public BodySlot BodySlot { get; private init; } - public ImcManipulation( EquipSlot equipSlot, ushort variant, ushort primaryId, ImcEntry entry ) + public ImcManipulation(EquipSlot equipSlot, ushort variant, SetId primaryId, ImcEntry entry) { Entry = entry; PrimaryId = primaryId; - Variant = ( byte )Math.Clamp( variant, ( ushort )0, byte.MaxValue ); + Variant = (Variant)Math.Clamp(variant, (ushort)0, byte.MaxValue); SecondaryId = 0; ObjectType = equipSlot.IsAccessory() ? ObjectType.Accessory : ObjectType.Equipment; EquipSlot = equipSlot; @@ -45,21 +44,21 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > // so we change the unused value to something nonsensical in that case, just so they do not compare equal, // and clamp the variant to 255. [JsonConstructor] - internal ImcManipulation( ObjectType objectType, BodySlot bodySlot, ushort primaryId, ushort secondaryId, ushort variant, - EquipSlot equipSlot, ImcEntry entry ) + internal ImcManipulation(ObjectType objectType, BodySlot bodySlot, SetId primaryId, SetId secondaryId, ushort variant, + EquipSlot equipSlot, ImcEntry entry) { Entry = entry; ObjectType = objectType; PrimaryId = primaryId; - Variant = ( byte )Math.Clamp( variant, ( ushort )0, byte.MaxValue ); + Variant = (Variant)Math.Clamp(variant, (ushort)0, byte.MaxValue); - if( objectType is ObjectType.Accessory or ObjectType.Equipment ) + if (objectType is ObjectType.Accessory or ObjectType.Equipment) { BodySlot = variant > byte.MaxValue ? BodySlot.Body : BodySlot.Unknown; SecondaryId = 0; EquipSlot = equipSlot; } - else if( objectType is ObjectType.DemiHuman ) + else if (objectType is ObjectType.DemiHuman) { BodySlot = variant > byte.MaxValue ? BodySlot.Body : BodySlot.Unknown; SecondaryId = secondaryId; @@ -73,85 +72,81 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > } } - public ImcManipulation Copy( ImcEntry entry ) - => new(ObjectType, BodySlot, PrimaryId, SecondaryId, Variant, EquipSlot, entry); + public ImcManipulation Copy(ImcEntry entry) + => new(ObjectType, BodySlot, PrimaryId, SecondaryId, Variant.Id, EquipSlot, entry); public override string ToString() => ObjectType is ObjectType.Equipment or ObjectType.Accessory ? $"Imc - {PrimaryId} - {EquipSlot} - {Variant}" : $"Imc - {PrimaryId} - {ObjectType} - {SecondaryId} - {BodySlot} - {Variant}"; - public bool Equals( ImcManipulation other ) - => PrimaryId == other.PrimaryId - && Variant == other.Variant + public bool Equals(ImcManipulation other) + => PrimaryId == other.PrimaryId + && Variant == other.Variant && SecondaryId == other.SecondaryId - && ObjectType == other.ObjectType - && EquipSlot == other.EquipSlot - && BodySlot == other.BodySlot; + && ObjectType == other.ObjectType + && EquipSlot == other.EquipSlot + && BodySlot == other.BodySlot; - public override bool Equals( object? obj ) - => obj is ImcManipulation other && Equals( other ); + public override bool Equals(object? obj) + => obj is ImcManipulation other && Equals(other); public override int GetHashCode() - => HashCode.Combine( PrimaryId, Variant, SecondaryId, ( int )ObjectType, ( int )EquipSlot, ( int )BodySlot ); + => HashCode.Combine(PrimaryId, Variant, SecondaryId, (int)ObjectType, (int)EquipSlot, (int)BodySlot); - public int CompareTo( ImcManipulation other ) + public int CompareTo(ImcManipulation other) { - var o = ObjectType.CompareTo( other.ObjectType ); - if( o != 0 ) - { + var o = ObjectType.CompareTo(other.ObjectType); + if (o != 0) return o; - } - var i = PrimaryId.CompareTo( other.PrimaryId ); - if( i != 0 ) - { + var i = PrimaryId.Id.CompareTo(other.PrimaryId.Id); + if (i != 0) return i; + + if (ObjectType is ObjectType.Equipment or ObjectType.Accessory) + { + var e = EquipSlot.CompareTo(other.EquipSlot); + return e != 0 ? e : Variant.Id.CompareTo(other.Variant.Id); } - if( ObjectType is ObjectType.Equipment or ObjectType.Accessory ) + if (ObjectType is ObjectType.DemiHuman) { - var e = EquipSlot.CompareTo( other.EquipSlot ); - return e != 0 ? e : Variant.CompareTo( other.Variant ); - } - - if( ObjectType is ObjectType.DemiHuman ) - { - var e = EquipSlot.CompareTo( other.EquipSlot ); - if( e != 0 ) - { + var e = EquipSlot.CompareTo(other.EquipSlot); + if (e != 0) return e; - } } - var s = SecondaryId.CompareTo( other.SecondaryId ); - if( s != 0 ) - { + var s = SecondaryId.Id.CompareTo(other.SecondaryId.Id); + if (s != 0) return s; - } - var b = BodySlot.CompareTo( other.BodySlot ); - return b != 0 ? b : Variant.CompareTo( other.Variant ); + var b = BodySlot.CompareTo(other.BodySlot); + return b != 0 ? b : Variant.Id.CompareTo(other.Variant.Id); } public MetaIndex FileIndex() - => ( MetaIndex )( -1 ); + => (MetaIndex)(-1); public Utf8GamePath GamePath() { return ObjectType switch { - ObjectType.Accessory => Utf8GamePath.FromString( GamePaths.Accessory.Imc.Path( PrimaryId ), out var p ) ? p : Utf8GamePath.Empty, - ObjectType.Equipment => Utf8GamePath.FromString( GamePaths.Equipment.Imc.Path( PrimaryId ), out var p ) ? p : Utf8GamePath.Empty, - ObjectType.DemiHuman => Utf8GamePath.FromString( GamePaths.DemiHuman.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty, - ObjectType.Monster => Utf8GamePath.FromString( GamePaths.Monster.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty, - ObjectType.Weapon => Utf8GamePath.FromString( GamePaths.Weapon.Imc.Path( PrimaryId, SecondaryId ), out var p ) ? p : Utf8GamePath.Empty, - _ => throw new NotImplementedException(), + ObjectType.Accessory => Utf8GamePath.FromString(GamePaths.Accessory.Imc.Path(PrimaryId), out var p) ? p : Utf8GamePath.Empty, + ObjectType.Equipment => Utf8GamePath.FromString(GamePaths.Equipment.Imc.Path(PrimaryId), out var p) ? p : Utf8GamePath.Empty, + ObjectType.DemiHuman => Utf8GamePath.FromString(GamePaths.DemiHuman.Imc.Path(PrimaryId, SecondaryId), out var p) + ? p + : Utf8GamePath.Empty, + ObjectType.Monster => Utf8GamePath.FromString(GamePaths.Monster.Imc.Path(PrimaryId, SecondaryId), out var p) + ? p + : Utf8GamePath.Empty, + ObjectType.Weapon => Utf8GamePath.FromString(GamePaths.Weapon.Imc.Path(PrimaryId, SecondaryId), out var p) ? p : Utf8GamePath.Empty, + _ => throw new NotImplementedException(), }; } - public bool Apply( ImcFile file ) - => file.SetEntry( ImcFile.PartIndex( EquipSlot ), Variant, Entry ); + public bool Apply(ImcFile file) + => file.SetEntry(ImcFile.PartIndex(EquipSlot), Variant.Id, Entry); public bool Validate() { @@ -165,12 +160,14 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > return false; if (SecondaryId != 0) return false; + break; case ObjectType.DemiHuman: if (BodySlot is not BodySlot.Unknown) return false; if (!EquipSlot.IsEquipment() && !EquipSlot.IsAccessory()) return false; + break; default: if (!Enum.IsDefined(BodySlot)) @@ -179,6 +176,7 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > return false; if (!Enum.IsDefined(ObjectType)) return false; + break; } @@ -187,4 +185,4 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > return true; } -} \ No newline at end of file +} diff --git a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs index a8aec374..7fd77199 100644 --- a/Penumbra/Mods/ItemSwap/CustomizationSwap.cs +++ b/Penumbra/Mods/ItemSwap/CustomizationSwap.cs @@ -15,7 +15,7 @@ public static class CustomizationSwap /// The .mdl file for customizations is unique per racecode, slot and id, thus the .mdl redirection itself is independent of the mode. public static FileSwap CreateMdl( MetaFileManager manager, Func< Utf8GamePath, FullPath > redirections, BodySlot slot, GenderRace race, SetId idFrom, SetId idTo ) { - if( idFrom.Value > byte.MaxValue ) + if( idFrom.Id > byte.MaxValue ) { throw new Exception( $"The Customization ID {idFrom} is too large for {slot}." ); } @@ -51,9 +51,9 @@ public static class CustomizationSwap var newFileName = fileName; newFileName = ItemSwap.ReplaceRace( newFileName, gameRaceTo, race, gameRaceTo != race ); - newFileName = ItemSwap.ReplaceBody( newFileName, slot, idTo, idFrom, idFrom.Value != idTo.Value ); + newFileName = ItemSwap.ReplaceBody( newFileName, slot, idTo, idFrom, idFrom != idTo ); newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_c{race.ToRaceCode()}", gameRaceFrom != race || MaterialHandling.IsSpecialCase( race, idFrom ) ); - newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Value:D4}", gameSetIdFrom.Value != idFrom.Value ); + newFileName = ItemSwap.AddSuffix( newFileName, ".mtrl", $"_{slot.ToAbbreviation()}{idFrom.Id:D4}", gameSetIdFrom != idFrom ); var actualMtrlFromPath = mtrlFromPath; if( newFileName != fileName ) diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index 3d444e1f..72cb9a03 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -54,11 +54,11 @@ public static class EquipmentSwap throw new ItemSwap.InvalidItemTypeException(); var (imcFileFrom, variants, affectedItems) = GetVariants(manager, identifier, slotFrom, idFrom, idTo, variantFrom); - var imcManip = new ImcManipulation(slotTo, variantTo, idTo.Value, default); + var imcManip = new ImcManipulation(slotTo, variantTo.Id, idTo.Id, default); var imcFileTo = new ImcFile(manager, imcManip); var skipFemale = false; var skipMale = false; - var mtrlVariantTo = manips(imcManip.Copy(imcFileTo.GetEntry(ImcFile.PartIndex(slotTo), variantTo))).Imc.Entry.MaterialId; + var mtrlVariantTo = manips(imcManip.Copy(imcFileTo.GetEntry(ImcFile.PartIndex(slotTo), variantTo.Id))).Imc.Entry.MaterialId; foreach (var gr in Enum.GetValues()) { switch (gr.Split().Item1) @@ -124,7 +124,7 @@ public static class EquipmentSwap foreach (var slot in ConvertSlots(slotFrom, rFinger, lFinger)) { (var imcFileFrom, var variants, affectedItems) = GetVariants(manager, identifier, slot, idFrom, idTo, variantFrom); - var imcManip = new ImcManipulation(slot, variantTo, idTo.Value, default); + var imcManip = new ImcManipulation(slot, variantTo.Id, idTo, default); var imcFileTo = new ImcFile(manager, imcManip); var isAccessory = slot.IsAccessory(); @@ -198,10 +198,10 @@ public static class EquipmentSwap SetId idTo, byte mtrlTo) { var (gender, race) = gr.Split(); - var eqdpFrom = new EqdpManipulation(ExpandedEqdpFile.GetDefault(manager, gr, slotFrom.IsAccessory(), idFrom.Value), slotFrom, gender, - race, idFrom.Value); - var eqdpTo = new EqdpManipulation(ExpandedEqdpFile.GetDefault(manager, gr, slotTo.IsAccessory(), idTo.Value), slotTo, gender, race, - idTo.Value); + var eqdpFrom = new EqdpManipulation(ExpandedEqdpFile.GetDefault(manager, gr, slotFrom.IsAccessory(), idFrom), slotFrom, gender, + race, idFrom); + var eqdpTo = new EqdpManipulation(ExpandedEqdpFile.GetDefault(manager, gr, slotTo.IsAccessory(), idTo), slotTo, gender, race, + idTo); var meta = new MetaSwap(manips, eqdpFrom, eqdpTo); var (ownMtrl, ownMdl) = meta.SwapApplied.Eqdp.Entry.ToBits(slotFrom); if (ownMdl) @@ -240,7 +240,7 @@ public static class EquipmentSwap return mdl; } - private static void LookupItem(EquipItem i, out EquipSlot slot, out SetId modelId, out byte variant) + private static void LookupItem(EquipItem i, out EquipSlot slot, out SetId modelId, out Variant variant) { slot = i.Type.ToSlot(); if (!slot.IsEquipmentPiece()) @@ -250,14 +250,14 @@ public static class EquipmentSwap variant = i.Variant; } - private static (ImcFile, byte[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom, - SetId idFrom, SetId idTo, byte variantFrom) + private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom, + SetId idFrom, SetId idTo, Variant variantFrom) { - var entry = new ImcManipulation(slotFrom, variantFrom, idFrom.Value, default); + var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default); var imc = new ImcFile(manager, entry); EquipItem[] items; - byte[] variants; - if (idFrom.Value == idTo.Value) + Variant[] variants; + if (idFrom == idTo) { items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray(); variants = new[] @@ -270,7 +270,7 @@ public static class EquipmentSwap items = identifier.Identify(slotFrom.IsEquipment() ? GamePaths.Equipment.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom) : GamePaths.Accessory.Mdl.Path(idFrom, GenderRace.MidlanderMale, slotFrom)).Select(kvp => kvp.Value).OfType().ToArray(); - variants = Enumerable.Range(0, imc.Count + 1).Select(i => (byte)i).ToArray(); + variants = Enumerable.Range(0, imc.Count + 1).Select(i => (Variant)i).ToArray(); } return (imc, variants, items); @@ -282,24 +282,23 @@ public static class EquipmentSwap if (slot is not EquipSlot.Head) return null; - var manipFrom = new GmpManipulation(ExpandedGmpFile.GetDefault(manager, idFrom.Value), idFrom.Value); - var manipTo = new GmpManipulation(ExpandedGmpFile.GetDefault(manager, idTo.Value), idTo.Value); + var manipFrom = new GmpManipulation(ExpandedGmpFile.GetDefault(manager, idFrom), idFrom); + var manipTo = new GmpManipulation(ExpandedGmpFile.GetDefault(manager, idTo), idTo); return new MetaSwap(manips, manipFrom, manipTo); } public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, Func manips, EquipSlot slot, - SetId idFrom, SetId idTo, - byte variantFrom, byte variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) + SetId idFrom, SetId idTo, Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) => CreateImc(manager, redirections, manips, slot, slot, idFrom, idTo, variantFrom, variantTo, imcFileFrom, imcFileTo); public static MetaSwap CreateImc(MetaFileManager manager, Func redirections, Func manips, EquipSlot slotFrom, EquipSlot slotTo, SetId idFrom, SetId idTo, - byte variantFrom, byte variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) + Variant variantFrom, Variant variantTo, ImcFile imcFileFrom, ImcFile imcFileTo) { var entryFrom = imcFileFrom.GetEntry(ImcFile.PartIndex(slotFrom), variantFrom); var entryTo = imcFileTo.GetEntry(ImcFile.PartIndex(slotTo), variantTo); - var manipulationFrom = new ImcManipulation(slotFrom, variantFrom, idFrom.Value, entryFrom); - var manipulationTo = new ImcManipulation(slotTo, variantTo, idTo.Value, entryTo); + var manipulationFrom = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, entryFrom); + var manipulationTo = new ImcManipulation(slotTo, variantTo.Id, idTo, entryTo); var imc = new MetaSwap(manips, manipulationFrom, manipulationTo); var decal = CreateDecal(manager, redirections, imc.SwapToModded.Imc.Entry.DecalId); @@ -332,8 +331,8 @@ public static class EquipmentSwap if (vfxId == 0) return null; - var vfxPathFrom = GamePaths.Equipment.Avfx.Path(idFrom.Value, vfxId); - var vfxPathTo = GamePaths.Equipment.Avfx.Path(idTo.Value, vfxId); + var vfxPathFrom = GamePaths.Equipment.Avfx.Path(idFrom, vfxId); + var vfxPathTo = GamePaths.Equipment.Avfx.Path(idTo, vfxId); var avfx = FileSwap.CreateSwap(manager, ResourceType.Avfx, redirections, vfxPathFrom, vfxPathTo); foreach (ref var filePath in avfx.AsAvfx()!.Textures.AsSpan()) @@ -351,10 +350,10 @@ public static class EquipmentSwap if (slot.IsAccessory()) return null; - var eqpValueFrom = ExpandedEqpFile.GetDefault(manager, idFrom.Value); - var eqpValueTo = ExpandedEqpFile.GetDefault(manager, idTo.Value); - var eqpFrom = new EqpManipulation(eqpValueFrom, slot, idFrom.Value); - var eqpTo = new EqpManipulation(eqpValueTo, slot, idFrom.Value); + var eqpValueFrom = ExpandedEqpFile.GetDefault(manager, idFrom); + var eqpValueTo = ExpandedEqpFile.GetDefault(manager, idTo); + var eqpFrom = new EqpManipulation(eqpValueFrom, slot, idFrom); + var eqpTo = new EqpManipulation(eqpValueTo, slot, idFrom); return new MetaSwap(manips, eqpFrom, eqpTo); } @@ -368,7 +367,7 @@ public static class EquipmentSwap ref bool dataWasChanged) { var prefix = slotTo.IsAccessory() ? 'a' : 'e'; - if (!fileName.Contains($"{prefix}{idTo.Value:D4}")) + if (!fileName.Contains($"{prefix}{idTo.Id:D4}")) return null; var folderTo = slotTo.IsAccessory() diff --git a/Penumbra/Mods/ItemSwap/ItemSwap.cs b/Penumbra/Mods/ItemSwap/ItemSwap.cs index 30159591..6ed2112a 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwap.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwap.cs @@ -9,7 +9,6 @@ using Penumbra.GameData.Structs; using Penumbra.Meta; using Penumbra.Meta.Files; using Penumbra.Meta.Manipulations; -using Penumbra.Services; using Penumbra.String.Classes; namespace Penumbra.Mods.ItemSwap; @@ -163,8 +162,8 @@ public static class ItemSwap } var (gender, race) = genderRace.Split(); - var fromDefault = new EstManipulation( gender, race, type, idFrom.Value, EstFile.GetDefault( manager, type, genderRace, idFrom.Value ) ); - var toDefault = new EstManipulation( gender, race, type, idTo.Value, EstFile.GetDefault( manager, type, genderRace, idTo.Value ) ); + var fromDefault = new EstManipulation( gender, race, type, idFrom, EstFile.GetDefault( manager, type, genderRace, idFrom ) ); + var toDefault = new EstManipulation( gender, race, type, idTo, EstFile.GetDefault( manager, type, genderRace, idTo ) ); var est = new MetaSwap( manips, fromDefault, toDefault ); if( ownMdl && est.SwapApplied.Est.Entry >= 2 ) @@ -206,7 +205,7 @@ public static class ItemSwap public static string ReplaceAnyId( string path, char idType, SetId id, bool condition = true ) => condition - ? Regex.Replace( path, $"{idType}\\d{{4}}", $"{idType}{id.Value:D4}" ) + ? Regex.Replace( path, $"{idType}\\d{{4}}", $"{idType}{id.Id:D4}" ) : path; public static string ReplaceAnyRace( string path, GenderRace to, bool condition = true ) @@ -217,7 +216,7 @@ public static class ItemSwap public static string ReplaceId( string path, char type, SetId idFrom, SetId idTo, bool condition = true ) => condition - ? path.Replace( $"{type}{idFrom.Value:D4}", $"{type}{idTo.Value:D4}" ) + ? path.Replace( $"{type}{idFrom.Id:D4}", $"{type}{idTo.Id:D4}" ) : path; public static string ReplaceSlot( string path, EquipSlot from, EquipSlot to, bool condition = true ) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs index 9607d2ac..3e81901b 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Meta.cs @@ -135,7 +135,7 @@ public partial class ModEditWindow // Identifier ImGui.TableNextColumn(); - if (IdInput("##eqpId", IdWidth, _new.SetId, out var setId, 1, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) + if (IdInput("##eqpId", IdWidth, _new.SetId.Id, out var setId, 1, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) _new = new EqpManipulation(ExpandedEqpFile.GetDefault(metaFileManager, setId), _new.Slot, setId); ImGuiUtil.HoverTooltip(ModelSetIdTooltip); @@ -224,7 +224,7 @@ public partial class ModEditWindow // Identifier ImGui.TableNextColumn(); - if (IdInput("##eqdpId", IdWidth, _new.SetId, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) + if (IdInput("##eqdpId", IdWidth, _new.SetId.Id, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) { var newDefaultEntry = ExpandedEqdpFile.GetDefault(metaFileManager, Names.CombinedRace(_new.Gender, _new.Race), _new.Slot.IsAccessory(), setId); _new = new EqdpManipulation(newDefaultEntry, _new.Slot, _new.Gender, _new.Race, setId); @@ -352,14 +352,14 @@ public partial class ModEditWindow _ => EquipSlot.Unknown, }; _new = new ImcManipulation(type, _new.BodySlot, _new.PrimaryId, _new.SecondaryId == 0 ? (ushort)1 : _new.SecondaryId, - _new.Variant, equipSlot, _new.Entry); + _new.Variant.Id, equipSlot, _new.Entry); } ImGuiUtil.HoverTooltip(ObjectTypeTooltip); ImGui.TableNextColumn(); - if (IdInput("##imcId", IdWidth, _new.PrimaryId, out var setId, 0, ushort.MaxValue, _new.PrimaryId <= 1)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, setId, _new.SecondaryId, _new.Variant, _new.EquipSlot, _new.Entry) + if (IdInput("##imcId", IdWidth, _new.PrimaryId.Id, out var setId, 0, ushort.MaxValue, _new.PrimaryId <= 1)) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, setId, _new.SecondaryId, _new.Variant.Id, _new.EquipSlot, _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -373,7 +373,7 @@ public partial class ModEditWindow if (_new.ObjectType is ObjectType.Equipment) { if (Combos.EqpEquipSlot("##imcSlot", 100, _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -382,7 +382,7 @@ public partial class ModEditWindow else if (_new.ObjectType is ObjectType.Accessory) { if (Combos.AccessorySlot("##imcSlot", _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -390,8 +390,8 @@ public partial class ModEditWindow } else { - if (IdInput("##imcId2", 100 * UiHelpers.Scale, _new.SecondaryId, out var setId2, 0, ushort.MaxValue, false)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant, _new.EquipSlot, _new.Entry) + if (IdInput("##imcId2", 100 * UiHelpers.Scale, _new.SecondaryId.Id, out var setId2, 0, ushort.MaxValue, false)) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, setId2, _new.Variant.Id, _new.EquipSlot, _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -399,7 +399,7 @@ public partial class ModEditWindow } ImGui.TableNextColumn(); - if (IdInput("##imcVariant", SmallIdWidth, _new.Variant, out var variant, 0, byte.MaxValue, false)) + if (IdInput("##imcVariant", SmallIdWidth, _new.Variant.Id, out var variant, 0, byte.MaxValue, false)) _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, variant, _new.EquipSlot, _new.Entry).Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -408,7 +408,7 @@ public partial class ModEditWindow if (_new.ObjectType is ObjectType.DemiHuman) { if (Combos.EqpEquipSlot("##imcSlot", 70, _new.EquipSlot, out var slot)) - _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant, slot, _new.Entry) + _new = new ImcManipulation(_new.ObjectType, _new.BodySlot, _new.PrimaryId, _new.SecondaryId, _new.Variant.Id, slot, _new.Entry) .Copy(GetDefault(metaFileManager, _new) ?? new ImcEntry()); @@ -557,7 +557,7 @@ public partial class ModEditWindow // Identifier ImGui.TableNextColumn(); - if (IdInput("##estId", IdWidth, _new.SetId, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) + if (IdInput("##estId", IdWidth, _new.SetId.Id, out var setId, 0, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) { var newDefaultEntry = EstFile.GetDefault(metaFileManager, _new.Slot, Names.CombinedRace(_new.Gender, _new.Race), setId); _new = new EstManipulation(_new.Gender, _new.Race, _new.Slot, setId, newDefaultEntry); @@ -656,7 +656,7 @@ public partial class ModEditWindow // Identifier ImGui.TableNextColumn(); - if (IdInput("##gmpId", IdWidth, _new.SetId, out var setId, 1, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) + if (IdInput("##gmpId", IdWidth, _new.SetId.Id, out var setId, 1, ExpandedEqpGmpBase.Count - 1, _new.SetId <= 1)) _new = new GmpManipulation(ExpandedGmpFile.GetDefault(metaFileManager, setId), setId); ImGuiUtil.HoverTooltip(ModelSetIdTooltip); diff --git a/Penumbra/UI/ChangedItemDrawer.cs b/Penumbra/UI/ChangedItemDrawer.cs index 41b5f420..b2f13e51 100644 --- a/Penumbra/UI/ChangedItemDrawer.cs +++ b/Penumbra/UI/ChangedItemDrawer.cs @@ -52,7 +52,7 @@ public class ChangedItemDrawer : IDisposable private readonly ExcelSheet _items; private readonly CommunicatorService _communicator; private readonly Dictionary _icons = new(16); - private float _smallestIconWidth = 0; + private float _smallestIconWidth; public ChangedItemDrawer(UiBuilder uiBuilder, DataManager gameData, CommunicatorService communicator, Configuration config) { @@ -265,7 +265,7 @@ public class ChangedItemDrawer : IDisposable switch (obj) { case EquipItem it: - text = it.WeaponType == 0 ? $"({it.ModelId.Value}-{it.Variant})" : $"({it.ModelId.Value}-{it.WeaponType.Value}-{it.Variant})"; + text = it.ModelString; return true; case ModelChara m: text = $"({((CharacterBase.ModelType)m.Type).ToName()} {m.Model}-{m.Base}-{m.Variant})"; @@ -280,7 +280,7 @@ public class ChangedItemDrawer : IDisposable private object? Convert(object? data) { if (data is EquipItem it) - return _items.GetRow(it.ItemId); + return _items.GetRow(it.ItemId.Id); return data; } diff --git a/Penumbra/UI/Tabs/DebugTab.cs b/Penumbra/UI/Tabs/DebugTab.cs index 2fd21c6f..9d5caa0c 100644 --- a/Penumbra/UI/Tabs/DebugTab.cs +++ b/Penumbra/UI/Tabs/DebugTab.cs @@ -8,6 +8,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Group; using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.System.Resource; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; using ImGuiNET; using OtterGui; using OtterGui.Classes; @@ -503,10 +504,10 @@ public class DebugTab : Window, ITab if (table) for (var i = 0; i < 8; ++i) { - var c = agent->Character(i); + ref var c = ref agent->Data->CharacterArraySpan[i]; ImGuiUtil.DrawTableColumn($"Character {i}"); - var name = c->Name1.ToString(); - ImGuiUtil.DrawTableColumn(name.Length == 0 ? "NULL" : $"{name} ({c->WorldId})"); + var name = c.Name1.ToString(); + ImGuiUtil.DrawTableColumn(name.Length == 0 ? "NULL" : $"{name} ({c.WorldId})"); } } else