hands ECS (#7081)
This commit is contained in:
@@ -108,8 +108,8 @@ namespace Content.Client.EscapeMenu.UI.Tabs
|
||||
AddHeader("ui-options-header-interaction-basic");
|
||||
AddButton(EngineKeyFunctions.Use);
|
||||
AddButton(ContentKeyFunctions.WideAttack);
|
||||
AddButton(ContentKeyFunctions.ActivateItemInHand);
|
||||
AddButton(ContentKeyFunctions.AltActivateItemInHand);
|
||||
AddButton(ContentKeyFunctions.UseItemInHand);
|
||||
AddButton(ContentKeyFunctions.AltUseItemInHand);
|
||||
AddButton(ContentKeyFunctions.ActivateItemInWorld);
|
||||
AddButton(ContentKeyFunctions.AltActivateItemInWorld);
|
||||
AddButton(ContentKeyFunctions.Drop);
|
||||
|
||||
@@ -4,17 +4,14 @@ using Content.Client.Animations;
|
||||
using Content.Client.HUD;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Hands
|
||||
@@ -25,11 +22,15 @@ namespace Content.Client.Hands
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(HandleContainerModified);
|
||||
SubscribeLocalEvent<SharedHandsComponent, EntInsertedIntoContainerMessage>(HandleContainerModified);
|
||||
|
||||
SubscribeLocalEvent<HandsComponent, PlayerAttachedEvent>(HandlePlayerAttached);
|
||||
SubscribeLocalEvent<HandsComponent, PlayerDetachedEvent>(HandlePlayerDetached);
|
||||
SubscribeLocalEvent<HandsComponent, ComponentRemove>(HandleCompRemove);
|
||||
@@ -45,46 +46,29 @@ namespace Content.Client.Hands
|
||||
if (args.Current is not HandsComponentState state)
|
||||
return;
|
||||
|
||||
// Do we have a NEW hand?
|
||||
var handsModified = component.Hands.Count != state.Hands.Count;
|
||||
if (!handsModified)
|
||||
var manager = EnsureComp<ContainerManagerComponent>(uid);
|
||||
foreach (var hand in state.Hands)
|
||||
{
|
||||
for (var i = 0; i < state.Hands.Count; i++)
|
||||
if (component.Hands.TryAdd(hand.Name, hand))
|
||||
{
|
||||
if (component.Hands[i].Name != state.Hands[i].Name ||
|
||||
component.Hands[i].Location != state.Hands[i].Location)
|
||||
{
|
||||
handsModified = true;
|
||||
break;
|
||||
}
|
||||
hand.Container = _containerSystem.EnsureContainer<ContainerSlot>(uid, hand.Name, manager);
|
||||
handsModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handsModified)
|
||||
{
|
||||
// we have new hands, get the new containers.
|
||||
component.Hands = state.Hands;
|
||||
UpdateHandContainers(uid, component);
|
||||
foreach (var name in component.Hands.Keys)
|
||||
{
|
||||
if (!state.HandNames.Contains(name))
|
||||
component.Hands.Remove(name);
|
||||
}
|
||||
|
||||
component.SortedHands = new(state.HandNames);
|
||||
}
|
||||
|
||||
TrySetActiveHand(uid, state.ActiveHand, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to update the hand-containers when hands have been added or removed. Also updates the GUI
|
||||
/// </summary>
|
||||
public void UpdateHandContainers(EntityUid uid, HandsComponent? hands = null, ContainerManagerComponent? containerMan = null)
|
||||
{
|
||||
if (!Resolve(uid, ref hands, ref containerMan))
|
||||
return;
|
||||
|
||||
foreach (var hand in hands.Hands)
|
||||
{
|
||||
if (hand.Container == null)
|
||||
{
|
||||
hand.Container = hands.Owner.EnsureContainer<ContainerSlot>(hand.Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (uid == _playerManager.LocalPlayer?.ControlledEntity)
|
||||
UpdateGui();
|
||||
@@ -117,9 +101,7 @@ namespace Content.Client.Hands
|
||||
|
||||
public EntityUid? GetActiveHandEntity()
|
||||
{
|
||||
return TryGetPlayerHands(out var hands) && hands.TryGetActiveHeldEntity(out var entity)
|
||||
? entity
|
||||
: null;
|
||||
return TryGetPlayerHands(out var hands) ? hands.ActiveHandEntity : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,56 +119,57 @@ namespace Content.Client.Hands
|
||||
/// </summary>
|
||||
public void UIHandClick(HandsComponent hands, string handName)
|
||||
{
|
||||
if (!hands.TryGetHand(handName, out var pressedHand))
|
||||
if (!hands.Hands.TryGetValue(handName, out var pressedHand))
|
||||
return;
|
||||
|
||||
if (!hands.TryGetActiveHand(out var activeHand))
|
||||
if (hands.ActiveHand == null)
|
||||
return;
|
||||
|
||||
var pressedEntity = pressedHand.HeldEntity;
|
||||
var activeEntity = activeHand.HeldEntity;
|
||||
var activeEntity = hands.ActiveHand.HeldEntity;
|
||||
|
||||
if (pressedHand == activeHand && activeEntity != null)
|
||||
if (pressedHand == hands.ActiveHand && activeEntity != null)
|
||||
{
|
||||
// use item in hand
|
||||
// it will always be attack_self() in my heart.
|
||||
RaiseNetworkEvent(new UseInHandMsg());
|
||||
EntityManager.RaisePredictiveEvent(new RequestUseInHandEvent());
|
||||
return;
|
||||
}
|
||||
|
||||
if (pressedHand != activeHand && pressedEntity == null)
|
||||
if (pressedHand != hands.ActiveHand && pressedEntity == null)
|
||||
{
|
||||
// change active hand
|
||||
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pressedHand != activeHand && pressedEntity != null && activeEntity != null)
|
||||
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity != null)
|
||||
{
|
||||
// use active item on held item
|
||||
RaiseNetworkEvent(new ClientInteractUsingInHandMsg(pressedHand.Name));
|
||||
EntityManager.RaisePredictiveEvent(new RequestHandInteractUsingEvent(pressedHand.Name));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pressedHand != activeHand && pressedEntity != default && activeEntity == default)
|
||||
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity == null)
|
||||
{
|
||||
// use active item on held item
|
||||
RaiseNetworkEvent(new MoveItemFromHandMsg(pressedHand.Name));
|
||||
// move the item to the active hand
|
||||
EntityManager.RaisePredictiveEvent(new RequestMoveHandItemEvent(pressedHand.Name));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a user clicks on an item in their hands GUI.
|
||||
/// Called when a user clicks on the little "activation" icon in the hands GUI. This is currently only used
|
||||
/// by storage (backpacks, etc).
|
||||
/// </summary>
|
||||
public void UIHandActivate(string handName)
|
||||
{
|
||||
RaiseNetworkEvent(new ActivateInHandMsg(handName));
|
||||
EntityManager.RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
|
||||
}
|
||||
|
||||
#region visuals
|
||||
protected override void HandleContainerModified(EntityUid uid, SharedHandsComponent handComp, ContainerModifiedMessage args)
|
||||
private void HandleContainerModified(EntityUid uid, SharedHandsComponent handComp, ContainerModifiedMessage args)
|
||||
{
|
||||
if (handComp.TryGetHand(args.Container.ID, out var hand))
|
||||
if (handComp.Hands.TryGetValue(args.Container.ID, out var hand))
|
||||
{
|
||||
UpdateHandVisuals(uid, args.Entity, hand);
|
||||
}
|
||||
@@ -267,25 +250,24 @@ namespace Content.Client.Hands
|
||||
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
|
||||
{
|
||||
// update hands visuals if this item is in a hand (rather then inventory or other container).
|
||||
if (component.TryGetHand(args.ContainerId, out var hand))
|
||||
if (component.Hands.TryGetValue(args.ContainerId, out var hand))
|
||||
{
|
||||
UpdateHandVisuals(uid, args.Item, hand, component);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Gui
|
||||
public void UpdateGui(HandsComponent? hands = null)
|
||||
{
|
||||
if (hands == null && !TryGetPlayerHands(out hands) || hands.Gui == null)
|
||||
return;
|
||||
|
||||
var states = hands.Hands
|
||||
var states = hands.Hands.Values
|
||||
.Select(hand => new GuiHand(hand.Name, hand.Location, hand.HeldEntity))
|
||||
.ToArray();
|
||||
|
||||
hands.Gui.Update(new HandsGuiState(states, hands.ActiveHand));
|
||||
hands.Gui.Update(new HandsGuiState(states, hands.ActiveHand?.Name));
|
||||
}
|
||||
|
||||
public override bool TrySetActiveHand(EntityUid uid, string? value, SharedHandsComponent? handComp = null)
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace Content.Client.Input
|
||||
var human = contexts.GetContext("human");
|
||||
human.AddFunction(ContentKeyFunctions.SwapHands);
|
||||
human.AddFunction(ContentKeyFunctions.Drop);
|
||||
human.AddFunction(ContentKeyFunctions.ActivateItemInHand);
|
||||
human.AddFunction(ContentKeyFunctions.AltActivateItemInHand);
|
||||
human.AddFunction(ContentKeyFunctions.UseItemInHand);
|
||||
human.AddFunction(ContentKeyFunctions.AltUseItemInHand);
|
||||
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
|
||||
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
|
||||
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
|
||||
|
||||
@@ -196,15 +196,15 @@ namespace Content.Client.Inventory
|
||||
if (!Resolve(uid, ref hands, false))
|
||||
return;
|
||||
|
||||
if (!hands.TryGetActiveHeldEntity(out var heldEntity))
|
||||
if (hands.ActiveHandEntity is not EntityUid heldEntity)
|
||||
return;
|
||||
|
||||
if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent))
|
||||
return;
|
||||
|
||||
_itemSlotManager.HoverInSlot(button, heldEntity.Value,
|
||||
CanEquip(uid, heldEntity.Value, slot, out _, slotDef, inventoryComponent) &&
|
||||
containerSlot.CanInsert(heldEntity.Value, EntityManager));
|
||||
_itemSlotManager.HoverInSlot(button, heldEntity,
|
||||
CanEquip(uid, heldEntity, slot, out _, slotDef, inventoryComponent) &&
|
||||
containerSlot.CanInsert(heldEntity, EntityManager));
|
||||
}
|
||||
|
||||
private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button,
|
||||
@@ -217,7 +217,7 @@ namespace Content.Client.Inventory
|
||||
return;
|
||||
|
||||
// only raise event if either itemUid is not null, or the user is holding something
|
||||
if (itemUid != null || TryComp(uid, out SharedHandsComponent? hands) && hands.TryGetActiveHeldEntity(out _))
|
||||
if (itemUid != null || TryComp(uid, out SharedHandsComponent? hands) && hands.ActiveHandEntity != null)
|
||||
EntityManager.RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace Content.Client.Weapons.Ranged
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hands.TryGetActiveHeldEntity(out var held) || !EntityManager.TryGetComponent(held, out ClientRangedWeaponComponent? weapon))
|
||||
if (hands.ActiveHandEntity is not EntityUid held || !EntityManager.TryGetComponent(held, out ClientRangedWeaponComponent? weapon))
|
||||
{
|
||||
_blocked = true;
|
||||
return;
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Part;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Standing;
|
||||
using NUnit.Framework;
|
||||
@@ -251,9 +252,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
{
|
||||
var akms = entityManager.SpawnEntity(ItemDummyId, coordinates);
|
||||
|
||||
// Equip items
|
||||
Assert.True(entityManager.TryGetComponent(akms, out SharedItemComponent item));
|
||||
Assert.True(hands.PutInHand(item));
|
||||
Assert.True(EntitySystem.Get<SharedHandsSystem>().TryPickupAnyHand(human, akms));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -265,9 +264,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.True(buckle.Buckled);
|
||||
|
||||
// With items in all hands
|
||||
foreach (var slot in hands.HandNames)
|
||||
foreach (var hand in hands.Hands.Values)
|
||||
{
|
||||
Assert.NotNull(hands.GetItem(slot));
|
||||
Assert.NotNull(hands.ActiveHandEntity);
|
||||
}
|
||||
|
||||
var legs = body.GetPartsOfType(BodyPartType.Leg);
|
||||
@@ -287,9 +286,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
||||
Assert.True(buckle.Buckled);
|
||||
|
||||
// Now with no item in any hand
|
||||
foreach (var slot in hands.HandNames)
|
||||
foreach (var hand in hands.Hands.Values)
|
||||
{
|
||||
Assert.Null(hands.GetItem(slot));
|
||||
Assert.Null(hands.ActiveHandEntity);
|
||||
}
|
||||
|
||||
buckle.TryUnbuckle(human, true);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
||||
AddHand(cuffed.Owner);
|
||||
|
||||
Assert.That(cuffed.CuffedHandCount, Is.EqualTo(2));
|
||||
Assert.That(hands.HandNames.Count(), Is.EqualTo(4));
|
||||
Assert.That(hands.SortedHands.Count(), Is.EqualTo(4));
|
||||
|
||||
// Test to give a player with 4 hands 2 sets of cuffs
|
||||
cuffed.TryAddNewCuffs(human, secondCuffs);
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Client.Items.Components;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
@@ -54,6 +55,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
var mapId = MapId.Nullspace;
|
||||
var coords = MapCoordinates.Nullspace;
|
||||
@@ -71,7 +74,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
server.Assert(() =>
|
||||
{
|
||||
user = sEntities.SpawnEntity(null, coords);
|
||||
user.EnsureComponent<HandsComponent>().AddHand("hand", HandLocation.Left);
|
||||
user.EnsureComponent<HandsComponent>();
|
||||
handSys.AddHand(user, "hand", HandLocation.Left);
|
||||
target = sEntities.SpawnEntity(null, coords);
|
||||
item = sEntities.SpawnEntity(null, coords);
|
||||
item.EnsureComponent<ItemComponent>();
|
||||
@@ -98,8 +102,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
Assert.That(interactUsing, Is.False);
|
||||
Assert.That(interactHand);
|
||||
|
||||
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
|
||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
||||
Assert.That(handSys.TryPickup(user, item));
|
||||
|
||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||
Assert.That(interactUsing);
|
||||
@@ -124,6 +127,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
var mapId = MapId.Nullspace;
|
||||
var coords = MapCoordinates.Nullspace;
|
||||
@@ -142,7 +147,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
server.Assert(() =>
|
||||
{
|
||||
user = sEntities.SpawnEntity(null, coords);
|
||||
user.EnsureComponent<HandsComponent>().AddHand("hand", HandLocation.Left);
|
||||
user.EnsureComponent<HandsComponent>();
|
||||
handSys.AddHand(user, "hand", HandLocation.Left);
|
||||
target = sEntities.SpawnEntity(null, new MapCoordinates((1.9f, 0), mapId));
|
||||
item = sEntities.SpawnEntity(null, coords);
|
||||
item.EnsureComponent<ItemComponent>();
|
||||
@@ -170,8 +176,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
Assert.That(interactUsing, Is.False);
|
||||
Assert.That(interactHand, Is.False);
|
||||
|
||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
||||
Assert.That(handSys.TryPickup(user, item));
|
||||
|
||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||
Assert.That(interactUsing, Is.False);
|
||||
@@ -195,6 +200,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
var mapId = MapId.Nullspace;
|
||||
var coords = MapCoordinates.Nullspace;
|
||||
@@ -212,7 +219,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
server.Assert(() =>
|
||||
{
|
||||
user = sEntities.SpawnEntity(null, coords);
|
||||
user.EnsureComponent<HandsComponent>().AddHand("hand", HandLocation.Left);
|
||||
user.EnsureComponent<HandsComponent>();
|
||||
handSys.AddHand(user, "hand", HandLocation.Left);
|
||||
target = sEntities.SpawnEntity(null, new MapCoordinates((InteractionSystem.InteractionRange - 0.1f, 0), mapId));
|
||||
item = sEntities.SpawnEntity(null, coords);
|
||||
item.EnsureComponent<ItemComponent>();
|
||||
@@ -239,8 +247,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
Assert.That(interactUsing, Is.False);
|
||||
Assert.That(interactHand);
|
||||
|
||||
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
|
||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
||||
Assert.That(handSys.TryPickup(user, item));
|
||||
|
||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||
Assert.That(interactUsing);
|
||||
@@ -265,6 +272,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
var mapId = MapId.Nullspace;
|
||||
var coords = MapCoordinates.Nullspace;
|
||||
@@ -282,7 +291,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
server.Assert(() =>
|
||||
{
|
||||
user = sEntities.SpawnEntity(null, coords);
|
||||
user.EnsureComponent<HandsComponent>().AddHand("hand", HandLocation.Left);
|
||||
user.EnsureComponent<HandsComponent>();
|
||||
handSys.AddHand(user, "hand", HandLocation.Left);
|
||||
target = sEntities.SpawnEntity(null, new MapCoordinates((SharedInteractionSystem.InteractionRange + 0.01f, 0), mapId));
|
||||
item = sEntities.SpawnEntity(null, coords);
|
||||
item.EnsureComponent<ItemComponent>();
|
||||
@@ -309,8 +319,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
Assert.That(interactUsing, Is.False);
|
||||
Assert.That(interactHand, Is.False);
|
||||
|
||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
||||
Assert.That(handSys.TryPickup(user, item));
|
||||
|
||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||
Assert.That(interactUsing, Is.False);
|
||||
@@ -335,6 +344,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
|
||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||
var mapManager = server.ResolveDependency<IMapManager>();
|
||||
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
var mapId = MapId.Nullspace;
|
||||
var coords = MapCoordinates.Nullspace;
|
||||
@@ -354,7 +365,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
server.Assert(() =>
|
||||
{
|
||||
user = sEntities.SpawnEntity(null, coords);
|
||||
user.EnsureComponent<HandsComponent>().AddHand("hand", HandLocation.Left);
|
||||
user.EnsureComponent<HandsComponent>();
|
||||
handSys.AddHand(user, "hand", HandLocation.Left);
|
||||
target = sEntities.SpawnEntity(null, coords);
|
||||
item = sEntities.SpawnEntity(null, coords);
|
||||
item.EnsureComponent<ItemComponent>();
|
||||
@@ -394,8 +406,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
||||
Assert.That(interactUsing, Is.False);
|
||||
Assert.That(interactHand);
|
||||
|
||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
||||
Assert.That(handSys.TryPickup(user, item));
|
||||
|
||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||
Assert.That(interactUsing, Is.False);
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.PDA;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.PDA;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.PDA
|
||||
{
|
||||
public sealed class PDAExtensionsTests : ContentIntegrationTest
|
||||
{
|
||||
private const string IdCardDummy = "DummyIdCard";
|
||||
private const string PdaDummy = "DummyPda";
|
||||
|
||||
private static readonly string Prototypes = $@"
|
||||
- type: entity
|
||||
id: {IdCardDummy}
|
||||
name: {IdCardDummy}
|
||||
components:
|
||||
- type: IdCard
|
||||
- type: Item
|
||||
|
||||
- type: entity
|
||||
id: {PdaDummy}
|
||||
name: {PdaDummy}
|
||||
components:
|
||||
- type: PDA
|
||||
idSlot:
|
||||
name: ID Card
|
||||
whitelist:
|
||||
components:
|
||||
- IdCard
|
||||
- type: Item";
|
||||
|
||||
[Test]
|
||||
public async Task PlayerGetIdComponent()
|
||||
{
|
||||
var clientOptions = new ClientIntegrationOptions
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
};
|
||||
|
||||
var serverOptions = new ServerIntegrationOptions
|
||||
{
|
||||
ExtraPrototypes = Prototypes
|
||||
};
|
||||
|
||||
var (client, server) = await StartConnectedServerClientPair(clientOptions, serverOptions);
|
||||
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
|
||||
var sPlayerManager = server.ResolveDependency<IPlayerManager>();
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
|
||||
var invSystem = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var player = sPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
|
||||
|
||||
Assert.That(player != default);
|
||||
|
||||
// The player spawns with an ID on by default
|
||||
Assert.NotNull(player.GetHeldId());
|
||||
Assert.True(player.TryGetHeldId(out var id));
|
||||
Assert.NotNull(id);
|
||||
|
||||
// Put PDA in hand
|
||||
var dummyPda = sEntityManager.SpawnEntity(PdaDummy, sEntityManager.GetComponent<TransformComponent>(player).MapPosition);
|
||||
var pdaItemComponent = sEntityManager.GetComponent<SharedItemComponent>(dummyPda);
|
||||
sEntityManager.GetComponent<HandsComponent>(player).PutInHand(pdaItemComponent);
|
||||
|
||||
var pdaComponent = sEntityManager.GetComponent<PDAComponent>(dummyPda);
|
||||
var pdaIdCard = sEntityManager.SpawnEntity(IdCardDummy, sEntityManager.GetComponent<TransformComponent>(player).MapPosition);
|
||||
|
||||
var itemSlots = sEntityManager.GetComponent<ItemSlotsComponent>(dummyPda);
|
||||
sEntityManager.EntitySysManager.GetEntitySystem<ItemSlotsSystem>()
|
||||
.TryInsert(dummyPda, pdaComponent.IdSlot, pdaIdCard, null);
|
||||
var pdaContainedId = pdaComponent.ContainedID;
|
||||
|
||||
// The PDA in the hand should be found first
|
||||
Assert.NotNull(player.GetHeldId());
|
||||
Assert.True(player.TryGetHeldId(out id));
|
||||
|
||||
Assert.NotNull(id);
|
||||
Assert.That(id, Is.EqualTo(pdaContainedId));
|
||||
|
||||
// Put ID card in hand
|
||||
var idDummy = sEntityManager.SpawnEntity(IdCardDummy, sEntityManager.GetComponent<TransformComponent>(player).MapPosition);
|
||||
var idItemComponent = sEntityManager.GetComponent<SharedItemComponent>(idDummy);
|
||||
sEntityManager.GetComponent<HandsComponent>(player).PutInHand(idItemComponent);
|
||||
|
||||
var idCardComponent = sEntityManager.GetComponent<IdCardComponent>(idDummy);
|
||||
|
||||
// The ID in the hand should be found first
|
||||
Assert.NotNull(player.GetHeldId());
|
||||
Assert.True(player.TryGetHeldId(out id));
|
||||
Assert.NotNull(id);
|
||||
Assert.That(id, Is.EqualTo(idCardComponent));
|
||||
|
||||
// Remove all IDs and PDAs
|
||||
Assert.That(invSystem.TryGetSlots(player, out var slots));
|
||||
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
if(!invSystem.TryGetSlotEntity(player, slot.Name, out var item))
|
||||
continue;
|
||||
|
||||
if (sEntityManager.HasComponent<PDAComponent>(item))
|
||||
{
|
||||
invSystem.TryUnequip(player, slot.Name, force: true);
|
||||
}
|
||||
}
|
||||
|
||||
var hands = sEntityManager.GetComponent<HandsComponent>(player);
|
||||
|
||||
hands.Drop(dummyPda, false);
|
||||
hands.Drop(idDummy, false);
|
||||
|
||||
// No ID
|
||||
Assert.Null(player.GetHeldId());
|
||||
Assert.False(player.TryGetHeldId(out id));
|
||||
Assert.Null(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,12 +66,12 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
if (!_entMan.TryGetComponent(_owner, out HandsComponent? hands) || hands.GetActiveHandItem == null)
|
||||
if (!_entMan.TryGetComponent(_owner, out HandsComponent? hands) || hands.ActiveHandEntity == null)
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
var meleeWeapon = hands.GetActiveHandItem.Owner;
|
||||
var meleeWeapon = hands.ActiveHandEntity;
|
||||
_entMan.TryGetComponent(meleeWeapon, out MeleeWeaponComponent? meleeWeaponComponent);
|
||||
|
||||
if ((_entMan.GetComponent<TransformComponent>(_target).Coordinates.Position - _entMan.GetComponent<TransformComponent>(_owner).Coordinates.Position).Length >
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Server.AI.Operators.Inventory
|
||||
{
|
||||
@@ -21,12 +20,7 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
/// <returns></returns>
|
||||
public override Outcome Execute(float frameTime)
|
||||
{
|
||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
return handsComponent.Drop(_entity) ? Outcome.Success : Outcome.Failed;
|
||||
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().TryDrop(_owner, _entity) ? Outcome.Success : Outcome.Failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Server.AI.Operators.Inventory
|
||||
{
|
||||
@@ -20,9 +19,12 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
foreach (var item in handsComponent.GetAllHeldItems())
|
||||
var sys = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
foreach (var hand in handsComponent.Hands.Values)
|
||||
{
|
||||
handsComponent.Drop(item.Owner);
|
||||
if (!hand.IsEmpty)
|
||||
sys.TryDrop(_owner, hand, handsComp: handsComponent);
|
||||
}
|
||||
|
||||
return Outcome.Success;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -16,19 +17,12 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
{
|
||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
var sys = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
// TODO: If in clothing then click on it
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(hand)?.Owner == _entity)
|
||||
{
|
||||
handsComponent.ActiveHand = hand;
|
||||
return Outcome.Success;
|
||||
}
|
||||
}
|
||||
|
||||
if (sys.TrySelect(_owner, _entity))
|
||||
return Outcome.Success;
|
||||
|
||||
// TODO: Get free hand count; if no hands free then fail right here
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Item;
|
||||
@@ -24,42 +25,22 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
public override Outcome Execute(float frameTime)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var interactionSystem = sysMan.GetEntitySystem<InteractionSystem>();
|
||||
var handsSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
if (entMan.Deleted(_target)
|
||||
|| !entMan.HasComponent<SharedItemComponent>(_target)
|
||||
|| _target.IsInContainer()
|
||||
|| !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(_owner, _target, popup: true))
|
||||
|| !interactionSystem.InRangeUnobstructed(_owner, _target, popup: true))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
if (!entMan.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
// select empty hand
|
||||
if (!handsSys.TrySelectEmptyHand(_owner))
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
var emptyHands = false;
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
if (handsComponent.ActiveHand != hand)
|
||||
{
|
||||
handsComponent.ActiveHand = hand;
|
||||
}
|
||||
|
||||
emptyHands = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emptyHands)
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
var interactionSystem = EntitySystem.Get<InteractionSystem>();
|
||||
|
||||
interactionSystem.InteractHand(_owner, _target);
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -22,27 +23,18 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
public override Outcome Execute(float frameTime)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var sys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
// TODO: Also have this check storage a la backpack etc.
|
||||
if (!entMan.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
if (!entMan.TryGetComponent(_owner, out HandsComponent? handsComponent)
|
||||
|| !sys.TrySelect(_owner, _target, handsComponent)
|
||||
|| !sys.TryUseItemInHand(_owner, false, handsComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
if (!entMan.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
foreach (var slot in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(slot) != itemComponent) continue;
|
||||
handsComponent.ActiveHand = slot;
|
||||
handsComponent.ActivateItem();
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
return Outcome.Failed;
|
||||
return Outcome.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.AI.Operators.Nutrition
|
||||
@@ -30,35 +28,23 @@ namespace Content.Server.AI.Operators.Nutrition
|
||||
}
|
||||
|
||||
var entities = IoCManager.Resolve<IEntityManager>();
|
||||
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var handsSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
// TODO: Also have this check storage a la backpack etc.
|
||||
if (entities.Deleted(_target) ||
|
||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
|
||||
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
DrinkComponent? drinkComponent = null;
|
||||
|
||||
foreach (var slot in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(slot) != itemComponent) continue;
|
||||
handsComponent.ActiveHand = slot;
|
||||
if (!entities.TryGetComponent(_target, out drinkComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
// This should also implicitly open it.
|
||||
handsComponent.ActivateItem();
|
||||
_interactionCooldown = IoCManager.Resolve<IRobustRandom>().NextFloat() + 0.5f;
|
||||
}
|
||||
|
||||
if (drinkComponent == null)
|
||||
{
|
||||
if (!handsSys.TrySelect<DrinkComponent>(_owner, out var drinkComponent, handsComponent))
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
if (!handsSys.TryUseItemInHand(_owner, false, handsComponent))
|
||||
return Outcome.Failed;
|
||||
|
||||
_interactionCooldown = IoCManager.Resolve<IRobustRandom>().NextFloat() + 0.5f;
|
||||
|
||||
if (drinkComponent.Deleted || EntitySystem.Get<DrinkSystem>().IsEmpty(drinkComponent.Owner, drinkComponent)
|
||||
|| entities.TryGetComponent(_owner, out ThirstComponent? thirstComponent) &&
|
||||
@@ -67,6 +53,7 @@ namespace Content.Server.AI.Operators.Nutrition
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
/// uuhhh do afters for drinks might mess this up?
|
||||
return Outcome.Continuing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -29,35 +30,21 @@ namespace Content.Server.AI.Operators.Nutrition
|
||||
}
|
||||
|
||||
var entities = IoCManager.Resolve<IEntityManager>();
|
||||
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var handsSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
// TODO: Also have this check storage a la backpack etc.
|
||||
if (entities.Deleted(_target) ||
|
||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
|
||||
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
FoodComponent? foodComponent = null;
|
||||
|
||||
foreach (var slot in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(slot) != itemComponent) continue;
|
||||
handsComponent.ActiveHand = slot;
|
||||
if (!entities.TryGetComponent(_target, out foodComponent))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
// This should also implicitly open it.
|
||||
handsComponent.ActivateItem();
|
||||
_interactionCooldown = IoCManager.Resolve<IRobustRandom>().NextFloat() + 0.5f;
|
||||
}
|
||||
|
||||
if (foodComponent == null)
|
||||
{
|
||||
if (!handsSys.TrySelect<FoodComponent>(_owner, out var foodComponent, handsComponent))
|
||||
return Outcome.Failed;
|
||||
|
||||
if (!handsSys.TryUseItemInHand(_owner, false, handsComponent))
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
if ((!entities.EntityExists(_target) ? EntityLifeStage.Deleted : entities.GetComponent<MetaDataComponent>(_target).EntityLifeStage) >= EntityLifeStage.Deleted ||
|
||||
foodComponent.UsesRemaining == 0 ||
|
||||
@@ -67,6 +54,7 @@ namespace Content.Server.AI.Operators.Nutrition
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
/// do afters for food might mess this up?
|
||||
return Outcome.Continuing;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.Hands.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Content.Shared.Hands.Components;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.AI.Utility.Considerations.Hands
|
||||
{
|
||||
@@ -12,24 +11,12 @@ namespace Content.Server.AI.Utility.Considerations.Hands
|
||||
{
|
||||
var owner = context.GetState<SelfState>().GetValue();
|
||||
|
||||
if (!owner.IsValid() || !IoCManager.Resolve<IEntityManager>().TryGetComponent(owner, out HandsComponent? handsComponent))
|
||||
if (!owner.IsValid() || !IoCManager.Resolve<IEntityManager>().TryGetComponent(owner, out SharedHandsComponent? handsComponent))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
var handCount = 0;
|
||||
var freeCount = 0;
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
handCount++;
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
freeCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (float) freeCount / handCount;
|
||||
return (float) handsComponent.CountFreeHands() / handsComponent.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -11,20 +12,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
public override string Name => "AnyFreeHand";
|
||||
public override bool GetValue()
|
||||
{
|
||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().TryGetEmptyHand(Owner, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Hands
|
||||
{
|
||||
@@ -17,18 +16,10 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
|
||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return result;
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
result.Add(hand);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return handsComponent.GetFreeHandNames().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Hands.Components;
|
||||
using System.Linq;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Hands
|
||||
{
|
||||
@@ -12,23 +10,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
public override string Name => "HandItems";
|
||||
public override List<EntityUid> GetValue()
|
||||
{
|
||||
var result = new List<EntityUid>();
|
||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
var item = handsComponent.GetItem(hand);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
result.Add(item.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().EnumerateHeld(Owner).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Content.Server.AI.WorldState.States.Inventory
|
||||
|
||||
public override EntityUid? GetValue()
|
||||
{
|
||||
return IoCManager.Resolve<IEntityManager>().GetComponentOrNull<HandsComponent>(Owner)?.GetActiveHandItem?.Owner;
|
||||
return IoCManager.Resolve<IEntityManager>().GetComponentOrNull<HandsComponent>(Owner)?.ActiveHandEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Inventory
|
||||
{
|
||||
@@ -13,17 +10,7 @@ namespace Content.Server.AI.WorldState.States.Inventory
|
||||
|
||||
public override IEnumerable<EntityUid> GetValue()
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
if (entMan.TryGetComponent(Owner, out HandsComponent? handsComponent))
|
||||
{
|
||||
foreach (var item in handsComponent.GetAllHeldItems())
|
||||
{
|
||||
if (entMan.Deleted(item.Owner))
|
||||
continue;
|
||||
|
||||
yield return item.Owner;
|
||||
}
|
||||
}
|
||||
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().EnumerateHeld(Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.AME;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Popups;
|
||||
@@ -23,6 +24,7 @@ namespace Content.Server.AME.Components
|
||||
public sealed class AMEControllerComponent : SharedAMEControllerComponent, IInteractUsing
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(AMEControllerUiKey.Key);
|
||||
private bool _injecting;
|
||||
@@ -210,10 +212,7 @@ namespace Content.Server.AME.Components
|
||||
_jarSlot.Remove(jar);
|
||||
UpdateUserInterface();
|
||||
|
||||
if (!_entities.TryGetComponent<HandsComponent?>(user, out var hands) || !_entities.TryGetComponent<SharedItemComponent?>(jar, out var item))
|
||||
return;
|
||||
if (hands.CanPutInHand(item))
|
||||
hands.PutInHand(item);
|
||||
_sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(user, jar);
|
||||
}
|
||||
|
||||
private void ToggleInjection()
|
||||
@@ -306,13 +305,13 @@ namespace Content.Server.AME.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hands.GetActiveHandItem == null)
|
||||
if (hands.ActiveHandEntity == null)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("ame-controller-component-interact-using-nothing-in-hands-text"));
|
||||
return false;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHandItem.Owner;
|
||||
var activeHandEntity = hands.ActiveHandEntity;
|
||||
if (_entities.HasComponent<AMEFuelContainerComponent?>(activeHandEntity))
|
||||
{
|
||||
if (HasJar)
|
||||
@@ -322,7 +321,7 @@ namespace Content.Server.AME.Components
|
||||
|
||||
else
|
||||
{
|
||||
_jarSlot.Insert(activeHandEntity);
|
||||
_jarSlot.Insert(activeHandEntity.Value);
|
||||
Owner.PopupMessage(args.User, Loc.GetString("ame-controller-component-interact-using-success"));
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ namespace Content.Server.Access.Systems
|
||||
{
|
||||
// check held item?
|
||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands) &&
|
||||
hands.TryGetActiveHeldEntity(out var heldItem) &&
|
||||
TryGetIdCard(heldItem.Value, out idCard))
|
||||
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||
TryGetIdCard(heldItem, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Content.Server.Atmos.Components
|
||||
if (!_entities.TryGetComponent(playerEntity, out HandsComponent? handsComponent))
|
||||
return;
|
||||
|
||||
if (handsComponent?.GetActiveHandItem?.Owner is not {Valid: true} activeHandEntity ||
|
||||
if (handsComponent?.ActiveHandEntity is not {Valid: true} activeHandEntity ||
|
||||
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
||||
{
|
||||
return;
|
||||
@@ -228,7 +228,7 @@ namespace Content.Server.Atmos.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (handsComponent.GetActiveHandItem?.Owner is not {Valid: true} activeHandEntity ||
|
||||
if (handsComponent.ActiveHandEntity is not {Valid: true} activeHandEntity ||
|
||||
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
||||
{
|
||||
serverMsg.Session.AttachedEntity.Value.PopupMessage(Loc.GetString("gas-analyzer-component-need-gas-analyzer-in-hand-message"));
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
@@ -8,19 +7,14 @@ using Content.Server.Hands.Components;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
{
|
||||
@@ -30,6 +24,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly AdminLogSystem _adminLogSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -248,11 +243,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
if (!EntityManager.TryGetComponent(args.Used, out GasTankComponent? _))
|
||||
return;
|
||||
|
||||
// Check the user has hands.
|
||||
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
||||
return;
|
||||
|
||||
if (!hands.Drop(args.Used, container))
|
||||
if (!_handsSystem.TryDropIntoContainer(args.User, args.Used, container))
|
||||
return;
|
||||
|
||||
_adminLogSystem.Add(LogType.CanisterTankInserted, LogImpact.Medium, $"Player {ToPrettyString(args.User):player} inserted tank {ToPrettyString(container.ContainedEntities[0]):tank} into {ToPrettyString(canister):canister}");
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace Content.Server.Botany.Components
|
||||
{
|
||||
if (_entMan.TryGetComponent(user, out HandsComponent? hands))
|
||||
{
|
||||
if (!botanySystem.CanHarvest(Seed, hands.GetActiveHandItem?.Owner))
|
||||
if (!botanySystem.CanHarvest(Seed, hands.ActiveHandEntity))
|
||||
return false;
|
||||
}
|
||||
else if (!botanySystem.CanHarvest(Seed))
|
||||
|
||||
@@ -89,9 +89,9 @@ namespace Content.Server.Chat.Commands
|
||||
|
||||
// Held item suicide
|
||||
if (_entities.TryGetComponent(owner, out HandsComponent handsComponent)
|
||||
&& handsComponent.GetActiveHandItem is {} itemComponent)
|
||||
&& handsComponent.ActiveHandEntity is EntityUid item)
|
||||
{
|
||||
var suicide = _entities.GetComponents<ISuicideAct>(itemComponent.Owner).FirstOrDefault();
|
||||
var suicide = _entities.GetComponents<ISuicideAct>(item).FirstOrDefault();
|
||||
|
||||
if (suicide != null)
|
||||
{
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Labels.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
@@ -28,6 +26,7 @@ namespace Content.Server.Chemistry.Components
|
||||
public sealed class ChemMasterComponent : SharedChemMasterComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private uint _pillType = 1;
|
||||
@@ -276,6 +275,9 @@ namespace Content.Server.Chemistry.Components
|
||||
return;
|
||||
}
|
||||
|
||||
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
var solSys = _sysMan.GetEntitySystem<SolutionContainerSystem>();
|
||||
|
||||
if (action == UiAction.CreateBottles)
|
||||
{
|
||||
var individualVolume = BufferSolution.TotalVolume / FixedPoint2.New(bottleAmount);
|
||||
@@ -298,25 +300,12 @@ namespace Content.Server.Chemistry.Components
|
||||
labelComponent.CurrentLabel = label;
|
||||
|
||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
||||
var bottleSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(bottle, "drink");
|
||||
var bottleSolution = solSys.EnsureSolution(bottle, "drink");
|
||||
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(bottle, bottleSolution, bufferSolution);
|
||||
solSys.TryAddSolution(bottle, bottleSolution, bufferSolution);
|
||||
|
||||
//Try to give them the bottle
|
||||
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
|
||||
_entities.TryGetComponent<SharedItemComponent?>(bottle, out var item))
|
||||
{
|
||||
if (hands.CanPutInHand(item))
|
||||
{
|
||||
hands.PutInHand(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Put it on the floor
|
||||
_entities.GetComponent<TransformComponent>(bottle).Coordinates = _entities.GetComponent<TransformComponent>(user).Coordinates;
|
||||
//Give it an offset
|
||||
bottle.RandomOffset(0.2f);
|
||||
handSys.PickupOrDrop(user, bottle);
|
||||
}
|
||||
}
|
||||
else //Pills
|
||||
@@ -342,7 +331,7 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
||||
var pillSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(pill, "food");
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(pill, pillSolution, bufferSolution);
|
||||
solSys.TryAddSolution(pill, pillSolution, bufferSolution);
|
||||
|
||||
//Change pill Sprite component state
|
||||
if (!_entities.TryGetComponent(pill, out SpriteComponent? sprite))
|
||||
@@ -352,20 +341,7 @@ namespace Content.Server.Chemistry.Components
|
||||
sprite?.LayerSetState(0, "pill" + _pillType);
|
||||
|
||||
//Try to give them the bottle
|
||||
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
|
||||
_entities.TryGetComponent<SharedItemComponent?>(pill, out var item))
|
||||
{
|
||||
if (hands.CanPutInHand(item))
|
||||
{
|
||||
hands.PutInHand(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Put it on the floor
|
||||
_entities.GetComponent<TransformComponent>(pill).Coordinates = _entities.GetComponent<TransformComponent>(user).Coordinates;
|
||||
//Give it an offset
|
||||
pill.RandomOffset(0.2f);
|
||||
handSys.PickupOrDrop(user, pill);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using Content.Server.Access.Systems;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.PDA;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.RoundEnd;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Communications;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
|
||||
namespace Content.Server.Communications
|
||||
@@ -23,6 +19,7 @@ namespace Content.Server.Communications
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
private bool Powered => !_entities.TryGetComponent(Owner, out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
@@ -101,9 +98,10 @@ namespace Content.Server.Communications
|
||||
UpdateBoundInterface();
|
||||
|
||||
var message = msg.Message.Length <= 256 ? msg.Message.Trim() : $"{msg.Message.Trim().Substring(0, 256)}...";
|
||||
var sys = _sysMan.GetEntitySystem<IdCardSystem>();
|
||||
|
||||
var author = "Unknown";
|
||||
if (obj.Session.AttachedEntity is {Valid: true} mob && mob.TryGetHeldId(out var id))
|
||||
if (obj.Session.AttachedEntity is {Valid: true} mob && sys.TryFindIdCard(mob, out var id))
|
||||
{
|
||||
author = $"{id.FullName} ({CultureInfo.CurrentCulture.TextInfo.ToTitleCase(id.JobTitle ?? string.Empty)})".Trim();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Construction;
|
||||
using Content.Shared.Construction.Prototypes;
|
||||
using Content.Shared.Construction.Steps;
|
||||
using Content.Shared.Coordinates;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Popups;
|
||||
@@ -25,6 +26,7 @@ namespace Content.Server.Construction
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
// --- WARNING! LEGACY CODE AHEAD! ---
|
||||
// This entire file contains the legacy code for initial construction.
|
||||
@@ -43,20 +45,17 @@ namespace Content.Server.Construction
|
||||
// LEGACY CODE. See warning at the top of the file!
|
||||
private IEnumerable<EntityUid> EnumerateNearby(EntityUid user)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(user, out HandsComponent? hands))
|
||||
foreach (var item in _handsSystem.EnumerateHeld(user))
|
||||
{
|
||||
foreach (var itemComponent in hands?.GetAllHeldItems()!)
|
||||
if (TryComp(item, out ServerStorageComponent? storage))
|
||||
{
|
||||
if (EntityManager.TryGetComponent(itemComponent.Owner, out ServerStorageComponent? storage))
|
||||
foreach (var storedEntity in storage.StoredEntities!)
|
||||
{
|
||||
foreach (var storedEntity in storage.StoredEntities!)
|
||||
{
|
||||
yield return storedEntity;
|
||||
}
|
||||
yield return storedEntity;
|
||||
}
|
||||
|
||||
yield return itemComponent.Owner;
|
||||
}
|
||||
|
||||
yield return item;
|
||||
}
|
||||
|
||||
if (_inventorySystem.TryGetContainerSlotEnumerator(user, out var containerSlotEnumerator))
|
||||
@@ -334,7 +333,7 @@ namespace Content.Server.Construction
|
||||
}
|
||||
|
||||
if (await Construct(user, "item_construction", constructionGraph, edge, targetNode) is {Valid: true} item)
|
||||
hands.PutInHandOrDrop(item);
|
||||
_handsSystem.PickupOrDrop(user, item);
|
||||
}
|
||||
|
||||
// LEGACY CODE. See warning at the top of the file!
|
||||
@@ -401,7 +400,7 @@ namespace Content.Server.Construction
|
||||
}
|
||||
|
||||
if (!_actionBlocker.CanInteract(user, null)
|
||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.GetActiveHandItem == null)
|
||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.ActiveHandEntity == null)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
@@ -426,7 +425,7 @@ namespace Content.Server.Construction
|
||||
|
||||
var valid = false;
|
||||
|
||||
if (hands.GetActiveHandItem?.Owner is not {Valid: true} holding)
|
||||
if (hands.ActiveHandEntity is not {Valid: true} holding)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.DoAfter;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Cuffs.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Popups;
|
||||
@@ -26,6 +27,7 @@ namespace Content.Server.Cuffs.Components
|
||||
public sealed class CuffableComponent : SharedCuffableComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
/// <summary>
|
||||
/// How many of this entity's hands are currently cuffed.
|
||||
@@ -103,15 +105,13 @@ namespace Content.Server.Cuffs.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
// Success!
|
||||
if (_entMan.TryGetComponent(user, out HandsComponent? handsComponent) && handsComponent.IsHolding(handcuff))
|
||||
{
|
||||
// Good lord handscomponent is scuffed, I hope some smug person will fix it someday
|
||||
handsComponent.Drop(handcuff);
|
||||
}
|
||||
sys.TryDrop(user, handcuff);
|
||||
|
||||
Container.Insert(handcuff);
|
||||
CanStillInteract = _entMan.TryGetComponent(Owner, out HandsComponent? ownerHands) && ownerHands.HandNames.Count() > CuffedHandCount;
|
||||
CanStillInteract = _entMan.TryGetComponent(Owner, out HandsComponent? ownerHands) && ownerHands.Hands.Count() > CuffedHandCount;
|
||||
|
||||
OnCuffedStateChanged?.Invoke();
|
||||
UpdateAlert();
|
||||
@@ -133,23 +133,22 @@ namespace Content.Server.Cuffs.Components
|
||||
{
|
||||
if (!_entMan.TryGetComponent(Owner, out HandsComponent? handsComponent)) return;
|
||||
|
||||
var itemCount = handsComponent.GetAllHeldItems().Count();
|
||||
var freeHandCount = handsComponent.HandNames.Count() - CuffedHandCount;
|
||||
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
if (freeHandCount < itemCount)
|
||||
var freeHandCount = handsComponent.Hands.Count() - CuffedHandCount;
|
||||
|
||||
foreach (var hand in handsComponent.Hands.Values)
|
||||
{
|
||||
foreach (var item in handsComponent.GetAllHeldItems())
|
||||
if (hand.IsEmpty)
|
||||
continue;
|
||||
|
||||
if (freeHandCount > 0)
|
||||
{
|
||||
if (freeHandCount < itemCount)
|
||||
{
|
||||
freeHandCount++;
|
||||
handsComponent.Drop(item.Owner, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
freeHandCount--;
|
||||
continue;
|
||||
}
|
||||
|
||||
sys.TryDrop(Owner, hand, checkActionBlocker: false, handsComp: handsComponent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +266,7 @@ namespace Content.Server.Cuffs.Components
|
||||
}
|
||||
}
|
||||
|
||||
CanStillInteract = _entMan.TryGetComponent(Owner, out HandsComponent? handsComponent) && handsComponent.HandNames.Count() > CuffedHandCount;
|
||||
CanStillInteract = _entMan.TryGetComponent(Owner, out HandsComponent? handsComponent) && handsComponent.SortedHands.Count() > CuffedHandCount;
|
||||
OnCuffedStateChanged?.Invoke();
|
||||
UpdateAlert();
|
||||
Dirty();
|
||||
|
||||
@@ -2,7 +2,7 @@ using Content.Server.Cuffs.Components;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Cuffs;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace Content.Server.Disposal.Tube.Components
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(Owner), _clickSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
|
||||
}
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Disposal.Tube.Components;
|
||||
using Content.Server.Disposal.Tube.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Movement;
|
||||
@@ -81,7 +81,7 @@ namespace Content.Server.Disposal.Tube
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHandItem?.Owner;
|
||||
var activeHandEntity = hands.ActiveHandEntity;
|
||||
if (activeHandEntity != null)
|
||||
{
|
||||
args.Cancel();
|
||||
@@ -96,7 +96,7 @@ namespace Content.Server.Disposal.Tube
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHandItem?.Owner;
|
||||
var activeHandEntity = hands.ActiveHandEntity;
|
||||
if (activeHandEntity != null)
|
||||
{
|
||||
args.Cancel();
|
||||
|
||||
@@ -16,21 +16,16 @@ using Content.Shared.Atmos;
|
||||
using Content.Shared.Disposal;
|
||||
using Content.Shared.Disposal.Components;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Movement;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
@@ -43,6 +38,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private readonly List<DisposalUnitComponent> _activeDisposals = new();
|
||||
|
||||
@@ -140,7 +136,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
||||
Category = VerbCategory.Insert,
|
||||
Act = () =>
|
||||
{
|
||||
args.Hands.Drop(args.Using.Value, component.Container);
|
||||
_handsSystem.TryDropIntoContainer(args.User, args.Using.Value, component.Container, checkActionBlocker: false, args.Hands);
|
||||
AfterInsert(component, args.Using.Value);
|
||||
}
|
||||
};
|
||||
@@ -248,8 +244,8 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanInsert(component, args.Used) || !hands.Drop(args.Used, component.Container))
|
||||
|
||||
if (!CanInsert(component, args.Used) || !_handsSystem.TryDropIntoContainer(args.User, args.Used, component.Container))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Item;
|
||||
@@ -30,7 +30,7 @@ namespace Content.Server.DoAfter
|
||||
|
||||
// NeedHand
|
||||
private readonly string? _activeHand;
|
||||
private readonly SharedItemComponent? _activeItem;
|
||||
private readonly EntityUid? _activeItem;
|
||||
|
||||
public DoAfter(DoAfterEventArgs eventArgs, IEntityManager entityManager)
|
||||
{
|
||||
@@ -52,8 +52,8 @@ namespace Content.Server.DoAfter
|
||||
// (or if there is no item there we need to keep it free).
|
||||
if (eventArgs.NeedHand && entityManager.TryGetComponent(eventArgs.User, out HandsComponent? handsComponent))
|
||||
{
|
||||
_activeHand = handsComponent.ActiveHand;
|
||||
_activeItem = handsComponent.GetActiveHandItem;
|
||||
_activeHand = handsComponent.ActiveHand?.Name;
|
||||
_activeItem = handsComponent.ActiveHandEntity;
|
||||
}
|
||||
|
||||
Tcs = new TaskCompletionSource<DoAfterStatus>();
|
||||
@@ -152,13 +152,13 @@ namespace Content.Server.DoAfter
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentActiveHand = handsComponent.ActiveHand;
|
||||
var currentActiveHand = handsComponent.ActiveHand?.Name;
|
||||
if (_activeHand != currentActiveHand)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var currentItem = handsComponent.GetActiveHandItem;
|
||||
var currentItem = handsComponent.ActiveHandEntity;
|
||||
if (_activeItem != currentItem)
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -19,6 +19,7 @@ using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Drone
|
||||
@@ -28,6 +29,7 @@ namespace Content.Server.Drone
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
@@ -118,13 +120,18 @@ namespace Content.Server.Drone
|
||||
|
||||
if (TryComp<HandsComponent>(uid, out var hands) && hands.Count >= drone.Tools.Count)
|
||||
{
|
||||
foreach (var entry in drone.Tools)
|
||||
{
|
||||
var item = EntityManager.SpawnEntity(entry.PrototypeId, spawnCoord);
|
||||
AddComp<UnremoveableComponent>(item);
|
||||
hands.PutInHand(item);
|
||||
drone.ToolUids.Add(item);
|
||||
}
|
||||
foreach (var entry in drone.Tools)
|
||||
{
|
||||
var item = EntityManager.SpawnEntity(entry.PrototypeId, spawnCoord);
|
||||
AddComp<UnremoveableComponent>(item);
|
||||
if (!_handsSystem.TryPickupAnyHand(uid, item, checkActionBlocker: false))
|
||||
{
|
||||
QueueDel(item);
|
||||
Logger.Error($"Drone ({ToPrettyString(uid)}) failed to pick up innate item ({ToPrettyString(item)})");
|
||||
continue;
|
||||
}
|
||||
drone.ToolUids.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (TryComp<ActionsComponent>(uid, out var actions) && TryComp<UnpoweredFlashlightComponent>(uid, out var flashlight))
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Engineering.Components;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Verbs;
|
||||
using JetBrains.Annotations;
|
||||
@@ -11,6 +10,8 @@ namespace Content.Server.Engineering.EntitySystems
|
||||
[UsedImplicitly]
|
||||
public sealed class DisassembleOnAltVerbSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -63,11 +64,7 @@ namespace Content.Server.Engineering.EntitySystems
|
||||
|
||||
var entity = EntityManager.SpawnEntity(component.Prototype, transformComp.Coordinates);
|
||||
|
||||
if (TryComp<HandsComponent?>(user, out var hands)
|
||||
&& TryComp<SharedItemComponent?>(entity, out var item))
|
||||
{
|
||||
hands.PutInHandOrDrop(item);
|
||||
}
|
||||
_handsSystem.TryPickup(user, entity);
|
||||
|
||||
EntityManager.DeleteEntity(component.Owner);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Shared.Access.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Preferences;
|
||||
@@ -33,6 +34,7 @@ namespace Content.Server.GameTicking
|
||||
|
||||
[Dependency] private readonly IdCardSystem _cardSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Can't yet be removed because every test ever seems to depend on it. I'll make removing this a different PR.
|
||||
@@ -319,14 +321,15 @@ namespace Content.Server.GameTicking
|
||||
}
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponent(entity, out HandsComponent? handsComponent))
|
||||
if (!TryComp(entity, out HandsComponent? handsComponent))
|
||||
return;
|
||||
|
||||
var inhand = startingGear.Inhand;
|
||||
var coords = EntityManager.GetComponent<TransformComponent>(entity).Coordinates;
|
||||
foreach (var (hand, prototype) in inhand)
|
||||
{
|
||||
var inhand = startingGear.Inhand;
|
||||
foreach (var (hand, prototype) in inhand)
|
||||
{
|
||||
var inhandEntity = EntityManager.SpawnEntity(prototype, EntityManager.GetComponent<TransformComponent>(entity).Coordinates);
|
||||
handsComponent.TryPickupEntity(hand, inhandEntity, checkActionBlocker: false);
|
||||
}
|
||||
var inhandEntity = EntityManager.SpawnEntity(prototype, coords);
|
||||
_handsSystem.TryPickup(entity, inhandEntity, hand, checkActionBlocker: false, handsComp: handsComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Actions;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.MobState;
|
||||
@@ -25,6 +26,7 @@ namespace Content.Server.Guardian
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageSystem = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -180,8 +182,7 @@ namespace Content.Server.Guardian
|
||||
|
||||
if (comp.Deleted ||
|
||||
comp.Used ||
|
||||
!TryComp<HandsComponent>(ev.User, out var hands) ||
|
||||
!hands.IsHolding(comp.Owner) ||
|
||||
!_handsSystem.IsHolding(ev.User, comp.Owner, out _) ||
|
||||
HasComp<GuardianHostComponent>(ev.Target))
|
||||
{
|
||||
comp.Injecting = false;
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Act;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Pulling;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Body.Part;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Pulling.Components;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Server.Hands.Components
|
||||
{
|
||||
@@ -24,9 +11,6 @@ namespace Content.Server.Hands.Components
|
||||
#pragma warning restore 618
|
||||
{
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
|
||||
#region Pull/Disarm
|
||||
|
||||
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs args)
|
||||
{
|
||||
@@ -43,7 +27,7 @@ namespace Content.Server.Hands.Components
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
AddHand(args.Slot, location);
|
||||
_entitySystemManager.GetEntitySystem<SharedHandsSystem>().AddHand(Owner, args.Slot, location);
|
||||
}
|
||||
|
||||
void IBodyPartRemoved.BodyPartRemoved(BodyPartRemovedEventArgs args)
|
||||
@@ -51,94 +35,8 @@ namespace Content.Server.Hands.Components
|
||||
if (args.Part.PartType != BodyPartType.Hand)
|
||||
return;
|
||||
|
||||
RemoveHand(args.Slot);
|
||||
_entitySystemManager.GetEntitySystem<SharedHandsSystem>().RemoveHand(Owner, args.Slot);
|
||||
}
|
||||
|
||||
public bool BreakPulls()
|
||||
{
|
||||
// What is this API??
|
||||
// I just wanted to do actions not deal with this shit...
|
||||
if (!_entities.TryGetComponent(Owner, out SharedPullerComponent? puller)
|
||||
|| puller.Pulling is not {Valid: true} pulling || !_entities.TryGetComponent(puller.Pulling.Value, out SharedPullableComponent? pullable))
|
||||
return false;
|
||||
|
||||
return _entitySystemManager.GetEntitySystem<PullingSystem>().TryStopPull(pullable);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Old public methods
|
||||
|
||||
public IEnumerable<string> HandNames => Hands.Select(h => h.Name);
|
||||
|
||||
public int Count => Hands.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all hand names, with the active hand being first.
|
||||
/// </summary>
|
||||
public IEnumerable<string> ActivePriorityEnumerable()
|
||||
{
|
||||
if (ActiveHand != null)
|
||||
yield return ActiveHand;
|
||||
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.Name == ActiveHand)
|
||||
continue;
|
||||
|
||||
yield return hand.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the ItemComponent on the entity held by a hand.
|
||||
/// </summary>
|
||||
public SharedItemComponent? GetItem(string handName)
|
||||
{
|
||||
if (!TryGetHeldEntity(handName, out var heldEntity))
|
||||
return null;
|
||||
|
||||
_entities.TryGetComponent(heldEntity, out SharedItemComponent? item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the ItemComponent on the entity held by a hand.
|
||||
/// </summary>
|
||||
public bool TryGetItem(string handName, [NotNullWhen(true)] out SharedItemComponent? item)
|
||||
{
|
||||
item = null;
|
||||
|
||||
if (!TryGetHeldEntity(handName, out var heldEntity))
|
||||
return false;
|
||||
|
||||
return _entities.TryGetComponent(heldEntity, out item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the ItemComponent off the entity in the active hand.
|
||||
/// </summary>
|
||||
public SharedItemComponent? GetActiveHandItem
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!TryGetActiveHeldEntity(out var heldEntity))
|
||||
return null;
|
||||
|
||||
_entities.TryGetComponent(heldEntity, out SharedItemComponent? item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<SharedItemComponent> GetAllHeldItems()
|
||||
{
|
||||
foreach (var entity in GetAllHeldEntities())
|
||||
{
|
||||
if (_entities.TryGetComponent(entity, out SharedItemComponent? item))
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.Hands.Systems
|
||||
{
|
||||
@@ -14,24 +13,15 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user)
|
||||
{
|
||||
if (EntityManager.TryGetComponent<HandsComponent>(user, out var hands))
|
||||
{
|
||||
foreach (var handName in hands.ActivePriorityEnumerable())
|
||||
{
|
||||
var hand = hands.GetHand(handName);
|
||||
if (hand.HeldEntity != null)
|
||||
continue;
|
||||
if (!_handsSystem.TryGetEmptyHand(user, out var hand))
|
||||
return false;
|
||||
|
||||
var pos = EntityManager.GetComponent<TransformComponent>(hands.Owner).Coordinates;
|
||||
var virtualItem = EntityManager.SpawnEntity("HandVirtualItem", pos);
|
||||
var virtualItemComp = EntityManager.GetComponent<HandVirtualItemComponent>(virtualItem);
|
||||
virtualItemComp.BlockingEntity = blockingEnt;
|
||||
_handsSystem.PutEntityIntoHand(user, hand, virtualItem, hands);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
var pos = EntityManager.GetComponent<TransformComponent>(user).Coordinates;
|
||||
var virtualItem = EntityManager.SpawnEntity("HandVirtualItem", pos);
|
||||
var virtualItemComp = EntityManager.GetComponent<HandVirtualItemComponent>(virtualItem);
|
||||
virtualItemComp.BlockingEntity = blockingEnt;
|
||||
_handsSystem.DoPickup(user, hand, virtualItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -40,20 +30,12 @@ namespace Content.Server.Hands.Systems
|
||||
/// </summary>
|
||||
public void DeleteInHandsMatching(EntityUid user, EntityUid matching)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent<HandsComponent>(user, out var hands))
|
||||
return;
|
||||
|
||||
foreach (var handName in hands.ActivePriorityEnumerable())
|
||||
foreach (var hand in _handsSystem.EnumerateHands(user))
|
||||
{
|
||||
var hand = hands.GetHand(handName);
|
||||
|
||||
if (!(hand.HeldEntity is { } heldEntity))
|
||||
continue;
|
||||
|
||||
if (EntityManager.TryGetComponent<HandVirtualItemComponent>(heldEntity, out var virt)
|
||||
&& virt.BlockingEntity == matching)
|
||||
if (TryComp(hand.HeldEntity, out HandVirtualItemComponent? virt) && virt.BlockingEntity == matching)
|
||||
{
|
||||
Delete(virt, user);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ using Content.Shared.Popups;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Input.Binding;
|
||||
@@ -29,6 +28,9 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.Pulling.Components;
|
||||
using Content.Server.Pulling;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Server.Hands.Systems
|
||||
{
|
||||
@@ -43,27 +45,24 @@ namespace Content.Server.Hands.Systems
|
||||
[Dependency] private readonly StrippableSystem _strippableSystem = default!;
|
||||
[Dependency] private readonly SharedHandVirtualItemSystem _virtualSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly PullingSystem _pullingSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HandsComponent, ExaminedEvent>(HandleExamined);
|
||||
SubscribeNetworkEvent<ActivateInHandMsg>(HandleActivateInHand);
|
||||
SubscribeNetworkEvent<ClientInteractUsingInHandMsg>(HandleInteractUsingInHand);
|
||||
SubscribeNetworkEvent<UseInHandMsg>(HandleUseInHand);
|
||||
SubscribeNetworkEvent<MoveItemFromHandMsg>(HandleMoveItemFromHand);
|
||||
SubscribeLocalEvent<HandsComponent, DisarmedEvent>(OnDisarmed, before: new[] { typeof(StunSystem) });
|
||||
|
||||
SubscribeLocalEvent<HandsComponent, PullAttemptMessage>(HandlePullAttempt);
|
||||
SubscribeLocalEvent<HandsComponent, PullStartedMessage>(HandlePullStarted);
|
||||
SubscribeLocalEvent<HandsComponent, PullStoppedMessage>(HandlePullStopped);
|
||||
|
||||
SubscribeLocalEvent<HandsComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
||||
|
||||
SubscribeLocalEvent<HandsComponent, ComponentGetState>(GetComponentState);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ActivateItemInHand, InputCmdHandler.FromDelegate(s => HandleActivateItem(s)))
|
||||
.Bind(ContentKeyFunctions.AltActivateItemInHand, InputCmdHandler.FromDelegate(s => HandleActivateItem(s, true)))
|
||||
.Bind(ContentKeyFunctions.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem))
|
||||
.Bind(ContentKeyFunctions.SmartEquipBackpack, InputCmdHandler.FromDelegate(HandleSmartEquipBackpack))
|
||||
.Bind(ContentKeyFunctions.SmartEquipBelt, InputCmdHandler.FromDelegate(HandleSmartEquipBelt))
|
||||
@@ -79,15 +78,19 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
private void GetComponentState(EntityUid uid, HandsComponent hands, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new HandsComponentState(hands.Hands, hands.ActiveHand);
|
||||
args.State = new HandsComponentState(hands);
|
||||
}
|
||||
|
||||
private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent args)
|
||||
{
|
||||
if (args.Handled || component.BreakPulls())
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (component.ActiveHand == null || !component.Drop(component.ActiveHand, false))
|
||||
// Break any pulls
|
||||
if (TryComp(uid, out SharedPullerComponent? puller) && puller.Pulling is EntityUid pulled && TryComp(pulled, out SharedPullableComponent? pullable))
|
||||
_pullingSystem.TryStopPull(pullable);
|
||||
|
||||
if (_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false))
|
||||
return;
|
||||
|
||||
var targetName = Name(args.Target);
|
||||
@@ -103,9 +106,9 @@ namespace Content.Server.Hands.Systems
|
||||
}
|
||||
|
||||
#region EntityInsertRemove
|
||||
public override void RemoveHeldEntityFromHand(EntityUid uid, Hand hand, SharedHandsComponent? hands = null)
|
||||
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, SharedHandsComponent? hands = null)
|
||||
{
|
||||
base.RemoveHeldEntityFromHand(uid, hand, hands);
|
||||
base.DoDrop(uid, hand,doDropInteraction, hands);
|
||||
|
||||
// update gui of anyone stripping this entity.
|
||||
_strippableSystem.SendUpdate(uid);
|
||||
@@ -114,9 +117,9 @@ namespace Content.Server.Hands.Systems
|
||||
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||
}
|
||||
|
||||
public override void PutEntityIntoHand(EntityUid uid, Hand hand, EntityUid entity, SharedHandsComponent? hands = null)
|
||||
public override void DoPickup(EntityUid uid, Hand hand, EntityUid entity, SharedHandsComponent? hands = null)
|
||||
{
|
||||
base.PutEntityIntoHand(uid, hand, entity, hands);
|
||||
base.DoPickup(uid, hand, entity, hands);
|
||||
|
||||
// update gui of anyone stripping this entity.
|
||||
_strippableSystem.SendUpdate(uid);
|
||||
@@ -124,6 +127,7 @@ namespace Content.Server.Hands.Systems
|
||||
_logSystem.Add(LogType.Pickup, LogImpact.Low, $"{uid} picked up {entity}");
|
||||
}
|
||||
|
||||
|
||||
public override void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||
EntityUid? exclude)
|
||||
{
|
||||
@@ -138,12 +142,10 @@ namespace Content.Server.Hands.Systems
|
||||
RaiseNetworkEvent(new PickupAnimationEvent(item, initialPosition, finalPosition), filter);
|
||||
}
|
||||
|
||||
protected override void HandleContainerRemoved(EntityUid uid, SharedHandsComponent component, ContainerModifiedMessage args)
|
||||
private void HandleEntityRemoved(EntityUid uid, SharedHandsComponent component, EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (!Deleted(args.Entity) && TryComp(args.Entity, out HandVirtualItemComponent? @virtual))
|
||||
_virtualSystem.Delete(@virtual, uid);
|
||||
|
||||
base.HandleContainerRemoved(uid, component, args);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -154,11 +156,10 @@ namespace Content.Server.Hands.Systems
|
||||
return;
|
||||
|
||||
// Cancel pull if all hands full.
|
||||
if (component.Hands.All(hand => !hand.IsEmpty))
|
||||
if (!component.IsAnyHandFree())
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
|
||||
private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args)
|
||||
{
|
||||
if (args.Puller.Owner != uid)
|
||||
@@ -177,7 +178,7 @@ namespace Content.Server.Hands.Systems
|
||||
|
||||
// Try find hand that is doing this pull.
|
||||
// and clear it.
|
||||
foreach (var hand in component.Hands)
|
||||
foreach (var hand in component.Hands.Values)
|
||||
{
|
||||
if (hand.HeldEntity == null
|
||||
|| !TryComp(hand.HeldEntity, out HandVirtualItemComponent? virtualItem)
|
||||
@@ -191,34 +192,6 @@ namespace Content.Server.Hands.Systems
|
||||
#endregion
|
||||
|
||||
#region interactions
|
||||
private void HandleMoveItemFromHand(MoveItemFromHandMsg msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.TryMoveHeldEntityToActiveHand(msg.HandName);
|
||||
}
|
||||
private void HandleUseInHand(UseInHandMsg msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.ActivateItem();
|
||||
}
|
||||
private void HandleInteractUsingInHand(ClientInteractUsingInHandMsg msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.InteractHandWithActiveHand(msg.HandName);
|
||||
}
|
||||
|
||||
private void HandleActivateInHand(ActivateInHandMsg msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.ActivateHeldEntity(msg.HandName);
|
||||
}
|
||||
|
||||
private void HandleActivateItem(ICommonSession? session, bool altInteract = false)
|
||||
{
|
||||
if (TryComp(session?.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.ActivateItem(altInteract);
|
||||
}
|
||||
|
||||
private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
if (session is not IPlayerSession playerSession)
|
||||
@@ -228,20 +201,20 @@ namespace Content.Server.Hands.Systems
|
||||
!Exists(player) ||
|
||||
player.IsInContainer() ||
|
||||
!TryComp(player, out SharedHandsComponent? hands) ||
|
||||
!hands.TryGetActiveHeldEntity(out var throwEnt) ||
|
||||
hands.ActiveHandEntity is not EntityUid throwEnt ||
|
||||
!_actionBlockerSystem.CanThrow(player))
|
||||
return false;
|
||||
|
||||
if (EntityManager.TryGetComponent(throwEnt.Value, out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually)
|
||||
if (EntityManager.TryGetComponent(throwEnt, out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually)
|
||||
{
|
||||
var splitStack = _stackSystem.Split(throwEnt.Value, 1, EntityManager.GetComponent<TransformComponent>(player).Coordinates, stack);
|
||||
var splitStack = _stackSystem.Split(throwEnt, 1, EntityManager.GetComponent<TransformComponent>(player).Coordinates, stack);
|
||||
|
||||
if (splitStack is not {Valid: true})
|
||||
return false;
|
||||
|
||||
throwEnt = splitStack.Value;
|
||||
}
|
||||
else if (!hands.Drop(throwEnt.Value))
|
||||
else if (!TryDrop(player, throwEnt, handsComp: hands))
|
||||
return false;
|
||||
|
||||
var direction = coords.ToMapPos(EntityManager) - Transform(player).WorldPosition;
|
||||
@@ -251,7 +224,7 @@ namespace Content.Server.Hands.Systems
|
||||
direction = direction.Normalized * Math.Min(direction.Length, hands.ThrowRange);
|
||||
|
||||
var throwStrength = hands.ThrowForceMultiplier;
|
||||
throwEnt.Value.TryThrow(direction, throwStrength, player);
|
||||
throwEnt.TryThrow(direction, throwStrength, player);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -287,7 +260,7 @@ namespace Content.Server.Hands.Systems
|
||||
return;
|
||||
}
|
||||
|
||||
if (hands.ActiveHandIsHoldingEntity())
|
||||
if (hands.ActiveHand?.HeldEntity != null)
|
||||
{
|
||||
storageComponent.PlayerInsertHeldEntity(plyEnt);
|
||||
}
|
||||
@@ -302,24 +275,11 @@ namespace Content.Server.Hands.Systems
|
||||
var lastStoredEntity = Enumerable.Last(storageComponent.StoredEntities);
|
||||
if (storageComponent.Remove(lastStoredEntity))
|
||||
{
|
||||
if (!hands.TryPickupEntityToActiveHand(lastStoredEntity, animateUser: true))
|
||||
Transform(lastStoredEntity).Coordinates = Transform(plyEnt).Coordinates;
|
||||
PickupOrDrop(plyEnt, lastStoredEntity, animateUser: true, handsComp: hands);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//TODO: Actually shows all items/clothing/etc.
|
||||
private void HandleExamined(EntityUid uid, HandsComponent component, ExaminedEvent args)
|
||||
{
|
||||
foreach (var inhand in component.GetAllHeldItems())
|
||||
{
|
||||
if (HasComp<HandVirtualItemComponent>(inhand.Owner))
|
||||
continue;
|
||||
|
||||
args.PushText(Loc.GetString("comp-hands-examine", ("user", component.Owner), ("item", inhand.Owner)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Content.Server.Interaction
|
||||
// Verify user has a hand, and find what object they are currently holding in their active hand
|
||||
if (TryComp(user, out HandsComponent? hands))
|
||||
{
|
||||
var item = hands.GetActiveHandItem?.Owner;
|
||||
var item = hands.ActiveHandEntity;
|
||||
|
||||
if (item != null && !Deleted(item.Value))
|
||||
{
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Holiday;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Jobs
|
||||
@@ -26,17 +22,16 @@ namespace Content.Server.Jobs
|
||||
if (string.IsNullOrEmpty(Holiday) || string.IsNullOrEmpty(Prototype))
|
||||
return;
|
||||
|
||||
if (!EntitySystem.Get<HolidaySystem>().IsCurrentlyHoliday(Holiday))
|
||||
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||
|
||||
if (!sysMan.GetEntitySystem<HolidaySystem>().IsCurrentlyHoliday(Holiday))
|
||||
return;
|
||||
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
var entity = entMan.SpawnEntity(Prototype, entMan.GetComponent<TransformComponent>(mob).Coordinates);
|
||||
|
||||
if (!entMan.TryGetComponent(entity, out SharedItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands))
|
||||
return;
|
||||
|
||||
hands.PutInHand(item, false);
|
||||
sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(mob, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Content.Server.Kitchen.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_entities.GetComponent<HandsComponent>(eventArgs.User).GetActiveHandItem?.Owner is not {Valid: true} itemEntity)
|
||||
if (_entities.GetComponent<HandsComponent>(eventArgs.User).ActiveHandEntity is not {Valid: true} itemEntity)
|
||||
{
|
||||
eventArgs.User.PopupMessage(Loc.GetString("microwave-component-interact-using-no-active-hand"));
|
||||
return false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Hands.Components;
|
||||
@@ -7,6 +7,7 @@ using Content.Server.Kitchen.Events;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Kitchen.Components;
|
||||
@@ -16,10 +17,6 @@ using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -29,6 +26,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
internal sealed class ReagentGrinderSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private Queue<ReagentGrinderComponent> _uiUpdateQueue = new();
|
||||
|
||||
@@ -267,7 +265,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
!EntityManager.TryGetComponent<SharedItemComponent?>(beaker, out var item))
|
||||
return;
|
||||
|
||||
hands.PutInHandOrDrop(item);
|
||||
_handsSystem.PickupOrDrop(user.Value, beaker, handsComp: hands, item: item);
|
||||
|
||||
component.HeldBeaker = null;
|
||||
EnqueueUiUpdate(component);
|
||||
|
||||
@@ -11,16 +11,13 @@ using Content.Shared.Audio;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Light;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -37,6 +34,7 @@ namespace Content.Server.Light.EntitySystems
|
||||
[Dependency] private readonly LightBulbSystem _bulbSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2);
|
||||
|
||||
@@ -171,11 +169,7 @@ namespace Content.Server.Light.EntitySystems
|
||||
return null;
|
||||
|
||||
// try to place bulb in hands
|
||||
if (userUid != null)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(userUid.Value, out SharedHandsComponent? hands))
|
||||
hands.PutInHand(bulb);
|
||||
}
|
||||
_handsSystem.PickupOrDrop(userUid, bulb);
|
||||
|
||||
UpdateLight(uid, light);
|
||||
return bulb;
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Content.Server.MachineLinking.System
|
||||
case SignalPortSelected portSelected:
|
||||
if (msg.Session.AttachedEntity == default ||
|
||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
||||
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
||||
hands.ActiveHandEntity is not EntityUid heldEntity ||
|
||||
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent) ||
|
||||
!signalLinkerComponent.Port.HasValue ||
|
||||
!signalLinkerComponent.Port.Value.transmitter.Outputs.ContainsPort(signalLinkerComponent.Port
|
||||
@@ -165,7 +165,7 @@ namespace Content.Server.MachineLinking.System
|
||||
case SignalPortSelected portSelected:
|
||||
if (msg.Session.AttachedEntity == default ||
|
||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
||||
!hands.TryGetActiveHeldEntity(out var heldEntity) ||
|
||||
hands.ActiveHandEntity is not EntityUid heldEntity ||
|
||||
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent))
|
||||
return;
|
||||
LinkerSaveInteraction(attached, signalLinkerComponent, component,
|
||||
|
||||
@@ -7,7 +7,6 @@ using Content.Server.DoAfter;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Nutrition.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
@@ -20,7 +19,7 @@ using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
@@ -39,6 +38,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -223,18 +223,12 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
var finisher = EntityManager.SpawnEntity(component.TrashPrototype, position);
|
||||
|
||||
// If the user is holding the item
|
||||
if (user != null &&
|
||||
EntityManager.TryGetComponent(user.Value, out HandsComponent? handsComponent) &&
|
||||
handsComponent.IsHolding(component.Owner))
|
||||
if (user != null && _handsSystem.IsHolding(user.Value, component.Owner, out var hand))
|
||||
{
|
||||
EntityManager.DeleteEntity((component).Owner);
|
||||
|
||||
// Put the trash in the user's hand
|
||||
if (EntityManager.TryGetComponent(finisher, out SharedItemComponent? item) &&
|
||||
handsComponent.CanPutInHand(item))
|
||||
{
|
||||
handsComponent.PutInHand(item);
|
||||
}
|
||||
_handsSystem.TryPickup(user.Value, finisher, hand);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,10 +323,10 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
var usedTypes = UtensilType.None;
|
||||
|
||||
foreach (var item in hands.GetAllHeldItems())
|
||||
foreach (var item in _handsSystem.EnumerateHeld(user, hands))
|
||||
{
|
||||
// Is utensil?
|
||||
if (!EntityManager.TryGetComponent(item.Owner, out UtensilComponent? utensil))
|
||||
if (!EntityManager.TryGetComponent(item, out UtensilComponent? utensil))
|
||||
continue;
|
||||
|
||||
if ((utensil.Types & component.Utensil) != 0 && // Acceptable type?
|
||||
|
||||
@@ -5,13 +5,11 @@ using Content.Server.Nutrition.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Nutrition.EntitySystems
|
||||
@@ -19,6 +17,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
internal sealed class SliceableFoodSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -67,9 +67,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
||||
|
||||
if (EntityManager.TryGetComponent(user, out HandsComponent? handsComponent))
|
||||
{
|
||||
if (ContainerHelpers.IsInContainer(component.Owner))
|
||||
if (_containerSystem.IsEntityInContainer(component.Owner))
|
||||
{
|
||||
handsComponent.PutInHandOrDrop(EntityManager.GetComponent<SharedItemComponent>(sliceUid));
|
||||
_handsSystem.PickupOrDrop(user, sliceUid, handsComp: handsComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.PDA
|
||||
{
|
||||
public static class PdaExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the id that a player is holding in their hands or inventory.
|
||||
/// Order: Hands > ID slot > PDA in ID slot
|
||||
/// </summary>
|
||||
/// <param name="player">The player to check in.</param>
|
||||
/// <returns>The id card component.</returns>
|
||||
public static IdCardComponent? GetHeldId(this EntityUid player)
|
||||
{
|
||||
IdCardComponent? foundPDAId = null;
|
||||
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
|
||||
if (entMan.TryGetComponent(player, out HandsComponent? hands))
|
||||
{
|
||||
foreach (var item in hands.GetAllHeldItems())
|
||||
{
|
||||
if (entMan.TryGetComponent(item.Owner, out PDAComponent? pda) &&
|
||||
pda.ContainedID != null)
|
||||
{
|
||||
foundPDAId = pda.ContainedID;
|
||||
}
|
||||
|
||||
if (entMan.TryGetComponent(item.Owner, out IdCardComponent? card))
|
||||
{
|
||||
return card;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPDAId != null) return foundPDAId;
|
||||
|
||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
||||
|
||||
if (invSystem.TryGetContainerSlotEnumerator(player, out var enumerator))
|
||||
{
|
||||
while (enumerator.MoveNext(out var containerSlot))
|
||||
{
|
||||
if(!containerSlot.ContainedEntity.HasValue) continue;
|
||||
|
||||
if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out PDAComponent? pda) &&
|
||||
pda.ContainedID != null)
|
||||
{
|
||||
foundPDAId = pda.ContainedID;
|
||||
}
|
||||
|
||||
if (entMan.TryGetComponent(containerSlot.ContainedEntity.Value, out IdCardComponent? card))
|
||||
{
|
||||
return card;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPDAId != null) return foundPDAId;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id that a player is holding in their hands or inventory.
|
||||
/// Order: Hands > ID slot > PDA in ID slot
|
||||
/// </summary>
|
||||
/// <param name="player">The player to check in.</param>
|
||||
/// <param name="id">The id card component.</param>
|
||||
/// <returns>true if found, false otherwise.</returns>
|
||||
public static bool TryGetHeldId(this EntityUid player, [NotNullWhen(true)] out IdCardComponent? id)
|
||||
{
|
||||
return (id = player.GetHeldId()) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Content.Server.Throwing;
|
||||
using Content.Server.Tools.Components;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.CombatMode;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.PneumaticCannon;
|
||||
@@ -19,11 +20,7 @@ using Content.Shared.StatusEffect;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
@@ -35,6 +32,7 @@ namespace Content.Server.PneumaticCannon
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||
[Dependency] private readonly CameraRecoilSystem _cameraRecoil = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private HashSet<PneumaticCannonComponent> _currentlyFiring = new();
|
||||
|
||||
@@ -320,11 +318,8 @@ namespace Content.Server.PneumaticCannon
|
||||
|
||||
if (component.GasTankSlot.Remove(contained))
|
||||
{
|
||||
if (EntityManager.TryGetComponent<HandsComponent?>(user, out var hands))
|
||||
{
|
||||
hands.PutInHand(contained);
|
||||
}
|
||||
|
||||
_handsSystem.TryPickupAnyHand(user, contained);
|
||||
|
||||
user.PopupMessage(Loc.GetString("pneumatic-cannon-component-gas-tank-remove",
|
||||
("tank", contained), ("cannon", component.Owner)));
|
||||
UpdateAppearance(component);
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.PDA;
|
||||
@@ -32,6 +33,7 @@ namespace Content.Server.Sandbox
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||
[Dependency] private readonly GameTicker _ticker = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private bool _isSandboxEnabled;
|
||||
|
||||
@@ -154,7 +156,7 @@ namespace Content.Server.Sandbox
|
||||
var card = CreateFreshId();
|
||||
if (!_inventory.TryEquip(attached, card, "id", true, true))
|
||||
{
|
||||
hands.PutInHandOrDrop(Comp<SharedItemComponent>(card));
|
||||
_handsSystem.PickupOrDrop(attached, card, handsComp: hands);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Stacks;
|
||||
@@ -25,6 +26,7 @@ namespace Content.Server.Stack
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 };
|
||||
|
||||
@@ -180,10 +182,7 @@ namespace Content.Server.Stack
|
||||
if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split)
|
||||
return;
|
||||
|
||||
if (TryComp<HandsComponent>(userUid, out var hands) && TryComp<SharedItemComponent>(split, out var item))
|
||||
{
|
||||
hands.PutInHandOrDrop(item);
|
||||
}
|
||||
_handsSystem.PickupOrDrop(userUid, split);
|
||||
|
||||
_popupSystem.PopupCursor(Loc.GetString("comp-stack-split"), Filter.Entities(userUid));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Standing;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Standing;
|
||||
@@ -10,22 +8,26 @@ namespace Content.Server.Standing;
|
||||
public sealed class StandingStateSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
private void FallOver(EntityUid uid, StandingStateComponent component, DropHandItemsEvent args)
|
||||
{
|
||||
var direction = EntityManager.TryGetComponent(uid, out PhysicsComponent? comp) ? comp.LinearVelocity / 50 : Vector2.Zero;
|
||||
var dropAngle = _random.NextFloat(0.8f, 1.2f);
|
||||
|
||||
if (!EntityManager.TryGetComponent(uid, out HandsComponent? hands))
|
||||
if (!TryComp(uid, out SharedHandsComponent? handsComp))
|
||||
return;
|
||||
|
||||
foreach (var heldItem in hands.GetAllHeldItems())
|
||||
var worldRotation = EntityManager.GetComponent<TransformComponent>(uid).WorldRotation.ToVec();
|
||||
foreach (var hand in handsComp.Hands.Values)
|
||||
{
|
||||
if (!hands.Drop(heldItem.Owner, false))
|
||||
if (hand.HeldEntity is not EntityUid held)
|
||||
continue;
|
||||
|
||||
var worldRotation = EntityManager.GetComponent<TransformComponent>(uid).WorldRotation.ToVec();
|
||||
Throwing.ThrowHelper.TryThrow(heldItem.Owner,
|
||||
if (!_handsSystem.TryDrop(uid, hand, null, checkActionBlocker: false, handsComp: handsComp))
|
||||
continue;
|
||||
|
||||
Throwing.ThrowHelper.TryThrow(held,
|
||||
_random.NextAngle().RotateVec(direction / dropAngle + worldRotation / 50),
|
||||
0.5f * dropAngle * _random.NextFloat(-0.9f, 1.1f),
|
||||
uid, 0);
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Server.Hands.Components;
|
||||
using Content.Server.Interaction;
|
||||
using Content.Shared.Acts;
|
||||
using Content.Shared.Coordinates;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Item;
|
||||
@@ -46,6 +47,7 @@ namespace Content.Server.Storage.Components
|
||||
public sealed class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IActivate, IStorageComponent, IDestroyAct, IExAct, IAfterInteract
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
|
||||
private const string LoggerName = "Storage";
|
||||
|
||||
@@ -243,22 +245,24 @@ namespace Content.Server.Storage.Components
|
||||
EnsureInitialCalculated();
|
||||
|
||||
if (!_entityManager.TryGetComponent(player, out HandsComponent? hands) ||
|
||||
hands.GetActiveHandItem == null)
|
||||
hands.ActiveHandEntity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var toInsert = hands.GetActiveHandItem;
|
||||
var toInsert = hands.ActiveHandEntity;
|
||||
|
||||
if (!hands.Drop(toInsert.Owner))
|
||||
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
if (!handSys.TryDrop(player, toInsert.Value, handsComp: hands))
|
||||
{
|
||||
Owner.PopupMessage(player, "Can't insert.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Insert(toInsert.Owner))
|
||||
if (!Insert(toInsert.Value))
|
||||
{
|
||||
hands.PutInHand(toInsert);
|
||||
handSys.PickupOrDrop(player, toInsert.Value, handsComp: hands);
|
||||
Owner.PopupMessage(player, "Can't insert.");
|
||||
return false;
|
||||
}
|
||||
@@ -475,18 +479,7 @@ namespace Content.Server.Storage.Components
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_entityManager.TryGetComponent(remove.EntityUid, out SharedItemComponent? item) || !_entityManager.TryGetComponent(player, out HandsComponent? hands))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hands.CanPutInHand(item))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
hands.PutInHand(item);
|
||||
|
||||
_sysMan.GetEntitySystem<SharedHandsSystem>().TryPickupAnyHand(player, remove.EntityUid);
|
||||
break;
|
||||
}
|
||||
case InsertEntityMessage _:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Clothing.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Acts;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Player;
|
||||
@@ -12,6 +12,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
public sealed class SecretStashSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -83,7 +84,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
}
|
||||
|
||||
// try to move item from hands to stash container
|
||||
if (!hands.Drop(itemToHideUid, container))
|
||||
if (!_handsSystem.TryDropIntoContainer(userUid, itemToHideUid, container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -115,13 +116,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
return false;
|
||||
}
|
||||
|
||||
// get item inside container
|
||||
var itemUid = container.ContainedEntity;
|
||||
if (!EntityManager.TryGetComponent(itemUid, out SharedItemComponent? item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
hands.PutInHandOrDrop(item);
|
||||
_handsSystem.PickupOrDrop(userUid, container.ContainedEntity.Value, handsComp: hands);
|
||||
|
||||
// show success message
|
||||
var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something",
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
@@ -13,6 +10,7 @@ namespace Content.Server.Storage.EntitySystems
|
||||
public sealed class SpawnItemsOnUseSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -57,10 +55,9 @@ namespace Content.Server.Storage.EntitySystems
|
||||
EntityManager.DeleteEntity(uid);
|
||||
}
|
||||
|
||||
if (entityToPlaceInHands != null
|
||||
&& EntityManager.TryGetComponent<SharedHandsComponent?>(args.User, out var hands))
|
||||
if (entityToPlaceInHands != null)
|
||||
{
|
||||
hands.TryPutInAnyHand(entityToPlaceInHands.Value);
|
||||
_handsSystem.PickupOrDrop(args.User, entityToPlaceInHands.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Content.Server.Cuffs.Components;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Inventory;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Strip.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.Strip
|
||||
{
|
||||
@@ -28,6 +22,7 @@ namespace Content.Server.Strip
|
||||
public sealed class StrippableComponent : SharedStrippableComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||
private StrippableSystem _strippableSystem = default!;
|
||||
|
||||
public const float StripDelay = 2f;
|
||||
@@ -84,18 +79,18 @@ namespace Content.Server.Strip
|
||||
private async void PlaceActiveHandItemInInventory(EntityUid user, string slot)
|
||||
{
|
||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||
var item = userHands.GetActiveHandItem;
|
||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
||||
var invSystem = _sysMan.GetEntitySystem<InventorySystem>();
|
||||
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (item == null)
|
||||
if (userHands.ActiveHand?.HeldEntity is not EntityUid held)
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!userHands.CanDrop(userHands.ActiveHand!))
|
||||
if (!handSys.CanDropHeld(user, userHands.ActiveHand))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
||||
return false;
|
||||
@@ -110,7 +105,7 @@ namespace Content.Server.Strip
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!invSystem.CanEquip(user, Owner, item.Owner, slot, out _))
|
||||
if (!invSystem.CanEquip(user, Owner, held, slot, out _))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-equip-message",("owner", Owner)));
|
||||
return false;
|
||||
@@ -134,8 +129,11 @@ namespace Content.Server.Strip
|
||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||
if (result != DoAfterStatus.Finished) return;
|
||||
|
||||
userHands.Drop(item!.Owner, false);
|
||||
invSystem.TryEquip(user, Owner, item.Owner, slot);
|
||||
if (userHands.ActiveHand?.HeldEntity is EntityUid held
|
||||
&& handSys.TryDrop(user, userHands.ActiveHand, handsComp: userHands))
|
||||
{
|
||||
invSystem.TryEquip(user, Owner, held, slot);
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
}
|
||||
@@ -143,38 +141,28 @@ namespace Content.Server.Strip
|
||||
/// <summary>
|
||||
/// Places item in user's active hand in one of the entity's hands.
|
||||
/// </summary>
|
||||
private async void PlaceActiveHandItemInHands(EntityUid user, string hand)
|
||||
private async void PlaceActiveHandItemInHands(EntityUid user, string handName)
|
||||
{
|
||||
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||
var item = userHands.GetActiveHandItem;
|
||||
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (item == null)
|
||||
if (userHands.ActiveHandEntity == null)
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!userHands.CanDrop(userHands.ActiveHand!))
|
||||
if (!sys.CanDropHeld(user, userHands.ActiveHand!))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hands.HasHand(hand))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hands.TryGetItem(hand, out var _))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-occupied-message", ("owner", Owner)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hands.CanPickupEntity(hand, item.Owner, checkActionBlocker: false))
|
||||
if (!hands.Hands.TryGetValue(handName, out var hand)
|
||||
|| !sys.CanPickupToHand(Owner, userHands.ActiveHandEntity.Value, hand, checkActionBlocker: false, hands))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-put-message",("owner", Owner)));
|
||||
return false;
|
||||
@@ -183,7 +171,7 @@ namespace Content.Server.Strip
|
||||
return true;
|
||||
}
|
||||
|
||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
||||
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||
|
||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
||||
{
|
||||
@@ -198,8 +186,11 @@ namespace Content.Server.Strip
|
||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||
if (result != DoAfterStatus.Finished) return;
|
||||
|
||||
userHands.Drop(hand);
|
||||
hands.TryPickupEntity(hand, item!.Owner, checkActionBlocker: false, animateUser: true);
|
||||
if (userHands.ActiveHandEntity is not EntityUid held)
|
||||
return;
|
||||
|
||||
sys.TryDrop(user, checkActionBlocker: false, handsComp: userHands);
|
||||
sys.TryPickup(Owner, held, handName, checkActionBlocker: false, animateUser: true, handsComp: hands);
|
||||
// hand update will trigger strippable update
|
||||
}
|
||||
|
||||
@@ -210,7 +201,7 @@ namespace Content.Server.Strip
|
||||
{
|
||||
var inventory = _entities.GetComponent<InventoryComponent>(Owner);
|
||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
||||
var invSystem = _sysMan.GetEntitySystem<InventorySystem>();
|
||||
|
||||
bool Check()
|
||||
{
|
||||
@@ -232,7 +223,7 @@ namespace Content.Server.Strip
|
||||
return true;
|
||||
}
|
||||
|
||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
||||
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||
|
||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
||||
{
|
||||
@@ -250,7 +241,8 @@ namespace Content.Server.Strip
|
||||
{
|
||||
// Raise a dropped event, so that things like gas tank internals properly deactivate when stripping
|
||||
_entities.EventBus.RaiseLocalEvent(item.Value, new DroppedEvent(user));
|
||||
userHands.PutInHandOrDrop(item.Value);
|
||||
|
||||
_sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(user, item.Value);
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
@@ -259,26 +251,24 @@ namespace Content.Server.Strip
|
||||
/// <summary>
|
||||
/// Takes an item from a hand and places it in the user's active hand.
|
||||
/// </summary>
|
||||
private async void TakeItemFromHands(EntityUid user, string hand)
|
||||
private async void TakeItemFromHands(EntityUid user, string handName)
|
||||
{
|
||||
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||
|
||||
bool Check()
|
||||
{
|
||||
if (!hands.HasHand(hand))
|
||||
return false;
|
||||
|
||||
if (!hands.TryGetItem(hand, out var heldItem))
|
||||
if (!hands.Hands.TryGetValue(handName, out var hand) || hand.HeldEntity == null)
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", Owner)));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_entities.HasComponent<HandVirtualItemComponent>(heldItem.Owner))
|
||||
if (_entities.HasComponent<HandVirtualItemComponent>(hand.HeldEntity))
|
||||
return false;
|
||||
|
||||
if (!hands.CanDrop(hand, false))
|
||||
if (!handSys.CanDropHeld(Owner, hand, false))
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop-message",("owner", Owner)));
|
||||
return false;
|
||||
@@ -287,7 +277,7 @@ namespace Content.Server.Strip
|
||||
return true;
|
||||
}
|
||||
|
||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
||||
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||
|
||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
||||
{
|
||||
@@ -301,11 +291,11 @@ namespace Content.Server.Strip
|
||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||
if (result != DoAfterStatus.Finished) return;
|
||||
|
||||
if (!hands.TryGetHeldEntity(hand, out var entity))
|
||||
if (!hands.Hands.TryGetValue(handName, out var hand) || hand.HeldEntity is not EntityUid held)
|
||||
return;
|
||||
|
||||
hands.Drop(hand, false);
|
||||
userHands.PutInHandOrDrop(entity.Value);
|
||||
handSys.TryDrop(Owner, hand, checkActionBlocker: false, handsComp: hands);
|
||||
handSys.PickupOrDrop(user, held, handsComp: userHands);
|
||||
// hand update will trigger strippable update
|
||||
}
|
||||
|
||||
@@ -315,14 +305,14 @@ namespace Content.Server.Strip
|
||||
!_entities.TryGetComponent(user, out HandsComponent? userHands))
|
||||
return;
|
||||
|
||||
var placingItem = userHands.GetActiveHandItem != null;
|
||||
var placingItem = userHands.ActiveHandEntity != null;
|
||||
|
||||
switch (obj.Message)
|
||||
{
|
||||
case StrippingInventoryButtonPressed inventoryMessage:
|
||||
if (_entities.TryGetComponent<InventoryComponent?>(Owner, out var inventory))
|
||||
{
|
||||
if (EntitySystem.Get<InventorySystem>().TryGetSlotEntity(Owner, inventoryMessage.Slot, out _, inventory))
|
||||
if (_sysMan.GetEntitySystem<InventorySystem>().TryGetSlotEntity(Owner, inventoryMessage.Slot, out _, inventory))
|
||||
placingItem = false;
|
||||
|
||||
if (placingItem)
|
||||
@@ -336,7 +326,7 @@ namespace Content.Server.Strip
|
||||
|
||||
if (_entities.TryGetComponent<HandsComponent?>(Owner, out var hands))
|
||||
{
|
||||
if (hands.TryGetItem(handMessage.Hand, out _))
|
||||
if (hands.Hands.TryGetValue(handMessage.Hand, out var hand) && !hand.IsEmpty)
|
||||
placingItem = false;
|
||||
|
||||
if (placingItem)
|
||||
|
||||
@@ -76,17 +76,15 @@ namespace Content.Server.Strip
|
||||
|
||||
if (TryComp(uid, out HandsComponent? handsComp))
|
||||
{
|
||||
foreach (var hand in handsComp.HandNames)
|
||||
foreach (var hand in handsComp.Hands.Values)
|
||||
{
|
||||
var owner = handsComp.GetItem(hand)?.Owner;
|
||||
|
||||
if (!owner.HasValue || HasComp<HandVirtualItemComponent>(owner.Value))
|
||||
if (hand.HeldEntity == null || HasComp<HandVirtualItemComponent>(hand.HeldEntity))
|
||||
{
|
||||
hands[hand] = "None";
|
||||
hands[hand.Name] = "None";
|
||||
continue;
|
||||
}
|
||||
|
||||
hands[hand] = Name(owner.Value);
|
||||
hands[hand.Name] = Name(hand.HeldEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.Traitor.Uplink.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Item;
|
||||
@@ -28,6 +29,7 @@ namespace Content.Server.Traitor.Uplink
|
||||
private readonly UplinkListingSytem _listing = default!;
|
||||
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -123,11 +125,7 @@ namespace Content.Server.Traitor.Uplink
|
||||
return;
|
||||
}
|
||||
|
||||
if (EntityManager.TryGetComponent(player, out HandsComponent? hands) &&
|
||||
EntityManager.TryGetComponent(entity.Value, out SharedItemComponent? item))
|
||||
{
|
||||
hands.PutInHandOrDrop(item);
|
||||
}
|
||||
_handsSystem.PickupOrDrop(player, entity.Value);
|
||||
|
||||
SoundSystem.Play(Filter.SinglePlayer(message.Session), uplink.BuySuccessSound.GetSound(),
|
||||
uplink.Owner, AudioParams.Default.WithVolume(-8f));
|
||||
@@ -149,8 +147,7 @@ namespace Content.Server.Traitor.Uplink
|
||||
return;
|
||||
|
||||
// try to put it into players hands
|
||||
if (EntityManager.TryGetComponent(player, out SharedHandsComponent? hands))
|
||||
hands.TryPutInAnyHand(tcUid.Value);
|
||||
_handsSystem.PickupOrDrop(player, tcUid.Value);
|
||||
|
||||
// play buying sound
|
||||
SoundSystem.Play(Filter.SinglePlayer(args.Session), uplink.BuySuccessSound.GetSound(),
|
||||
@@ -217,14 +214,10 @@ namespace Content.Server.Traitor.Uplink
|
||||
}
|
||||
|
||||
// Also check hands
|
||||
if (EntityManager.TryGetComponent(user, out HandsComponent? hands))
|
||||
foreach (var item in _handsSystem.EnumerateHeld(user))
|
||||
{
|
||||
var heldItems = hands.GetAllHeldItems();
|
||||
foreach (var item in heldItems)
|
||||
{
|
||||
if (EntityManager.HasComponent<PDAComponent>(item.Owner))
|
||||
return item.Owner;
|
||||
}
|
||||
if (HasComp<PDAComponent>(item))
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Content.Server.Verbs
|
||||
// first get the held item. again.
|
||||
EntityUid? holding = null;
|
||||
if (TryComp(user, out SharedHandsComponent? hands) &&
|
||||
hands.TryGetActiveHeldEntity(out var heldEntity))
|
||||
hands.ActiveHandEntity is EntityUid heldEntity)
|
||||
{
|
||||
holding = heldEntity;
|
||||
}
|
||||
|
||||
@@ -152,15 +152,10 @@ public sealed partial class GunSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TryComp(ammo, out ItemComponent? item))
|
||||
if (!_handsSystem.TryPickup(user, ammo, handsComp: handsComponent))
|
||||
{
|
||||
if (!handsComponent.CanPutInHand(item))
|
||||
{
|
||||
TryInsertAmmo(user, ammo, ammoBox);
|
||||
return false;
|
||||
}
|
||||
|
||||
handsComponent.PutInHand(item);
|
||||
TryInsertAmmo(user, ammo, ammoBox);
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateAmmoBoxAppearance(ammoBox.Owner, ammoBox);
|
||||
|
||||
@@ -36,7 +36,7 @@ public sealed partial class GunSystem
|
||||
{
|
||||
if (!TryComp(gun.Owner, out ServerRangedBarrelComponent? barrel)) return;
|
||||
|
||||
if (!TryComp(user, out HandsComponent? hands) || hands.GetActiveHand()?.HeldEntity != gun.Owner) return;
|
||||
if (!TryComp(user, out HandsComponent? hands) || hands.ActiveHand?.HeldEntity != gun.Owner) return;
|
||||
|
||||
if (!TryComp(user, out CombatModeComponent? combat) ||
|
||||
!combat.IsInCombatMode ||
|
||||
|
||||
@@ -28,8 +28,8 @@ public sealed partial class GunSystem
|
||||
if (args.Hands == null ||
|
||||
!args.CanAccess ||
|
||||
!args.CanInteract ||
|
||||
!component.HasMagazine ||
|
||||
!_blocker.CanPickup(args.User))
|
||||
component.MagazineContainer.ContainedEntity is not EntityUid mag ||
|
||||
!_blocker.CanPickup(args.User, mag))
|
||||
return;
|
||||
|
||||
if (component.MagNeedsOpenBolt && !component.BoltOpen)
|
||||
@@ -37,7 +37,7 @@ public sealed partial class GunSystem
|
||||
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
Text = MetaData(component.MagazineContainer.ContainedEntity!.Value).EntityName,
|
||||
Text = MetaData(mag).EntityName,
|
||||
Category = VerbCategory.Eject,
|
||||
Act = () => RemoveMagazine(args.User, component)
|
||||
};
|
||||
@@ -325,10 +325,7 @@ public sealed partial class GunSystem
|
||||
component.MagazineContainer.Remove(mag.Value);
|
||||
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundMagEject.GetSound(), component.Owner, AudioParams.Default.WithVolume(-2));
|
||||
|
||||
if (TryComp(user, out HandsComponent? handsComponent))
|
||||
{
|
||||
handsComponent.PutInHandOrDrop(EntityManager.GetComponent<SharedItemComponent>(mag.Value));
|
||||
}
|
||||
_handsSystem.PickupOrDrop(user, mag.Value);
|
||||
|
||||
component.Dirty(EntityManager);
|
||||
UpdateMagazineAppearance(component);
|
||||
|
||||
@@ -70,16 +70,8 @@ public sealed partial class GunSystem
|
||||
if (TakeAmmo(component) is not {Valid: true} ammo)
|
||||
return;
|
||||
|
||||
var itemComponent = EntityManager.GetComponent<SharedItemComponent>(ammo);
|
||||
if (!handsComponent.CanPutInHand(itemComponent))
|
||||
{
|
||||
Transform(ammo).Coordinates = Transform(args.User).Coordinates;
|
||||
EjectCasing(ammo);
|
||||
}
|
||||
else
|
||||
{
|
||||
handsComponent.PutInHand(itemComponent);
|
||||
}
|
||||
_handsSystem.PickupOrDrop(args.User, ammo, handsComp: handsComponent);
|
||||
EjectCasing(ammo);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -75,15 +75,10 @@ public sealed partial class GunSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var itemComponent = EntityManager.GetComponent<SharedItemComponent>(ammo.Value);
|
||||
if (!handsComponent.CanPutInHand(itemComponent))
|
||||
if (!_handsSystem.TryPickup(args.User, ammo.Value, handsComp: handsComponent))
|
||||
{
|
||||
EjectCasing(ammo.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
handsComponent.PutInHand(itemComponent);
|
||||
}
|
||||
|
||||
UpdateSpeedLoaderAppearance(component);
|
||||
args.Handled = true;
|
||||
|
||||
@@ -11,6 +11,7 @@ using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
@@ -47,6 +48,7 @@ public sealed partial class GunSystem : EntitySystem
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// How many sounds are allowed to be played on ejecting multiple casings.
|
||||
@@ -141,7 +143,7 @@ public sealed partial class GunSystem : EntitySystem
|
||||
return;
|
||||
|
||||
// TODO: Not exactly robust
|
||||
var gun = handsComponent.GetActiveHand()?.HeldEntity;
|
||||
var gun = handsComponent.ActiveHand?.HeldEntity;
|
||||
|
||||
if (gun == null || !TryComp(gun, out ServerRangedWeaponComponent? weapon))
|
||||
return;
|
||||
|
||||
@@ -4,15 +4,15 @@ using Content.Server.Hands.Systems;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Server.Wieldable.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Player;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.Wieldable
|
||||
{
|
||||
@@ -20,6 +20,7 @@ namespace Content.Server.Wieldable
|
||||
{
|
||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -75,7 +76,8 @@ namespace Content.Server.Wieldable
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hands.GetFreeHands() < component.FreeHandsRequired)
|
||||
if (hands.CountFreeHands()
|
||||
< component.FreeHandsRequired)
|
||||
{
|
||||
// TODO FLUENT need function to change 'hands' to 'hand' when there's only 1 required
|
||||
if (!quiet)
|
||||
@@ -89,7 +91,7 @@ namespace Content.Server.Wieldable
|
||||
}
|
||||
|
||||
// Is it.. actually in one of their hands?
|
||||
if (!hands.TryGetHandHoldingEntity(uid, out _))
|
||||
if (!_handsSystem.IsHolding(user, uid, out _, hands))
|
||||
{
|
||||
if (!quiet)
|
||||
{
|
||||
|
||||
@@ -338,7 +338,7 @@ namespace Content.Server.WireHacking
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handsComponent.GetActiveHand()?.HeldEntity is not { Valid: true } activeHandEntity ||
|
||||
if (handsComponent.ActiveHand?.HeldEntity is not { Valid: true } activeHandEntity ||
|
||||
!_entities.TryGetComponent(activeHandEntity, out tool))
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.Clothing.Components;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
||||
@@ -9,6 +8,7 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
||||
public sealed class SpawnArtifactSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -40,12 +40,7 @@ public sealed class SpawnArtifactSystem : EntitySystem
|
||||
|
||||
// if there is an user - try to put spawned item in their hands
|
||||
// doesn't work for spawners
|
||||
if (args.Activator != null &&
|
||||
EntityManager.TryGetComponent(args.Activator.Value, out SharedHandsComponent? hands) &&
|
||||
EntityManager.HasComponent<ItemComponent>(spawned))
|
||||
{
|
||||
hands.TryPutInAnyHand(spawned);
|
||||
}
|
||||
_handsSystem.PickupOrDrop(args.Activator, spawned);
|
||||
}
|
||||
|
||||
private void ChooseRandomPrototype(EntityUid uid, SpawnArtifactComponent? component = null)
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Emag.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Content.Shared.Access.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
|
||||
namespace Content.Shared.Access.Systems
|
||||
{
|
||||
@@ -18,6 +13,7 @@ namespace Content.Shared.Access.Systems
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -54,7 +50,7 @@ namespace Content.Shared.Access.Systems
|
||||
/// <remarks>
|
||||
/// If no access is found, an empty set is used instead.
|
||||
/// </remarks>
|
||||
/// <param name="entity">The entity to be searched for access.</param>
|
||||
/// <param name="entity">The entity to bor access.</param>
|
||||
public bool IsAllowed(AccessReaderComponent reader, EntityUid entity)
|
||||
{
|
||||
var tags = FindAccessTags(entity);
|
||||
@@ -78,14 +74,10 @@ namespace Content.Shared.Access.Systems
|
||||
if (FindAccessTagsItem(uid, out var tags))
|
||||
return tags;
|
||||
|
||||
// maybe access component inside its hands?
|
||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands))
|
||||
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||
{
|
||||
if (hands.TryGetActiveHeldEntity(out var heldItem) &&
|
||||
FindAccessTagsItem(heldItem.Value, out tags))
|
||||
{
|
||||
if (FindAccessTagsItem(item, out tags))
|
||||
return tags;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe its inside an inventory slot?
|
||||
|
||||
@@ -95,12 +95,18 @@ namespace Content.Shared.ActionBlocker
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
public bool CanPickup(EntityUid uid)
|
||||
public bool CanPickup(EntityUid user, EntityUid item)
|
||||
{
|
||||
var ev = new PickupAttemptEvent(uid);
|
||||
RaiseLocalEvent(uid, ev);
|
||||
var userEv = new PickupAttemptEvent(user, item);
|
||||
RaiseLocalEvent(user, userEv, false);
|
||||
|
||||
if (userEv.Cancelled)
|
||||
return false;
|
||||
|
||||
var itemEv = new GettingPickedUpAttemptEvent(user, item);
|
||||
RaiseLocalEvent(item, itemEv, false);
|
||||
return !itemEv.Cancelled;
|
||||
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
public bool CanEmote(EntityUid uid)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Acts;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Popups;
|
||||
@@ -8,14 +9,9 @@ using Content.Shared.Sound;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Shared.Containers.ItemSlots
|
||||
@@ -27,6 +23,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
{
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -175,11 +172,11 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
continue;
|
||||
|
||||
// Drop the held item onto the floor. Return if the user cannot drop.
|
||||
if (!hands.Drop(args.Used))
|
||||
if (!_handsSystem.TryDrop(args.User, args.Used, handsComp: hands))
|
||||
return;
|
||||
|
||||
if (slot.Item != null)
|
||||
hands.TryPutInAnyHand(slot.Item.Value);
|
||||
_handsSystem.TryPickupAnyHand(args.User, slot.Item.Value, handsComp: hands);
|
||||
|
||||
Insert(uid, slot, args.Used, args.User, excludeUserAudio: args.Predicted);
|
||||
args.Handled = true;
|
||||
@@ -287,18 +284,17 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
if (!Resolve(user, ref hands, false))
|
||||
return false;
|
||||
|
||||
if (!hands.TryGetActiveHeldEntity(out var item))
|
||||
if (hands.ActiveHand?.HeldEntity is not EntityUid held)
|
||||
return false;
|
||||
var heldItem = item.Value;
|
||||
|
||||
if (!CanInsert(uid, item.Value, slot))
|
||||
if (!CanInsert(uid, held, slot))
|
||||
return false;
|
||||
|
||||
// hands.Drop(item) checks CanDrop action blocker
|
||||
if (hands.Drop(heldItem))
|
||||
if (_handsSystem.TryDrop(user, hands.ActiveHand))
|
||||
return false;
|
||||
|
||||
Insert(uid, slot, heldItem, user);
|
||||
Insert(uid, slot, held, user);
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
@@ -374,8 +370,8 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
if (!TryEject(uid, slot, user, out var item, excludeUserAudio))
|
||||
return false;
|
||||
|
||||
if (user != null && EntityManager.TryGetComponent(user.Value, out SharedHandsComponent? hands))
|
||||
hands.PutInHand(item.Value);
|
||||
if (user != null)
|
||||
_handsSystem.PickupOrDrop(user.Value, item.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -384,25 +380,27 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
#region Verbs
|
||||
private void AddEjectVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (args.Hands == null || !args.CanAccess ||!args.CanInteract ||
|
||||
!_actionBlockerSystem.CanPickup(args.User))
|
||||
if (args.Hands == null || !args.CanAccess ||!args.CanInteract)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var slot in itemSlots.Slots.Values)
|
||||
{
|
||||
if (!CanEject(slot))
|
||||
continue;
|
||||
|
||||
if (slot.EjectOnInteract)
|
||||
// For this item slot, ejecting/inserting is a primary interaction. Instead of an eject category
|
||||
// alt-click verb, there will be a "Take item" primary interaction verb.
|
||||
continue;
|
||||
|
||||
if (!CanEject(slot))
|
||||
continue;
|
||||
|
||||
if (!_actionBlockerSystem.CanPickup(args.User, slot.Item!.Value))
|
||||
continue;
|
||||
|
||||
var verbSubject = slot.Name != string.Empty
|
||||
? Loc.GetString(slot.Name)
|
||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
|
||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item.Value).EntityName ?? string.Empty;
|
||||
|
||||
AlternativeVerb verb = new();
|
||||
verb.IconEntity = slot.Item;
|
||||
@@ -428,28 +426,28 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
return;
|
||||
|
||||
// If there are any slots that eject on left-click, add a "Take <item>" verb.
|
||||
if (_actionBlockerSystem.CanPickup(args.User))
|
||||
foreach (var slot in itemSlots.Slots.Values)
|
||||
{
|
||||
foreach (var slot in itemSlots.Slots.Values)
|
||||
{
|
||||
if (!slot.EjectOnInteract || !CanEject(slot))
|
||||
continue;
|
||||
if (!slot.EjectOnInteract || !CanEject(slot))
|
||||
continue;
|
||||
|
||||
var verbSubject = slot.Name != string.Empty
|
||||
? Loc.GetString(slot.Name)
|
||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
|
||||
if (!_actionBlockerSystem.CanPickup(args.User, slot.Item!.Value))
|
||||
continue;
|
||||
|
||||
InteractionVerb takeVerb = new();
|
||||
takeVerb.IconEntity = slot.Item;
|
||||
takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
|
||||
var verbSubject = slot.Name != string.Empty
|
||||
? Loc.GetString(slot.Name)
|
||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
|
||||
|
||||
if (slot.EjectVerbText == null)
|
||||
takeVerb.Text = Loc.GetString("take-item-verb-text", ("subject", verbSubject));
|
||||
else
|
||||
takeVerb.Text = Loc.GetString(slot.EjectVerbText);
|
||||
InteractionVerb takeVerb = new();
|
||||
takeVerb.IconEntity = slot.Item;
|
||||
takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
|
||||
|
||||
args.Verbs.Add(takeVerb);
|
||||
}
|
||||
if (slot.EjectVerbText == null)
|
||||
takeVerb.Text = Loc.GetString("take-item-verb-text", ("subject", verbSubject));
|
||||
else
|
||||
takeVerb.Text = Loc.GetString(slot.EjectVerbText);
|
||||
|
||||
args.Verbs.Add(takeVerb);
|
||||
}
|
||||
|
||||
// Next, add the insert-item verbs
|
||||
|
||||
34
Content.Shared/Hands/Components/HandHelpers.cs
Normal file
34
Content.Shared/Hands/Components/HandHelpers.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Shared.Hands.Components;
|
||||
|
||||
/// <summary>
|
||||
/// These helpers exist to make getting basic information out of the hands component more convenient, without
|
||||
/// needing to resolve hands system or something like that.
|
||||
/// </summary>
|
||||
public static class HandHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if any hand is free. This is a LinQ method, not a property, so
|
||||
/// cache it instead of accessing this multiple times.
|
||||
/// </summary>
|
||||
public static bool IsAnyHandFree(this SharedHandsComponent component) => component.Hands.Values.Any(hand => hand.IsEmpty);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of hands that are not currently holding anything. This is a LinQ method, not a property, so
|
||||
/// cache it instead of accessing this multiple times.
|
||||
/// </summary>
|
||||
public static int CountFreeHands(this SharedHandsComponent component) => component.Hands.Values.Count(hand => hand.IsEmpty);
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of hands that are currently holding nothing. This is a LinQ method, not a property, so cache
|
||||
/// it instead of accessing this multiple times.
|
||||
/// </summary>
|
||||
public static IEnumerable<Hand> GetFreeHands(this SharedHandsComponent component) => component.Hands.Values.Where(hand => !hand.IsEmpty);
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of hands that are currently holding nothing. This is a LinQ method, not a property, so cache
|
||||
/// it instead of accessing this multiple times.
|
||||
/// </summary>
|
||||
public static IEnumerable<string> GetFreeHandNames(this SharedHandsComponent component) => GetFreeHands(component).Select(hand => hand.Name);
|
||||
}
|
||||
@@ -1,825 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Robust.Shared.GameObjects.SharedSpriteComponent;
|
||||
|
||||
namespace Content.Shared.Hands.Components
|
||||
namespace Content.Shared.Hands.Components;
|
||||
|
||||
[NetworkedComponent]
|
||||
public abstract class SharedHandsComponent : Component
|
||||
{
|
||||
[NetworkedComponent]
|
||||
public abstract class SharedHandsComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the currently active hand.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public string? ActiveHand;
|
||||
|
||||
[ViewVariables]
|
||||
public List<Hand> Hands = new();
|
||||
|
||||
/// <summary>
|
||||
/// The amount of throw impulse per distance the player is from the throw target.
|
||||
/// </summary>
|
||||
[DataField("throwForceMultiplier")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ThrowForceMultiplier { get; set; } = 10f; //should be tuned so that a thrown item lands about under the player's cursor
|
||||
|
||||
/// <summary>
|
||||
/// Distance after which longer throw targets stop increasing throw impulse.
|
||||
/// </summary>
|
||||
[DataField("throwRange")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ThrowRange { get; set; } = 8f;
|
||||
|
||||
private bool PlayerCanDrop => EntitySystem.Get<ActionBlockerSystem>().CanDrop(Owner);
|
||||
private bool PlayerCanPickup => EntitySystem.Get<ActionBlockerSystem>().CanPickup(Owner);
|
||||
|
||||
public void AddHand(string handName, HandLocation handLocation)
|
||||
{
|
||||
if (HasHand(handName))
|
||||
return;
|
||||
|
||||
var container = Owner.EnsureContainer<ContainerSlot>(handName);
|
||||
container.OccludesLight = false;
|
||||
|
||||
Hands.Add(new Hand(handName, handLocation, container));
|
||||
|
||||
if (ActiveHand == null)
|
||||
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, handName, this);
|
||||
|
||||
HandCountChanged();
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void RemoveHand(string handName)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return;
|
||||
|
||||
RemoveHand(hand);
|
||||
}
|
||||
|
||||
private void RemoveHand(Hand hand)
|
||||
{
|
||||
DropHeldEntityToFloor(hand);
|
||||
hand.Container?.Shutdown();
|
||||
Hands.Remove(hand);
|
||||
|
||||
if (ActiveHand == hand.Name)
|
||||
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, Hands.FirstOrDefault()?.Name, this);
|
||||
|
||||
HandCountChanged();
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public Hand? GetActiveHand()
|
||||
{
|
||||
if (ActiveHand == null)
|
||||
return null;
|
||||
|
||||
return GetHandOrNull(ActiveHand);
|
||||
}
|
||||
|
||||
public bool HasHand(string handName)
|
||||
{
|
||||
return TryGetHand(handName, out _);
|
||||
}
|
||||
|
||||
public Hand? GetHandOrNull(string handName)
|
||||
{
|
||||
return TryGetHand(handName, out var hand) ? hand : null;
|
||||
}
|
||||
|
||||
public Hand GetHand(string handName)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
throw new KeyNotFoundException($"Unable to find hand with name {handName}");
|
||||
|
||||
return hand;
|
||||
}
|
||||
|
||||
public bool TryGetHand(string handName, [NotNullWhen(true)] out Hand? foundHand)
|
||||
{
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.Name == handName)
|
||||
{
|
||||
foundHand = hand;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
foundHand = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetActiveHand([NotNullWhen(true)] out Hand? activeHand)
|
||||
{
|
||||
activeHand = GetActiveHand();
|
||||
return activeHand != null;
|
||||
}
|
||||
|
||||
#region Held Entities
|
||||
|
||||
public bool ActiveHandIsHoldingEntity()
|
||||
{
|
||||
if (!TryGetActiveHand(out var hand))
|
||||
return false;
|
||||
|
||||
return hand.HeldEntity != null;
|
||||
}
|
||||
|
||||
public bool TryGetHeldEntity(string handName, [NotNullWhen(true)] out EntityUid? heldEntity)
|
||||
{
|
||||
heldEntity = null;
|
||||
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
heldEntity = hand.HeldEntity;
|
||||
return heldEntity != null;
|
||||
}
|
||||
|
||||
public bool TryGetActiveHeldEntity([NotNullWhen(true)] out EntityUid? heldEntity)
|
||||
{
|
||||
heldEntity = GetActiveHand()?.HeldEntity;
|
||||
return heldEntity != null;
|
||||
}
|
||||
|
||||
public bool IsHolding(EntityUid entity)
|
||||
{
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.HeldEntity == entity)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<EntityUid> GetAllHeldEntities()
|
||||
{
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.HeldEntity != null)
|
||||
yield return hand.HeldEntity.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of hands that have no items in them.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetFreeHands()
|
||||
{
|
||||
int acc = 0;
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
acc += 1;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
public bool TryGetHandHoldingEntity(EntityUid entity, [NotNullWhen(true)] out Hand? handFound)
|
||||
{
|
||||
handFound = null;
|
||||
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.HeldEntity == entity)
|
||||
{
|
||||
handFound = hand;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dropping
|
||||
|
||||
/// <summary>
|
||||
/// Checks all the conditions relevant to a player being able to drop an item.
|
||||
/// </summary>
|
||||
public bool CanDrop(string handName, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop the contents of the active hand to the target location.
|
||||
/// </summary>
|
||||
public bool TryDropActiveHand(EntityCoordinates targetDropLocation, bool doMobChecks = true)
|
||||
{
|
||||
if (!TryGetActiveHand(out var hand))
|
||||
return false;
|
||||
|
||||
return TryDropHeldEntity(hand, targetDropLocation, doMobChecks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop the contents of a hand to the target location.
|
||||
/// </summary>
|
||||
public bool TryDropHand(string handName, EntityCoordinates targetDropLocation, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
return TryDropHeldEntity(hand, targetDropLocation, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop a held entity to the target location.
|
||||
/// </summary>
|
||||
public bool TryDropEntity(EntityUid entity, EntityCoordinates coords, bool doMobChecks = true)
|
||||
{
|
||||
if (!TryGetHandHoldingEntity(entity, out var hand))
|
||||
return false;
|
||||
|
||||
return TryDropHeldEntity(hand, coords, doMobChecks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move the contents of a hand into a container that is not another hand, without dropping it on the floor inbetween.
|
||||
/// </summary>
|
||||
public bool TryPutHandIntoContainer(string handName, BaseContainer targetContainer, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanPutHeldEntityIntoContainer(hand, targetContainer, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
PutHeldEntityIntoContainer(hand, targetContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move a held item from a hand into a container that is not another hand, without dropping it on the floor in-between.
|
||||
/// </summary>
|
||||
public bool Drop(EntityUid entity, BaseContainer targetContainer, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHandHoldingEntity(entity, out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanPutHeldEntityIntoContainer(hand, targetContainer, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
PutHeldEntityIntoContainer(hand, targetContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop the contents of a hand directly under the player.
|
||||
/// </summary>
|
||||
public bool Drop(string handName, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
return TryDropHeldEntity(hand, _entMan.GetComponent<TransformComponent>(Owner).Coordinates, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop a held entity directly under the player.
|
||||
/// </summary>
|
||||
public bool Drop(EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHandHoldingEntity(entity, out var hand))
|
||||
return false;
|
||||
|
||||
return TryDropHeldEntity(hand, _entMan.GetComponent<TransformComponent>(Owner).Coordinates, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to remove the item in the active hand, without dropping it.
|
||||
/// For transferring the held item to another location, like an inventory slot,
|
||||
/// which shouldn't trigger the drop interaction
|
||||
/// </summary>
|
||||
public bool TryDropNoInteraction()
|
||||
{
|
||||
if (!TryGetActiveHand(out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the contents of a hand is able to be removed from its container.
|
||||
/// </summary>
|
||||
private bool CanRemoveHeldEntityFromHand(Hand hand)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
if (!hand.Container!.CanRemove(hand.HeldEntity.Value))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops a hands contents to the target location.
|
||||
/// </summary>
|
||||
public void DropHeldEntity(Hand hand, EntityCoordinates targetDropLocation)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
return;
|
||||
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
|
||||
EntitySystem.Get<SharedInteractionSystem>().DroppedInteraction(Owner, heldEntity);
|
||||
|
||||
_entMan.GetComponent<TransformComponent>(heldEntity).WorldPosition = GetFinalDropCoordinates(targetDropLocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the final location a dropped item will end up at, accounting for max drop range and collision along the targeted drop path.
|
||||
/// </summary>
|
||||
private Vector2 GetFinalDropCoordinates(EntityCoordinates targetCoords)
|
||||
{
|
||||
var origin = _entMan.GetComponent<TransformComponent>(Owner).MapPosition;
|
||||
var target = targetCoords.ToMap(_entMan);
|
||||
|
||||
var dropVector = target.Position - origin.Position;
|
||||
var requestedDropDistance = dropVector.Length;
|
||||
|
||||
if (dropVector.Length > SharedInteractionSystem.InteractionRange)
|
||||
{
|
||||
dropVector = dropVector.Normalized * SharedInteractionSystem.InteractionRange;
|
||||
target = new MapCoordinates(origin.Position + dropVector, target.MapId);
|
||||
}
|
||||
|
||||
|
||||
var dropLength = EntitySystem.Get<SharedInteractionSystem>().UnobstructedDistance(origin, target, predicate: e => e == Owner);
|
||||
|
||||
if (dropLength < requestedDropDistance)
|
||||
return origin.Position + dropVector.Normalized * dropLength;
|
||||
return target.Position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to drop a hands contents to the target location.
|
||||
/// </summary>
|
||||
private bool TryDropHeldEntity(Hand hand, EntityCoordinates location, bool checkActionBlocker)
|
||||
{
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
DropHeldEntity(hand, location);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops the contents of a hand directly under the player.
|
||||
/// </summary>
|
||||
private void DropHeldEntityToFloor(Hand hand)
|
||||
{
|
||||
DropHeldEntity(hand, _entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||
}
|
||||
|
||||
private bool CanPutHeldEntityIntoContainer(Hand hand, IContainer targetContainer, bool checkActionBlocker)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
if (!targetContainer.CanInsert(heldEntity))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For putting the contents of a hand into a container that is not another hand.
|
||||
/// </summary>
|
||||
private void PutHeldEntityIntoContainer(Hand hand, IContainer targetContainer)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
return;
|
||||
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
|
||||
if (!targetContainer.Insert(heldEntity))
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {Owner} could not insert {heldEntity} into {targetContainer}.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pickup
|
||||
|
||||
public bool CanPickupEntity(string handName, EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanPickup)
|
||||
return false;
|
||||
|
||||
if (!CanInsertEntityIntoHand(hand, entity))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanPickupEntityToActiveHand(EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
return ActiveHand != null && CanPickupEntity(ActiveHand, entity, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity to a specific hand.
|
||||
/// </summary>
|
||||
public bool TryPickupEntity(string handName, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
return TryPickupEntity(hand, entity, checkActionBlocker, animateUser);
|
||||
}
|
||||
|
||||
public bool TryPickupEntityToActiveHand(EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||
{
|
||||
return ActiveHand != null && TryPickupEntity(ActiveHand, entity, checkActionBlocker, animateUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if an entity can be put into a hand's container.
|
||||
/// </summary>
|
||||
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
||||
{
|
||||
var handContainer = hand.Container;
|
||||
if (handContainer == null) return false;
|
||||
|
||||
if (!_entMan.HasComponent<SharedItemComponent>(entity))
|
||||
return false;
|
||||
|
||||
if (_entMan.TryGetComponent(entity, out IPhysBody? physics) && physics.BodyType == BodyType.Static)
|
||||
return false;
|
||||
|
||||
if (!handContainer.CanInsert(entity)) return false;
|
||||
|
||||
var @event = new AttemptItemPickupEvent();
|
||||
_entMan.EventBus.RaiseLocalEvent(entity, @event);
|
||||
|
||||
if (@event.Cancelled) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryPickupEntity(Hand hand, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||
{
|
||||
if (!CanInsertEntityIntoHand(hand, entity))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanPickup)
|
||||
return false;
|
||||
|
||||
// animation
|
||||
var handSys = EntitySystem.Get<SharedHandsSystem>();
|
||||
var coordinateEntity = _entMan.GetComponent<TransformComponent>(Owner).Parent?.Owner ?? Owner;
|
||||
var initialPosition = EntityCoordinates.FromMap(coordinateEntity, _entMan.GetComponent<TransformComponent>(entity).MapPosition);
|
||||
var finalPosition = _entMan.GetComponent<TransformComponent>(Owner).LocalPosition;
|
||||
|
||||
handSys.PickupAnimation(entity, initialPosition, finalPosition, animateUser ? null : Owner);
|
||||
handSys.PutEntityIntoHand(Owner, hand, entity, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hand Interactions
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the hand that a swap hands would result in.
|
||||
/// </summary>
|
||||
public bool TryGetSwapHandsResult([NotNullWhen(true)] out string? nextHand)
|
||||
{
|
||||
nextHand = null;
|
||||
|
||||
if (!TryGetActiveHand(out var activeHand) || Hands.Count == 1)
|
||||
return false;
|
||||
|
||||
var newActiveIndex = Hands.IndexOf(activeHand) + 1;
|
||||
var finalHandIndex = Hands.Count - 1;
|
||||
if (newActiveIndex > finalHandIndex)
|
||||
newActiveIndex = 0;
|
||||
|
||||
nextHand = Hands[newActiveIndex].Name;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to interact with the item in a hand using the active held item.
|
||||
/// </summary>
|
||||
public void InteractHandWithActiveHand(string handName)
|
||||
{
|
||||
if (!TryGetActiveHeldEntity(out var activeHeldEntity))
|
||||
return;
|
||||
|
||||
if (!TryGetHeldEntity(handName, out var heldEntity))
|
||||
return;
|
||||
|
||||
if (activeHeldEntity == heldEntity)
|
||||
return;
|
||||
|
||||
EntitySystem.Get<SharedInteractionSystem>()
|
||||
.InteractUsing(Owner, activeHeldEntity.Value, heldEntity.Value, EntityCoordinates.Invalid);
|
||||
}
|
||||
|
||||
public void ActivateItem(bool altInteract = false)
|
||||
{
|
||||
if (!TryGetActiveHeldEntity(out var heldEntity))
|
||||
return;
|
||||
|
||||
var sys = EntitySystem.Get<SharedInteractionSystem>();
|
||||
if (altInteract)
|
||||
sys.AltInteract(Owner, heldEntity.Value);
|
||||
else
|
||||
sys.UseInHandInteraction(Owner, heldEntity.Value);
|
||||
}
|
||||
|
||||
public void ActivateHeldEntity(string handName)
|
||||
{
|
||||
if (!TryGetHeldEntity(handName, out var heldEntity))
|
||||
return;
|
||||
|
||||
EntitySystem.Get<SharedInteractionSystem>()
|
||||
.InteractionActivate(Owner, heldEntity.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves an entity from one hand to the active hand.
|
||||
/// </summary>
|
||||
public bool TryMoveHeldEntityToActiveHand(string handName, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryGetHand(handName, out var hand) || !TryGetActiveHand(out var activeHand))
|
||||
return false;
|
||||
|
||||
if (!TryGetHeldEntity(handName, out var heldEntity))
|
||||
return false;
|
||||
|
||||
if (!CanInsertEntityIntoHand(activeHand, heldEntity.Value) || !CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && (!PlayerCanDrop || !PlayerCanPickup))
|
||||
return false;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
EntitySystem.Get<SharedHandsSystem>().PutEntityIntoHand(Owner, activeHand, heldEntity.Value, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void HandCountChanged()
|
||||
{
|
||||
_entMan.EventBus.RaiseEvent(EventSource.Local, new HandCountChangedEvent(Owner));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
public bool PutInHand(SharedItemComponent item, bool checkActionBlocker = true)
|
||||
{
|
||||
return PutInHand(item.Owner, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an item any hand, preferring the active hand, or puts it on the floor under the player.
|
||||
/// </summary>
|
||||
public void PutInHandOrDrop(EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
if (PutInHand(entity, checkActionBlocker))
|
||||
return;
|
||||
|
||||
_entMan.GetComponent<TransformComponent>(entity).AttachParentToContainerOrGrid(_entMan);
|
||||
_entMan.EventBus.RaiseLocalEvent(entity, new DroppedEvent(Owner));
|
||||
}
|
||||
|
||||
public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true)
|
||||
{
|
||||
PutInHandOrDrop(item.Owner, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
public bool PutInHand(EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
return PutInHand(entity, GetActiveHand(), checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the priority hand, if provided. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
public bool TryPutInAnyHand(EntityUid entity, string? priorityHandName = null, bool checkActionBlocker = true)
|
||||
{
|
||||
Hand? priorityHand = null;
|
||||
|
||||
if (priorityHandName != null)
|
||||
priorityHand = GetHandOrNull(priorityHandName);
|
||||
|
||||
return PutInHand(entity, priorityHand, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the priority hand, if provided. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
private bool PutInHand(EntityUid entity, Hand? priorityHand = null, bool checkActionBlocker = true)
|
||||
{
|
||||
if (priorityHand != null)
|
||||
{
|
||||
if (TryPickupEntity(priorityHand, entity, checkActionBlocker))
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (TryPickupEntity(hand, entity, checkActionBlocker))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any hand can pick up an item.
|
||||
/// </summary>
|
||||
public bool CanPutInHand(SharedItemComponent item, bool mobCheck = true)
|
||||
{
|
||||
var entity = item.Owner;
|
||||
|
||||
if (mobCheck && !PlayerCanPickup)
|
||||
return false;
|
||||
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (CanInsertEntityIntoHand(hand, entity))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class Hand
|
||||
{
|
||||
[ViewVariables]
|
||||
public string Name { get; }
|
||||
|
||||
[ViewVariables]
|
||||
public HandLocation Location { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
|
||||
/// which may not be synced with the server when the client hands are created.
|
||||
/// </summary>
|
||||
[ViewVariables, NonSerialized]
|
||||
public ContainerSlot? Container;
|
||||
|
||||
[ViewVariables]
|
||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||
|
||||
public bool IsEmpty => HeldEntity == null;
|
||||
|
||||
public Hand(string name, HandLocation location, ContainerSlot? container = null)
|
||||
{
|
||||
Name = name;
|
||||
Location = location;
|
||||
Container = container;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class HandsComponentState : ComponentState
|
||||
{
|
||||
public List<Hand> Hands { get; }
|
||||
public string? ActiveHand { get; }
|
||||
|
||||
public HandsComponentState(List<Hand> hands, string? activeHand = null)
|
||||
{
|
||||
Hands = hands;
|
||||
ActiveHand = activeHand;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The currently active hand.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Hand? ActiveHand;
|
||||
|
||||
/// <summary>
|
||||
/// A message that calls the use interaction on an item in hand, presumed for now the interaction will occur only on the active hand.
|
||||
/// The item currently held in the active hand.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class UseInHandMsg : EntityEventArgs
|
||||
{
|
||||
}
|
||||
[ViewVariables]
|
||||
public EntityUid? ActiveHandEntity => ActiveHand?.HeldEntity;
|
||||
|
||||
[ViewVariables]
|
||||
public Dictionary<string, Hand> Hands = new();
|
||||
|
||||
public int Count => Hands.Count;
|
||||
|
||||
/// <summary>
|
||||
/// A message that calls the activate interaction on the item in the specified hand.
|
||||
/// List of hand-names. These are keys for <see cref="Hands"/>. The order of this list determines the order in which hands are iterated over.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ActivateInHandMsg : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
|
||||
public ActivateInHandMsg(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
public List<string> SortedHands = new();
|
||||
|
||||
/// <summary>
|
||||
/// Uses the item in the active hand on the item in the specified hand.
|
||||
/// The amount of throw impulse per distance the player is from the throw target.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ClientInteractUsingInHandMsg : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
|
||||
public ClientInteractUsingInHandMsg(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
[DataField("throwForceMultiplier")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ThrowForceMultiplier { get; set; } = 10f; //should be tuned so that a thrown item lands about under the player's cursor
|
||||
|
||||
/// <summary>
|
||||
/// Moves an item from one hand to the active hand.
|
||||
/// Distance after which longer throw targets stop increasing throw impulse.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class MoveItemFromHandMsg : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
[DataField("throwRange")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ThrowRange { get; set; } = 8f;
|
||||
}
|
||||
|
||||
public MoveItemFromHandMsg(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class Hand
|
||||
{
|
||||
[ViewVariables]
|
||||
public string Name { get; }
|
||||
|
||||
[ViewVariables]
|
||||
public HandLocation Location { get; }
|
||||
|
||||
/// <summary>
|
||||
/// What side of the body this hand is on.
|
||||
/// The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
|
||||
/// which may not be synced with the server when the client hands are created.
|
||||
/// </summary>
|
||||
public enum HandLocation : byte
|
||||
{
|
||||
Left,
|
||||
Middle,
|
||||
Right
|
||||
}
|
||||
[ViewVariables, NonSerialized]
|
||||
public ContainerSlot? Container;
|
||||
|
||||
public sealed class HandCountChangedEvent : EntityEventArgs
|
||||
{
|
||||
public HandCountChangedEvent(EntityUid sender)
|
||||
{
|
||||
Sender = sender;
|
||||
}
|
||||
[ViewVariables]
|
||||
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||
|
||||
public EntityUid Sender { get; }
|
||||
public bool IsEmpty => HeldEntity == null;
|
||||
|
||||
public Hand(string name, HandLocation location, ContainerSlot? container = null)
|
||||
{
|
||||
Name = name;
|
||||
Location = location;
|
||||
Container = container;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class HandsComponentState : ComponentState
|
||||
{
|
||||
public readonly List<Hand> Hands;
|
||||
public readonly List<string> HandNames;
|
||||
public readonly string? ActiveHand;
|
||||
|
||||
public HandsComponentState(SharedHandsComponent handComp)
|
||||
{
|
||||
Hands = new(handComp.Hands.Values);
|
||||
HandNames = handComp.SortedHands;
|
||||
ActiveHand = handComp.ActiveHand?.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What side of the body this hand is on.
|
||||
/// </summary>
|
||||
public enum HandLocation : byte
|
||||
{
|
||||
Left,
|
||||
Middle,
|
||||
Right
|
||||
}
|
||||
|
||||
39
Content.Shared/Hands/EntitySystems/SharedHandsSystem.AI.cs
Normal file
39
Content.Shared/Hands/EntitySystems/SharedHandsSystem.AI.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
// These functions are mostly unused except for some AI operator stuff
|
||||
// Nothing stops them from being used in general. If they ever get used elsewhere, then this file probably needs to be renamed.
|
||||
|
||||
public abstract partial class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
public bool TrySelect(EntityUid uid, EntityUid? entity, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
return false;
|
||||
|
||||
SetActiveHand(uid, hand, handsComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TrySelect<TComponent>(EntityUid uid, [NotNullWhen(true)] out TComponent? component, SharedHandsComponent? handsComp = null) where TComponent : Component
|
||||
{
|
||||
component = null;
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
foreach (var hand in handsComp.Hands.Values)
|
||||
{
|
||||
if (TryComp(hand.HeldEntity, out component))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TrySelectEmptyHand(EntityUid uid, SharedHandsComponent? handsComp = null) => TrySelect(uid, null, handsComp);
|
||||
}
|
||||
159
Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs
Normal file
159
Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
public abstract partial class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the contents of a hand is able to be removed from its container.
|
||||
/// </summary>
|
||||
public bool CanDropHeld(EntityUid uid, Hand hand, bool checkActionBlocker = true)
|
||||
{
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
if (!hand.Container!.CanRemove(hand.HeldEntity.Value, EntityManager))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !_actionBlocker.CanDrop(uid))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to drop the item in the currently active hand.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHand == null)
|
||||
return false;
|
||||
|
||||
return TryDrop(uid, handsComp.ActiveHand, targetDropLocation, checkActionBlocker, doDropInteraction, handsComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops an item at the target location.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, EntityUid entity, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
return false;
|
||||
|
||||
return TryDrop(uid, hand, targetDropLocation, checkActionBlocker, doDropInteraction, handsComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops a hands contents at the target location.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return false;
|
||||
|
||||
if (!CanDropHeld(uid, hand, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
var entity = hand.HeldEntity!.Value;
|
||||
DoDrop(uid, hand, doDropInteraction: doDropInteraction, handsComp);
|
||||
|
||||
var xform = Transform(uid);
|
||||
|
||||
if (targetDropLocation == null)
|
||||
{
|
||||
// TODO recursively check upwards for containers
|
||||
Transform(entity).AttachParentToContainerOrGrid(EntityManager);
|
||||
return true;
|
||||
}
|
||||
|
||||
var target = targetDropLocation.Value.ToMap(EntityManager);
|
||||
Transform(entity).WorldPosition = GetFinalDropCoordinates(uid, xform.MapPosition, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move a held item from a hand into a container that is not another hand, without dropping it on the floor in-between.
|
||||
/// </summary>
|
||||
public bool TryDropIntoContainer(EntityUid uid, EntityUid entity, BaseContainer targetContainer, bool checkActionBlocker = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
return false;
|
||||
|
||||
if (!CanDropHeld(uid, hand, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
if (!targetContainer.CanInsert(entity, EntityManager))
|
||||
return false;
|
||||
|
||||
DoDrop(uid, hand, false, handsComp);
|
||||
targetContainer.Insert(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the final location a dropped item will end up at, accounting for max drop range and collision along the targeted drop path.
|
||||
/// </summary>
|
||||
private Vector2 GetFinalDropCoordinates(EntityUid user, MapCoordinates origin, MapCoordinates target)
|
||||
{
|
||||
var dropVector = target.Position - origin.Position;
|
||||
var requestedDropDistance = dropVector.Length;
|
||||
|
||||
if (dropVector.Length > SharedInteractionSystem.InteractionRange)
|
||||
{
|
||||
dropVector = dropVector.Normalized * SharedInteractionSystem.InteractionRange;
|
||||
target = new MapCoordinates(origin.Position + dropVector, target.MapId);
|
||||
}
|
||||
|
||||
var dropLength = _interactionSystem.UnobstructedDistance(origin, target, predicate: e => e == user);
|
||||
|
||||
if (dropLength < requestedDropDistance)
|
||||
return origin.Position + dropVector.Normalized * dropLength;
|
||||
return target.Position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the contents of a hand from its container. Assumes that the removal is allowed. In general, you should not be calling this directly.
|
||||
/// </summary>
|
||||
public virtual void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return;
|
||||
|
||||
if (hand.Container?.ContainedEntity == null)
|
||||
return;
|
||||
|
||||
var entity = hand.Container.ContainedEntity.Value;
|
||||
|
||||
if (!hand.Container!.Remove(entity, EntityManager))
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {uid} could not remove {entity} from {hand.Container}.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dirty(handsComp);
|
||||
|
||||
if (doDropInteraction)
|
||||
_interactionSystem.DroppedInteraction(uid, entity);
|
||||
|
||||
var gotUnequipped = new GotUnequippedHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(entity, gotUnequipped, false);
|
||||
|
||||
var didUnequip = new DidUnequipHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(uid, didUnequip);
|
||||
|
||||
if (hand == handsComp.ActiveHand)
|
||||
RaiseLocalEvent(entity, new HandDeselectedEvent(uid), false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
public abstract partial class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
private void InitializeInteractions()
|
||||
{
|
||||
SubscribeAllEvent<RequestSetHandEvent>(HandleSetHand);
|
||||
SubscribeAllEvent<RequestActivateInHandEvent>(HandleActivateItemInHand);
|
||||
SubscribeAllEvent<RequestHandInteractUsingEvent>(HandleInteractUsingInHand);
|
||||
SubscribeAllEvent<RequestUseInHandEvent>(HandleUseInHand);
|
||||
SubscribeAllEvent<RequestMoveHandItemEvent>(HandleMoveItemFromHand);
|
||||
|
||||
SubscribeLocalEvent<SharedHandsComponent, ExaminedEvent>(HandleExamined);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.UseItemInHand, InputCmdHandler.FromDelegate(HandleUseItem, handle: false))
|
||||
.Bind(ContentKeyFunctions.AltUseItemInHand, InputCmdHandler.FromDelegate(HandleAltUseInHand, handle: false))
|
||||
.Bind(ContentKeyFunctions.SwapHands, InputCmdHandler.FromDelegate(SwapHandsPressed, handle: false))
|
||||
.Bind(ContentKeyFunctions.Drop, new PointerInputCmdHandler(DropPressed))
|
||||
.Register<SharedHandsSystem>();
|
||||
}
|
||||
|
||||
#region Event and Key-binding Handlers
|
||||
private void HandleAltUseInHand(ICommonSession? session)
|
||||
{
|
||||
if (session?.AttachedEntity != null)
|
||||
TryUseItemInHand(session.AttachedEntity.Value, true);
|
||||
}
|
||||
|
||||
private void HandleUseItem(ICommonSession? session)
|
||||
{
|
||||
if (session?.AttachedEntity != null)
|
||||
TryUseItemInHand(session.AttachedEntity.Value);
|
||||
}
|
||||
|
||||
private void HandleMoveItemFromHand(RequestMoveHandItemEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity != null)
|
||||
TryMoveHeldEntityToActiveHand(args.SenderSession.AttachedEntity.Value, msg.HandName);
|
||||
}
|
||||
|
||||
private void HandleUseInHand(RequestUseInHandEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity != null)
|
||||
TryUseItemInHand(args.SenderSession.AttachedEntity.Value);
|
||||
}
|
||||
|
||||
private void HandleActivateItemInHand(RequestActivateInHandEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity != null)
|
||||
TryActivateItemInHand(args.SenderSession.AttachedEntity.Value);
|
||||
}
|
||||
|
||||
private void HandleInteractUsingInHand(RequestHandInteractUsingEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity != null)
|
||||
TryInteractHandWithActiveHand(args.SenderSession.AttachedEntity.Value, msg.HandName);
|
||||
}
|
||||
|
||||
private void SwapHandsPressed(ICommonSession? session)
|
||||
{
|
||||
if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? component))
|
||||
return;
|
||||
|
||||
if (component.ActiveHand == null || component.Hands.Count < 2)
|
||||
return;
|
||||
|
||||
var newActiveIndex = component.SortedHands.IndexOf(component.ActiveHand.Name) + 1;
|
||||
var nextHand = component.SortedHands[newActiveIndex % component.Hands.Count];
|
||||
|
||||
TrySetActiveHand(component.Owner, nextHand, component);
|
||||
}
|
||||
|
||||
private bool DropPressed(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
if (TryComp(session?.AttachedEntity, out SharedHandsComponent? hands) && hands.ActiveHand != null)
|
||||
TryDrop(session!.AttachedEntity!.Value, hands.ActiveHand, coords, handsComp: hands);
|
||||
|
||||
// always send to server.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public bool TryActivateItemInHand(EntityUid uid, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHandEntity == null)
|
||||
return false;
|
||||
|
||||
return _interactionSystem.InteractionActivate(uid, handsComp.ActiveHandEntity.Value);
|
||||
}
|
||||
|
||||
public bool TryInteractHandWithActiveHand(EntityUid uid, string handName, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHandEntity == null)
|
||||
return false;
|
||||
|
||||
if (!handsComp.Hands.TryGetValue(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
_interactionSystem.InteractUsing(uid, handsComp.ActiveHandEntity.Value, hand.HeldEntity.Value, Transform(hand.HeldEntity.Value).Coordinates);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryUseItemInHand(EntityUid uid, bool altInteract = false, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHandEntity == null)
|
||||
return false;
|
||||
|
||||
if (altInteract)
|
||||
return _interactionSystem.AltInteract(uid, handsComp.ActiveHandEntity.Value);
|
||||
else
|
||||
return _interactionSystem.UseInHandInteraction(uid, handsComp.ActiveHandEntity.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves an entity from one hand to the active hand.
|
||||
/// </summary>
|
||||
public bool TryMoveHeldEntityToActiveHand(EntityUid uid, string handName, bool checkActionBlocker = true, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHand == null || !handsComp.ActiveHand.IsEmpty)
|
||||
return false;
|
||||
|
||||
if (!handsComp.Hands.TryGetValue(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanDropHeld(uid, hand, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
var entity = hand.HeldEntity!.Value;
|
||||
|
||||
if (!CanPickupToHand(uid, entity, handsComp.ActiveHand, checkActionBlocker, handsComp))
|
||||
return false;
|
||||
|
||||
DoDrop(uid, hand, false, handsComp);
|
||||
DoPickup(uid, handsComp.ActiveHand, entity, handsComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: Actually shows all items/clothing/etc.
|
||||
private void HandleExamined(EntityUid uid, SharedHandsComponent handsComp, ExaminedEvent args)
|
||||
{
|
||||
foreach (var inhand in EnumerateHeld(uid, handsComp))
|
||||
{
|
||||
if (HasComp<HandVirtualItemComponent>(inhand))
|
||||
continue;
|
||||
|
||||
args.PushText(Loc.GetString("comp-hands-examine", ("user", handsComp.Owner), ("item", inhand)));
|
||||
}
|
||||
}
|
||||
}
|
||||
161
Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs
Normal file
161
Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
public abstract partial class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity to a specific hand. If no explicit hand is specified, defaults to using the currently active hand.
|
||||
/// </summary>
|
||||
public bool TryPickup(EntityUid uid, EntityUid entity, string? handName = null, bool checkActionBlocker = true, bool animateUser = false, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
var hand = handsComp.ActiveHand;
|
||||
if (handName != null && !handsComp.Hands.TryGetValue(handName, out hand))
|
||||
return false;
|
||||
|
||||
if (hand == null)
|
||||
return false;
|
||||
|
||||
return TryPickup(uid, entity, hand, checkActionBlocker, animateUser, handsComp, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to pick up an item into any empty hand. Prioritizes the currently active hand.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If one empty hand fails to pick up the item, this will NOT check other hands. If ever hand-specific item
|
||||
/// restrictions are added, there a might need to be a TryPickupAllHands or something like that.
|
||||
/// </remarks>
|
||||
public bool TryPickupAnyHand(EntityUid uid, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (!TryGetEmptyHand(uid, out var hand, handsComp))
|
||||
return false;
|
||||
|
||||
return TryPickup(uid, entity, hand, checkActionBlocker, animateUser, handsComp, item);
|
||||
}
|
||||
|
||||
public bool TryPickup(EntityUid uid, EntityUid entity, Hand hand, bool checkActionBlocker = true, bool animateUser = false, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (!Resolve(entity, ref item, false))
|
||||
return false;
|
||||
|
||||
if (!CanPickupToHand(uid, entity, hand, checkActionBlocker, handsComp, item))
|
||||
return false;
|
||||
|
||||
// animation
|
||||
var xform = Transform(uid);
|
||||
var coordinateEntity = xform.ParentUid.IsValid() ? xform.ParentUid : uid;
|
||||
var initialPosition = EntityCoordinates.FromMap(EntityManager, coordinateEntity, Transform(entity).MapPosition);
|
||||
|
||||
PickupAnimation(entity, initialPosition, xform.LocalPosition, animateUser ? null : uid);
|
||||
DoPickup(uid, hand, entity, handsComp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanPickupAnyHand(EntityUid uid, EntityUid entity, bool checkActionBlocker = true, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
if (!TryGetEmptyHand(uid, out var hand, handsComp))
|
||||
return false;
|
||||
|
||||
return CanPickupToHand(uid, entity, hand, checkActionBlocker, handsComp, item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a given item will fit into a specific user's hand. Unless otherwise specified, this will also check the general CanPickup action blocker.
|
||||
/// </summary>
|
||||
public bool CanPickupToHand(EntityUid uid, EntityUid entity, Hand hand, bool checkActionBlocker = true, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
var handContainer = hand.Container;
|
||||
if (handContainer == null || handContainer.ContainedEntity != null)
|
||||
return false;
|
||||
|
||||
if (!Resolve(entity, ref item, false))
|
||||
return false;
|
||||
|
||||
if (TryComp(entity, out PhysicsComponent? physics) && physics.BodyType == BodyType.Static)
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !_actionBlocker.CanPickup(uid, entity))
|
||||
return false;
|
||||
|
||||
// check can insert (including raising attempt events).
|
||||
return handContainer.CanInsert(entity, EntityManager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an item any hand, preferring the active hand, or puts it on the floor.
|
||||
/// </summary>
|
||||
public void PickupOrDrop(EntityUid? uid, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false, SharedHandsComponent? handsComp = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (uid == null
|
||||
|| !Resolve(uid.Value, ref handsComp, false)
|
||||
|| !TryGetEmptyHand(uid.Value, out var hand, handsComp)
|
||||
|| !TryPickup(uid.Value, entity, hand, checkActionBlocker, animateUser, handsComp, item))
|
||||
{
|
||||
// TODO make this check upwards for any container, and parent to that.
|
||||
// Currently this just checks the direct parent, so items can still teleport through containers.
|
||||
Transform(entity).AttachParentToContainerOrGrid(EntityManager);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an entity into the player's hand, assumes that the insertion is allowed. In general, you should not be calling this function directly.
|
||||
/// </summary>
|
||||
public virtual void DoPickup(EntityUid uid, Hand hand, EntityUid entity, SharedHandsComponent? hands = null)
|
||||
{
|
||||
if (!Resolve(uid, ref hands))
|
||||
return;
|
||||
|
||||
var handContainer = hand.Container;
|
||||
if (handContainer == null || handContainer.ContainedEntity != null)
|
||||
return;
|
||||
|
||||
if (!handContainer.Insert(entity, EntityManager))
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {uid} could not insert {entity} into {handContainer}.");
|
||||
return;
|
||||
}
|
||||
|
||||
_adminLogSystem.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}");
|
||||
|
||||
Dirty(hands);
|
||||
|
||||
var didEquip = new DidEquipHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(uid, didEquip, false);
|
||||
|
||||
var gotEquipped = new GotEquippedHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(entity, gotEquipped);
|
||||
|
||||
// TODO this should REALLY be a cancellable thing, not a handled event.
|
||||
// If one of the interactions resulted in the item being dropped, return early.
|
||||
if (gotEquipped.Handled)
|
||||
return;
|
||||
|
||||
if (hand == hands.ActiveHand)
|
||||
RaiseLocalEvent(entity, new HandSelectedEvent(uid), false);
|
||||
}
|
||||
|
||||
public abstract void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||
EntityUid? exclude);
|
||||
}
|
||||
209
Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs
Normal file
209
Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
public abstract partial class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
InitializeInteractions();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
CommandBinds.Unregister<SharedHandsSystem>();
|
||||
}
|
||||
|
||||
public void AddHand(EntityUid uid, string handName, HandLocation handLocation, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return;
|
||||
|
||||
if (handsComp.Hands.ContainsKey(handName))
|
||||
return;
|
||||
|
||||
var container = _containerSystem.EnsureContainer<ContainerSlot>(uid, handName);
|
||||
container.OccludesLight = false;
|
||||
|
||||
var newHand = new Hand(handName, handLocation, container);
|
||||
handsComp.Hands.Add(handName, newHand);
|
||||
handsComp.SortedHands.Add(handName);
|
||||
|
||||
if (handsComp.ActiveHand == null)
|
||||
SetActiveHand(uid, newHand, handsComp);
|
||||
|
||||
RaiseLocalEvent(uid, new HandCountChangedEvent(uid), false);
|
||||
Dirty(handsComp);
|
||||
}
|
||||
|
||||
public void RemoveHand(EntityUid uid, string handName, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return;
|
||||
|
||||
if (!handsComp.Hands.Remove(handName, out var hand))
|
||||
return;
|
||||
|
||||
TryDrop(uid, hand, null, false, true, handsComp);
|
||||
hand.Container?.Shutdown();
|
||||
handsComp.SortedHands.Remove(hand.Name);
|
||||
|
||||
if (handsComp.ActiveHand == hand)
|
||||
TrySetActiveHand(uid, handsComp.SortedHands.FirstOrDefault(), handsComp);
|
||||
|
||||
RaiseLocalEvent(uid, new HandCountChangedEvent(uid), false);
|
||||
Dirty(handsComp);
|
||||
}
|
||||
|
||||
private void HandleSetHand(RequestSetHandEvent msg, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.SenderSession.AttachedEntity == null)
|
||||
return;
|
||||
|
||||
TrySetActiveHand(eventArgs.SenderSession.AttachedEntity.Value, msg.HandName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get any empty hand. Prioritizes the currently active hand.
|
||||
/// </summary>
|
||||
public bool TryGetEmptyHand(EntityUid uid, [NotNullWhen(true)] out Hand? emptyHand, SharedHandsComponent? handComp = null)
|
||||
{
|
||||
emptyHand = null;
|
||||
if (!Resolve(uid, ref handComp, false))
|
||||
return false;
|
||||
|
||||
foreach (var hand in EnumerateHands(uid, handComp))
|
||||
{
|
||||
if (hand.IsEmpty)
|
||||
{
|
||||
emptyHand = hand;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerate over hands, starting with the currently active hand.
|
||||
/// </summary>
|
||||
public IEnumerable<Hand> EnumerateHands(EntityUid uid, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
yield break;
|
||||
|
||||
if (handsComp.ActiveHand != null)
|
||||
yield return handsComp.ActiveHand;
|
||||
|
||||
foreach (var name in handsComp.SortedHands)
|
||||
{
|
||||
if (name != handsComp.ActiveHand?.Name)
|
||||
yield return handsComp.Hands[name];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerate over hands, with the active hand being first.
|
||||
/// </summary>
|
||||
public IEnumerable<EntityUid> EnumerateHeld(EntityUid uid, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
yield break;
|
||||
|
||||
if (handsComp.ActiveHandEntity != null)
|
||||
yield return handsComp.ActiveHandEntity.Value;
|
||||
|
||||
foreach (var name in handsComp.SortedHands)
|
||||
{
|
||||
if (name == handsComp.ActiveHand?.Name)
|
||||
continue;
|
||||
|
||||
if (handsComp.Hands[name].HeldEntity is EntityUid held)
|
||||
yield return held;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the currently active hand and raise hand (de)selection events directed at the held entities.
|
||||
/// </summary>
|
||||
/// <returns>True if the active hand was set to a NEW value. Setting it to the same value returns false and does
|
||||
/// not trigger interactions.</returns>
|
||||
public virtual bool TrySetActiveHand(EntityUid uid, string? name, SharedHandsComponent? handComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handComp))
|
||||
return false;
|
||||
|
||||
if (name == handComp.ActiveHand?.Name)
|
||||
return false;
|
||||
|
||||
Hand? hand = null;
|
||||
if (name != null && !handComp.Hands.TryGetValue(name, out hand))
|
||||
return false;
|
||||
|
||||
return SetActiveHand(uid, hand, handComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the currently active hand and raise hand (de)selection events directed at the held entities.
|
||||
/// </summary>
|
||||
/// <returns>True if the active hand was set to a NEW value. Setting it to the same value returns false and does
|
||||
/// not trigger interactions.</returns>
|
||||
public virtual bool SetActiveHand(EntityUid uid, Hand? hand, SharedHandsComponent? handComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handComp))
|
||||
return false;
|
||||
|
||||
if (hand == handComp.ActiveHand)
|
||||
return false;
|
||||
|
||||
if (handComp.ActiveHand?.HeldEntity is EntityUid held)
|
||||
RaiseLocalEvent(held, new HandDeselectedEvent(uid), false);
|
||||
|
||||
if (hand == null)
|
||||
{
|
||||
handComp.ActiveHand = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
handComp.ActiveHand = hand;
|
||||
|
||||
if (hand.HeldEntity != null)
|
||||
RaiseLocalEvent(hand.HeldEntity.Value, new HandSelectedEvent(uid), false);
|
||||
|
||||
Dirty(handComp);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsHolding(EntityUid uid, EntityUid? entity, [NotNullWhen(true)] out Hand? inHand, SharedHandsComponent? handsComp = null)
|
||||
{
|
||||
inHand = null;
|
||||
if (!Resolve(uid, ref handsComp, false))
|
||||
return false;
|
||||
|
||||
foreach (var hand in handsComp.Hands.Values)
|
||||
{
|
||||
if (hand.HeldEntity == entity)
|
||||
{
|
||||
inHand = hand;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Hands.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using static Robust.Shared.GameObjects.SharedSpriteComponent;
|
||||
|
||||
|
||||
namespace Content.Shared.Hands
|
||||
{
|
||||
/// <summary>
|
||||
@@ -73,15 +70,9 @@ namespace Content.Shared.Hands
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Item in the hand that was deselected.
|
||||
/// </summary>
|
||||
public EntityUid Item { get; }
|
||||
|
||||
public HandDeselectedEvent(EntityUid user, EntityUid item)
|
||||
public HandDeselectedEvent(EntityUid user)
|
||||
{
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,15 +87,9 @@ namespace Content.Shared.Hands
|
||||
/// </summary>
|
||||
public EntityUid User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Item in the hand that was selected.
|
||||
/// </summary>
|
||||
public EntityUid Item { get; }
|
||||
|
||||
public HandSelectedEvent(EntityUid user, EntityUid item)
|
||||
public HandSelectedEvent(EntityUid user)
|
||||
{
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,4 +216,64 @@ namespace Content.Shared.Hands
|
||||
{
|
||||
public DidUnequipHandEvent(EntityUid user, EntityUid unequipped, Hand hand) : base(user, unequipped, hand) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised by a client when they want to use the item currently held in their hands.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestUseInHandEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised by a client when they want to activate the item currently in their hands.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestActivateInHandEvent : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
|
||||
public RequestActivateInHandEvent(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised by a client when they want to use the currently held item on some other held item
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestHandInteractUsingEvent : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
|
||||
public RequestHandInteractUsingEvent(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised by a client when they want to move an item held in another hand to their currently active hand
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestMoveHandItemEvent : EntityEventArgs
|
||||
{
|
||||
public string HandName { get; }
|
||||
|
||||
public RequestMoveHandItemEvent(string handName)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class HandCountChangedEvent : EntityEventArgs
|
||||
{
|
||||
public HandCountChangedEvent(EntityUid sender)
|
||||
{
|
||||
Sender = sender;
|
||||
}
|
||||
|
||||
public EntityUid Sender { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
|
||||
namespace Content.Shared.Hands
|
||||
{
|
||||
public abstract class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeAllEvent<RequestSetHandEvent>(HandleSetHand);
|
||||
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(HandleContainerRemoved);
|
||||
SubscribeLocalEvent<SharedHandsComponent, EntInsertedIntoContainerMessage>(HandleContainerInserted);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.Drop, new PointerInputCmdHandler(DropPressed))
|
||||
.Bind(ContentKeyFunctions.SwapHands, InputCmdHandler.FromDelegate(SwapHandsPressed, handle: false))
|
||||
.Register<SharedHandsSystem>();
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
CommandBinds.Unregister<SharedHandsSystem>();
|
||||
}
|
||||
|
||||
#region interactions
|
||||
private void SwapHandsPressed(ICommonSession? session)
|
||||
{
|
||||
if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? hands))
|
||||
return;
|
||||
|
||||
if (!hands.TryGetSwapHandsResult(out var nextHand))
|
||||
return;
|
||||
|
||||
TrySetActiveHand(hands.Owner, nextHand, hands);
|
||||
}
|
||||
|
||||
private bool DropPressed(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||
{
|
||||
if (TryComp(session?.AttachedEntity, out SharedHandsComponent? hands))
|
||||
hands.TryDropActiveHand(coords);
|
||||
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EntityInsertRemove
|
||||
/// <summary>
|
||||
/// Removes the contents of a hand from its container. Assumes that the removal is allowed.
|
||||
/// </summary>
|
||||
public virtual void RemoveHeldEntityFromHand(EntityUid uid, Hand hand, SharedHandsComponent? hands = null)
|
||||
{
|
||||
if (!Resolve(uid, ref hands))
|
||||
return;
|
||||
|
||||
if (hand.Container?.ContainedEntity == null)
|
||||
return;
|
||||
|
||||
var entity = hand.Container.ContainedEntity.Value;
|
||||
|
||||
if (!hand.Container!.Remove(entity))
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {uid} could not remove {entity} from {hand.Container}.");
|
||||
return;
|
||||
}
|
||||
|
||||
hands.Dirty();
|
||||
|
||||
var gotUnequipped = new GotUnequippedHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(entity, gotUnequipped, false);
|
||||
|
||||
var didUnequip = new DidUnequipHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(uid, didUnequip);
|
||||
|
||||
if (hand.Name == hands.ActiveHand)
|
||||
RaiseLocalEvent(entity, new HandDeselectedEvent(uid, entity), false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an entity into the player's hand, assumes that the insertion is allowed.
|
||||
/// </summary>
|
||||
public virtual void PutEntityIntoHand(EntityUid uid, Hand hand, EntityUid entity, SharedHandsComponent? hands = null)
|
||||
{
|
||||
if (!Resolve(uid, ref hands))
|
||||
return;
|
||||
|
||||
var handContainer = hand.Container;
|
||||
if (handContainer == null || handContainer.ContainedEntity != null)
|
||||
return;
|
||||
|
||||
if (!handContainer.Insert(entity))
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {uid} could not insert {entity} into {handContainer}.");
|
||||
return;
|
||||
}
|
||||
|
||||
_adminLogSystem.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}");
|
||||
|
||||
hands.Dirty();
|
||||
|
||||
var didEquip = new DidEquipHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(uid, didEquip, false);
|
||||
|
||||
var gotEquipped = new GotEquippedHandEvent(uid, entity, hand);
|
||||
RaiseLocalEvent(entity, gotEquipped);
|
||||
|
||||
// TODO this should REALLY be a cancellable thing, not a handled event.
|
||||
// If one of the interactions resulted in the item being dropped, return early.
|
||||
if (gotEquipped.Handled)
|
||||
return;
|
||||
|
||||
if (hand.Name == hands.ActiveHand)
|
||||
RaiseLocalEvent(entity, new HandSelectedEvent(uid, entity), false);
|
||||
}
|
||||
|
||||
public abstract void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||
EntityUid? exclude);
|
||||
#endregion
|
||||
|
||||
protected virtual void HandleContainerRemoved(EntityUid uid, SharedHandsComponent component, ContainerModifiedMessage args)
|
||||
{
|
||||
HandleContainerModified(uid, component, args);
|
||||
}
|
||||
|
||||
protected virtual void HandleContainerModified(EntityUid uid, SharedHandsComponent hands, ContainerModifiedMessage args)
|
||||
{
|
||||
// client updates hand visuals here.
|
||||
}
|
||||
|
||||
private void HandleContainerInserted(EntityUid uid, SharedHandsComponent component, EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
// un-rotate entities. needed for things like directional flashlights
|
||||
Transform(args.Entity).LocalRotation = 0;
|
||||
|
||||
HandleContainerModified(uid, component, args);
|
||||
}
|
||||
|
||||
private void HandleSetHand(RequestSetHandEvent msg, EntitySessionEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.SenderSession.AttachedEntity == null)
|
||||
return;
|
||||
|
||||
TrySetActiveHand(eventArgs.SenderSession.AttachedEntity.Value, msg.HandName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the currently active hand and raise hand (de)selection events directed at the held entities.
|
||||
/// </summary>
|
||||
/// <returns>True if the active hand was set to a NEW value. Setting it to the same value returns false and does
|
||||
/// not trigger interactions.</returns>
|
||||
public virtual bool TrySetActiveHand(EntityUid uid, string? value, SharedHandsComponent? handComp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref handComp))
|
||||
return false;
|
||||
|
||||
if (value == handComp.ActiveHand)
|
||||
return false;
|
||||
|
||||
if (value != null && !handComp.HasHand(value))
|
||||
{
|
||||
Logger.Warning($"{nameof(SharedHandsComponent)} on {handComp.Owner} tried to set its active hand to {value}, which was not a hand.");
|
||||
return false;
|
||||
}
|
||||
if (value == null && handComp.Hands.Count != 0)
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {handComp.Owner} tried to set its active hand to null, when it still had another hand.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handComp.TryGetActiveHeldEntity(out var entity))
|
||||
RaiseLocalEvent(entity.Value, new HandDeselectedEvent(uid, entity.Value), false);
|
||||
|
||||
handComp.ActiveHand = value;
|
||||
|
||||
if (handComp.TryGetActiveHeldEntity(out entity))
|
||||
RaiseLocalEvent(entity.Value, new HandSelectedEvent(uid, entity.Value), false);
|
||||
|
||||
handComp.Dirty();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ namespace Content.Shared.Input
|
||||
public static class ContentKeyFunctions
|
||||
{
|
||||
public static readonly BoundKeyFunction WideAttack = "WideAttack";
|
||||
public static readonly BoundKeyFunction ActivateItemInHand = "ActivateItemInHand";
|
||||
public static readonly BoundKeyFunction AltActivateItemInHand = "AltActivateItemInHand";
|
||||
public static readonly BoundKeyFunction UseItemInHand = "ActivateItemInHand";
|
||||
public static readonly BoundKeyFunction AltUseItemInHand = "AltActivateItemInHand";
|
||||
public static readonly BoundKeyFunction ActivateItemInWorld = "ActivateItemInWorld";
|
||||
public static readonly BoundKeyFunction AltActivateItemInWorld = "AltActivateItemInWorld";
|
||||
public static readonly BoundKeyFunction Drop = "Drop";
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Content.Shared.Interaction
|
||||
|
||||
// Does the user have hands?
|
||||
Hand? hand;
|
||||
if (!TryComp(user, out SharedHandsComponent? hands) || !hands.TryGetActiveHand(out hand))
|
||||
if (!TryComp(user, out SharedHandsComponent? hands) || hands.ActiveHand == null)
|
||||
return;
|
||||
|
||||
var inRangeUnobstructed = target == null
|
||||
@@ -224,7 +224,7 @@ namespace Content.Shared.Interaction
|
||||
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
||||
|
||||
// empty-hand interactions
|
||||
if (hand.HeldEntity == null)
|
||||
if (hands.ActiveHandEntity is not EntityUid held)
|
||||
{
|
||||
if (inRangeUnobstructed && target != null)
|
||||
InteractHand(user, target.Value);
|
||||
@@ -236,7 +236,7 @@ namespace Content.Shared.Interaction
|
||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
||||
return;
|
||||
|
||||
if (target == hand.HeldEntity)
|
||||
if (target == held)
|
||||
{
|
||||
UseInHandInteraction(user, target.Value, checkCanUse: false, checkCanInteract: false);
|
||||
return;
|
||||
@@ -246,7 +246,7 @@ namespace Content.Shared.Interaction
|
||||
{
|
||||
InteractUsing(
|
||||
user,
|
||||
hand.HeldEntity.Value,
|
||||
held,
|
||||
target.Value,
|
||||
coordinates,
|
||||
checkCanInteract: false,
|
||||
@@ -257,7 +257,7 @@ namespace Content.Shared.Interaction
|
||||
|
||||
InteractUsingRanged(
|
||||
user,
|
||||
hand.HeldEntity.Value,
|
||||
held,
|
||||
target,
|
||||
coordinates,
|
||||
inRangeUnobstructed);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
@@ -21,6 +22,7 @@ public abstract partial class InventorySystem
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private void InitializeEquip()
|
||||
@@ -52,7 +54,7 @@ public abstract partial class InventorySystem
|
||||
if (!TryEquip(args.User, uid, slotDef.Name, true, inventory: inv))
|
||||
continue;
|
||||
|
||||
hands.PutInHandOrDrop(slotEntity.Value);
|
||||
_handsSystem.PickupOrDrop(args.User, slotEntity.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -104,7 +106,7 @@ public abstract partial class InventorySystem
|
||||
if (!TryComp(actor, out InventoryComponent? inventory) || !TryComp<SharedHandsComponent>(actor, out var hands))
|
||||
return;
|
||||
|
||||
hands.TryGetActiveHeldEntity(out var held);
|
||||
var held = hands.ActiveHandEntity;
|
||||
TryGetSlotEntity(actor, ev.Slot, out var itemUid, inventory);
|
||||
|
||||
// attempt to perform some interaction
|
||||
@@ -118,8 +120,8 @@ public abstract partial class InventorySystem
|
||||
// un-equip to hands
|
||||
if (itemUid != null)
|
||||
{
|
||||
if (hands.CanPickupEntityToActiveHand(itemUid.Value) && TryUnequip(actor, ev.Slot, inventory: inventory))
|
||||
hands.PutInHand(itemUid.Value, false);
|
||||
if (_handsSystem.CanPickupAnyHand(actor, itemUid.Value, handsComp: hands) && TryUnequip(actor, ev.Slot, inventory: inventory))
|
||||
_handsSystem.TryPickup(actor, itemUid.Value, checkActionBlocker: false, handsComp: hands);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,7 +137,7 @@ public abstract partial class InventorySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (hands.TryDropNoInteraction())
|
||||
if (_handsSystem.TryDrop(actor, hands.ActiveHand!, doDropInteraction: false, handsComp: hands))
|
||||
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
namespace Content.Shared.Item;
|
||||
|
||||
namespace Content.Shared.Item
|
||||
/// <summary>
|
||||
/// Raised on a *mob* when it tries to pickup something
|
||||
/// </summary>
|
||||
public sealed class PickupAttemptEvent : BasePickupAttemptEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Raised on a *mob* when it tries to pickup something
|
||||
/// </summary>
|
||||
public sealed class PickupAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
public PickupAttemptEvent(EntityUid uid)
|
||||
{
|
||||
Uid = uid;
|
||||
}
|
||||
public PickupAttemptEvent(EntityUid user, EntityUid item) : base(user, item) { }
|
||||
}
|
||||
|
||||
public EntityUid Uid { get; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Raised directed at entity being picked up when someone tries to pick it up
|
||||
/// </summary>
|
||||
public sealed class GettingPickedUpAttemptEvent : BasePickupAttemptEvent
|
||||
{
|
||||
public GettingPickedUpAttemptEvent(EntityUid user, EntityUid item) : base(user, item) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised on the *item* when tried to be picked up
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Doesn't just handle "items" but calling it "PickedUpAttempt" is too close to "Pickup" for the sleep deprived brain.
|
||||
/// </remarks>
|
||||
public sealed class AttemptItemPickupEvent : CancellableEntityEventArgs
|
||||
[Virtual]
|
||||
public class BasePickupAttemptEvent : CancellableEntityEventArgs
|
||||
{
|
||||
public readonly EntityUid User;
|
||||
public readonly EntityUid Item;
|
||||
|
||||
public BasePickupAttemptEvent(EntityUid user, EntityUid item)
|
||||
{
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Localization;
|
||||
using System;
|
||||
|
||||
namespace Content.Shared.Item
|
||||
{
|
||||
public abstract class SharedItemSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -30,13 +30,7 @@ namespace Content.Shared.Item
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.User, out SharedHandsComponent? hands))
|
||||
return;
|
||||
|
||||
if (hands.ActiveHand == null)
|
||||
return;
|
||||
|
||||
args.Handled = hands.TryPickupEntity(hands.ActiveHand, uid, false, animateUser: false);
|
||||
args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, SharedItemComponent component, ref ComponentHandleState args)
|
||||
@@ -74,11 +68,11 @@ namespace Content.Shared.Item
|
||||
args.Using != null ||
|
||||
!args.CanAccess ||
|
||||
!args.CanInteract ||
|
||||
!args.Hands.CanPickupEntityToActiveHand(args.Target))
|
||||
!_handsSystem.CanPickupAnyHand(args.User, args.Target, handsComp: args.Hands, item: component))
|
||||
return;
|
||||
|
||||
InteractionVerb verb = new();
|
||||
verb.Act = () => args.Hands.TryPickupEntityToActiveHand(args.Target);
|
||||
verb.Act = () => _handsSystem.TryPickupAnyHand(args.User, args.Target, checkActionBlocker: false, handsComp: args.Hands, item: component);
|
||||
verb.IconTexture = "/Textures/Interface/VerbIcons/pickup.svg.192dpi.png";
|
||||
|
||||
// if the item already in a container (that is not the same as the user's), then change the text.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Shared.Placeable
|
||||
{
|
||||
public sealed class PlaceableSurfaceSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -52,16 +52,13 @@ namespace Content.Shared.Placeable
|
||||
if (!surface.IsPlaceable)
|
||||
return;
|
||||
|
||||
if(!EntityManager.TryGetComponent<SharedHandsComponent?>(args.User, out var handComponent))
|
||||
return;
|
||||
|
||||
if(!handComponent.TryDropEntity(args.Used, EntityManager.GetComponent<TransformComponent>(surface.Owner).Coordinates))
|
||||
if (!_handsSystem.TryDrop(args.User, args.Used))
|
||||
return;
|
||||
|
||||
if (surface.PlaceCentered)
|
||||
EntityManager.GetComponent<TransformComponent>(args.Used).LocalPosition = EntityManager.GetComponent<TransformComponent>(uid).LocalPosition + surface.PositionOffset;
|
||||
Transform(args.Used).LocalPosition = Transform(uid).LocalPosition + surface.PositionOffset;
|
||||
else
|
||||
EntityManager.GetComponent<TransformComponent>(args.Used).Coordinates = args.ClickLocation;
|
||||
Transform(args.Used).Coordinates = args.ClickLocation;
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Content.Shared.Verbs
|
||||
EntityUid? @using = null;
|
||||
if (TryComp(user, out SharedHandsComponent? hands) && (force || _actionBlockerSystem.CanUseHeldEntity(user)))
|
||||
{
|
||||
hands.TryGetActiveHeldEntity(out @using);
|
||||
@using = hands.ActiveHandEntity;
|
||||
|
||||
// Check whether the "Held" entity is a virtual pull entity. If yes, set that as the entity being "Used".
|
||||
// This allows you to do things like buckle a dragged person onto a surgery table, without click-dragging
|
||||
|
||||
Submodule RobustToolbox updated: 419e63ecd5...ea7012d114
Reference in New Issue
Block a user