Fix broken layer hiding on clothes with multiple equipment slots (#34080)
* Fix broken layer hiding on clothes with multiple equipment slots * Refactor ToggleVisualLayers, HideLayerClothingComponent, and ClothingComponent to allow more precise layer hide behavior and more CPU efficient layer toggling. * Adjust HumanoidAppearaceSystem to track which slots are hiding a given layer (e.g. gas mask and welding mask) Add documentation Change gas masks to use the new HideLayerClothingComponent structure as an example of its usage * Fix the delayed snout bug * Misc cleanup * Make `bool permanent` implicit from SlotFlags any non-permanent visibility toggle with `SlotFlags.None` isn't supported with how its set up. And similarly, the slot flags argument does nothing if permanent = true. So IMO it makes more sense to infer it from a nullable arg. * Split into separate system Too much pasta * Remove (hopefully unnecessary) refresh * Fisk mask networking AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA * Keep old behaviour, use clearer names? I'm just guessing at what this was meant to do * english * Separate slot name & flag * dirty = true * fix comment * Improved SetLayerVisibility with dirtying logic suggested by @ElectroJr * Only set mask toggled if DisableOnFold is true * FoldableClothingSystem fixes * fix bandana state * Better comment --------- Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
This commit is contained in:
@@ -16,9 +16,9 @@ public abstract class ClothingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _itemSys = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSys = default!;
|
||||
[Dependency] private readonly SharedHumanoidAppearanceSystem _humanoidSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _invSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly HideLayerClothingSystem _hideLayer = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -29,7 +29,6 @@ public abstract class ClothingSystem : EntitySystem
|
||||
SubscribeLocalEvent<ClothingComponent, ComponentHandleState>(OnHandleState);
|
||||
SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<ClothingComponent, GotUnequippedEvent>(OnGotUnequipped);
|
||||
SubscribeLocalEvent<ClothingComponent, ItemMaskToggledEvent>(OnMaskToggled);
|
||||
|
||||
SubscribeLocalEvent<ClothingComponent, ClothingEquipDoAfterEvent>(OnEquipDoAfter);
|
||||
SubscribeLocalEvent<ClothingComponent, ClothingUnequipDoAfterEvent>(OnUnequipDoAfter);
|
||||
@@ -85,59 +84,19 @@ public abstract class ClothingSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleVisualLayers(EntityUid equipee, HashSet<HumanoidVisualLayers> layers, HashSet<HumanoidVisualLayers> appearanceLayers)
|
||||
{
|
||||
foreach (HumanoidVisualLayers layer in layers)
|
||||
{
|
||||
if (!appearanceLayers.Contains(layer))
|
||||
continue;
|
||||
|
||||
InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee);
|
||||
|
||||
bool shouldLayerShow = true;
|
||||
while (enumerator.NextItem(out EntityUid item, out SlotDefinition? slot))
|
||||
{
|
||||
if (TryComp(item, out HideLayerClothingComponent? comp))
|
||||
{
|
||||
if (comp.Slots.Contains(layer))
|
||||
{
|
||||
if (TryComp(item, out ClothingComponent? clothing) && clothing.Slots == slot.SlotFlags)
|
||||
{
|
||||
//Checks for mask toggling. TODO: Make a generic system for this
|
||||
if (comp.HideOnToggle && TryComp(item, out MaskComponent? mask))
|
||||
{
|
||||
if (clothing.EquippedPrefix != mask.EquippedPrefix)
|
||||
{
|
||||
shouldLayerShow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldLayerShow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_humanoidSystem.SetLayerVisibility(equipee, layer, shouldLayerShow);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args)
|
||||
{
|
||||
component.InSlot = args.Slot;
|
||||
CheckEquipmentForLayerHide(args.Equipment, args.Equipee);
|
||||
component.InSlotFlag = args.SlotFlags;
|
||||
|
||||
if ((component.Slots & args.SlotFlags) != SlotFlags.NONE)
|
||||
{
|
||||
var gotEquippedEvent = new ClothingGotEquippedEvent(args.Equipee, component);
|
||||
RaiseLocalEvent(uid, ref gotEquippedEvent);
|
||||
if ((component.Slots & args.SlotFlags) == SlotFlags.NONE)
|
||||
return;
|
||||
|
||||
var didEquippedEvent = new ClothingDidEquippedEvent((uid, component));
|
||||
RaiseLocalEvent(args.Equipee, ref didEquippedEvent);
|
||||
}
|
||||
var gotEquippedEvent = new ClothingGotEquippedEvent(args.Equipee, component);
|
||||
RaiseLocalEvent(uid, ref gotEquippedEvent);
|
||||
|
||||
var didEquippedEvent = new ClothingDidEquippedEvent((uid, component));
|
||||
RaiseLocalEvent(args.Equipee, ref didEquippedEvent);
|
||||
}
|
||||
|
||||
protected virtual void OnGotUnequipped(EntityUid uid, ClothingComponent component, GotUnequippedEvent args)
|
||||
@@ -152,7 +111,7 @@ public abstract class ClothingSystem : EntitySystem
|
||||
}
|
||||
|
||||
component.InSlot = null;
|
||||
CheckEquipmentForLayerHide(args.Equipment, args.Equipee);
|
||||
component.InSlotFlag = null;
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, ClothingComponent component, ref ComponentGetState args)
|
||||
@@ -162,21 +121,10 @@ public abstract class ClothingSystem : EntitySystem
|
||||
|
||||
private void OnHandleState(EntityUid uid, ClothingComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is ClothingComponentState state)
|
||||
{
|
||||
SetEquippedPrefix(uid, state.EquippedPrefix, component);
|
||||
if (component.InSlot != null && _containerSys.TryGetContainingContainer((uid, null, null), out var container))
|
||||
{
|
||||
CheckEquipmentForLayerHide(uid, container.Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.Current is not ClothingComponentState state)
|
||||
return;
|
||||
|
||||
private void OnMaskToggled(Entity<ClothingComponent> ent, ref ItemMaskToggledEvent args)
|
||||
{
|
||||
//TODO: sprites for 'pulled down' state. defaults to invisible due to no sprite with this prefix
|
||||
SetEquippedPrefix(ent, args.IsToggled ? args.equippedPrefix : null, ent);
|
||||
CheckEquipmentForLayerHide(ent.Owner, args.Wearer);
|
||||
SetEquippedPrefix(uid, state.EquippedPrefix, component);
|
||||
}
|
||||
|
||||
private void OnEquipDoAfter(Entity<ClothingComponent> ent, ref ClothingEquipDoAfterEvent args)
|
||||
@@ -200,12 +148,6 @@ public abstract class ClothingSystem : EntitySystem
|
||||
args.Additive += ent.Comp.StripDelay;
|
||||
}
|
||||
|
||||
private void CheckEquipmentForLayerHide(EntityUid equipment, EntityUid equipee)
|
||||
{
|
||||
if (TryComp(equipment, out HideLayerClothingComponent? clothesComp) && TryComp(equipee, out HumanoidAppearanceComponent? appearanceComp))
|
||||
ToggleVisualLayers(equipee, clothesComp.Slots, appearanceComp.HideLayersOnEquip);
|
||||
}
|
||||
|
||||
#region Public API
|
||||
|
||||
public void SetEquippedPrefix(EntityUid uid, string? prefix, ClothingComponent? clothing = null)
|
||||
|
||||
Reference in New Issue
Block a user