Files
tbd-station-14/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs
paige404 2e7f01b99e 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>
2025-03-21 00:30:47 +11:00

90 lines
3.8 KiB
C#

using Content.Shared.Clothing.Components;
using Content.Shared.Foldable;
using Content.Shared.Inventory;
using Content.Shared.Item;
namespace Content.Shared.Clothing.EntitySystems;
public sealed class FoldableClothingSystem : EntitySystem
{
[Dependency] private readonly ClothingSystem _clothingSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FoldableClothingComponent, FoldAttemptEvent>(OnFoldAttempt);
SubscribeLocalEvent<FoldableClothingComponent, FoldedEvent>(OnFolded,
after: [typeof(MaskSystem)]); // Mask system also modifies clothing / equipment RSI state prefixes.
}
private void OnFoldAttempt(Entity<FoldableClothingComponent> ent, ref FoldAttemptEvent args)
{
if (args.Cancelled)
return;
if (!_inventorySystem.TryGetContainingSlot(ent.Owner, out var slot))
return;
// Cannot fold clothing equipped to a slot if the slot becomes disallowed
var newSlots = args.Comp.IsFolded ? ent.Comp.UnfoldedSlots : ent.Comp.FoldedSlots;
if (newSlots != null && (newSlots.Value & slot.SlotFlags) != slot.SlotFlags)
{
args.Cancelled = true;
return;
}
// Setting hidden layers while equipped is not currently supported.
if (ent.Comp.FoldedHideLayers != null || ent.Comp.UnfoldedHideLayers != null)
args.Cancelled = true;
}
private void OnFolded(Entity<FoldableClothingComponent> ent, ref FoldedEvent args)
{
if (!TryComp<ClothingComponent>(ent.Owner, out var clothingComp) ||
!TryComp<ItemComponent>(ent.Owner, out var itemComp))
return;
if (args.IsFolded)
{
if (ent.Comp.FoldedSlots.HasValue)
_clothingSystem.SetSlots(ent.Owner, ent.Comp.FoldedSlots.Value, clothingComp);
if (ent.Comp.FoldedEquippedPrefix != null)
_clothingSystem.SetEquippedPrefix(ent.Owner, ent.Comp.FoldedEquippedPrefix, clothingComp);
if (ent.Comp.FoldedHeldPrefix != null)
_itemSystem.SetHeldPrefix(ent.Owner, ent.Comp.FoldedHeldPrefix, false, itemComp);
// This is janky and likely to lead to bugs.
// I.e., overriding this and resetting it again later will lead to bugs if someone tries to modify clothing
// in yaml, but doesn't realise theres actually two other fields on an unrelated component that they also need
// to modify.
// This should instead work via an event or something that gets raised to optionally modify the currently hidden layers.
// Or at the very least it should stash the old layers and restore them when unfolded.
// TODO CLOTHING fix this.
if (ent.Comp.FoldedHideLayers != null && TryComp<HideLayerClothingComponent>(ent.Owner, out var hideLayerComp))
hideLayerComp.Slots = ent.Comp.FoldedHideLayers;
}
else
{
if (ent.Comp.UnfoldedSlots.HasValue)
_clothingSystem.SetSlots(ent.Owner, ent.Comp.UnfoldedSlots.Value, clothingComp);
if (ent.Comp.FoldedEquippedPrefix != null)
_clothingSystem.SetEquippedPrefix(ent.Owner, null, clothingComp);
if (ent.Comp.FoldedHeldPrefix != null)
_itemSystem.SetHeldPrefix(ent.Owner, null, false, itemComp);
// TODO CLOTHING fix this.
if (ent.Comp.UnfoldedHideLayers != null && TryComp<HideLayerClothingComponent>(ent.Owner, out var hideLayerComp))
hideLayerComp.Slots = ent.Comp.UnfoldedHideLayers;
}
}
}