diff --git a/Penumbra/Collections/Cache/ShapeAttributeHashSet.cs b/Penumbra/Collections/Cache/ShapeAttributeHashSet.cs index f1fc7127..74691e41 100644 --- a/Penumbra/Collections/Cache/ShapeAttributeHashSet.cs +++ b/Penumbra/Collections/Cache/ShapeAttributeHashSet.cs @@ -21,43 +21,39 @@ public sealed class ShapeAttributeHashSet : Dictionary<(HumanSlot Slot, PrimaryI private readonly BitArray _allIds = new((ShapeAttributeManager.ModelSlotSize + 1) * GenderRaceValues.Count); - public bool this[HumanSlot slot] - => slot is HumanSlot.Unknown ? All : _allIds[(int)slot * GenderRaceIndices.Count]; - - public bool this[GenderRace genderRace] - => GenderRaceIndices.TryGetValue(genderRace, out var index) - && _allIds[ShapeAttributeManager.ModelSlotSize * GenderRaceIndices.Count + index]; - - public bool this[HumanSlot slot, GenderRace genderRace] + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private bool CheckGroups(HumanSlot slot, GenderRace genderRace) { - get - { - if (!GenderRaceIndices.TryGetValue(genderRace, out var index)) - return false; + if (All || this[slot]) + return true; - if (_allIds[ShapeAttributeManager.ModelSlotSize * GenderRaceIndices.Count + index]) - return true; + if (!GenderRaceIndices.TryGetValue(genderRace, out var index)) + return false; - return _allIds[(int)slot * GenderRaceIndices.Count + index]; - } - set - { - if (!GenderRaceIndices.TryGetValue(genderRace, out var index)) - return; + if (_allIds[ToIndex(HumanSlot.Unknown, index)]) + return true; - var genderRaceCount = GenderRaceValues.Count; - if (slot is HumanSlot.Unknown) - _allIds[ShapeAttributeManager.ModelSlotSize * genderRaceCount + index] = value; - else - _allIds[(int)slot * genderRaceCount + index] = value; - } + return _allIds[ToIndex(slot, index)]; } + public bool this[HumanSlot slot] + => _allIds[ToIndex(slot, 0)]; + + public bool this[GenderRace genderRace] + => ToIndex(HumanSlot.Unknown, genderRace, out var index) && _allIds[index]; + + public bool this[HumanSlot slot, GenderRace genderRace] + => ToIndex(slot, genderRace, out var index) && _allIds[index]; + public bool All - => _allIds[ShapeAttributeManager.ModelSlotSize * GenderRaceIndices.Count]; + => _allIds[AllIndex]; + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private static int ToIndex(HumanSlot slot, int genderRaceIndex) + => slot is HumanSlot.Unknown ? genderRaceIndex + AllIndex : genderRaceIndex + (int)slot * GenderRaceValues.Count; public bool Contains(HumanSlot slot, PrimaryId id, GenderRace genderRace) - => All || this[slot, genderRace] || ContainsEntry(slot, id, genderRace); + => CheckGroups(slot, genderRace) || ContainsEntry(slot, id, genderRace); [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private bool ContainsEntry(HumanSlot slot, PrimaryId id, GenderRace genderRace) @@ -72,9 +68,9 @@ public sealed class ShapeAttributeHashSet : Dictionary<(HumanSlot Slot, PrimaryI if (!id.HasValue) { - var slotIndex = slot is HumanSlot.Unknown ? ShapeAttributeManager.ModelSlotSize : (int)slot; - var old = _allIds[slotIndex * GenderRaceIndices.Count + index]; - _allIds[slotIndex * GenderRaceIndices.Count + index] = value; + var slotIndex = ToIndex(slot, index); + var old = _allIds[slotIndex]; + _allIds[slotIndex] = value; return old != value; } @@ -120,4 +116,16 @@ public sealed class ShapeAttributeHashSet : Dictionary<(HumanSlot Slot, PrimaryI public bool IsEmpty => !_allIds.HasAnySet() && Count is 0; + + private static readonly int AllIndex = ShapeAttributeManager.ModelSlotSize * GenderRaceValues.Count; + + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private static bool ToIndex(HumanSlot slot, GenderRace genderRace, out int index) + { + if (!GenderRaceIndices.TryGetValue(genderRace, out index)) + return false; + + index = ToIndex(slot, index); + return true; + } } diff --git a/Penumbra/UI/Tabs/Debug/ShapeInspector.cs b/Penumbra/UI/Tabs/Debug/ShapeInspector.cs index 3180a212..fd37bf35 100644 --- a/Penumbra/UI/Tabs/Debug/ShapeInspector.cs +++ b/Penumbra/UI/Tabs/Debug/ShapeInspector.cs @@ -1,6 +1,7 @@ using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using ImGuiNET; +using OtterGui.Extensions; using OtterGui.Services; using OtterGui.Text; using Penumbra.Collections.Cache; @@ -167,7 +168,7 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) ImUtf8.TableSetupColumn("Slot"u8, ImGuiTableColumnFlags.WidthFixed, 150 * ImUtf8.GlobalScale); ImUtf8.TableSetupColumn("Address"u8, ImGuiTableColumnFlags.WidthFixed, UiBuilder.MonoFont.GetCharAdvance('0') * 14); ImUtf8.TableSetupColumn("Mask"u8, ImGuiTableColumnFlags.WidthFixed, UiBuilder.MonoFont.GetCharAdvance('0') * 8); - ImUtf8.TableSetupColumn("Count"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImUtf8.GlobalScale); + ImUtf8.TableSetupColumn("Count"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImUtf8.GlobalScale); ImUtf8.TableSetupColumn("Shapes"u8, ImGuiTableColumnFlags.WidthStretch); ImGui.TableHeadersRow(); @@ -187,9 +188,9 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) ImUtf8.DrawTableColumn($"{mask:X8}"); ImUtf8.DrawTableColumn($"{model->ModelResourceHandle->Shapes.Count}"); ImGui.TableNextColumn(); - foreach (var (shape, idx) in model->ModelResourceHandle->Shapes) + foreach (var ((shape, flag), idx) in model->ModelResourceHandle->Shapes.WithIndex()) { - var disabled = (mask & (1u << idx)) is 0; + var disabled = (mask & (1u << flag)) is 0; using var color = ImRaii.PushColor(ImGuiCol.Text, disabledColor, disabled); ImUtf8.Text(shape.AsSpan()); ImGui.SameLine(0, 0); @@ -241,9 +242,9 @@ public class ShapeInspector(ObjectManager objects, CollectionResolver resolver) ImUtf8.DrawTableColumn($"{mask:X8}"); ImUtf8.DrawTableColumn($"{model->ModelResourceHandle->Attributes.Count}"); ImGui.TableNextColumn(); - foreach (var (attribute, idx) in model->ModelResourceHandle->Attributes) + foreach (var ((attribute, flag), idx) in model->ModelResourceHandle->Attributes.WithIndex()) { - var disabled = (mask & (1u << idx)) is 0; + var disabled = (mask & (1u << flag)) is 0; using var color = ImRaii.PushColor(ImGuiCol.Text, disabledColor, disabled); ImUtf8.Text(attribute.AsSpan()); ImGui.SameLine(0, 0);