Fix forensics not being applied to held items (#30609)

* Initial commit

* Fix merge changes

* sloth comment: bitmask

* fix MIA parameter

---------

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: EmoGarbage404 <retron404@gmail.com>
This commit is contained in:
SlamBamActionman
2025-04-19 03:02:41 +02:00
committed by GitHub
parent 00c4833c9a
commit a44baec417
7 changed files with 52 additions and 22 deletions

View File

@@ -31,8 +31,8 @@ namespace Content.Server.Inventory
var enumerator = new InventorySlotEnumerator(source.Comp); var enumerator = new InventorySlotEnumerator(source.Comp);
while (enumerator.NextItem(out var item, out var slot)) while (enumerator.NextItem(out var item, out var slot))
{ {
if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp)) if (TryUnequip(source, slot.Name, true, true, inventory: source.Comp, triggerHandContact: true))
TryEquip(target, item, slot.Name , true, true, inventory: target.Comp); TryEquip(target, item, slot.Name , true, true, inventory: target.Comp, triggerHandContact: true);
} }
} }
} }

View File

@@ -9,6 +9,7 @@ using Content.Shared.Ensnaring.Components;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Events;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.Inventory.VirtualItem; using Content.Shared.Inventory.VirtualItem;

View File

@@ -65,14 +65,14 @@ public abstract class ClothingSystem : EntitySystem
if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, checkDoafter: true)) if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, checkDoafter: true))
continue; continue;
if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true)) if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true, triggerHandContact: true))
continue; continue;
_handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt); _handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt);
} }
else else
{ {
if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true)) if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt, checkDoafter: true, triggerHandContact: true))
continue; continue;
} }
@@ -134,7 +134,7 @@ public abstract class ClothingSystem : EntitySystem
{ {
if (args.Handled || args.Cancelled || args.Target is not { } target) if (args.Handled || args.Cancelled || args.Target is not { } target)
return; return;
args.Handled = _invSystem.TryUnequip(args.User, target, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false); args.Handled = _invSystem.TryUnequip(args.User, target, args.Slot, clothing: ent.Comp, predicted: true, checkDoafter: false, triggerHandContact: true);
if (args.Handled) if (args.Handled)
_handsSystem.TryPickup(args.User, ent); _handsSystem.TryPickup(args.User, ent);
} }

View File

@@ -160,7 +160,7 @@ public sealed class ToggleableClothingSystem : EntitySystem
// This should maybe double check that the entity currently in the slot is actually the attached clothing, but // This should maybe double check that the entity currently in the slot is actually the attached clothing, but
// if its not, then something else has gone wrong already... // if its not, then something else has gone wrong already...
if (component.Container != null && component.Container.ContainedEntity == null && component.ClothingUid != null) if (component.Container != null && component.Container.ContainedEntity == null && component.ClothingUid != null)
_inventorySystem.TryUnequip(args.Equipee, component.Slot, force: true); _inventorySystem.TryUnequip(args.Equipee, component.Slot, force: true, triggerHandContact: true);
} }
private void OnRemoveToggleable(EntityUid uid, ToggleableClothingComponent component, ComponentRemove args) private void OnRemoveToggleable(EntityUid uid, ToggleableClothingComponent component, ComponentRemove args)
@@ -248,7 +248,7 @@ public sealed class ToggleableClothingSystem : EntitySystem
user, user); user, user);
} }
else else
_inventorySystem.TryEquip(user, parent, component.ClothingUid.Value, component.Slot); _inventorySystem.TryEquip(user, parent, component.ClothingUid.Value, component.Slot, triggerHandContact: true);
} }
private void OnGetActions(EntityUid uid, ToggleableClothingComponent component, GetItemActionsEvent args) private void OnGetActions(EntityUid uid, ToggleableClothingComponent component, GetItemActionsEvent args)

View File

@@ -242,6 +242,8 @@ public abstract partial class SharedHandsSystem : EntitySystem
return; return;
} }
_interactionSystem.DoContactInteraction(uid, entity); //Possibly fires twice if manually picked up via interacting with the object
if (log) if (log)
_adminLogger.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}"); _adminLogger.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}");

View File

