Update shp conditions.

This commit is contained in:
Ottermandias 2025-05-18 15:52:47 +02:00
parent fbc4c2d054
commit e326e3d809
8 changed files with 137 additions and 179 deletions

View file

@ -1,4 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
@ -7,7 +8,16 @@ using Penumbra.Interop.Structs;
namespace Penumbra.Meta.Manipulations;
public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, ShapeString Shape, ShapeString ShapeCondition)
[JsonConverter(typeof(StringEnumConverter))]
public enum ShapeConnectorCondition : byte
{
None = 0,
Wrists = 1,
Waist = 2,
Ankles = 3,
}
public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, ShapeString Shape, ShapeConnectorCondition ConnectorCondition)
: IComparable<ShpIdentifier>, IMetaIdentifier
{
public int CompareTo(ShpIdentifier other)
@ -34,11 +44,11 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape
return 1;
}
var shapeComparison = Shape.CompareTo(other.Shape);
if (shapeComparison is not 0)
return shapeComparison;
var conditionComparison = ConnectorCondition.CompareTo(other.ConnectorCondition);
if (conditionComparison is not 0)
return conditionComparison;
return ShapeCondition.CompareTo(other.ShapeCondition);
return Shape.CompareTo(other.Shape);
}
@ -62,9 +72,13 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape
sb.Append("All IDs");
}
if (ShapeCondition.Length > 0)
sb.Append(" - ")
.Append(ShapeCondition);
switch (ConnectorCondition)
{
case ShapeConnectorCondition.Wrists: sb.Append(" - Wrist Connector"); break;
case ShapeConnectorCondition.Waist: sb.Append(" - Waist Connector"); break;
case ShapeConnectorCondition.Ankles: sb.Append(" - Ankle Connector"); break;
}
return sb.ToString();
}
@ -87,20 +101,16 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape
if (!ValidateCustomShapeString(Shape))
return false;
if (ShapeCondition.Length is 0)
return true;
if (!ValidateCustomShapeString(ShapeCondition))
if (!Enum.IsDefined(ConnectorCondition))
return false;
return Slot switch
return ConnectorCondition switch
{
HumanSlot.Hands when ShapeCondition.IsWrist() => true,
HumanSlot.Body when ShapeCondition.IsWrist() || ShapeCondition.IsWaist() => true,
HumanSlot.Legs when ShapeCondition.IsWaist() || ShapeCondition.IsAnkle() => true,
HumanSlot.Feet when ShapeCondition.IsAnkle() => true,
HumanSlot.Unknown when ShapeCondition.IsWrist() || ShapeCondition.IsWaist() || ShapeCondition.IsAnkle() => true,
_ => false,
ShapeConnectorCondition.None => true,
ShapeConnectorCondition.Wrists => Slot is HumanSlot.Body or HumanSlot.Hands or HumanSlot.Unknown,
ShapeConnectorCondition.Waist => Slot is HumanSlot.Body or HumanSlot.Legs or HumanSlot.Unknown,
ShapeConnectorCondition.Ankles => Slot is HumanSlot.Legs or HumanSlot.Feet or HumanSlot.Unknown,
_ => false,
};
}
@ -145,8 +155,8 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape
if (Id.HasValue)
jObj["Id"] = Id.Value.Id.ToString();
jObj["Shape"] = Shape.ToString();
if (ShapeCondition.Length > 0)
jObj["ShapeCondition"] = ShapeCondition.ToString();
if (ConnectorCondition is not ShapeConnectorCondition.None)
jObj["ConnectorCondition"] = ConnectorCondition.ToString();
return jObj;
}
@ -156,11 +166,10 @@ public readonly record struct ShpIdentifier(HumanSlot Slot, PrimaryId? Id, Shape
if (shape is null || !ShapeString.TryRead(shape, out var shapeString))
return null;
var slot = jObj["Slot"]?.ToObject<HumanSlot>() ?? HumanSlot.Unknown;
var id = jObj["Id"]?.ToObject<ushort>();
var shapeCondition = jObj["ShapeCondition"]?.ToObject<string>();
var shapeConditionString = shapeCondition is null || !ShapeString.TryRead(shapeCondition, out var s) ? ShapeString.Empty : s;
var identifier = new ShpIdentifier(slot, id, shapeString, shapeConditionString);
var slot = jObj["Slot"]?.ToObject<HumanSlot>() ?? HumanSlot.Unknown;
var id = jObj["Id"]?.ToObject<ushort>();
var connectorCondition = jObj["ConnectorCondition"]?.ToObject<ShapeConnectorCondition>() ?? ShapeConnectorCondition.None;
var identifier = new ShpIdentifier(slot, id, shapeString, connectorCondition);
return identifier.Validate() ? identifier : null;
}

