HandsSystem Refactor (#38438)
* checkpoint * pt 2 * pt... i forgot * pt 4 * patch * More test fixes * optimization!!! * the REAL hand system * fix RetractableItemActionSystem.cs oversight * the review * test * remove test usage of body prototype * Update Content.IntegrationTests/Tests/Interaction/InteractionTest.cs Co-authored-by: Tayrtahn <tayrtahn@gmail.com> * hellcode * hellcode 2 * Minor cleanup * test * Chasing the last of the bugs * changes --------- Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
This commit is contained in:
@@ -42,13 +42,12 @@ public sealed class StripAllCommand : LocalizedEntityCommands
|
||||
|
||||
if (EntityManager.TryGetComponent<HandsComponent>(targetEntity, out var hands))
|
||||
{
|
||||
foreach (var hand in _handsSystem.EnumerateHands(targetEntity.Value, hands))
|
||||
foreach (var hand in _handsSystem.EnumerateHands((targetEntity.Value, hands)))
|
||||
{
|
||||
_handsSystem.TryDrop(targetEntity.Value,
|
||||
_handsSystem.TryDrop((targetEntity.Value, hands),
|
||||
hand,
|
||||
checkActionBlocker: false,
|
||||
doDropInteraction: false,
|
||||
handsComp: hands);
|
||||
doDropInteraction: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,9 +433,9 @@ public sealed class AdminSystem : EntitySystem
|
||||
|
||||
if (TryComp(entity, out HandsComponent? hands))
|
||||
{
|
||||
foreach (var hand in _hands.EnumerateHands(entity, hands))
|
||||
foreach (var hand in _hands.EnumerateHands((entity, hands)))
|
||||
{
|
||||
_hands.TryDrop(entity, hand, checkActionBlocker: false, doDropInteraction: false, handsComp: hands);
|
||||
_hands.TryDrop((entity, hands), hand, checkActionBlocker: false, doDropInteraction: false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -820,7 +820,7 @@ public sealed partial class AdminVerbSystem
|
||||
}
|
||||
else if (TryComp<HandsComponent>(target, out var hands))
|
||||
{
|
||||
foreach (var held in _handsSystem.EnumerateHeld(target, hands))
|
||||
foreach (var held in _handsSystem.EnumerateHeld((target, hands)))
|
||||
{
|
||||
if (HasComp<AccessComponent>(held))
|
||||
{
|
||||
|
||||
@@ -97,8 +97,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
EntityUid? entity = null;
|
||||
if (args.Type == CryostorageRemoveItemBuiMessage.RemovalType.Hand)
|
||||
{
|
||||
if (_hands.TryGetHand(cryoContained, args.Key, out var hand))
|
||||
entity = hand.HeldEntity;
|
||||
entity = _hands.GetHeldItem(cryoContained, args.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -320,10 +319,10 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
|
||||
foreach (var hand in _hands.EnumerateHands(uid))
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
if (!_hands.TryGetHeldItem(uid, hand, out var heldEntity))
|
||||
continue;
|
||||
|
||||
data.HeldItems.Add(hand.Name, Name(hand.HeldEntity.Value));
|
||||
data.HeldItems.Add(hand, Name(heldEntity.Value));
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Kitchen.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
@@ -37,6 +38,7 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
[Dependency] private readonly MutationSystem _mutation = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
@@ -45,7 +47,7 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
|
||||
public const float HydroponicsSpeedMultiplier = 1f;
|
||||
public const float HydroponicsConsumptionMultiplier = 2f;
|
||||
|
||||
@@ -706,9 +708,9 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
|
||||
if (component.Harvest && !component.Dead)
|
||||
{
|
||||
if (TryComp<HandsComponent>(user, out var hands))
|
||||
if (_hands.TryGetActiveItem(user, out var activeItem))
|
||||
{
|
||||
if (!_botany.CanHarvest(component.Seed, hands.ActiveHandEntity))
|
||||
if (!_botany.CanHarvest(component.Seed, activeItem))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("plant-holder-component-ligneous-cant-harvest-message"), user);
|
||||
return false;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
@@ -22,6 +22,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
@@ -116,10 +117,9 @@ public sealed class SuicideSystem : EntitySystem
|
||||
var suicideByEnvironmentEvent = new SuicideByEnvironmentEvent(victim);
|
||||
|
||||
// Try to suicide by raising an event on the held item
|
||||
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
|
||||
&& handsComponent.ActiveHandEntity is { } item)
|
||||
if (_hands.TryGetActiveItem(victim.Owner, out var item))
|
||||
{
|
||||
RaiseLocalEvent(item, suicideByEnvironmentEvent);
|
||||
RaiseLocalEvent(item.Value, suicideByEnvironmentEvent);
|
||||
if (suicideByEnvironmentEvent.Handled)
|
||||
{
|
||||
args.Handled = suicideByEnvironmentEvent.Handled;
|
||||
|
||||
@@ -471,7 +471,7 @@ namespace Content.Server.Construction
|
||||
}
|
||||
|
||||
if (!_actionBlocker.CanInteract(user, null)
|
||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.ActiveHandEntity == null)
|
||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || _handsSystem.GetActiveItem((user, hands)) == null)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
@@ -496,7 +496,7 @@ namespace Content.Server.Construction
|
||||
|
||||
var valid = false;
|
||||
|
||||
if (hands.ActiveHandEntity is not {Valid: true} holding)
|
||||
if (_handsSystem.GetActiveItem((user, hands)) is not {Valid: true} holding)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Numerics;
|
||||
using Content.Server.Inventory;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared.ActionBlocker;
|
||||
@@ -10,9 +9,7 @@ using Content.Shared.Explosion;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Pulling.Events;
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Standing;
|
||||
@@ -24,7 +21,6 @@ using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Hands.Systems
|
||||
{
|
||||
@@ -87,10 +83,9 @@ namespace Content.Server.Hands.Systems
|
||||
if (ent.Comp.DisableExplosionRecursion)
|
||||
return;
|
||||
|
||||
foreach (var hand in ent.Comp.Hands.Values)
|
||||
foreach (var held in EnumerateHeld(ent.AsNullable()))
|
||||
{
|
||||
if (hand.HeldEntity is { } uid)
|
||||
args.Contents.Add(uid);
|
||||
args.Contents.Add(held);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +107,7 @@ namespace Content.Server.Hands.Systems
|
||||
args.Handled = true; // no shove/stun.
|
||||
}
|
||||
|
||||
private void HandleBodyPartAdded(EntityUid uid, HandsComponent component, ref BodyPartAddedEvent args)
|
||||
private void HandleBodyPartAdded(Entity<HandsComponent> ent, ref BodyPartAddedEvent args)
|
||||
{
|
||||
if (args.Part.Comp.PartType != BodyPartType.Hand)
|
||||
return;
|
||||
@@ -127,7 +122,7 @@ namespace Content.Server.Hands.Systems
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(args.Part.Comp.Symmetry))
|
||||
};
|
||||
|
||||
AddHand(uid, args.Slot, location);
|
||||
AddHand(ent.AsNullable(), args.Slot, location);
|
||||
}
|
||||
|
||||
private void HandleBodyPartRemoved(EntityUid uid, HandsComponent component, ref BodyPartRemovedEvent args)
|
||||
@@ -155,8 +150,8 @@ namespace Content.Server.Hands.Systems
|
||||
{
|
||||
if (ContainerSystem.IsEntityInContainer(player) ||
|
||||
!TryComp(player, out HandsComponent? hands) ||
|
||||
hands.ActiveHandEntity is not { } throwEnt ||
|
||||
!_actionBlockerSystem.CanThrow(player, throwEnt))
|
||||
!TryGetActiveItem((player, hands), out var throwEnt) ||
|
||||
!_actionBlockerSystem.CanThrow(player, throwEnt.Value))
|
||||
return false;
|
||||
|
||||
if (_timing.CurTime < hands.NextThrowTime)
|
||||
@@ -165,7 +160,7 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
if (EntityManager.TryGetComponent(throwEnt, out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually)
|
||||
{
|
||||
var splitStack = _stackSystem.Split(throwEnt, 1, EntityManager.GetComponent<TransformComponent>(player).Coordinates, stack);
|
||||
var splitStack = _stackSystem.Split(throwEnt.Value, 1, EntityManager.GetComponent<TransformComponent>(player).Coordinates, stack);
|
||||
|
||||
if (splitStack is not {Valid: true})
|
||||
return false;
|
||||
@@ -185,14 +180,14 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
// Let other systems change the thrown entity (useful for virtual items)
|
||||
// or the throw strength.
|
||||
var ev = new BeforeThrowEvent(throwEnt, direction, throwSpeed, player);
|
||||
var ev = new BeforeThrowEvent(throwEnt.Value, direction, throwSpeed, player);
|
||||
RaiseLocalEvent(player, ref ev);
|
||||
|
||||
if (ev.Cancelled)
|
||||
return true;
|
||||
|
||||
// This can grief the above event so we raise it afterwards
|
||||
if (IsHolding(player, throwEnt, out _, hands) && !TryDrop(player, throwEnt, handsComp: hands))
|
||||
if (IsHolding((player, hands), throwEnt, out _) && !TryDrop(player, throwEnt.Value))
|
||||
return false;
|
||||
|
||||
_throwingSystem.TryThrow(ev.ItemUid, ev.Direction, ev.ThrowSpeed, ev.PlayerUid, compensateFriction: !HasComp<LandAtCursorComponent>(ev.ItemUid));
|
||||
@@ -207,20 +202,20 @@ namespace Content.Server.Hands.Systems
|
||||
var spreadMaxAngle = Angle.FromDegrees(DropHeldItemsSpread);
|
||||
|
||||
var fellEvent = new FellDownEvent(entity);
|
||||
RaiseLocalEvent(entity, fellEvent, false);
|
||||
RaiseLocalEvent(entity, fellEvent);
|
||||
|
||||
foreach (var hand in entity.Comp.Hands.Values)
|
||||
foreach (var hand in entity.Comp.Hands.Keys)
|
||||
{
|
||||
if (hand.HeldEntity is not EntityUid held)
|
||||
if (!TryGetHeldItem(entity.AsNullable(), hand, out var heldEntity))
|
||||
continue;
|
||||
|
||||
var throwAttempt = new FellDownThrowAttemptEvent(entity);
|
||||
RaiseLocalEvent(hand.HeldEntity.Value, ref throwAttempt);
|
||||
RaiseLocalEvent(heldEntity.Value, ref throwAttempt);
|
||||
|
||||
if (throwAttempt.Cancelled)
|
||||
continue;
|
||||
|
||||
if (!TryDrop(entity, hand, null, checkActionBlocker: false, handsComp: entity.Comp))
|
||||
if (!TryDrop(entity.AsNullable(), hand, checkActionBlocker: false))
|
||||
continue;
|
||||
|
||||
// Rotate the item's throw vector a bit for each item
|
||||
@@ -231,12 +226,12 @@ namespace Content.Server.Hands.Systems
|
||||
itemVelocity *= _random.NextFloat(1f);
|
||||
// Heavier objects don't get thrown as far
|
||||
// If the item doesn't have a physics component, it isn't going to get thrown anyway, but we'll assume infinite mass
|
||||
itemVelocity *= _physicsQuery.TryComp(held, out var heldPhysics) ? heldPhysics.InvMass : 0;
|
||||
itemVelocity *= _physicsQuery.TryComp(heldEntity, out var heldPhysics) ? heldPhysics.InvMass : 0;
|
||||
// Throw at half the holder's intentional throw speed and
|
||||
// vary the speed a little to make it look more interesting
|
||||
var throwSpeed = entity.Comp.BaseThrowspeed * _random.NextFloat(0.45f, 0.55f);
|
||||
|
||||
_throwingSystem.TryThrow(held,
|
||||
_throwingSystem.TryThrow(heldEntity.Value,
|
||||
itemVelocity,
|
||||
throwSpeed,
|
||||
entity,
|
||||
|
||||
@@ -43,7 +43,7 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
|
||||
if (!TryComp<HandsComponent>(hitEntity, out var hands))
|
||||
continue;
|
||||
|
||||
if (!_hands.IsHolding(hitEntity, uid, out _, hands) && _hands.TryForcePickupAnyHand(hitEntity, uid, handsComp: hands))
|
||||
if (!_hands.IsHolding((hitEntity, hands), uid, out _) && _hands.TryForcePickupAnyHand(hitEntity, uid, handsComp: hands))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("hot-potato-passed",
|
||||
("from", args.User), ("to", hitEntity)), uid, PopupType.Medium);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.NPC.HTN.Preconditions;
|
||||
@@ -18,14 +18,18 @@ public sealed partial class ActiveHandComponentPrecondition : HTNPrecondition
|
||||
|
||||
public override bool IsMet(NPCBlackboard blackboard)
|
||||
{
|
||||
if (!blackboard.TryGetValue<Hand>(NPCBlackboard.ActiveHand, out var hand, _entManager) || hand.HeldEntity == null)
|
||||
if (!blackboard.TryGetValue<EntityUid>(NPCBlackboard.Owner, out var owner, _entManager) ||
|
||||
!blackboard.TryGetValue<string>(NPCBlackboard.ActiveHand, out var hand, _entManager))
|
||||
{
|
||||
return Invert;
|
||||
}
|
||||
|
||||
if (!_entManager.System<HandsSystem>().TryGetHeldItem(owner, hand, out var entity))
|
||||
return Invert;
|
||||
|
||||
foreach (var comp in Components)
|
||||
{
|
||||
var hasComp = _entManager.HasComponent(hand.HeldEntity, comp.Value.Component.GetType());
|
||||
var hasComp = _entManager.HasComponent(entity, comp.Value.Component.GetType());
|
||||
|
||||
if (!hasComp ||
|
||||
Invert && hasComp)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
|
||||
namespace Content.Server.NPC.HTN.Preconditions;
|
||||
|
||||
@@ -11,11 +11,12 @@ public sealed partial class ActiveHandEntityPrecondition : HTNPrecondition
|
||||
|
||||
public override bool IsMet(NPCBlackboard blackboard)
|
||||
{
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out Hand? activeHand, _entManager))
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.Owner, out EntityUid owner, _entManager) ||
|
||||
!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out string? activeHand, _entManager))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return activeHand.HeldEntity != null;
|
||||
return !_entManager.System<HandsSystem>().HandIsEmpty(owner, activeHand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public sealed partial class DropOperator : HTNOperator
|
||||
|
||||
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
|
||||
{
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out Hand? activeHand, _entManager))
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out string? activeHand, _entManager))
|
||||
{
|
||||
return HTNOperatorStatus.Finished;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -152,6 +151,8 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
|
||||
value = default;
|
||||
EntityUid owner;
|
||||
|
||||
var handSys = entManager.System<HandsSystem>();
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Access:
|
||||
@@ -168,25 +169,24 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
|
||||
case ActiveHand:
|
||||
{
|
||||
if (!TryGetValue(Owner, out owner, entManager) ||
|
||||
!entManager.TryGetComponent<HandsComponent>(owner, out var hands) ||
|
||||
hands.ActiveHand == null)
|
||||
handSys.GetActiveHand(owner) is not { } activeHand)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = hands.ActiveHand;
|
||||
value = activeHand;
|
||||
return true;
|
||||
}
|
||||
case ActiveHandFree:
|
||||
{
|
||||
if (!TryGetValue(Owner, out owner, entManager) ||
|
||||
!entManager.TryGetComponent<HandsComponent>(owner, out var hands) ||
|
||||
hands.ActiveHand == null)
|
||||
handSys.GetActiveHand(owner) is not { } activeHand)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = hands.ActiveHand.IsEmpty;
|
||||
value = handSys.HandIsEmpty((owner, hands), activeHand);
|
||||
return true;
|
||||
}
|
||||
case CanMove:
|
||||
@@ -204,16 +204,16 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
|
||||
{
|
||||
if (!TryGetValue(Owner, out owner, entManager) ||
|
||||
!entManager.TryGetComponent<HandsComponent>(owner, out var hands) ||
|
||||
hands.ActiveHand == null)
|
||||
handSys.GetActiveHand(owner) is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var handos = new List<string>();
|
||||
|
||||
foreach (var (id, hand) in hands.Hands)
|
||||
foreach (var id in hands.Hands.Keys)
|
||||
{
|
||||
if (!hand.IsEmpty)
|
||||
if (!handSys.HandIsEmpty((owner, hands), id))
|
||||
continue;
|
||||
|
||||
handos.Add(id);
|
||||
@@ -226,16 +226,16 @@ public sealed partial class NPCBlackboard : IEnumerable<KeyValuePair<string, obj
|
||||
{
|
||||
if (!TryGetValue(Owner, out owner, entManager) ||
|
||||
!entManager.TryGetComponent<HandsComponent>(owner, out var hands) ||
|
||||
hands.ActiveHand == null)
|
||||
handSys.GetActiveHand(owner) is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var handos = new List<string>();
|
||||
|
||||
foreach (var (id, hand) in hands.Hands)
|
||||
foreach (var id in hands.Hands.Keys)
|
||||
{
|
||||
if (!hand.IsEmpty)
|
||||
if (!handSys.HandIsEmpty((owner, hands), id))
|
||||
continue;
|
||||
|
||||
handos.Add(id);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.NPC.Queries;
|
||||
using Content.Server.NPC.Queries.Considerations;
|
||||
using Content.Server.NPC.Queries.Curves;
|
||||
@@ -44,6 +45,7 @@ public sealed class NPCUtilitySystem : EntitySystem
|
||||
[Dependency] private readonly DrinkSystem _drink = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly FoodSystem _food = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
||||
@@ -256,8 +258,9 @@ public sealed class NPCUtilitySystem : EntitySystem
|
||||
}
|
||||
case TargetAmmoMatchesCon:
|
||||
{
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out Hand? activeHand, EntityManager) ||
|
||||
!TryComp<BallisticAmmoProviderComponent>(activeHand.HeldEntity, out var heldGun))
|
||||
if (!blackboard.TryGetValue(NPCBlackboard.ActiveHand, out string? activeHand, EntityManager) ||
|
||||
!_hands.TryGetHeldItem(owner, activeHand, out var heldEntity) ||
|
||||
!TryComp<BallisticAmmoProviderComponent>(heldEntity, out var heldGun))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ public sealed class FTLDiskCommand : LocalizedCommands
|
||||
|
||||
if (_entManager.TryGetComponent<StorageComponent>(cdCaseUid, out var storage) && storageSystem.Insert(cdCaseUid, cdUid, out _, storageComp: storage, playSound: false))
|
||||
{
|
||||
if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand(entity, out var emptyHand, handsComponent))
|
||||
if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand((entity, handsComponent), out var emptyHand))
|
||||
{
|
||||
handsSystem.TryPickup(entity, cdCaseUid, emptyHand, checkActionBlocker: false, handsComp: handsComponent);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public sealed class FTLDiskCommand : LocalizedCommands
|
||||
{
|
||||
_entManager.DeleteEntity(cdCaseUid); // something went wrong so just yeet the chaf
|
||||
|
||||
if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand(entity, out var emptyHand, handsComponent))
|
||||
if (_entManager.TryGetComponent<HandsComponent>(entity, out var handsComponent) && handsSystem.TryGetEmptyHand((entity, handsComponent), out var emptyHand))
|
||||
{
|
||||
handsSystem.TryPickup(entity, cdUid, emptyHand, checkActionBlocker: false, handsComp: handsComponent);
|
||||
}
|
||||
|
||||
@@ -217,8 +217,8 @@ public sealed partial class BorgSystem
|
||||
|
||||
var handId = $"{uid}-item{component.HandCounter}";
|
||||
component.HandCounter++;
|
||||
_hands.AddHand(chassis, handId, HandLocation.Middle, hands);
|
||||
_hands.DoPickup(chassis, hands.Hands[handId], item, hands);
|
||||
_hands.AddHand((chassis, hands), handId, HandLocation.Middle);
|
||||
_hands.DoPickup(chassis, handId, item, hands);
|
||||
EnsureComp<UnremoveableComponent>(item);
|
||||
component.ProvidedItems.Add(handId, item);
|
||||
}
|
||||
@@ -239,7 +239,7 @@ public sealed partial class BorgSystem
|
||||
foreach (var (hand, item) in component.ProvidedItems)
|
||||
{
|
||||
QueueDel(item);
|
||||
_hands.RemoveHand(chassis, hand, hands);
|
||||
_hands.RemoveHand(chassis, hand);
|
||||
}
|
||||
component.ProvidedItems.Clear();
|
||||
return;
|
||||
@@ -252,7 +252,7 @@ public sealed partial class BorgSystem
|
||||
RemComp<UnremoveableComponent>(item);
|
||||
_container.Insert(item, component.ProvidedContainer);
|
||||
}
|
||||
_hands.RemoveHand(chassis, handId, hands);
|
||||
_hands.RemoveHand(chassis, handId);
|
||||
}
|
||||
component.ProvidedItems.Clear();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Tabletop.Components;
|
||||
using Content.Shared.CCVar;
|
||||
@@ -22,6 +23,7 @@ namespace Content.Server.Tabletop
|
||||
{
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly EyeSystem _eye = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly ViewSubscriberSystem _viewSubscriberSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
@@ -84,18 +86,13 @@ namespace Content.Server.Tabletop
|
||||
if (component.Session is not { } session)
|
||||
return;
|
||||
|
||||
if (hands.ActiveHand == null)
|
||||
if (!_hands.TryGetActiveItem(uid, out var handEnt))
|
||||
return;
|
||||
|
||||
if (hands.ActiveHand.HeldEntity == null)
|
||||
return;
|
||||
|
||||
var handEnt = hands.ActiveHand.HeldEntity.Value;
|
||||
|
||||
if (!TryComp<ItemComponent>(handEnt, out var item))
|
||||
return;
|
||||
|
||||
var meta = MetaData(handEnt);
|
||||
var meta = MetaData(handEnt.Value);
|
||||
var protoId = meta.EntityPrototype?.ID;
|
||||
|
||||
var hologram = Spawn(protoId, session.Position.Offset(-1, 0));
|
||||
|
||||
@@ -90,9 +90,9 @@ public sealed class InnateToolSystem : EntitySystem
|
||||
|
||||
if (TryComp<HandsComponent>(uid, out var hands))
|
||||
{
|
||||
foreach (var hand in hands.Hands)
|
||||
foreach (var hand in hands.Hands.Keys)
|
||||
{
|
||||
_sharedHandsSystem.TryDrop(uid, hand.Value, checkActionBlocker: false, handsComp: hands);
|
||||
_sharedHandsSystem.TryDrop((uid, hands), hand, checkActionBlocker: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory.VirtualItem;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -14,6 +14,7 @@ namespace Content.Server.Verbs
|
||||
public sealed class VerbSystem : SharedVerbSystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly IAdminManager _adminMgr = default!;
|
||||
|
||||
@@ -91,8 +92,7 @@ namespace Content.Server.Verbs
|
||||
{
|
||||
// first get the held item. again.
|
||||
EntityUid? holding = null;
|
||||
if (TryComp(user, out HandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is EntityUid heldEntity)
|
||||
if (_hands.GetActiveItem(user) is { } heldEntity)
|
||||
{
|
||||
holding = heldEntity;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using Content.Server.Hands.Systems;
|
||||
using Content.Server.Storage.EntitySystems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Storage;
|
||||
@@ -40,24 +39,20 @@ public sealed class StorageVoiceControlSystem : EntitySystem
|
||||
if (!TryComp<StorageComponent>(ent, out var storage))
|
||||
return;
|
||||
|
||||
// Get the hands component
|
||||
if (!TryComp<HandsComponent>(args.Source, out var hands))
|
||||
return;
|
||||
|
||||
// If the player has something in their hands, try to insert it into the storage
|
||||
if (hands.ActiveHand != null && hands.ActiveHand.HeldEntity.HasValue)
|
||||
if (_hands.TryGetActiveItem(ent.Owner, out var activeItem))
|
||||
{
|
||||
// Disallow insertion and provide a reason why if the person decides to insert the item into itself
|
||||
if (ent.Owner.Equals(hands.ActiveHand.HeldEntity.Value))
|
||||
if (ent.Owner.Equals(activeItem.Value))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("comp-storagevoicecontrol-self-insert", ("entity", hands.ActiveHand.HeldEntity.Value)), ent, args.Source);
|
||||
_popup.PopupEntity(Loc.GetString("comp-storagevoicecontrol-self-insert", ("entity", activeItem.Value)), ent, args.Source);
|
||||
return;
|
||||
}
|
||||
if (_storage.CanInsert(ent, hands.ActiveHand.HeldEntity.Value, out var failedReason))
|
||||
if (_storage.CanInsert(ent, activeItem.Value, out var failedReason))
|
||||
{
|
||||
// We adminlog before insertion, otherwise the logger will attempt to pull info on an entity that no longer is present and throw an exception
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Source)} inserted {ToPrettyString(hands.ActiveHand.HeldEntity.Value)} into {ToPrettyString(ent)} via voice control");
|
||||
_storage.Insert(ent, hands.ActiveHand.HeldEntity.Value, out _);
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.Source)} inserted {ToPrettyString(activeItem.Value)} into {ToPrettyString(ent)} via voice control");
|
||||
_storage.Insert(ent, activeItem.Value, out _);
|
||||
return;
|
||||
}
|
||||
{
|
||||
@@ -67,7 +62,7 @@ public sealed class StorageVoiceControlSystem : EntitySystem
|
||||
_popup.PopupEntity(Loc.GetString(failedReason), ent, args.Source);
|
||||
_adminLogger.Add(LogType.Action,
|
||||
LogImpact.Low,
|
||||
$"{ToPrettyString(args.Source)} failed to insert {ToPrettyString(hands.ActiveHand.HeldEntity.Value)} into {ToPrettyString(ent)} via voice control");
|
||||
$"{ToPrettyString(args.Source)} failed to insert {ToPrettyString(activeItem.Value)} into {ToPrettyString(ent)} via voice control");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -80,7 +75,7 @@ public sealed class StorageVoiceControlSystem : EntitySystem
|
||||
// E.g "go go s" would give you the screwdriver because "screwdriver" contains "s"
|
||||
if (Name(item).Contains(args.MessageWithoutPhrase))
|
||||
{
|
||||
ExtractItemFromStorage(ent, item, args.Source, hands);
|
||||
ExtractItemFromStorage(ent, item, args.Source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -92,16 +87,14 @@ public sealed class StorageVoiceControlSystem : EntitySystem
|
||||
/// <param name="ent">The entity with the <see cref="StorageVoiceControlComponent"/></param>
|
||||
/// <param name="item">The entity to be extracted from the attached storage</param>
|
||||
/// <param name="source">The entity wearing the item</param>
|
||||
/// <param name="hands">The <see cref="HandsComponent"/> of the person wearing the item</param>
|
||||
private void ExtractItemFromStorage(Entity<StorageVoiceControlComponent> ent,
|
||||
EntityUid item,
|
||||
EntityUid source,
|
||||
HandsComponent hands)
|
||||
EntityUid source)
|
||||
{
|
||||
_container.RemoveEntity(ent, item);
|
||||
_adminLogger.Add(LogType.Action,
|
||||
LogImpact.Low,
|
||||
$"{ToPrettyString(source)} retrieved {ToPrettyString(item)} from {ToPrettyString(ent)} via voice control");
|
||||
_hands.TryPickup(source, item, handsComp: hands);
|
||||
_hands.TryPickup(source, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using Content.Server.Construction;
|
||||
using Content.Server.Construction.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.GameTicking;
|
||||
@@ -24,6 +25,7 @@ public sealed class WiresSystem : SharedWiresSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
@@ -405,19 +407,13 @@ public sealed class WiresSystem : SharedWiresSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHand = handsComponent.ActiveHand;
|
||||
|
||||
if (activeHand == null)
|
||||
if (!_hands.TryGetActiveItem((player, handsComponent), out var heldEntity))
|
||||
return;
|
||||
|
||||
if (activeHand.HeldEntity == null)
|
||||
if (!EntityManager.TryGetComponent(heldEntity, out ToolComponent? tool))
|
||||
return;
|
||||
|
||||
var activeHandEntity = activeHand.HeldEntity.Value;
|
||||
if (!EntityManager.TryGetComponent(activeHandEntity, out ToolComponent? tool))
|
||||
return;
|
||||
|
||||
TryDoWireAction(uid, player, activeHandEntity, args.Id, args.Action, component, tool);
|
||||
TryDoWireAction(uid, player, heldEntity.Value, args.Id, args.Action, component, tool);
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, WiresComponent component, WireDoAfterEvent args)
|
||||
|
||||
Reference in New Issue
Block a user