mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Add some Metadata validation.
This commit is contained in:
parent
5567134a56
commit
e14fedf59e
17 changed files with 254 additions and 158 deletions
|
|
@ -69,7 +69,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatingCharacterBase.Subscribe(new Action<nint, string, nint, nint, nint>(value), Communication.CreatingCharacterBase.Priority.Api);
|
||||
_communicator.CreatingCharacterBase.Subscribe(new Action<nint, string, nint, nint, nint>(value),
|
||||
Communication.CreatingCharacterBase.Priority.Api);
|
||||
}
|
||||
remove
|
||||
{
|
||||
|
|
@ -89,7 +90,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
return;
|
||||
|
||||
CheckInitialized();
|
||||
_communicator.CreatedCharacterBase.Subscribe(new Action<nint, string, nint>(value), Communication.CreatedCharacterBase.Priority.Api);
|
||||
_communicator.CreatedCharacterBase.Subscribe(new Action<nint, string, nint>(value),
|
||||
Communication.CreatedCharacterBase.Priority.Api);
|
||||
}
|
||||
remove
|
||||
{
|
||||
|
|
@ -181,7 +183,8 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public event ChangedItemClick? ChangedItemClicked
|
||||
{
|
||||
add => _communicator.ChangedItemClick.Subscribe(new Action<MouseButton, object?>(value!), Communication.ChangedItemClick.Priority.Default);
|
||||
add => _communicator.ChangedItemClick.Subscribe(new Action<MouseButton, object?>(value!),
|
||||
Communication.ChangedItemClick.Priority.Default);
|
||||
remove => _communicator.ChangedItemClick.Unsubscribe(new Action<MouseButton, object?>(value!));
|
||||
}
|
||||
|
||||
|
|
@ -1120,14 +1123,15 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
}
|
||||
|
||||
manips = new HashSet<MetaManipulation>(manipArray!.Length);
|
||||
foreach (var manip in manipArray.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
||||
{
|
||||
if (!manips.Add(manip))
|
||||
foreach (var manip in manipArray.Where(m => m.Validate()))
|
||||
{
|
||||
if (manips.Add(manip))
|
||||
continue;
|
||||
|
||||
Penumbra.Log.Warning($"Manipulation {manip} {manip.EntryToString()} is invalid and was skipped.");
|
||||
manips = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public readonly struct ImcCache : IDisposable
|
|||
|
||||
public bool ApplyMod( MetaFileManager manager, ModCollection collection, ImcManipulation manip )
|
||||
{
|
||||
if( !manip.Valid )
|
||||
if( !manip.Validate() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ public readonly struct ImcCache : IDisposable
|
|||
|
||||
public bool RevertMod( MetaFileManager manager, ModCollection collection, ImcManipulation m )
|
||||
{
|
||||
if( !m.Valid || !_imcManipulations.Remove( m ) )
|
||||
if( !m.Validate() || !_imcManipulations.Remove( m ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
|
@ -12,7 +13,7 @@ public sealed class CreatedCharacterBase : EventWrapper<Action<nint, string, nin
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.PenumbraApi.CreatedCharacterBase"/>
|
||||
/// <seealso cref="PenumbraApi.CreatedCharacterBase"/>
|
||||
Api = 0,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
|
@ -16,7 +17,7 @@ public sealed class CreatingCharacterBase : EventWrapper<Action<nint, string, ni
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.PenumbraApi.CreatingCharacterBase"/>
|
||||
/// <seealso cref="PenumbraApi.CreatingCharacterBase"/>
|
||||
Api = 0,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
|
@ -13,7 +14,7 @@ public sealed class EnabledChanged : EventWrapper<Action<bool>, EnabledChanged.P
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.PenumbraApi.EnabledChange"/>
|
||||
/// <seealso cref="Ipc.EnabledChange"/>
|
||||
Api = int.MinValue,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Communication;
|
||||
|
|
@ -14,7 +15,7 @@ public sealed class ModDirectoryChanged : EventWrapper<Action<string, bool>, Mod
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.PenumbraApi.ModDirectoryChanged"/>
|
||||
/// <seealso cref="PenumbraApi.ModDirectoryChanged"/>
|
||||
Api = 0,
|
||||
|
||||
/// <seealso cref="UI.FileDialogService.OnModDirectoryChange"/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Util;
|
||||
|
|
@ -22,7 +23,7 @@ public sealed class ModPathChanged : EventWrapper<Action<ModPathChangeType, Mod,
|
|||
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnModChangeAddition"/>
|
||||
CollectionCacheManagerAddition = -100,
|
||||
|
||||
/// <seealso cref="Api.PenumbraApi.ModPathChangeSubscriber"/>
|
||||
/// <seealso cref="PenumbraApi.ModPathChangeSubscriber"/>
|
||||
Api = 0,
|
||||
|
||||
/// <seealso cref="Mods.Manager.ModCacheManager.OnModPathChange"/>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Penumbra.Api;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.Mods;
|
||||
|
|
@ -21,7 +22,7 @@ public sealed class ModSettingChanged : EventWrapper<Action<ModCollection, ModSe
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Api.PenumbraApi.OnModSettingChange"/>
|
||||
/// <seealso cref="PenumbraApi.OnModSettingChange"/>
|
||||
Api = int.MinValue,
|
||||
|
||||
/// <seealso cref="Collections.Cache.CollectionCacheManager.OnModSettingChange"/>
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public partial class TexToolsMeta
|
|||
{
|
||||
var imc = new ImcManipulation(manip.ObjectType, manip.BodySlot, manip.PrimaryId, manip.SecondaryId, i, manip.EquipSlot,
|
||||
value);
|
||||
if (imc.Valid)
|
||||
if (imc.Validate())
|
||||
MetaManipulations.Add(imc);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public readonly struct EqdpManipulation : IMetaManipulation< EqdpManipulation >
|
|||
var (bit1, bit2) = entry.Entry.ToBits(entry.Slot);
|
||||
return new EqdpManipulation(Eqdp.FromSlotAndBits(Slot, bit1, bit2), Slot, Gender, Race, SetId);
|
||||
}
|
||||
|
||||
return new EqdpManipulation(entry.Entry, Slot, Gender, Race, SetId);
|
||||
}
|
||||
|
||||
|
|
@ -67,15 +68,11 @@ public readonly struct EqdpManipulation : IMetaManipulation< EqdpManipulation >
|
|||
{
|
||||
var r = Race.CompareTo(other.Race);
|
||||
if (r != 0)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
var g = Gender.CompareTo(other.Gender);
|
||||
if (g != 0)
|
||||
{
|
||||
return g;
|
||||
}
|
||||
|
||||
var set = SetId.CompareTo(other.SetId);
|
||||
return set != 0 ? set : Slot.CompareTo(other.Slot);
|
||||
|
|
@ -89,11 +86,25 @@ public readonly struct EqdpManipulation : IMetaManipulation< EqdpManipulation >
|
|||
var entry = file[SetId];
|
||||
var mask = Eqdp.Mask(Slot);
|
||||
if ((entry & mask) == Entry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file[SetId] = (entry & ~mask) | Entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
var mask = Eqdp.Mask(Slot);
|
||||
if (mask == 0)
|
||||
return false;
|
||||
|
||||
if ((mask & Entry) != Entry)
|
||||
return false;
|
||||
|
||||
if (FileIndex() == (MetaIndex)(-1))
|
||||
return false;
|
||||
|
||||
// No check for set id.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -67,4 +67,17 @@ public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation >
|
|||
file[ SetId ] = ( entry & ~mask ) | Entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
var mask = Eqp.Mask(Slot);
|
||||
if (mask == 0)
|
||||
return false;
|
||||
if ((Entry & mask) != Entry)
|
||||
return false;
|
||||
|
||||
// No check for set id.
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -103,4 +103,14 @@ public readonly struct EstManipulation : IMetaManipulation< EstManipulation >
|
|||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
if (!Enum.IsDefined(Slot))
|
||||
return false;
|
||||
if (Names.CombinedRace(Gender, Race) == GenderRace.Unknown)
|
||||
return false;
|
||||
// No known check for set id or entry.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,4 +51,10 @@ public readonly struct GmpManipulation : IMetaManipulation< GmpManipulation >
|
|||
file[ SetId ] = Entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
// No known conditions.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Runtime.InteropServices;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
|
@ -72,15 +73,6 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation >
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -160,4 +152,39 @@ public readonly struct ImcManipulation : IMetaManipulation< ImcManipulation >
|
|||
|
||||
public bool Apply( ImcFile file )
|
||||
=> file.SetEntry( ImcFile.PartIndex( EquipSlot ), Variant, Entry );
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
switch (ObjectType)
|
||||
{
|
||||
case ObjectType.Accessory:
|
||||
case ObjectType.Equipment:
|
||||
if (BodySlot is not BodySlot.Unknown)
|
||||
return false;
|
||||
if (!EquipSlot.IsEquipmentPiece())
|
||||
return false;
|
||||
if (SecondaryId != 0)
|
||||
return false;
|
||||
break;
|
||||
case ObjectType.DemiHuman:
|
||||
if (BodySlot is not BodySlot.Unknown)
|
||||
return false;
|
||||
if (!EquipSlot.IsEquipmentPiece())
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (!Enum.IsDefined(BodySlot))
|
||||
return false;
|
||||
if (EquipSlot is not EquipSlot.Unknown)
|
||||
return false;
|
||||
if (!Enum.IsDefined(ObjectType))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Entry.MaterialId == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -80,32 +80,46 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
{
|
||||
case EqpManipulation m:
|
||||
Eqp = m;
|
||||
ManipulationType = Type.Eqp;
|
||||
ManipulationType = m.Validate() ? Type.Eqp : Type.Unknown;
|
||||
return;
|
||||
case EqdpManipulation m:
|
||||
Eqdp = m;
|
||||
ManipulationType = Type.Eqdp;
|
||||
ManipulationType = m.Validate() ? Type.Eqdp : Type.Unknown;
|
||||
return;
|
||||
case GmpManipulation m:
|
||||
Gmp = m;
|
||||
ManipulationType = Type.Gmp;
|
||||
ManipulationType = m.Validate() ? Type.Gmp : Type.Unknown;
|
||||
return;
|
||||
case EstManipulation m:
|
||||
Est = m;
|
||||
ManipulationType = Type.Est;
|
||||
ManipulationType = m.Validate() ? Type.Est : Type.Unknown;
|
||||
return;
|
||||
case RspManipulation m:
|
||||
Rsp = m;
|
||||
ManipulationType = Type.Rsp;
|
||||
ManipulationType = m.Validate() ? Type.Rsp : Type.Unknown;
|
||||
return;
|
||||
case ImcManipulation m:
|
||||
Imc = m;
|
||||
ManipulationType = m.Valid ? Type.Imc : Type.Unknown;
|
||||
ManipulationType = m.Validate() ? Type.Imc : Type.Unknown;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
return ManipulationType switch
|
||||
{
|
||||
Type.Imc => Imc.Validate(),
|
||||
Type.Eqdp => Eqdp.Validate(),
|
||||
Type.Eqp => Eqp.Validate(),
|
||||
Type.Est => Est.Validate(),
|
||||
Type.Gmp => Gmp.Validate(),
|
||||
Type.Rsp => Rsp.Validate(),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
public MetaManipulation(EqpManipulation eqp)
|
||||
{
|
||||
Eqp = eqp;
|
||||
|
|
@ -163,9 +177,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
public bool EntryEquals(MetaManipulation other)
|
||||
{
|
||||
if (ManipulationType != other.ManipulationType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManipulationType switch
|
||||
{
|
||||
|
|
@ -182,9 +194,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
public bool Equals(MetaManipulation other)
|
||||
{
|
||||
if (ManipulationType != other.ManipulationType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ManipulationType switch
|
||||
{
|
||||
|
|
@ -201,9 +211,7 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
public MetaManipulation WithEntryOf(MetaManipulation other)
|
||||
{
|
||||
if (ManipulationType != other.ManipulationType)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return ManipulationType switch
|
||||
{
|
||||
|
|
@ -255,7 +263,8 @@ public readonly struct MetaManipulation : IEquatable< MetaManipulation >, ICompa
|
|||
public string EntryToString()
|
||||
=> ManipulationType switch
|
||||
{
|
||||
Type.Imc => $"{Imc.Entry.DecalId}-{Imc.Entry.MaterialId}-{Imc.Entry.VfxId}-{Imc.Entry.SoundId}-{Imc.Entry.MaterialAnimationId}-{Imc.Entry.AttributeMask}",
|
||||
Type.Imc =>
|
||||
$"{Imc.Entry.DecalId}-{Imc.Entry.MaterialId}-{Imc.Entry.VfxId}-{Imc.Entry.SoundId}-{Imc.Entry.MaterialAnimationId}-{Imc.Entry.AttributeMask}",
|
||||
Type.Eqdp => $"{(ushort)Eqdp.Entry:X}",
|
||||
Type.Eqp => $"{(ulong)Eqp.Entry:X}",
|
||||
Type.Est => $"{Est.Entry}",
|
||||
|
|
|
|||
|
|
@ -56,11 +56,21 @@ public readonly struct RspManipulation : IMetaManipulation< RspManipulation >
|
|||
{
|
||||
var value = file[SubRace, Attribute];
|
||||
if (value == Entry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file[SubRace, Attribute] = Entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
if (SubRace is SubRace.Unknown || !Enum.IsDefined(SubRace))
|
||||
return false;
|
||||
if (!Enum.IsDefined(Attribute))
|
||||
return false;
|
||||
if (Entry is <= 1e-2f or > 8f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ public sealed class SubMod : ISubMod
|
|||
var manips = json[nameof(Manipulations)];
|
||||
if (manips != null)
|
||||
foreach (var s in manips.Children().Select(c => c.ToObject<MetaManipulation>())
|
||||
.Where(m => m.ManipulationType != MetaManipulation.Type.Unknown))
|
||||
.Where(m => m.Validate()))
|
||||
ManipulationData.Add(s);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue