diff --git a/Penumbra/Meta/Manipulations/ShpIdentifier.cs b/Penumbra/Meta/Manipulations/ShpIdentifier.cs index fffa51ba..c642167f 100644 --- a/Penumbra/Meta/Manipulations/ShpIdentifier.cs +++ b/Penumbra/Meta/Manipulations/ShpIdentifier.cs @@ -1,4 +1,3 @@ -using Lumina.Models.Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Penumbra.GameData.Data; @@ -61,34 +60,16 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape return ValidateCustomShapeString(Shape); } - public static bool ValidateCustomShapeString(ReadOnlySpan shape) - { - // "shp_xx_y" - if (shape.Length < 8) - return false; - - if (shape[0] is not (byte)'s' - || shape[1] is not (byte)'h' - || shape[2] is not (byte)'p' - || shape[3] is not (byte)'_' - || shape[6] is not (byte)'_') - return false; - - return true; - } - public static unsafe bool ValidateCustomShapeString(byte* shape) { - // "shp_xx_y" + // "shpx_*" if (shape is null) return false; if (*shape++ is not (byte)'s' || *shape++ is not (byte)'h' || *shape++ is not (byte)'p' - || *shape++ is not (byte)'_' - || *shape++ is 0 - || *shape++ is 0 + || *shape++ is not (byte)'x' || *shape++ is not (byte)'_' || *shape is 0) return false; @@ -98,16 +79,16 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape public static bool ValidateCustomShapeString(in ShapeString shape) { - // "shp_xx_y" - if (shape.Length < 8) + // "shpx_*" + if (shape.Length < 6) return false; var span = shape.AsSpan; if (span[0] is not (byte)'s' || span[1] is not (byte)'h' || span[2] is not (byte)'p' - || span[3] is not (byte)'_' - || span[6] is not (byte)'_') + || span[3] is not (byte)'x' + || span[4] is not (byte)'_') return false; return true; diff --git a/Penumbra/Meta/ShapeManager.cs b/Penumbra/Meta/ShapeManager.cs index ec8ddb50..dc3e1a1c 100644 --- a/Penumbra/Meta/ShapeManager.cs +++ b/Penumbra/Meta/ShapeManager.cs @@ -93,13 +93,13 @@ public class ShapeManager : IRequiredService, IDisposable { foreach (var (shape, topIndex) in _temporaryIndices[1]) { - if (shape[4] is (byte)'w' && shape[5] is (byte)'r' && _temporaryIndices[2].TryGetValue(shape, out var handIndex)) + if (CheckCenter(shape, 'w', 'r') && _temporaryIndices[2].TryGetValue(shape, out var handIndex)) { _temporaryValues[1] |= 1u << topIndex; _temporaryValues[2] |= 1u << handIndex; } - if (shape[4] is (byte)'w' && shape[5] is (byte)'a' && _temporaryIndices[3].TryGetValue(shape, out var legIndex)) + if (CheckCenter(shape, 'w', 'a') && _temporaryIndices[3].TryGetValue(shape, out var legIndex)) { _temporaryValues[1] |= 1u << topIndex; _temporaryValues[3] |= 1u << legIndex; @@ -108,11 +108,15 @@ public class ShapeManager : IRequiredService, IDisposable foreach (var (shape, bottomIndex) in _temporaryIndices[3]) { - if (shape[4] is (byte)'a' && shape[5] is (byte)'n' && _temporaryIndices[4].TryGetValue(shape, out var footIndex)) + if (CheckCenter(shape, 'a', 'n') && _temporaryIndices[4].TryGetValue(shape, out var footIndex)) { _temporaryValues[3] |= 1u << bottomIndex; _temporaryValues[4] |= 1u << footIndex; } } } + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private static bool CheckCenter(in ShapeString shape, char first, char second) + => shape.Length > 8 && shape[4] == first && shape[5] == second && shape[6] is (byte)'_'; } diff --git a/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs b/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs index 4be6e6aa..2c99af02 100644 --- a/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs +++ b/Penumbra/UI/AdvancedWindow/Meta/ShpMetaDrawer.cs @@ -19,7 +19,7 @@ public sealed class ShpMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile public override ReadOnlySpan Label => "Shape Keys (SHP)###SHP"u8; - private ShapeString _buffer = ShapeString.TryRead("shp_"u8, out var s) ? s : ShapeString.Empty; + private ShapeString _buffer = ShapeString.TryRead("shpx_"u8, out var s) ? s : ShapeString.Empty; private bool _identifierValid; public override int NumColumns @@ -200,7 +200,7 @@ public sealed class ShpMetaDrawer(ModMetaEditor editor, MetaFileManager metaFile } } - ImUtf8.HoverTooltip("Supported shape keys need to have the format `shp_xx_*` and a maximum length of 30 characters."u8); + ImUtf8.HoverTooltip("Supported shape keys need to have the format `shpx_*` and a maximum length of 30 characters."u8); return ret; } diff --git a/schemas/structs/meta_shp.json b/schemas/structs/meta_shp.json index e6b66420..197f3104 100644 --- a/schemas/structs/meta_shp.json +++ b/schemas/structs/meta_shp.json @@ -13,8 +13,9 @@ }, "Shape": { "type": "string", - "minLength": 8, - "maxLength": 30 + "minLength": 5, + "maxLength": 30, + "pattern": "^shpx_" } }, "required": [