From 33b4905ae28c251c19e2851b761d6462f0ecfd80 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 31 Dec 2022 12:26:05 +0100 Subject: [PATCH] Add some checks for valid variants in IMC Meta Edits. --- Penumbra/Api/PenumbraApi.cs | 2 +- .../Import/TexToolsMeta.Deserialization.cs | 6 ++++- Penumbra/Meta/Manager/MetaManager.Imc.cs | 7 ++++- .../Meta/Manipulations/ImcManipulation.cs | 26 ++++++++++++++----- .../Meta/Manipulations/MetaManipulation.cs | 8 +++--- Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs | 2 +- Penumbra/UI/Classes/ModEditWindow.Meta.cs | 4 +-- 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 54be2b27..d9a198ec 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -963,7 +963,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi } manips = new HashSet< MetaManipulation >( manipArray!.Length ); - foreach( var manip in manipArray ) + foreach( var manip in manipArray.Where( m => m.ManipulationType != MetaManipulation.Type.Unknown ) ) { if( !manips.Add( manip ) ) { diff --git a/Penumbra/Import/TexToolsMeta.Deserialization.cs b/Penumbra/Import/TexToolsMeta.Deserialization.cs index 2ea01648..252a1720 100644 --- a/Penumbra/Import/TexToolsMeta.Deserialization.cs +++ b/Penumbra/Import/TexToolsMeta.Deserialization.cs @@ -138,7 +138,11 @@ public partial class TexToolsMeta { if( _keepDefault || !value.Equals( def.GetEntry( partIdx, i ) ) ) { - MetaManipulations.Add( new ImcManipulation( manip.ObjectType, manip.BodySlot, manip.PrimaryId, manip.SecondaryId, i, manip.EquipSlot, value ) ); + var imc = new ImcManipulation( manip.ObjectType, manip.BodySlot, manip.PrimaryId, manip.SecondaryId, i, manip.EquipSlot, value ); + if( imc.Valid ) + { + MetaManipulations.Add( imc ); + } } ++i; diff --git a/Penumbra/Meta/Manager/MetaManager.Imc.cs b/Penumbra/Meta/Manager/MetaManager.Imc.cs index d61f158f..406b5671 100644 --- a/Penumbra/Meta/Manager/MetaManager.Imc.cs +++ b/Penumbra/Meta/Manager/MetaManager.Imc.cs @@ -53,6 +53,11 @@ public partial class MetaManager public bool ApplyMod( ImcManipulation manip ) { + if( !manip.Valid ) + { + return false; + } + _imcManipulations.AddOrReplace( manip ); var path = manip.GamePath(); try @@ -91,7 +96,7 @@ public partial class MetaManager public bool RevertMod( ImcManipulation m ) { - if( !_imcManipulations.Remove( m ) ) + if( !m.Valid || !_imcManipulations.Remove( m ) ) { return false; } diff --git a/Penumbra/Meta/Manipulations/ImcManipulation.cs b/Penumbra/Meta/Manipulations/ImcManipulation.cs index 4c65fd6d..f4656a79 100644 --- a/Penumbra/Meta/Manipulations/ImcManipulation.cs +++ b/Penumbra/Meta/Manipulations/ImcManipulation.cs @@ -32,13 +32,17 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > { Entry = entry; PrimaryId = primaryId; - Variant = ( byte )variant; + Variant = ( byte )Math.Clamp( variant, ( ushort )0, byte.MaxValue ); SecondaryId = 0; ObjectType = equipSlot.IsAccessory() ? ObjectType.Accessory : ObjectType.Equipment; EquipSlot = equipSlot; - BodySlot = BodySlot.Unknown; + BodySlot = variant > byte.MaxValue ? BodySlot.Body : BodySlot.Unknown; } + // Variants were initially ushorts but got shortened to bytes. + // There are still some manipulations around that have values > 255 for variant, + // 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 ) @@ -46,16 +50,17 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > Entry = entry; ObjectType = objectType; PrimaryId = primaryId; - Variant = ( byte )variant; + Variant = ( byte )Math.Clamp( variant, ( ushort )0, byte.MaxValue ); + if( objectType is ObjectType.Accessory or ObjectType.Equipment ) { - BodySlot = BodySlot.Unknown; + BodySlot = variant > byte.MaxValue ? BodySlot.Body : BodySlot.Unknown; SecondaryId = 0; EquipSlot = equipSlot; } else if( objectType is ObjectType.DemiHuman ) { - BodySlot = BodySlot.Unknown; + BodySlot = variant > byte.MaxValue ? BodySlot.Body : BodySlot.Unknown; SecondaryId = secondaryId; EquipSlot = equipSlot == EquipSlot.Unknown ? EquipSlot.Head : equipSlot; } @@ -63,10 +68,19 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation > { BodySlot = bodySlot; SecondaryId = secondaryId; - EquipSlot = EquipSlot.Unknown; + EquipSlot = variant > byte.MaxValue ? EquipSlot.All : EquipSlot.Unknown; } } + public bool Valid + => ObjectType switch + { + ObjectType.Accessory => BodySlot == BodySlot.Unknown, + ObjectType.Equipment => BodySlot == BodySlot.Unknown, + ObjectType.DemiHuman => BodySlot == BodySlot.Unknown, + _ => EquipSlot == EquipSlot.Unknown, + }; + public ImcManipulation Copy( ImcEntry entry ) => new(ObjectType, BodySlot, PrimaryId, SecondaryId, Variant, EquipSlot, entry); diff --git a/Penumbra/Meta/Manipulations/MetaManipulation.cs b/Penumbra/Meta/Manipulations/MetaManipulation.cs index 5cc96f98..d1ec5f3a 100644 --- a/Penumbra/Meta/Manipulations/MetaManipulation.cs +++ b/Penumbra/Meta/Manipulations/MetaManipulation.cs @@ -100,7 +100,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa return; case ImcManipulation m: Imc = m; - ManipulationType = Type.Imc; + ManipulationType = m.Valid ? Type.Imc : Type.Unknown; return; } } @@ -194,7 +194,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa Type.Est => Est.Equals( other.Est ), Type.Rsp => Rsp.Equals( other.Rsp ), Type.Imc => Imc.Equals( other.Imc ), - _ => throw new ArgumentOutOfRangeException(), + _ => false, }; } @@ -229,7 +229,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa Type.Est => Est.GetHashCode(), Type.Rsp => Rsp.GetHashCode(), Type.Imc => Imc.GetHashCode(), - _ => throw new ArgumentOutOfRangeException(), + _ => 0, }; public unsafe int CompareTo( MetaManipulation other ) @@ -249,7 +249,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa Type.Est => Est.ToString(), Type.Rsp => Rsp.ToString(), Type.Imc => Imc.ToString(), - _ => throw new ArgumentOutOfRangeException(), + _ => "Invalid", }; public string EntryToString() diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs index b38307be..a7b4981f 100644 --- a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs +++ b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs @@ -173,7 +173,7 @@ public partial class Mod var manips = json[ nameof( Manipulations ) ]; if( manips != null ) { - foreach( var s in manips.Children().Select( c => c.ToObject< MetaManipulation >() ) ) + foreach( var s in manips.Children().Select( c => c.ToObject< MetaManipulation >() ).Where( m => m.ManipulationType != MetaManipulation.Type.Unknown ) ) { ManipulationData.Add( s ); } diff --git a/Penumbra/UI/Classes/ModEditWindow.Meta.cs b/Penumbra/UI/Classes/ModEditWindow.Meta.cs index 9707fb6f..66ac4a87 100644 --- a/Penumbra/UI/Classes/ModEditWindow.Meta.cs +++ b/Penumbra/UI/Classes/ModEditWindow.Meta.cs @@ -930,7 +930,7 @@ public partial class ModEditWindow var version = Functions.FromCompressedBase64< MetaManipulation[] >( clipboard, out var manips ); if( version == MetaManipulation.CurrentVersion && manips != null ) { - foreach( var manip in manips ) + foreach( var manip in manips.Where( m => m.ManipulationType != MetaManipulation.Type.Unknown ) ) { _editor!.Meta.Set( manip ); } @@ -950,7 +950,7 @@ public partial class ModEditWindow if( version == MetaManipulation.CurrentVersion && manips != null ) { _editor!.Meta.Clear(); - foreach( var manip in manips ) + foreach( var manip in manips.Where( m => m.ManipulationType != MetaManipulation.Type.Unknown ) ) { _editor!.Meta.Set( manip ); }