View file

@ -1,4 +1,3 @@
using System.Reflection.Metadata.Ecma335;
using OtterGui.Services;
using Penumbra.Collections;
using Penumbra.Collections.Cache;
@ -80,8 +79,7 @@ public class ShapeManager : IRequiredService, IDisposable
{
_temporaryIndices[i].TryAdd(shapeString, index);
_temporaryMasks[i] |= (ushort)(1 << index);
if (cache.State.Count > 0
&& cache.ShouldBeEnabled(shapeString, modelIndex, _ids[(int)modelIndex]))
if (cache.ShouldBeEnabled(shapeString, modelIndex, _ids[(int)modelIndex]))
_temporaryValues[i] |= (ushort)(1 << index);
}
else
@ -102,14 +100,14 @@ public class ShapeManager : IRequiredService, IDisposable
{
_temporaryValues[1] |= 1u << topIndex;
_temporaryValues[2] |= 1u << handIndex;
CheckCondition(shape, HumanSlot.Body, HumanSlot.Hands, 1, 2);
CheckCondition(cache.State(ShapeConnectorCondition.Wrists), HumanSlot.Body, HumanSlot.Hands, 1, 2);
}
if (shape.IsWaist() && _temporaryIndices[3].TryGetValue(shape, out var legIndex))
{
_temporaryValues[1] |= 1u << topIndex;
_temporaryValues[3] |= 1u << legIndex;
CheckCondition(shape, HumanSlot.Body, HumanSlot.Legs, 1, 3);
CheckCondition(cache.State(ShapeConnectorCondition.Waist), HumanSlot.Body, HumanSlot.Legs, 1, 3);
}
}
@ -119,25 +117,23 @@ public class ShapeManager : IRequiredService, IDisposable
{
_temporaryValues[3] |= 1u << bottomIndex;
_temporaryValues[4] |= 1u << footIndex;
CheckCondition(shape, HumanSlot.Legs, HumanSlot.Feet, 3, 4);
CheckCondition(cache.State(ShapeConnectorCondition.Ankles), HumanSlot.Legs, HumanSlot.Feet, 3, 4);
}
}
return;
void CheckCondition(in ShapeString shape, HumanSlot slot1, HumanSlot slot2, int idx1, int idx2)
void CheckCondition(IReadOnlyDictionary<ShapeString, ShpCache.ShpHashSet> dict, HumanSlot slot1, HumanSlot slot2, int idx1, int idx2)
{
if (!cache.CheckConditionState(shape, out var dict))
if (dict.Count is 0)
return;
foreach (var (subShape, set) in dict)
foreach (var (shape, set) in dict)
{
if (set.Contains(slot1, _ids[idx1]))
if (_temporaryIndices[idx1].TryGetValue(subShape, out var subIndex))
_temporaryValues[idx1] |= 1u << subIndex;
if (set.Contains(slot2, _ids[idx2]))
if (_temporaryIndices[idx2].TryGetValue(subShape, out var subIndex))
_temporaryValues[idx2] |= 1u << subIndex;
if (set.Contains(slot1, _ids[idx1]) && _temporaryIndices[idx1].TryGetValue(shape, out var index1))
_temporaryValues[idx1] |= 1u << index1;
if (set.Contains(slot2, _ids[idx2]) && _temporaryIndices[idx2].TryGetValue(shape, out var index2))
_temporaryValues[idx2] |= 1u << index2;
}
}
}