Use strongly typed ids in most places.

This commit is contained in:
Ottermandias 2023-07-29 02:22:31 +02:00
parent dccd347432
commit 18b6b87e6b
26 changed files with 192 additions and 193 deletions

View file

@ -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<int> entries)
public void Reset(IEnumerable<SetId> 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);
}

View file

@ -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<EqpEntry>
: 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<EqpEntry>
*ptr = (ulong)Eqp.DefaultEntry;
}
public void Reset(IEnumerable<int> entries)
public void Reset(IEnumerable<SetId> entries)
{
foreach (var entry in entries)
this[entry] = GetDefault(Manager, entry);
@ -142,7 +142,7 @@ public sealed class ExpandedEqpFile : ExpandedEqpGmpBase, IEnumerable<EqpEntry>
public IEnumerator<EqpEntry> 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<GmpEntry>
: 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<int> entries)
public void Reset(IEnumerable<SetId> entries)
{
foreach (var entry in entries)
this[entry] = GetDefault(Manager, entry);
@ -176,7 +176,7 @@ public sealed class ExpandedGmpFile : ExpandedEqpGmpBase, IEnumerable<GmpEntry>
public IEnumerator<GmpEntry> GetEnumerator()
{
for (var idx = 1; idx < Count; ++idx)
for (ushort idx = 1; idx < Count; ++idx)
yield return this[idx];
}

View file

@ -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<Info>(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);
}

View file

@ -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;

View file

@ -20,13 +20,13 @@ public readonly struct EqdpManipulation : IMetaManipulation<EqdpManipulation>
[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<EqdpManipulation>
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);
}

View file

@ -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 );
}

View file

@ -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,

View file

@ -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;

View file

@ -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<ImcManipulation>
{
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;
}
}
}