@@ -97,7 +97,7 @@ public abstract partial class InventorySystem
// unequip the item. // unequip the item.
if (itemUid != null) if (itemUid != null)
{ {
if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory, checkDoafter: true)) if (!TryUnequip(actor, ev.Slot, out var item, predicted: true, inventory: inventory, checkDoafter: true, triggerHandContact: true))
return; return;
_handsSystem.PickupOrDrop(actor, item.Value); _handsSystem.PickupOrDrop(actor, item.Value);
@@ -120,15 +120,15 @@ public abstract partial class InventorySystem
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor)); RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor));
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: true); TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter: true, triggerHandContact: true);
} }
public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false, public bool TryEquip(EntityUid uid, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false,
InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) => InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false, bool triggerHandContact = false) =>
TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter); TryEquip(uid, uid, itemUid, slot, silent, force, predicted, inventory, clothing, checkDoafter, triggerHandContact);
public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false, public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false, bool predicted = false,
InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false) InventoryComponent? inventory = null, ClothingComponent? clothing = null, bool checkDoafter = false, bool triggerHandContact = false)
{ {
if (!Resolve(target, ref inventory, false)) if (!Resolve(target, ref inventory, false))
{ {
@@ -190,6 +190,10 @@ public abstract partial class InventorySystem
_audio.PlayPredicted(clothing.EquipSound, target, actor); _audio.PlayPredicted(clothing.EquipSound, target, actor);
} }
// If new gloves are equipped, trigger OnContactInteraction for held items
if (triggerHandContact && !((slotDefinition.SlotFlags & SlotFlags.GLOVES) == 0))
TriggerHandContactInteraction(target);
Dirty(target, inventory); Dirty(target, inventory);
_movementSpeed.RefreshMovementSpeedModifiers(target); _movementSpeed.RefreshMovementSpeedModifiers(target);
@@ -320,9 +324,10 @@ public abstract partial class InventorySystem
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true, bool reparent = true,
bool checkDoafter = false) bool checkDoafter = false,
bool triggerHandContact = false)
{ {
return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent, checkDoafter); return TryUnequip(uid, uid, slot, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact);
} }
public bool TryUnequip( public bool TryUnequip(
@@ -335,9 +340,10 @@ public abstract partial class InventorySystem
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true, bool reparent = true,
bool checkDoafter = false) bool checkDoafter = false,
bool triggerHandContact = false)
{ {
return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent, checkDoafter); return TryUnequip(actor, target, slot, out _, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact);
} }
public bool TryUnequip( public bool TryUnequip(
@@ -350,9 +356,10 @@ public abstract partial class InventorySystem
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true, bool reparent = true,
bool checkDoafter = false) bool checkDoafter = false,
bool triggerHandContact = false)
{ {
return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent, checkDoafter); return TryUnequip(uid, uid, slot, out removedItem, silent, force, predicted, inventory, clothing, reparent, checkDoafter, triggerHandContact);
} }
public bool TryUnequip( public bool TryUnequip(
@@ -366,7 +373,8 @@ public abstract partial class InventorySystem
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true, bool reparent = true,
bool checkDoafter = false) bool checkDoafter = false,
bool triggerHandContact = false)
{ {
var itemsDropped = 0; var itemsDropped = 0;
return TryUnequip(actor, target, slot, out removedItem, ref itemsDropped, return TryUnequip(actor, target, slot, out removedItem, ref itemsDropped,
@@ -385,7 +393,8 @@ public abstract partial class InventorySystem
InventoryComponent? inventory = null, InventoryComponent? inventory = null,
ClothingComponent? clothing = null, ClothingComponent? clothing = null,
bool reparent = true, bool reparent = true,
bool checkDoafter = false) bool checkDoafter = false,
bool triggerHandContact = false)
{ {
removedItem = null; removedItem = null;
@@ -476,6 +485,10 @@ public abstract partial class InventorySystem
_audio.PlayPredicted(clothing.UnequipSound, target, actor); _audio.PlayPredicted(clothing.UnequipSound, target, actor);
} }
// If gloves are unequipped, OnContactInteraction should trigger for held items
if (triggerHandContact && !((slotDefinition.SlotFlags & SlotFlags.GLOVES) == 0))
TriggerHandContactInteraction(target);
Dirty(target, inventory); Dirty(target, inventory);
_movementSpeed.RefreshMovementSpeedModifiers(target); _movementSpeed.RefreshMovementSpeedModifiers(target);
@@ -551,4 +564,12 @@ public abstract partial class InventorySystem
entityUid = container.ContainedEntity; entityUid = container.ContainedEntity;
return entityUid != null; return entityUid != null;
} }
public void TriggerHandContactInteraction(EntityUid uid)
{
foreach (var item in _handsSystem.EnumerateHeld(uid))
{
_interactionSystem.DoContactInteraction(uid, item);
}
}
} }

View File

@@ -23,6 +23,8 @@ namespace Content.Shared.Strip;
public abstract class SharedStrippableSystem : EntitySystem public abstract class SharedStrippableSystem : EntitySystem
{ {
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!; [Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!;
@@ -244,7 +246,7 @@ public abstract class SharedStrippableSystem : EntitySystem
if (!_handsSystem.TryDrop(user, handsComp: user.Comp)) if (!_handsSystem.TryDrop(user, handsComp: user.Comp))
return; return;
_inventorySystem.TryEquip(user, target, held, slot); _inventorySystem.TryEquip(user, target, held, slot, triggerHandContact: true);
_adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot");
} }
@@ -306,6 +308,8 @@ public abstract class SharedStrippableSystem : EntitySystem
var prefix = stealth ? "stealthily " : ""; var prefix = stealth ? "stealthily " : "";
_adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot");
_interactionSystem.DoContactInteraction(user, item);
var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, true, slot), user, target, item) var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, true, slot), user, target, item)
{ {
Hidden = stealth, Hidden = stealth,
@@ -333,7 +337,7 @@ public abstract class SharedStrippableSystem : EntitySystem
if (!CanStripRemoveInventory(user, target, item, slot)) if (!CanStripRemoveInventory(user, target, item, slot))
return; return;
if (!_inventorySystem.TryUnequip(user, target, slot)) if (!_inventorySystem.TryUnequip(user, target, slot, triggerHandContact: true))
return; return;
RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc. RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc.
@@ -511,6 +515,8 @@ public abstract class SharedStrippableSystem : EntitySystem
var prefix = stealth ? "stealthily " : ""; var prefix = stealth ? "stealthily " : "";
_adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands");
_interactionSystem.DoContactInteraction(user, item);
var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, false, handName), user, target, item) var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, false, handName), user, target, item)
{ {
Hidden = stealth, Hidden = stealth,