hands ECS (#7081)
This commit is contained in:
@@ -108,8 +108,8 @@ namespace Content.Client.EscapeMenu.UI.Tabs
|
|||||||
AddHeader("ui-options-header-interaction-basic");
|
AddHeader("ui-options-header-interaction-basic");
|
||||||
AddButton(EngineKeyFunctions.Use);
|
AddButton(EngineKeyFunctions.Use);
|
||||||
AddButton(ContentKeyFunctions.WideAttack);
|
AddButton(ContentKeyFunctions.WideAttack);
|
||||||
AddButton(ContentKeyFunctions.ActivateItemInHand);
|
AddButton(ContentKeyFunctions.UseItemInHand);
|
||||||
AddButton(ContentKeyFunctions.AltActivateItemInHand);
|
AddButton(ContentKeyFunctions.AltUseItemInHand);
|
||||||
AddButton(ContentKeyFunctions.ActivateItemInWorld);
|
AddButton(ContentKeyFunctions.ActivateItemInWorld);
|
||||||
AddButton(ContentKeyFunctions.AltActivateItemInWorld);
|
AddButton(ContentKeyFunctions.AltActivateItemInWorld);
|
||||||
AddButton(ContentKeyFunctions.Drop);
|
AddButton(ContentKeyFunctions.Drop);
|
||||||
|
|||||||
@@ -4,17 +4,14 @@ using Content.Client.Animations;
|
|||||||
using Content.Client.HUD;
|
using Content.Client.HUD;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Hands
|
namespace Content.Client.Hands
|
||||||
@@ -25,11 +22,15 @@ namespace Content.Client.Hands
|
|||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(HandleContainerModified);
|
||||||
|
SubscribeLocalEvent<SharedHandsComponent, EntInsertedIntoContainerMessage>(HandleContainerModified);
|
||||||
|
|
||||||
SubscribeLocalEvent<HandsComponent, PlayerAttachedEvent>(HandlePlayerAttached);
|
SubscribeLocalEvent<HandsComponent, PlayerAttachedEvent>(HandlePlayerAttached);
|
||||||
SubscribeLocalEvent<HandsComponent, PlayerDetachedEvent>(HandlePlayerDetached);
|
SubscribeLocalEvent<HandsComponent, PlayerDetachedEvent>(HandlePlayerDetached);
|
||||||
SubscribeLocalEvent<HandsComponent, ComponentRemove>(HandleCompRemove);
|
SubscribeLocalEvent<HandsComponent, ComponentRemove>(HandleCompRemove);
|
||||||
@@ -45,46 +46,29 @@ namespace Content.Client.Hands
|
|||||||
if (args.Current is not HandsComponentState state)
|
if (args.Current is not HandsComponentState state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Do we have a NEW hand?
|
|
||||||
var handsModified = component.Hands.Count != state.Hands.Count;
|
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 ||
|
hand.Container = _containerSystem.EnsureContainer<ContainerSlot>(uid, hand.Name, manager);
|
||||||
component.Hands[i].Location != state.Hands[i].Location)
|
handsModified = true;
|
||||||
{
|
|
||||||
handsModified = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handsModified)
|
if (handsModified)
|
||||||
{
|
{
|
||||||
// we have new hands, get the new containers.
|
foreach (var name in component.Hands.Keys)
|
||||||
component.Hands = state.Hands;
|
{
|
||||||
UpdateHandContainers(uid, component);
|
if (!state.HandNames.Contains(name))
|
||||||
|
component.Hands.Remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
component.SortedHands = new(state.HandNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrySetActiveHand(uid, state.ActiveHand, component);
|
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)
|
if (uid == _playerManager.LocalPlayer?.ControlledEntity)
|
||||||
UpdateGui();
|
UpdateGui();
|
||||||
@@ -117,9 +101,7 @@ namespace Content.Client.Hands
|
|||||||
|
|
||||||
public EntityUid? GetActiveHandEntity()
|
public EntityUid? GetActiveHandEntity()
|
||||||
{
|
{
|
||||||
return TryGetPlayerHands(out var hands) && hands.TryGetActiveHeldEntity(out var entity)
|
return TryGetPlayerHands(out var hands) ? hands.ActiveHandEntity : null;
|
||||||
? entity
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -137,56 +119,57 @@ namespace Content.Client.Hands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UIHandClick(HandsComponent hands, string handName)
|
public void UIHandClick(HandsComponent hands, string handName)
|
||||||
{
|
{
|
||||||
if (!hands.TryGetHand(handName, out var pressedHand))
|
if (!hands.Hands.TryGetValue(handName, out var pressedHand))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!hands.TryGetActiveHand(out var activeHand))
|
if (hands.ActiveHand == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var pressedEntity = pressedHand.HeldEntity;
|
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
|
// use item in hand
|
||||||
// it will always be attack_self() in my heart.
|
// it will always be attack_self() in my heart.
|
||||||
RaiseNetworkEvent(new UseInHandMsg());
|
EntityManager.RaisePredictiveEvent(new RequestUseInHandEvent());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != activeHand && pressedEntity == null)
|
if (pressedHand != hands.ActiveHand && pressedEntity == null)
|
||||||
{
|
{
|
||||||
// change active hand
|
// change active hand
|
||||||
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != activeHand && pressedEntity != null && activeEntity != null)
|
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity != null)
|
||||||
{
|
{
|
||||||
// use active item on held item
|
// use active item on held item
|
||||||
RaiseNetworkEvent(new ClientInteractUsingInHandMsg(pressedHand.Name));
|
EntityManager.RaisePredictiveEvent(new RequestHandInteractUsingEvent(pressedHand.Name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressedHand != activeHand && pressedEntity != default && activeEntity == default)
|
if (pressedHand != hands.ActiveHand && pressedEntity != null && activeEntity == null)
|
||||||
{
|
{
|
||||||
// use active item on held item
|
// move the item to the active hand
|
||||||
RaiseNetworkEvent(new MoveItemFromHandMsg(pressedHand.Name));
|
EntityManager.RaisePredictiveEvent(new RequestMoveHandItemEvent(pressedHand.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public void UIHandActivate(string handName)
|
public void UIHandActivate(string handName)
|
||||||
{
|
{
|
||||||
RaiseNetworkEvent(new ActivateInHandMsg(handName));
|
EntityManager.RaisePredictiveEvent(new RequestActivateInHandEvent(handName));
|
||||||
}
|
}
|
||||||
|
|
||||||
#region visuals
|
#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);
|
UpdateHandVisuals(uid, args.Entity, hand);
|
||||||
}
|
}
|
||||||
@@ -267,25 +250,24 @@ namespace Content.Client.Hands
|
|||||||
private void OnVisualsChanged(EntityUid uid, HandsComponent component, VisualsChangedEvent args)
|
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).
|
// 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);
|
UpdateHandVisuals(uid, args.Item, hand, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Gui
|
#region Gui
|
||||||
public void UpdateGui(HandsComponent? hands = null)
|
public void UpdateGui(HandsComponent? hands = null)
|
||||||
{
|
{
|
||||||
if (hands == null && !TryGetPlayerHands(out hands) || hands.Gui == null)
|
if (hands == null && !TryGetPlayerHands(out hands) || hands.Gui == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var states = hands.Hands
|
var states = hands.Hands.Values
|
||||||
.Select(hand => new GuiHand(hand.Name, hand.Location, hand.HeldEntity))
|
.Select(hand => new GuiHand(hand.Name, hand.Location, hand.HeldEntity))
|
||||||
.ToArray();
|
.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)
|
public override bool TrySetActiveHand(EntityUid uid, string? value, SharedHandsComponent? handComp = null)
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ namespace Content.Client.Input
|
|||||||
var human = contexts.GetContext("human");
|
var human = contexts.GetContext("human");
|
||||||
human.AddFunction(ContentKeyFunctions.SwapHands);
|
human.AddFunction(ContentKeyFunctions.SwapHands);
|
||||||
human.AddFunction(ContentKeyFunctions.Drop);
|
human.AddFunction(ContentKeyFunctions.Drop);
|
||||||
human.AddFunction(ContentKeyFunctions.ActivateItemInHand);
|
human.AddFunction(ContentKeyFunctions.UseItemInHand);
|
||||||
human.AddFunction(ContentKeyFunctions.AltActivateItemInHand);
|
human.AddFunction(ContentKeyFunctions.AltUseItemInHand);
|
||||||
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
|
human.AddFunction(ContentKeyFunctions.OpenCharacterMenu);
|
||||||
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
|
human.AddFunction(ContentKeyFunctions.ActivateItemInWorld);
|
||||||
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
|
human.AddFunction(ContentKeyFunctions.ThrowItemInHand);
|
||||||
|
|||||||
@@ -196,15 +196,15 @@ namespace Content.Client.Inventory
|
|||||||
if (!Resolve(uid, ref hands, false))
|
if (!Resolve(uid, ref hands, false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!hands.TryGetActiveHeldEntity(out var heldEntity))
|
if (hands.ActiveHandEntity is not EntityUid heldEntity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent))
|
if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_itemSlotManager.HoverInSlot(button, heldEntity.Value,
|
_itemSlotManager.HoverInSlot(button, heldEntity,
|
||||||
CanEquip(uid, heldEntity.Value, slot, out _, slotDef, inventoryComponent) &&
|
CanEquip(uid, heldEntity, slot, out _, slotDef, inventoryComponent) &&
|
||||||
containerSlot.CanInsert(heldEntity.Value, EntityManager));
|
containerSlot.CanInsert(heldEntity, EntityManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button,
|
private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button,
|
||||||
@@ -217,7 +217,7 @@ namespace Content.Client.Inventory
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// only raise event if either itemUid is not null, or the user is holding something
|
// 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));
|
EntityManager.RaisePredictiveEvent(new UseSlotNetworkMessage(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace Content.Client.Weapons.Ranged
|
|||||||
return;
|
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;
|
_blocked = true;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Shared.ActionBlocker;
|
|||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Body.Part;
|
using Content.Shared.Body.Part;
|
||||||
using Content.Shared.Buckle.Components;
|
using Content.Shared.Buckle.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Standing;
|
using Content.Shared.Standing;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
@@ -251,9 +252,7 @@ namespace Content.IntegrationTests.Tests.Buckle
|
|||||||
{
|
{
|
||||||
var akms = entityManager.SpawnEntity(ItemDummyId, coordinates);
|
var akms = entityManager.SpawnEntity(ItemDummyId, coordinates);
|
||||||
|
|
||||||
// Equip items
|
Assert.True(EntitySystem.Get<SharedHandsSystem>().TryPickupAnyHand(human, akms));
|
||||||
Assert.True(entityManager.TryGetComponent(akms, out SharedItemComponent item));
|
|
||||||
Assert.True(hands.PutInHand(item));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -265,9 +264,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
|||||||
Assert.True(buckle.Buckled);
|
Assert.True(buckle.Buckled);
|
||||||
|
|
||||||
// With items in all hands
|
// 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);
|
var legs = body.GetPartsOfType(BodyPartType.Leg);
|
||||||
@@ -287,9 +286,9 @@ namespace Content.IntegrationTests.Tests.Buckle
|
|||||||
Assert.True(buckle.Buckled);
|
Assert.True(buckle.Buckled);
|
||||||
|
|
||||||
// Now with no item in any hand
|
// 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);
|
buckle.TryUnbuckle(human, true);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
|
|||||||
AddHand(cuffed.Owner);
|
AddHand(cuffed.Owner);
|
||||||
|
|
||||||
Assert.That(cuffed.CuffedHandCount, Is.EqualTo(2));
|
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
|
// Test to give a player with 4 hands 2 sets of cuffs
|
||||||
cuffed.TryAddNewCuffs(human, secondCuffs);
|
cuffed.TryAddNewCuffs(human, secondCuffs);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Client.Items.Components;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
@@ -54,6 +55,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
|
|
||||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
var mapId = MapId.Nullspace;
|
var mapId = MapId.Nullspace;
|
||||||
var coords = MapCoordinates.Nullspace;
|
var coords = MapCoordinates.Nullspace;
|
||||||
@@ -71,7 +74,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
user = sEntities.SpawnEntity(null, coords);
|
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);
|
target = sEntities.SpawnEntity(null, coords);
|
||||||
item = sEntities.SpawnEntity(null, coords);
|
item = sEntities.SpawnEntity(null, coords);
|
||||||
item.EnsureComponent<ItemComponent>();
|
item.EnsureComponent<ItemComponent>();
|
||||||
@@ -98,8 +102,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
Assert.That(interactHand);
|
Assert.That(interactHand);
|
||||||
|
|
||||||
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
|
Assert.That(handSys.TryPickup(user, item));
|
||||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
|
||||||
|
|
||||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||||
Assert.That(interactUsing);
|
Assert.That(interactUsing);
|
||||||
@@ -124,6 +127,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
|
|
||||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
var mapId = MapId.Nullspace;
|
var mapId = MapId.Nullspace;
|
||||||
var coords = MapCoordinates.Nullspace;
|
var coords = MapCoordinates.Nullspace;
|
||||||
@@ -142,7 +147,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
user = sEntities.SpawnEntity(null, coords);
|
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));
|
target = sEntities.SpawnEntity(null, new MapCoordinates((1.9f, 0), mapId));
|
||||||
item = sEntities.SpawnEntity(null, coords);
|
item = sEntities.SpawnEntity(null, coords);
|
||||||
item.EnsureComponent<ItemComponent>();
|
item.EnsureComponent<ItemComponent>();
|
||||||
@@ -170,8 +176,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
Assert.That(interactHand, Is.False);
|
Assert.That(interactHand, Is.False);
|
||||||
|
|
||||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
Assert.That(handSys.TryPickup(user, item));
|
||||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
|
||||||
|
|
||||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
@@ -195,6 +200,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
|
|
||||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
var mapId = MapId.Nullspace;
|
var mapId = MapId.Nullspace;
|
||||||
var coords = MapCoordinates.Nullspace;
|
var coords = MapCoordinates.Nullspace;
|
||||||
@@ -212,7 +219,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
user = sEntities.SpawnEntity(null, coords);
|
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));
|
target = sEntities.SpawnEntity(null, new MapCoordinates((InteractionSystem.InteractionRange - 0.1f, 0), mapId));
|
||||||
item = sEntities.SpawnEntity(null, coords);
|
item = sEntities.SpawnEntity(null, coords);
|
||||||
item.EnsureComponent<ItemComponent>();
|
item.EnsureComponent<ItemComponent>();
|
||||||
@@ -239,8 +247,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
Assert.That(interactHand);
|
Assert.That(interactHand);
|
||||||
|
|
||||||
Assert.That(sEntities.TryGetComponent<HandsComponent>(user, out var hands));
|
Assert.That(handSys.TryPickup(user, item));
|
||||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
|
||||||
|
|
||||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||||
Assert.That(interactUsing);
|
Assert.That(interactUsing);
|
||||||
@@ -265,6 +272,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
|
|
||||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
var mapId = MapId.Nullspace;
|
var mapId = MapId.Nullspace;
|
||||||
var coords = MapCoordinates.Nullspace;
|
var coords = MapCoordinates.Nullspace;
|
||||||
@@ -282,7 +291,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
user = sEntities.SpawnEntity(null, coords);
|
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));
|
target = sEntities.SpawnEntity(null, new MapCoordinates((SharedInteractionSystem.InteractionRange + 0.01f, 0), mapId));
|
||||||
item = sEntities.SpawnEntity(null, coords);
|
item = sEntities.SpawnEntity(null, coords);
|
||||||
item.EnsureComponent<ItemComponent>();
|
item.EnsureComponent<ItemComponent>();
|
||||||
@@ -309,8 +319,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
Assert.That(interactHand, Is.False);
|
Assert.That(interactHand, Is.False);
|
||||||
|
|
||||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
Assert.That(handSys.TryPickup(user, item));
|
||||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
|
||||||
|
|
||||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
@@ -335,6 +344,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
|
|
||||||
var sEntities = server.ResolveDependency<IEntityManager>();
|
var sEntities = server.ResolveDependency<IEntityManager>();
|
||||||
var mapManager = server.ResolveDependency<IMapManager>();
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var sysMan = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var handSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
var mapId = MapId.Nullspace;
|
var mapId = MapId.Nullspace;
|
||||||
var coords = MapCoordinates.Nullspace;
|
var coords = MapCoordinates.Nullspace;
|
||||||
@@ -354,7 +365,8 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
server.Assert(() =>
|
server.Assert(() =>
|
||||||
{
|
{
|
||||||
user = sEntities.SpawnEntity(null, coords);
|
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);
|
target = sEntities.SpawnEntity(null, coords);
|
||||||
item = sEntities.SpawnEntity(null, coords);
|
item = sEntities.SpawnEntity(null, coords);
|
||||||
item.EnsureComponent<ItemComponent>();
|
item.EnsureComponent<ItemComponent>();
|
||||||
@@ -394,8 +406,7 @@ namespace Content.IntegrationTests.Tests.Interaction.Click
|
|||||||
Assert.That(interactUsing, Is.False);
|
Assert.That(interactUsing, Is.False);
|
||||||
Assert.That(interactHand);
|
Assert.That(interactHand);
|
||||||
|
|
||||||
Assert.That(sEntities.TryGetComponent<HandsComponent?>(user, out var hands));
|
Assert.That(handSys.TryPickup(user, item));
|
||||||
Assert.That(hands.PutInHand(sEntities.GetComponent<SharedItemComponent>(item)));
|
|
||||||
|
|
||||||
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
interactionSystem.UserInteraction(user, sEntities.GetComponent<TransformComponent>(target).Coordinates, target);
|
||||||
Assert.That(interactUsing, Is.False);
|
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;
|
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;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
var meleeWeapon = hands.GetActiveHandItem.Owner;
|
var meleeWeapon = hands.ActiveHandEntity;
|
||||||
_entMan.TryGetComponent(meleeWeapon, out MeleeWeaponComponent? meleeWeaponComponent);
|
_entMan.TryGetComponent(meleeWeapon, out MeleeWeaponComponent? meleeWeaponComponent);
|
||||||
|
|
||||||
if ((_entMan.GetComponent<TransformComponent>(_target).Coordinates.Position - _entMan.GetComponent<TransformComponent>(_owner).Coordinates.Position).Length >
|
if ((_entMan.GetComponent<TransformComponent>(_target).Coordinates.Position - _entMan.GetComponent<TransformComponent>(_owner).Coordinates.Position).Length >
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.Operators.Inventory
|
namespace Content.Server.AI.Operators.Inventory
|
||||||
{
|
{
|
||||||
@@ -21,12 +20,7 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override Outcome Execute(float frameTime)
|
public override Outcome Execute(float frameTime)
|
||||||
{
|
{
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(_owner, out HandsComponent? handsComponent))
|
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().TryDrop(_owner, _entity) ? Outcome.Success : Outcome.Failed;
|
||||||
{
|
|
||||||
return Outcome.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handsComponent.Drop(_entity) ? Outcome.Success : Outcome.Failed;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.Operators.Inventory
|
namespace Content.Server.AI.Operators.Inventory
|
||||||
{
|
{
|
||||||
@@ -20,9 +19,12 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
return Outcome.Failed;
|
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;
|
return Outcome.Success;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
@@ -16,19 +17,12 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
|
|
||||||
public override Outcome Execute(float frameTime)
|
public override Outcome Execute(float frameTime)
|
||||||
{
|
{
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(_owner, out HandsComponent? handsComponent))
|
var sys = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>();
|
||||||
{
|
|
||||||
return Outcome.Failed;
|
|
||||||
}
|
|
||||||
// TODO: If in clothing then click on it
|
// TODO: If in clothing then click on it
|
||||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
|
||||||
{
|
if (sys.TrySelect(_owner, _entity))
|
||||||
if (handsComponent.GetItem(hand)?.Owner == _entity)
|
return Outcome.Success;
|
||||||
{
|
|
||||||
handsComponent.ActiveHand = hand;
|
|
||||||
return Outcome.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Get free hand count; if no hands free then fail right here
|
// 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.Hands.Components;
|
||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
@@ -24,42 +25,22 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
public override Outcome Execute(float frameTime)
|
public override Outcome Execute(float frameTime)
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||||
|
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||||
|
var interactionSystem = sysMan.GetEntitySystem<InteractionSystem>();
|
||||||
|
var handsSys = sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
if (entMan.Deleted(_target)
|
if (entMan.Deleted(_target)
|
||||||
|| !entMan.HasComponent<SharedItemComponent>(_target)
|
|| !entMan.HasComponent<SharedItemComponent>(_target)
|
||||||
|| _target.IsInContainer()
|
|| _target.IsInContainer()
|
||||||
|| !EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(_owner, _target, popup: true))
|
|| !interactionSystem.InRangeUnobstructed(_owner, _target, popup: true))
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entMan.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
// select empty hand
|
||||||
{
|
if (!handsSys.TrySelectEmptyHand(_owner))
|
||||||
return Outcome.Failed;
|
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);
|
interactionSystem.InteractHand(_owner, _target);
|
||||||
return Outcome.Success;
|
return Outcome.Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -22,27 +23,18 @@ namespace Content.Server.AI.Operators.Inventory
|
|||||||
public override Outcome Execute(float frameTime)
|
public override Outcome Execute(float frameTime)
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
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.
|
// 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;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entMan.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
return Outcome.Success;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.AI.Operators.Nutrition
|
namespace Content.Server.AI.Operators.Nutrition
|
||||||
@@ -30,35 +28,23 @@ namespace Content.Server.AI.Operators.Nutrition
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entities = IoCManager.Resolve<IEntityManager>();
|
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.
|
// TODO: Also have this check storage a la backpack etc.
|
||||||
if (entities.Deleted(_target) ||
|
if (entities.Deleted(_target) ||
|
||||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
|
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||||
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrinkComponent? drinkComponent = null;
|
if (!handsSys.TrySelect<DrinkComponent>(_owner, out var drinkComponent, handsComponent))
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
return Outcome.Failed;
|
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)
|
if (drinkComponent.Deleted || EntitySystem.Get<DrinkSystem>().IsEmpty(drinkComponent.Owner, drinkComponent)
|
||||||
|| entities.TryGetComponent(_owner, out ThirstComponent? thirstComponent) &&
|
|| entities.TryGetComponent(_owner, out ThirstComponent? thirstComponent) &&
|
||||||
@@ -67,6 +53,7 @@ namespace Content.Server.AI.Operators.Nutrition
|
|||||||
return Outcome.Success;
|
return Outcome.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// uuhhh do afters for drinks might mess this up?
|
||||||
return Outcome.Continuing;
|
return Outcome.Continuing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -29,35 +30,21 @@ namespace Content.Server.AI.Operators.Nutrition
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entities = IoCManager.Resolve<IEntityManager>();
|
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.
|
// TODO: Also have this check storage a la backpack etc.
|
||||||
if (entities.Deleted(_target) ||
|
if (entities.Deleted(_target) ||
|
||||||
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent) ||
|
!entities.TryGetComponent(_owner, out HandsComponent? handsComponent))
|
||||||
!entities.TryGetComponent(_target, out SharedItemComponent? itemComponent))
|
|
||||||
{
|
{
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
FoodComponent? foodComponent = null;
|
if (!handsSys.TrySelect<FoodComponent>(_owner, out var foodComponent, handsComponent))
|
||||||
|
return Outcome.Failed;
|
||||||
foreach (var slot in handsComponent.ActivePriorityEnumerable())
|
|
||||||
{
|
if (!handsSys.TryUseItemInHand(_owner, false, handsComponent))
|
||||||
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)
|
|
||||||
{
|
|
||||||
return Outcome.Failed;
|
return Outcome.Failed;
|
||||||
}
|
|
||||||
|
|
||||||
if ((!entities.EntityExists(_target) ? EntityLifeStage.Deleted : entities.GetComponent<MetaDataComponent>(_target).EntityLifeStage) >= EntityLifeStage.Deleted ||
|
if ((!entities.EntityExists(_target) ? EntityLifeStage.Deleted : entities.GetComponent<MetaDataComponent>(_target).EntityLifeStage) >= EntityLifeStage.Deleted ||
|
||||||
foodComponent.UsesRemaining == 0 ||
|
foodComponent.UsesRemaining == 0 ||
|
||||||
@@ -67,6 +54,7 @@ namespace Content.Server.AI.Operators.Nutrition
|
|||||||
return Outcome.Success;
|
return Outcome.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// do afters for food might mess this up?
|
||||||
return Outcome.Continuing;
|
return Outcome.Continuing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using Content.Server.AI.WorldState;
|
using Content.Server.AI.WorldState;
|
||||||
using Content.Server.AI.WorldState.States;
|
using Content.Server.AI.WorldState.States;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using System.Linq;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.Utility.Considerations.Hands
|
namespace Content.Server.AI.Utility.Considerations.Hands
|
||||||
{
|
{
|
||||||
@@ -12,24 +11,12 @@ namespace Content.Server.AI.Utility.Considerations.Hands
|
|||||||
{
|
{
|
||||||
var owner = context.GetState<SelfState>().GetValue();
|
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;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
var handCount = 0;
|
return (float) handsComponent.CountFreeHands() / handsComponent.Count;
|
||||||
var freeCount = 0;
|
|
||||||
|
|
||||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
|
||||||
{
|
|
||||||
handCount++;
|
|
||||||
if (handsComponent.GetItem(hand) == null)
|
|
||||||
{
|
|
||||||
freeCount += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (float) freeCount / handCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -11,20 +12,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
|||||||
public override string Name => "AnyFreeHand";
|
public override string Name => "AnyFreeHand";
|
||||||
public override bool GetValue()
|
public override bool GetValue()
|
||||||
{
|
{
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out HandsComponent? handsComponent))
|
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().TryGetEmptyHand(Owner, out _);
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
|
||||||
{
|
|
||||||
if (handsComponent.GetItem(hand) == null)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.WorldState.States.Hands
|
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))
|
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out HandsComponent? handsComponent))
|
||||||
{
|
{
|
||||||
return result;
|
return new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
return handsComponent.GetFreeHandNames().ToList();
|
||||||
{
|
|
||||||
if (handsComponent.GetItem(hand) == null)
|
|
||||||
{
|
|
||||||
result.Add(hand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.WorldState.States.Hands
|
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 string Name => "HandItems";
|
||||||
public override List<EntityUid> GetValue()
|
public override List<EntityUid> GetValue()
|
||||||
{
|
{
|
||||||
var result = new List<EntityUid>();
|
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().EnumerateHeld(Owner).ToList();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Content.Server.AI.WorldState.States.Inventory
|
|||||||
|
|
||||||
public override EntityUid? GetValue()
|
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.Shared.Hands.EntitySystems;
|
||||||
using Content.Server.Hands.Components;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.AI.WorldState.States.Inventory
|
namespace Content.Server.AI.WorldState.States.Inventory
|
||||||
{
|
{
|
||||||
@@ -13,17 +10,7 @@ namespace Content.Server.AI.WorldState.States.Inventory
|
|||||||
|
|
||||||
public override IEnumerable<EntityUid> GetValue()
|
public override IEnumerable<EntityUid> GetValue()
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
return IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SharedHandsSystem>().EnumerateHeld(Owner);
|
||||||
if (entMan.TryGetComponent(Owner, out HandsComponent? handsComponent))
|
|
||||||
{
|
|
||||||
foreach (var item in handsComponent.GetAllHeldItems())
|
|
||||||
{
|
|
||||||
if (entMan.Deleted(item.Owner))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
yield return item.Owner;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Content.Server.Power.Components;
|
|||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.AME;
|
using Content.Shared.AME;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -23,6 +24,7 @@ namespace Content.Server.AME.Components
|
|||||||
public sealed class AMEControllerComponent : SharedAMEControllerComponent, IInteractUsing
|
public sealed class AMEControllerComponent : SharedAMEControllerComponent, IInteractUsing
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
|
||||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(AMEControllerUiKey.Key);
|
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(AMEControllerUiKey.Key);
|
||||||
private bool _injecting;
|
private bool _injecting;
|
||||||
@@ -210,10 +212,7 @@ namespace Content.Server.AME.Components
|
|||||||
_jarSlot.Remove(jar);
|
_jarSlot.Remove(jar);
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
|
|
||||||
if (!_entities.TryGetComponent<HandsComponent?>(user, out var hands) || !_entities.TryGetComponent<SharedItemComponent?>(jar, out var item))
|
_sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(user, jar);
|
||||||
return;
|
|
||||||
if (hands.CanPutInHand(item))
|
|
||||||
hands.PutInHand(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleInjection()
|
private void ToggleInjection()
|
||||||
@@ -306,13 +305,13 @@ namespace Content.Server.AME.Components
|
|||||||
return true;
|
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"));
|
Owner.PopupMessage(args.User, Loc.GetString("ame-controller-component-interact-using-nothing-in-hands-text"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var activeHandEntity = hands.GetActiveHandItem.Owner;
|
var activeHandEntity = hands.ActiveHandEntity;
|
||||||
if (_entities.HasComponent<AMEFuelContainerComponent?>(activeHandEntity))
|
if (_entities.HasComponent<AMEFuelContainerComponent?>(activeHandEntity))
|
||||||
{
|
{
|
||||||
if (HasJar)
|
if (HasJar)
|
||||||
@@ -322,7 +321,7 @@ namespace Content.Server.AME.Components
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_jarSlot.Insert(activeHandEntity);
|
_jarSlot.Insert(activeHandEntity.Value);
|
||||||
Owner.PopupMessage(args.User, Loc.GetString("ame-controller-component-interact-using-success"));
|
Owner.PopupMessage(args.User, Loc.GetString("ame-controller-component-interact-using-success"));
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ namespace Content.Server.Access.Systems
|
|||||||
{
|
{
|
||||||
// check held item?
|
// check held item?
|
||||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands) &&
|
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands) &&
|
||||||
hands.TryGetActiveHeldEntity(out var heldItem) &&
|
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||||
TryGetIdCard(heldItem.Value, out idCard))
|
TryGetIdCard(heldItem, out idCard))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ namespace Content.Server.Atmos.Components
|
|||||||
if (!_entities.TryGetComponent(playerEntity, out HandsComponent? handsComponent))
|
if (!_entities.TryGetComponent(playerEntity, out HandsComponent? handsComponent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (handsComponent?.GetActiveHandItem?.Owner is not {Valid: true} activeHandEntity ||
|
if (handsComponent?.ActiveHandEntity is not {Valid: true} activeHandEntity ||
|
||||||
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -228,7 +228,7 @@ namespace Content.Server.Atmos.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handsComponent.GetActiveHandItem?.Owner is not {Valid: true} activeHandEntity ||
|
if (handsComponent.ActiveHandEntity is not {Valid: true} activeHandEntity ||
|
||||||
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
!_entities.TryGetComponent(activeHandEntity, out GasAnalyzerComponent? gasAnalyzer))
|
||||||
{
|
{
|
||||||
serverMsg.Session.AttachedEntity.Value.PopupMessage(Loc.GetString("gas-analyzer-component-need-gas-analyzer-in-hand-message"));
|
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.Administration.Logs;
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
@@ -8,19 +7,14 @@ using Content.Server.Hands.Components;
|
|||||||
using Content.Server.NodeContainer;
|
using Content.Server.NodeContainer;
|
||||||
using Content.Server.NodeContainer.NodeGroups;
|
using Content.Server.NodeContainer.NodeGroups;
|
||||||
using Content.Server.NodeContainer.Nodes;
|
using Content.Server.NodeContainer.Nodes;
|
||||||
using Content.Shared.ActionBlocker;
|
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Containers;
|
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
|
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 UserInterfaceSystem _userInterfaceSystem = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
[Dependency] private readonly AdminLogSystem _adminLogSystem = default!;
|
[Dependency] private readonly AdminLogSystem _adminLogSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -248,11 +243,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
|||||||
if (!EntityManager.TryGetComponent(args.Used, out GasTankComponent? _))
|
if (!EntityManager.TryGetComponent(args.Used, out GasTankComponent? _))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check the user has hands.
|
if (!_handsSystem.TryDropIntoContainer(args.User, args.Used, container))
|
||||||
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!hands.Drop(args.Used, container))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_adminLogSystem.Add(LogType.CanisterTankInserted, LogImpact.Medium, $"Player {ToPrettyString(args.User):player} inserted tank {ToPrettyString(container.ContainedEntities[0]):tank} into {ToPrettyString(canister):canister}");
|
_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 (_entMan.TryGetComponent(user, out HandsComponent? hands))
|
||||||
{
|
{
|
||||||
if (!botanySystem.CanHarvest(Seed, hands.GetActiveHandItem?.Owner))
|
if (!botanySystem.CanHarvest(Seed, hands.ActiveHandEntity))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!botanySystem.CanHarvest(Seed))
|
else if (!botanySystem.CanHarvest(Seed))
|
||||||
|
|||||||
@@ -89,9 +89,9 @@ namespace Content.Server.Chat.Commands
|
|||||||
|
|
||||||
// Held item suicide
|
// Held item suicide
|
||||||
if (_entities.TryGetComponent(owner, out HandsComponent handsComponent)
|
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)
|
if (suicide != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Hands.Components;
|
|
||||||
using Content.Server.Labels.Components;
|
using Content.Server.Labels.Components;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Random.Helpers;
|
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -28,6 +26,7 @@ namespace Content.Server.Chemistry.Components
|
|||||||
public sealed class ChemMasterComponent : SharedChemMasterComponent
|
public sealed class ChemMasterComponent : SharedChemMasterComponent
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private uint _pillType = 1;
|
private uint _pillType = 1;
|
||||||
@@ -276,6 +275,9 @@ namespace Content.Server.Chemistry.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
var solSys = _sysMan.GetEntitySystem<SolutionContainerSystem>();
|
||||||
|
|
||||||
if (action == UiAction.CreateBottles)
|
if (action == UiAction.CreateBottles)
|
||||||
{
|
{
|
||||||
var individualVolume = BufferSolution.TotalVolume / FixedPoint2.New(bottleAmount);
|
var individualVolume = BufferSolution.TotalVolume / FixedPoint2.New(bottleAmount);
|
||||||
@@ -298,25 +300,12 @@ namespace Content.Server.Chemistry.Components
|
|||||||
labelComponent.CurrentLabel = label;
|
labelComponent.CurrentLabel = label;
|
||||||
|
|
||||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
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
|
//Try to give them the bottle
|
||||||
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
|
handSys.PickupOrDrop(user, bottle);
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //Pills
|
else //Pills
|
||||||
@@ -342,7 +331,7 @@ namespace Content.Server.Chemistry.Components
|
|||||||
|
|
||||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
||||||
var pillSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(pill, "food");
|
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
|
//Change pill Sprite component state
|
||||||
if (!_entities.TryGetComponent(pill, out SpriteComponent? sprite))
|
if (!_entities.TryGetComponent(pill, out SpriteComponent? sprite))
|
||||||
@@ -352,20 +341,7 @@ namespace Content.Server.Chemistry.Components
|
|||||||
sprite?.LayerSetState(0, "pill" + _pillType);
|
sprite?.LayerSetState(0, "pill" + _pillType);
|
||||||
|
|
||||||
//Try to give them the bottle
|
//Try to give them the bottle
|
||||||
if (_entities.TryGetComponent<HandsComponent?>(user, out var hands) &&
|
handSys.PickupOrDrop(user, pill);
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
using System;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Content.Server.Access.Systems;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.PDA;
|
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.Communications;
|
using Content.Shared.Communications;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
using Timer = Robust.Shared.Timing.Timer;
|
using Timer = Robust.Shared.Timing.Timer;
|
||||||
|
|
||||||
namespace Content.Server.Communications
|
namespace Content.Server.Communications
|
||||||
@@ -23,6 +19,7 @@ namespace Content.Server.Communications
|
|||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
|
||||||
private bool Powered => !_entities.TryGetComponent(Owner, out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
private bool Powered => !_entities.TryGetComponent(Owner, out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||||
|
|
||||||
@@ -101,9 +98,10 @@ namespace Content.Server.Communications
|
|||||||
UpdateBoundInterface();
|
UpdateBoundInterface();
|
||||||
|
|
||||||
var message = msg.Message.Length <= 256 ? msg.Message.Trim() : $"{msg.Message.Trim().Substring(0, 256)}...";
|
var message = msg.Message.Length <= 256 ? msg.Message.Trim() : $"{msg.Message.Trim().Substring(0, 256)}...";
|
||||||
|
var sys = _sysMan.GetEntitySystem<IdCardSystem>();
|
||||||
|
|
||||||
var author = "Unknown";
|
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();
|
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.Prototypes;
|
||||||
using Content.Shared.Construction.Steps;
|
using Content.Shared.Construction.Steps;
|
||||||
using Content.Shared.Coordinates;
|
using Content.Shared.Coordinates;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -25,6 +26,7 @@ namespace Content.Server.Construction
|
|||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
// --- WARNING! LEGACY CODE AHEAD! ---
|
// --- WARNING! LEGACY CODE AHEAD! ---
|
||||||
// This entire file contains the legacy code for initial construction.
|
// 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!
|
// LEGACY CODE. See warning at the top of the file!
|
||||||
private IEnumerable<EntityUid> EnumerateNearby(EntityUid user)
|
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))
|
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)
|
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!
|
// LEGACY CODE. See warning at the top of the file!
|
||||||
@@ -401,7 +400,7 @@ namespace Content.Server.Construction
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!_actionBlocker.CanInteract(user, null)
|
if (!_actionBlocker.CanInteract(user, null)
|
||||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.GetActiveHandItem == null)
|
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.ActiveHandEntity == null)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
return;
|
return;
|
||||||
@@ -426,7 +425,7 @@ namespace Content.Server.Construction
|
|||||||
|
|
||||||
var valid = false;
|
var valid = false;
|
||||||
|
|
||||||
if (hands.GetActiveHandItem?.Owner is not {Valid: true} holding)
|
if (hands.ActiveHandEntity is not {Valid: true} holding)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Server.DoAfter;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Cuffs.Components;
|
using Content.Shared.Cuffs.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -26,6 +27,7 @@ namespace Content.Server.Cuffs.Components
|
|||||||
public sealed class CuffableComponent : SharedCuffableComponent
|
public sealed class CuffableComponent : SharedCuffableComponent
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many of this entity's hands are currently cuffed.
|
/// How many of this entity's hands are currently cuffed.
|
||||||
@@ -103,15 +105,13 @@ namespace Content.Server.Cuffs.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
// Success!
|
// Success!
|
||||||
if (_entMan.TryGetComponent(user, out HandsComponent? handsComponent) && handsComponent.IsHolding(handcuff))
|
sys.TryDrop(user, handcuff);
|
||||||
{
|
|
||||||
// Good lord handscomponent is scuffed, I hope some smug person will fix it someday
|
|
||||||
handsComponent.Drop(handcuff);
|
|
||||||
}
|
|
||||||
|
|
||||||
Container.Insert(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();
|
OnCuffedStateChanged?.Invoke();
|
||||||
UpdateAlert();
|
UpdateAlert();
|
||||||
@@ -133,23 +133,22 @@ namespace Content.Server.Cuffs.Components
|
|||||||
{
|
{
|
||||||
if (!_entMan.TryGetComponent(Owner, out HandsComponent? handsComponent)) return;
|
if (!_entMan.TryGetComponent(Owner, out HandsComponent? handsComponent)) return;
|
||||||
|
|
||||||
var itemCount = handsComponent.GetAllHeldItems().Count();
|
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
var freeHandCount = handsComponent.HandNames.Count() - CuffedHandCount;
|
|
||||||
|
|
||||||
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--;
|
||||||
{
|
continue;
|
||||||
freeHandCount++;
|
|
||||||
handsComponent.Drop(item.Owner, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
OnCuffedStateChanged?.Invoke();
|
||||||
UpdateAlert();
|
UpdateAlert();
|
||||||
Dirty();
|
Dirty();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Content.Server.Cuffs.Components;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Cuffs;
|
using Content.Shared.Cuffs;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Verbs;
|
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));
|
SoundSystem.Play(Filter.Pvs(Owner), _clickSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnRemove()
|
protected override void OnRemove()
|
||||||
{
|
{
|
||||||
base.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.UserInterface;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Movement;
|
using Content.Shared.Movement;
|
||||||
@@ -81,7 +81,7 @@ namespace Content.Server.Disposal.Tube
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var activeHandEntity = hands.GetActiveHandItem?.Owner;
|
var activeHandEntity = hands.ActiveHandEntity;
|
||||||
if (activeHandEntity != null)
|
if (activeHandEntity != null)
|
||||||
{
|
{
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
@@ -96,7 +96,7 @@ namespace Content.Server.Disposal.Tube
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var activeHandEntity = hands.GetActiveHandItem?.Owner;
|
var activeHandEntity = hands.ActiveHandEntity;
|
||||||
if (activeHandEntity != null)
|
if (activeHandEntity != null)
|
||||||
{
|
{
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
|
|||||||
@@ -16,21 +16,16 @@ using Content.Shared.Atmos;
|
|||||||
using Content.Shared.Disposal;
|
using Content.Shared.Disposal;
|
||||||
using Content.Shared.Disposal.Components;
|
using Content.Shared.Disposal.Components;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Movement;
|
using Content.Shared.Movement;
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
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.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
@@ -43,6 +38,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
|
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
|
||||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private readonly List<DisposalUnitComponent> _activeDisposals = new();
|
private readonly List<DisposalUnitComponent> _activeDisposals = new();
|
||||||
|
|
||||||
@@ -140,7 +136,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
Category = VerbCategory.Insert,
|
Category = VerbCategory.Insert,
|
||||||
Act = () =>
|
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);
|
AfterInsert(component, args.Using.Value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -248,8 +244,8 @@ namespace Content.Server.Disposal.Unit.EntitySystems
|
|||||||
{
|
{
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
@@ -30,7 +30,7 @@ namespace Content.Server.DoAfter
|
|||||||
|
|
||||||
// NeedHand
|
// NeedHand
|
||||||
private readonly string? _activeHand;
|
private readonly string? _activeHand;
|
||||||
private readonly SharedItemComponent? _activeItem;
|
private readonly EntityUid? _activeItem;
|
||||||
|
|
||||||
public DoAfter(DoAfterEventArgs eventArgs, IEntityManager entityManager)
|
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).
|
// (or if there is no item there we need to keep it free).
|
||||||
if (eventArgs.NeedHand && entityManager.TryGetComponent(eventArgs.User, out HandsComponent? handsComponent))
|
if (eventArgs.NeedHand && entityManager.TryGetComponent(eventArgs.User, out HandsComponent? handsComponent))
|
||||||
{
|
{
|
||||||
_activeHand = handsComponent.ActiveHand;
|
_activeHand = handsComponent.ActiveHand?.Name;
|
||||||
_activeItem = handsComponent.GetActiveHandItem;
|
_activeItem = handsComponent.ActiveHandEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tcs = new TaskCompletionSource<DoAfterStatus>();
|
Tcs = new TaskCompletionSource<DoAfterStatus>();
|
||||||
@@ -152,13 +152,13 @@ namespace Content.Server.DoAfter
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var currentActiveHand = handsComponent.ActiveHand;
|
var currentActiveHand = handsComponent.ActiveHand?.Name;
|
||||||
if (_activeHand != currentActiveHand)
|
if (_activeHand != currentActiveHand)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentItem = handsComponent.GetActiveHandItem;
|
var currentItem = handsComponent.ActiveHandEntity;
|
||||||
if (_activeItem != currentItem)
|
if (_activeItem != currentItem)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using Content.Server.Ghost.Roles.Components;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Drone
|
namespace Content.Server.Drone
|
||||||
@@ -28,6 +29,7 @@ namespace Content.Server.Drone
|
|||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = 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)
|
if (TryComp<HandsComponent>(uid, out var hands) && hands.Count >= drone.Tools.Count)
|
||||||
{
|
{
|
||||||
foreach (var entry in drone.Tools)
|
foreach (var entry in drone.Tools)
|
||||||
{
|
{
|
||||||
var item = EntityManager.SpawnEntity(entry.PrototypeId, spawnCoord);
|
var item = EntityManager.SpawnEntity(entry.PrototypeId, spawnCoord);
|
||||||
AddComp<UnremoveableComponent>(item);
|
AddComp<UnremoveableComponent>(item);
|
||||||
hands.PutInHand(item);
|
if (!_handsSystem.TryPickupAnyHand(uid, item, checkActionBlocker: false))
|
||||||
drone.ToolUids.Add(item);
|
{
|
||||||
}
|
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))
|
if (TryComp<ActionsComponent>(uid, out var actions) && TryComp<UnpoweredFlashlightComponent>(uid, out var flashlight))
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Engineering.Components;
|
using Content.Server.Engineering.Components;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Helpers;
|
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@@ -11,6 +10,8 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class DisassembleOnAltVerbSystem : EntitySystem
|
public sealed class DisassembleOnAltVerbSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -63,11 +64,7 @@ namespace Content.Server.Engineering.EntitySystems
|
|||||||
|
|
||||||
var entity = EntityManager.SpawnEntity(component.Prototype, transformComp.Coordinates);
|
var entity = EntityManager.SpawnEntity(component.Prototype, transformComp.Coordinates);
|
||||||
|
|
||||||
if (TryComp<HandsComponent?>(user, out var hands)
|
_handsSystem.TryPickup(user, entity);
|
||||||
&& TryComp<SharedItemComponent?>(entity, out var item))
|
|
||||||
{
|
|
||||||
hands.PutInHandOrDrop(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityManager.DeleteEntity(component.Owner);
|
EntityManager.DeleteEntity(component.Owner);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Content.Shared.Access.Components;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Ghost;
|
using Content.Shared.Ghost;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
@@ -33,6 +34,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
[Dependency] private readonly IdCardSystem _cardSystem = default!;
|
[Dependency] private readonly IdCardSystem _cardSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can't yet be removed because every test ever seems to depend on it. I'll make removing this a different PR.
|
/// 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;
|
var inhandEntity = EntityManager.SpawnEntity(prototype, coords);
|
||||||
foreach (var (hand, prototype) in inhand)
|
_handsSystem.TryPickup(entity, inhandEntity, hand, checkActionBlocker: false, handsComp: handsComponent);
|
||||||
{
|
|
||||||
var inhandEntity = EntityManager.SpawnEntity(prototype, EntityManager.GetComponent<TransformComponent>(entity).Coordinates);
|
|
||||||
handsComponent.TryPickupEntity(hand, inhandEntity, checkActionBlocker: false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Shared.Actions;
|
|||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.MobState;
|
using Content.Shared.MobState;
|
||||||
@@ -25,6 +26,7 @@ namespace Content.Server.Guardian
|
|||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageSystem = default!;
|
[Dependency] private readonly DamageableSystem _damageSystem = default!;
|
||||||
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
|
[Dependency] private readonly SharedActionsSystem _actionSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -180,8 +182,7 @@ namespace Content.Server.Guardian
|
|||||||
|
|
||||||
if (comp.Deleted ||
|
if (comp.Deleted ||
|
||||||
comp.Used ||
|
comp.Used ||
|
||||||
!TryComp<HandsComponent>(ev.User, out var hands) ||
|
!_handsSystem.IsHolding(ev.User, comp.Owner, out _) ||
|
||||||
!hands.IsHolding(comp.Owner) ||
|
|
||||||
HasComp<GuardianHostComponent>(ev.Target))
|
HasComp<GuardianHostComponent>(ev.Target))
|
||||||
{
|
{
|
||||||
comp.Injecting = false;
|
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.Body.Part;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Pulling.Components;
|
|
||||||
using Content.Shared.Sound;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Hands.Components
|
namespace Content.Server.Hands.Components
|
||||||
{
|
{
|
||||||
@@ -24,9 +11,6 @@ namespace Content.Server.Hands.Components
|
|||||||
#pragma warning restore 618
|
#pragma warning restore 618
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
|
||||||
|
|
||||||
#region Pull/Disarm
|
|
||||||
|
|
||||||
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs args)
|
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs args)
|
||||||
{
|
{
|
||||||
@@ -43,7 +27,7 @@ namespace Content.Server.Hands.Components
|
|||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
|
|
||||||
AddHand(args.Slot, location);
|
_entitySystemManager.GetEntitySystem<SharedHandsSystem>().AddHand(Owner, args.Slot, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBodyPartRemoved.BodyPartRemoved(BodyPartRemovedEventArgs args)
|
void IBodyPartRemoved.BodyPartRemoved(BodyPartRemovedEventArgs args)
|
||||||
@@ -51,94 +35,8 @@ namespace Content.Server.Hands.Components
|
|||||||
if (args.Part.PartType != BodyPartType.Hand)
|
if (args.Part.PartType != BodyPartType.Hand)
|
||||||
return;
|
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.Server.Hands.Components;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.Hands.Systems
|
namespace Content.Server.Hands.Systems
|
||||||
{
|
{
|
||||||
@@ -14,24 +13,15 @@ namespace Content.Server.Hands.Systems
|
|||||||
|
|
||||||
public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user)
|
public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent<HandsComponent>(user, out var hands))
|
if (!_handsSystem.TryGetEmptyHand(user, out var hand))
|
||||||
{
|
return false;
|
||||||
foreach (var handName in hands.ActivePriorityEnumerable())
|
|
||||||
{
|
|
||||||
var hand = hands.GetHand(handName);
|
|
||||||
if (hand.HeldEntity != null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var pos = EntityManager.GetComponent<TransformComponent>(hands.Owner).Coordinates;
|
var pos = EntityManager.GetComponent<TransformComponent>(user).Coordinates;
|
||||||
var virtualItem = EntityManager.SpawnEntity("HandVirtualItem", pos);
|
var virtualItem = EntityManager.SpawnEntity("HandVirtualItem", pos);
|
||||||
var virtualItemComp = EntityManager.GetComponent<HandVirtualItemComponent>(virtualItem);
|
var virtualItemComp = EntityManager.GetComponent<HandVirtualItemComponent>(virtualItem);
|
||||||
virtualItemComp.BlockingEntity = blockingEnt;
|
virtualItemComp.BlockingEntity = blockingEnt;
|
||||||
_handsSystem.PutEntityIntoHand(user, hand, virtualItem, hands);
|
_handsSystem.DoPickup(user, hand, virtualItem);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,20 +30,12 @@ namespace Content.Server.Hands.Systems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void DeleteInHandsMatching(EntityUid user, EntityUid matching)
|
public void DeleteInHandsMatching(EntityUid user, EntityUid matching)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent<HandsComponent>(user, out var hands))
|
foreach (var hand in _handsSystem.EnumerateHands(user))
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var handName in hands.ActivePriorityEnumerable())
|
|
||||||
{
|
{
|
||||||
var hand = hands.GetHand(handName);
|
if (TryComp(hand.HeldEntity, out HandVirtualItemComponent? virt) && virt.BlockingEntity == matching)
|
||||||
|
|
||||||
if (!(hand.HeldEntity is { } heldEntity))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent<HandVirtualItemComponent>(heldEntity, out var virt)
|
|
||||||
&& virt.BlockingEntity == matching)
|
|
||||||
{
|
{
|
||||||
Delete(virt, user);
|
Delete(virt, user);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ using Content.Shared.Popups;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
@@ -29,6 +28,9 @@ using Robust.Shared.Map;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Server.Pulling;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
|
||||||
namespace Content.Server.Hands.Systems
|
namespace Content.Server.Hands.Systems
|
||||||
{
|
{
|
||||||
@@ -43,27 +45,24 @@ namespace Content.Server.Hands.Systems
|
|||||||
[Dependency] private readonly StrippableSystem _strippableSystem = default!;
|
[Dependency] private readonly StrippableSystem _strippableSystem = default!;
|
||||||
[Dependency] private readonly SharedHandVirtualItemSystem _virtualSystem = default!;
|
[Dependency] private readonly SharedHandVirtualItemSystem _virtualSystem = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
[Dependency] private readonly PullingSystem _pullingSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.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, DisarmedEvent>(OnDisarmed, before: new[] { typeof(StunSystem) });
|
||||||
|
|
||||||
SubscribeLocalEvent<HandsComponent, PullAttemptMessage>(HandlePullAttempt);
|
SubscribeLocalEvent<HandsComponent, PullAttemptMessage>(HandlePullAttempt);
|
||||||
SubscribeLocalEvent<HandsComponent, PullStartedMessage>(HandlePullStarted);
|
SubscribeLocalEvent<HandsComponent, PullStartedMessage>(HandlePullStarted);
|
||||||
SubscribeLocalEvent<HandsComponent, PullStoppedMessage>(HandlePullStopped);
|
SubscribeLocalEvent<HandsComponent, PullStoppedMessage>(HandlePullStopped);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<HandsComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
||||||
|
|
||||||
SubscribeLocalEvent<HandsComponent, ComponentGetState>(GetComponentState);
|
SubscribeLocalEvent<HandsComponent, ComponentGetState>(GetComponentState);
|
||||||
|
|
||||||
CommandBinds.Builder
|
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.ThrowItemInHand, new PointerInputCmdHandler(HandleThrowItem))
|
||||||
.Bind(ContentKeyFunctions.SmartEquipBackpack, InputCmdHandler.FromDelegate(HandleSmartEquipBackpack))
|
.Bind(ContentKeyFunctions.SmartEquipBackpack, InputCmdHandler.FromDelegate(HandleSmartEquipBackpack))
|
||||||
.Bind(ContentKeyFunctions.SmartEquipBelt, InputCmdHandler.FromDelegate(HandleSmartEquipBelt))
|
.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)
|
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)
|
private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled || component.BreakPulls())
|
if (args.Handled)
|
||||||
return;
|
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;
|
return;
|
||||||
|
|
||||||
var targetName = Name(args.Target);
|
var targetName = Name(args.Target);
|
||||||
@@ -103,9 +106,9 @@ namespace Content.Server.Hands.Systems
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region EntityInsertRemove
|
#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.
|
// update gui of anyone stripping this entity.
|
||||||
_strippableSystem.SendUpdate(uid);
|
_strippableSystem.SendUpdate(uid);
|
||||||
@@ -114,9 +117,9 @@ namespace Content.Server.Hands.Systems
|
|||||||
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
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.
|
// update gui of anyone stripping this entity.
|
||||||
_strippableSystem.SendUpdate(uid);
|
_strippableSystem.SendUpdate(uid);
|
||||||
@@ -124,6 +127,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
_logSystem.Add(LogType.Pickup, LogImpact.Low, $"{uid} picked up {entity}");
|
_logSystem.Add(LogType.Pickup, LogImpact.Low, $"{uid} picked up {entity}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
public override void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||||
EntityUid? exclude)
|
EntityUid? exclude)
|
||||||
{
|
{
|
||||||
@@ -138,12 +142,10 @@ namespace Content.Server.Hands.Systems
|
|||||||
RaiseNetworkEvent(new PickupAnimationEvent(item, initialPosition, finalPosition), filter);
|
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))
|
if (!Deleted(args.Entity) && TryComp(args.Entity, out HandVirtualItemComponent? @virtual))
|
||||||
_virtualSystem.Delete(@virtual, uid);
|
_virtualSystem.Delete(@virtual, uid);
|
||||||
|
|
||||||
base.HandleContainerRemoved(uid, component, args);
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -154,11 +156,10 @@ namespace Content.Server.Hands.Systems
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Cancel pull if all hands full.
|
// Cancel pull if all hands full.
|
||||||
if (component.Hands.All(hand => !hand.IsEmpty))
|
if (!component.IsAnyHandFree())
|
||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args)
|
private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args)
|
||||||
{
|
{
|
||||||
if (args.Puller.Owner != uid)
|
if (args.Puller.Owner != uid)
|
||||||
@@ -177,7 +178,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
|
|
||||||
// Try find hand that is doing this pull.
|
// Try find hand that is doing this pull.
|
||||||
// and clear it.
|
// and clear it.
|
||||||
foreach (var hand in component.Hands)
|
foreach (var hand in component.Hands.Values)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity == null
|
if (hand.HeldEntity == null
|
||||||
|| !TryComp(hand.HeldEntity, out HandVirtualItemComponent? virtualItem)
|
|| !TryComp(hand.HeldEntity, out HandVirtualItemComponent? virtualItem)
|
||||||
@@ -191,34 +192,6 @@ namespace Content.Server.Hands.Systems
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region interactions
|
#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)
|
private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||||
{
|
{
|
||||||
if (session is not IPlayerSession playerSession)
|
if (session is not IPlayerSession playerSession)
|
||||||
@@ -228,20 +201,20 @@ namespace Content.Server.Hands.Systems
|
|||||||
!Exists(player) ||
|
!Exists(player) ||
|
||||||
player.IsInContainer() ||
|
player.IsInContainer() ||
|
||||||
!TryComp(player, out SharedHandsComponent? hands) ||
|
!TryComp(player, out SharedHandsComponent? hands) ||
|
||||||
!hands.TryGetActiveHeldEntity(out var throwEnt) ||
|
hands.ActiveHandEntity is not EntityUid throwEnt ||
|
||||||
!_actionBlockerSystem.CanThrow(player))
|
!_actionBlockerSystem.CanThrow(player))
|
||||||
return false;
|
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})
|
if (splitStack is not {Valid: true})
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
throwEnt = splitStack.Value;
|
throwEnt = splitStack.Value;
|
||||||
}
|
}
|
||||||
else if (!hands.Drop(throwEnt.Value))
|
else if (!TryDrop(player, throwEnt, handsComp: hands))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var direction = coords.ToMapPos(EntityManager) - Transform(player).WorldPosition;
|
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);
|
direction = direction.Normalized * Math.Min(direction.Length, hands.ThrowRange);
|
||||||
|
|
||||||
var throwStrength = hands.ThrowForceMultiplier;
|
var throwStrength = hands.ThrowForceMultiplier;
|
||||||
throwEnt.Value.TryThrow(direction, throwStrength, player);
|
throwEnt.TryThrow(direction, throwStrength, player);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -287,7 +260,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hands.ActiveHandIsHoldingEntity())
|
if (hands.ActiveHand?.HeldEntity != null)
|
||||||
{
|
{
|
||||||
storageComponent.PlayerInsertHeldEntity(plyEnt);
|
storageComponent.PlayerInsertHeldEntity(plyEnt);
|
||||||
}
|
}
|
||||||
@@ -302,24 +275,11 @@ namespace Content.Server.Hands.Systems
|
|||||||
var lastStoredEntity = Enumerable.Last(storageComponent.StoredEntities);
|
var lastStoredEntity = Enumerable.Last(storageComponent.StoredEntities);
|
||||||
if (storageComponent.Remove(lastStoredEntity))
|
if (storageComponent.Remove(lastStoredEntity))
|
||||||
{
|
{
|
||||||
if (!hands.TryPickupEntityToActiveHand(lastStoredEntity, animateUser: true))
|
PickupOrDrop(plyEnt, lastStoredEntity, animateUser: true, handsComp: hands);
|
||||||
Transform(lastStoredEntity).Coordinates = Transform(plyEnt).Coordinates;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#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
|
// Verify user has a hand, and find what object they are currently holding in their active hand
|
||||||
if (TryComp(user, out HandsComponent? hands))
|
if (TryComp(user, out HandsComponent? hands))
|
||||||
{
|
{
|
||||||
var item = hands.GetActiveHandItem?.Owner;
|
var item = hands.ActiveHandEntity;
|
||||||
|
|
||||||
if (item != null && !Deleted(item.Value))
|
if (item != null && !Deleted(item.Value))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
using Content.Server.Hands.Components;
|
|
||||||
using Content.Server.Holiday;
|
using Content.Server.Holiday;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Jobs
|
namespace Content.Server.Jobs
|
||||||
@@ -26,17 +22,16 @@ namespace Content.Server.Jobs
|
|||||||
if (string.IsNullOrEmpty(Holiday) || string.IsNullOrEmpty(Prototype))
|
if (string.IsNullOrEmpty(Holiday) || string.IsNullOrEmpty(Prototype))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!EntitySystem.Get<HolidaySystem>().IsCurrentlyHoliday(Holiday))
|
var sysMan = IoCManager.Resolve<IEntitySystemManager>();
|
||||||
|
|
||||||
|
if (!sysMan.GetEntitySystem<HolidaySystem>().IsCurrentlyHoliday(Holiday))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
var entity = entMan.SpawnEntity(Prototype, entMan.GetComponent<TransformComponent>(mob).Coordinates);
|
var entity = entMan.SpawnEntity(Prototype, entMan.GetComponent<TransformComponent>(mob).Coordinates);
|
||||||
|
|
||||||
if (!entMan.TryGetComponent(entity, out SharedItemComponent? item) || !entMan.TryGetComponent(mob, out HandsComponent? hands))
|
sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(mob, entity);
|
||||||
return;
|
|
||||||
|
|
||||||
hands.PutInHand(item, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace Content.Server.Kitchen.Components
|
|||||||
return false;
|
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"));
|
eventArgs.User.PopupMessage(Loc.GetString("microwave-component-interact-using-no-active-hand"));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
@@ -7,6 +7,7 @@ using Content.Server.Kitchen.Events;
|
|||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Kitchen.Components;
|
using Content.Shared.Kitchen.Components;
|
||||||
@@ -16,10 +17,6 @@ using JetBrains.Annotations;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
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.Player;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -29,6 +26,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
internal sealed class ReagentGrinderSystem : EntitySystem
|
internal sealed class ReagentGrinderSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private Queue<ReagentGrinderComponent> _uiUpdateQueue = new();
|
private Queue<ReagentGrinderComponent> _uiUpdateQueue = new();
|
||||||
|
|
||||||
@@ -267,7 +265,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
!EntityManager.TryGetComponent<SharedItemComponent?>(beaker, out var item))
|
!EntityManager.TryGetComponent<SharedItemComponent?>(beaker, out var item))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hands.PutInHandOrDrop(item);
|
_handsSystem.PickupOrDrop(user.Value, beaker, handsComp: hands, item: item);
|
||||||
|
|
||||||
component.HeldBeaker = null;
|
component.HeldBeaker = null;
|
||||||
EnqueueUiUpdate(component);
|
EnqueueUiUpdate(component);
|
||||||
|
|||||||
@@ -11,16 +11,13 @@ using Content.Shared.Audio;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Light;
|
using Content.Shared.Light;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
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.Player;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
@@ -37,6 +34,7 @@ namespace Content.Server.Light.EntitySystems
|
|||||||
[Dependency] private readonly LightBulbSystem _bulbSystem = default!;
|
[Dependency] private readonly LightBulbSystem _bulbSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2);
|
||||||
|
|
||||||
@@ -171,11 +169,7 @@ namespace Content.Server.Light.EntitySystems
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// try to place bulb in hands
|
// try to place bulb in hands
|
||||||
if (userUid != null)
|
_handsSystem.PickupOrDrop(userUid, bulb);
|
||||||
{
|
|
||||||
if (EntityManager.TryGetComponent(userUid.Value, out SharedHandsComponent? hands))
|
|
||||||
hands.PutInHand(bulb);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateLight(uid, light);
|
UpdateLight(uid, light);
|
||||||
return bulb;
|
return bulb;
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace Content.Server.MachineLinking.System
|
|||||||
case SignalPortSelected portSelected:
|
case SignalPortSelected portSelected:
|
||||||
if (msg.Session.AttachedEntity == default ||
|
if (msg.Session.AttachedEntity == default ||
|
||||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
!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) ||
|
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent) ||
|
||||||
!signalLinkerComponent.Port.HasValue ||
|
!signalLinkerComponent.Port.HasValue ||
|
||||||
!signalLinkerComponent.Port.Value.transmitter.Outputs.ContainsPort(signalLinkerComponent.Port
|
!signalLinkerComponent.Port.Value.transmitter.Outputs.ContainsPort(signalLinkerComponent.Port
|
||||||
@@ -165,7 +165,7 @@ namespace Content.Server.MachineLinking.System
|
|||||||
case SignalPortSelected portSelected:
|
case SignalPortSelected portSelected:
|
||||||
if (msg.Session.AttachedEntity == default ||
|
if (msg.Session.AttachedEntity == default ||
|
||||||
!EntityManager.TryGetComponent(msg.Session.AttachedEntity, out HandsComponent? hands) ||
|
!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))
|
!EntityManager.TryGetComponent(heldEntity, out SignalLinkerComponent? signalLinkerComponent))
|
||||||
return;
|
return;
|
||||||
LinkerSaveInteraction(attached, signalLinkerComponent, component,
|
LinkerSaveInteraction(attached, signalLinkerComponent, component,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Content.Server.DoAfter;
|
|||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.ActionBlocker;
|
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Body.Components;
|
using Content.Shared.Body.Components;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
@@ -20,7 +19,7 @@ using Robust.Shared.Audio;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems
|
namespace Content.Server.Nutrition.EntitySystems
|
||||||
@@ -39,6 +38,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
[Dependency] private readonly SharedAdminLogSystem _logSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -223,18 +223,12 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
var finisher = EntityManager.SpawnEntity(component.TrashPrototype, position);
|
var finisher = EntityManager.SpawnEntity(component.TrashPrototype, position);
|
||||||
|
|
||||||
// If the user is holding the item
|
// If the user is holding the item
|
||||||
if (user != null &&
|
if (user != null && _handsSystem.IsHolding(user.Value, component.Owner, out var hand))
|
||||||
EntityManager.TryGetComponent(user.Value, out HandsComponent? handsComponent) &&
|
|
||||||
handsComponent.IsHolding(component.Owner))
|
|
||||||
{
|
{
|
||||||
EntityManager.DeleteEntity((component).Owner);
|
EntityManager.DeleteEntity((component).Owner);
|
||||||
|
|
||||||
// Put the trash in the user's hand
|
// Put the trash in the user's hand
|
||||||
if (EntityManager.TryGetComponent(finisher, out SharedItemComponent? item) &&
|
_handsSystem.TryPickup(user.Value, finisher, hand);
|
||||||
handsComponent.CanPutInHand(item))
|
|
||||||
{
|
|
||||||
handsComponent.PutInHand(item);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,10 +323,10 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
var usedTypes = UtensilType.None;
|
var usedTypes = UtensilType.None;
|
||||||
|
|
||||||
foreach (var item in hands.GetAllHeldItems())
|
foreach (var item in _handsSystem.EnumerateHeld(user, hands))
|
||||||
{
|
{
|
||||||
// Is utensil?
|
// Is utensil?
|
||||||
if (!EntityManager.TryGetComponent(item.Owner, out UtensilComponent? utensil))
|
if (!EntityManager.TryGetComponent(item, out UtensilComponent? utensil))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((utensil.Types & component.Utensil) != 0 && // Acceptable type?
|
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.Chemistry.Components;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems
|
namespace Content.Server.Nutrition.EntitySystems
|
||||||
@@ -19,6 +17,8 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
internal sealed class SliceableFoodSystem : EntitySystem
|
internal sealed class SliceableFoodSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -67,9 +67,9 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
if (EntityManager.TryGetComponent(user, out HandsComponent? handsComponent))
|
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.Server.Tools.Components;
|
||||||
using Content.Shared.Camera;
|
using Content.Shared.Camera;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.PneumaticCannon;
|
using Content.Shared.PneumaticCannon;
|
||||||
@@ -19,11 +20,7 @@ using Content.Shared.StatusEffect;
|
|||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
@@ -35,6 +32,7 @@ namespace Content.Server.PneumaticCannon
|
|||||||
[Dependency] private readonly StunSystem _stun = default!;
|
[Dependency] private readonly StunSystem _stun = default!;
|
||||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||||
[Dependency] private readonly CameraRecoilSystem _cameraRecoil = default!;
|
[Dependency] private readonly CameraRecoilSystem _cameraRecoil = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private HashSet<PneumaticCannonComponent> _currentlyFiring = new();
|
private HashSet<PneumaticCannonComponent> _currentlyFiring = new();
|
||||||
|
|
||||||
@@ -320,11 +318,8 @@ namespace Content.Server.PneumaticCannon
|
|||||||
|
|
||||||
if (component.GasTankSlot.Remove(contained))
|
if (component.GasTankSlot.Remove(contained))
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent<HandsComponent?>(user, out var hands))
|
_handsSystem.TryPickupAnyHand(user, contained);
|
||||||
{
|
|
||||||
hands.PutInHand(contained);
|
|
||||||
}
|
|
||||||
|
|
||||||
user.PopupMessage(Loc.GetString("pneumatic-cannon-component-gas-tank-remove",
|
user.PopupMessage(Loc.GetString("pneumatic-cannon-component-gas-tank-remove",
|
||||||
("tank", contained), ("cannon", component.Owner)));
|
("tank", contained), ("cannon", component.Owner)));
|
||||||
UpdateAppearance(component);
|
UpdateAppearance(component);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Shared.Access;
|
|||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
@@ -32,6 +33,7 @@ namespace Content.Server.Sandbox
|
|||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
[Dependency] private readonly ItemSlotsSystem _slots = default!;
|
||||||
[Dependency] private readonly GameTicker _ticker = default!;
|
[Dependency] private readonly GameTicker _ticker = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private bool _isSandboxEnabled;
|
private bool _isSandboxEnabled;
|
||||||
|
|
||||||
@@ -154,7 +156,7 @@ namespace Content.Server.Sandbox
|
|||||||
var card = CreateFreshId();
|
var card = CreateFreshId();
|
||||||
if (!_inventory.TryEquip(attached, card, "id", true, true))
|
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 System;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Stacks;
|
using Content.Shared.Stacks;
|
||||||
@@ -25,6 +26,7 @@ namespace Content.Server.Stack
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 };
|
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)
|
if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryComp<HandsComponent>(userUid, out var hands) && TryComp<SharedItemComponent>(split, out var item))
|
_handsSystem.PickupOrDrop(userUid, split);
|
||||||
{
|
|
||||||
hands.PutInHandOrDrop(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
_popupSystem.PopupCursor(Loc.GetString("comp-stack-split"), Filter.Entities(userUid));
|
_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 Content.Shared.Standing;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Standing;
|
namespace Content.Server.Standing;
|
||||||
@@ -10,22 +8,26 @@ namespace Content.Server.Standing;
|
|||||||
public sealed class StandingStateSystem : EntitySystem
|
public sealed class StandingStateSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
private void FallOver(EntityUid uid, StandingStateComponent component, DropHandItemsEvent args)
|
private void FallOver(EntityUid uid, StandingStateComponent component, DropHandItemsEvent args)
|
||||||
{
|
{
|
||||||
var direction = EntityManager.TryGetComponent(uid, out PhysicsComponent? comp) ? comp.LinearVelocity / 50 : Vector2.Zero;
|
var direction = EntityManager.TryGetComponent(uid, out PhysicsComponent? comp) ? comp.LinearVelocity / 50 : Vector2.Zero;
|
||||||
var dropAngle = _random.NextFloat(0.8f, 1.2f);
|
var dropAngle = _random.NextFloat(0.8f, 1.2f);
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(uid, out HandsComponent? hands))
|
if (!TryComp(uid, out SharedHandsComponent? handsComp))
|
||||||
return;
|
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;
|
continue;
|
||||||
|
|
||||||
var worldRotation = EntityManager.GetComponent<TransformComponent>(uid).WorldRotation.ToVec();
|
if (!_handsSystem.TryDrop(uid, hand, null, checkActionBlocker: false, handsComp: handsComp))
|
||||||
Throwing.ThrowHelper.TryThrow(heldItem.Owner,
|
continue;
|
||||||
|
|
||||||
|
Throwing.ThrowHelper.TryThrow(held,
|
||||||
_random.NextAngle().RotateVec(direction / dropAngle + worldRotation / 50),
|
_random.NextAngle().RotateVec(direction / dropAngle + worldRotation / 50),
|
||||||
0.5f * dropAngle * _random.NextFloat(-0.9f, 1.1f),
|
0.5f * dropAngle * _random.NextFloat(-0.9f, 1.1f),
|
||||||
uid, 0);
|
uid, 0);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Server.Hands.Components;
|
|||||||
using Content.Server.Interaction;
|
using Content.Server.Interaction;
|
||||||
using Content.Shared.Acts;
|
using Content.Shared.Acts;
|
||||||
using Content.Shared.Coordinates;
|
using Content.Shared.Coordinates;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
@@ -46,6 +47,7 @@ namespace Content.Server.Storage.Components
|
|||||||
public sealed class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IActivate, IStorageComponent, IDestroyAct, IExAct, IAfterInteract
|
public sealed class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IActivate, IStorageComponent, IDestroyAct, IExAct, IAfterInteract
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
|
|
||||||
private const string LoggerName = "Storage";
|
private const string LoggerName = "Storage";
|
||||||
|
|
||||||
@@ -243,22 +245,24 @@ namespace Content.Server.Storage.Components
|
|||||||
EnsureInitialCalculated();
|
EnsureInitialCalculated();
|
||||||
|
|
||||||
if (!_entityManager.TryGetComponent(player, out HandsComponent? hands) ||
|
if (!_entityManager.TryGetComponent(player, out HandsComponent? hands) ||
|
||||||
hands.GetActiveHandItem == null)
|
hands.ActiveHandEntity == null)
|
||||||
{
|
{
|
||||||
return false;
|
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.");
|
Owner.PopupMessage(player, "Can't insert.");
|
||||||
return false;
|
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.");
|
Owner.PopupMessage(player, "Can't insert.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -475,18 +479,7 @@ namespace Content.Server.Storage.Components
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_entityManager.TryGetComponent(remove.EntityUid, out SharedItemComponent? item) || !_entityManager.TryGetComponent(player, out HandsComponent? hands))
|
_sysMan.GetEntitySystem<SharedHandsSystem>().TryPickupAnyHand(player, remove.EntityUid);
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hands.CanPutInHand(item))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
hands.PutInHand(item);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InsertEntityMessage _:
|
case InsertEntityMessage _:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Content.Server.Clothing.Components;
|
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
using Content.Shared.Acts;
|
using Content.Shared.Acts;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -12,6 +12,7 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
public sealed class SecretStashSystem : EntitySystem
|
public sealed class SecretStashSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -83,7 +84,7 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to move item from hands to stash container
|
// try to move item from hands to stash container
|
||||||
if (!hands.Drop(itemToHideUid, container))
|
if (!_handsSystem.TryDropIntoContainer(userUid, itemToHideUid, container))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -115,13 +116,7 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get item inside container
|
_handsSystem.PickupOrDrop(userUid, container.ContainedEntity.Value, handsComp: hands);
|
||||||
var itemUid = container.ContainedEntity;
|
|
||||||
if (!EntityManager.TryGetComponent(itemUid, out SharedItemComponent? item))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hands.PutInHandOrDrop(item);
|
|
||||||
|
|
||||||
// show success message
|
// show success message
|
||||||
var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something",
|
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.Server.Storage.Components;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
@@ -13,6 +10,7 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
public sealed class SpawnItemsOnUseSystem : EntitySystem
|
public sealed class SpawnItemsOnUseSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -57,10 +55,9 @@ namespace Content.Server.Storage.EntitySystems
|
|||||||
EntityManager.DeleteEntity(uid);
|
EntityManager.DeleteEntity(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityToPlaceInHands != null
|
if (entityToPlaceInHands != null)
|
||||||
&& EntityManager.TryGetComponent<SharedHandsComponent?>(args.User, out var hands))
|
|
||||||
{
|
{
|
||||||
hands.TryPutInAnyHand(entityToPlaceInHands.Value);
|
_handsSystem.PickupOrDrop(args.User, entityToPlaceInHands.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.Cuffs.Components;
|
using Content.Server.Cuffs.Components;
|
||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Inventory;
|
using Content.Server.Inventory;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.ActionBlocker;
|
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Strip.Components;
|
using Content.Shared.Strip.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Player;
|
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
|
namespace Content.Server.Strip
|
||||||
{
|
{
|
||||||
@@ -28,6 +22,7 @@ namespace Content.Server.Strip
|
|||||||
public sealed class StrippableComponent : SharedStrippableComponent
|
public sealed class StrippableComponent : SharedStrippableComponent
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
private StrippableSystem _strippableSystem = default!;
|
private StrippableSystem _strippableSystem = default!;
|
||||||
|
|
||||||
public const float StripDelay = 2f;
|
public const float StripDelay = 2f;
|
||||||
@@ -84,18 +79,18 @@ namespace Content.Server.Strip
|
|||||||
private async void PlaceActiveHandItemInInventory(EntityUid user, string slot)
|
private async void PlaceActiveHandItemInInventory(EntityUid user, string slot)
|
||||||
{
|
{
|
||||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||||
var item = userHands.GetActiveHandItem;
|
var invSystem = _sysMan.GetEntitySystem<InventorySystem>();
|
||||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
bool Check()
|
bool Check()
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (userHands.ActiveHand?.HeldEntity is not EntityUid held)
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userHands.CanDrop(userHands.ActiveHand!))
|
if (!handSys.CanDropHeld(user, userHands.ActiveHand))
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
||||||
return false;
|
return false;
|
||||||
@@ -110,7 +105,7 @@ namespace Content.Server.Strip
|
|||||||
return false;
|
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)));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-equip-message",("owner", Owner)));
|
||||||
return false;
|
return false;
|
||||||
@@ -134,8 +129,11 @@ namespace Content.Server.Strip
|
|||||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||||
if (result != DoAfterStatus.Finished) return;
|
if (result != DoAfterStatus.Finished) return;
|
||||||
|
|
||||||
userHands.Drop(item!.Owner, false);
|
if (userHands.ActiveHand?.HeldEntity is EntityUid held
|
||||||
invSystem.TryEquip(user, Owner, item.Owner, slot);
|
&& handSys.TryDrop(user, userHands.ActiveHand, handsComp: userHands))
|
||||||
|
{
|
||||||
|
invSystem.TryEquip(user, Owner, held, slot);
|
||||||
|
}
|
||||||
|
|
||||||
UpdateState();
|
UpdateState();
|
||||||
}
|
}
|
||||||
@@ -143,38 +141,28 @@ namespace Content.Server.Strip
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Places item in user's active hand in one of the entity's hands.
|
/// Places item in user's active hand in one of the entity's hands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async void PlaceActiveHandItemInHands(EntityUid user, string hand)
|
private async void PlaceActiveHandItemInHands(EntityUid user, string handName)
|
||||||
{
|
{
|
||||||
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
||||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||||
var item = userHands.GetActiveHandItem;
|
var sys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
bool Check()
|
bool Check()
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (userHands.ActiveHandEntity == null)
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userHands.CanDrop(userHands.ActiveHand!))
|
if (!sys.CanDropHeld(user, userHands.ActiveHand!))
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hands.HasHand(hand))
|
if (!hands.Hands.TryGetValue(handName, out var hand)
|
||||||
{
|
|| !sys.CanPickupToHand(Owner, userHands.ActiveHandEntity.Value, hand, checkActionBlocker: false, hands))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-put-message",("owner", Owner)));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-put-message",("owner", Owner)));
|
||||||
return false;
|
return false;
|
||||||
@@ -183,7 +171,7 @@ namespace Content.Server.Strip
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||||
|
|
||||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
||||||
{
|
{
|
||||||
@@ -198,8 +186,11 @@ namespace Content.Server.Strip
|
|||||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||||
if (result != DoAfterStatus.Finished) return;
|
if (result != DoAfterStatus.Finished) return;
|
||||||
|
|
||||||
userHands.Drop(hand);
|
if (userHands.ActiveHandEntity is not EntityUid held)
|
||||||
hands.TryPickupEntity(hand, item!.Owner, checkActionBlocker: false, animateUser: true);
|
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
|
// hand update will trigger strippable update
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +201,7 @@ namespace Content.Server.Strip
|
|||||||
{
|
{
|
||||||
var inventory = _entities.GetComponent<InventoryComponent>(Owner);
|
var inventory = _entities.GetComponent<InventoryComponent>(Owner);
|
||||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
var invSystem = _sysMan.GetEntitySystem<InventorySystem>();
|
||||||
|
|
||||||
bool Check()
|
bool Check()
|
||||||
{
|
{
|
||||||
@@ -232,7 +223,7 @@ namespace Content.Server.Strip
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||||
|
|
||||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
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
|
// Raise a dropped event, so that things like gas tank internals properly deactivate when stripping
|
||||||
_entities.EventBus.RaiseLocalEvent(item.Value, new DroppedEvent(user));
|
_entities.EventBus.RaiseLocalEvent(item.Value, new DroppedEvent(user));
|
||||||
userHands.PutInHandOrDrop(item.Value);
|
|
||||||
|
_sysMan.GetEntitySystem<SharedHandsSystem>().PickupOrDrop(user, item.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateState();
|
UpdateState();
|
||||||
@@ -259,26 +251,24 @@ namespace Content.Server.Strip
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Takes an item from a hand and places it in the user's active hand.
|
/// Takes an item from a hand and places it in the user's active hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async void TakeItemFromHands(EntityUid user, string hand)
|
private async void TakeItemFromHands(EntityUid user, string handName)
|
||||||
{
|
{
|
||||||
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
var hands = _entities.GetComponent<HandsComponent>(Owner);
|
||||||
var userHands = _entities.GetComponent<HandsComponent>(user);
|
var userHands = _entities.GetComponent<HandsComponent>(user);
|
||||||
|
var handSys = _sysMan.GetEntitySystem<SharedHandsSystem>();
|
||||||
|
|
||||||
bool Check()
|
bool Check()
|
||||||
{
|
{
|
||||||
if (!hands.HasHand(hand))
|
if (!hands.Hands.TryGetValue(handName, out var hand) || hand.HeldEntity == null)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!hands.TryGetItem(hand, out var heldItem))
|
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", Owner)));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", Owner)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_entities.HasComponent<HandVirtualItemComponent>(heldItem.Owner))
|
if (_entities.HasComponent<HandVirtualItemComponent>(hand.HeldEntity))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!hands.CanDrop(hand, false))
|
if (!handSys.CanDropHeld(Owner, hand, false))
|
||||||
{
|
{
|
||||||
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop-message",("owner", Owner)));
|
user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop-message",("owner", Owner)));
|
||||||
return false;
|
return false;
|
||||||
@@ -287,7 +277,7 @@ namespace Content.Server.Strip
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
var doAfterSystem = _sysMan.GetEntitySystem<DoAfterSystem>();
|
||||||
|
|
||||||
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner)
|
||||||
{
|
{
|
||||||
@@ -301,11 +291,11 @@ namespace Content.Server.Strip
|
|||||||
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
|
||||||
if (result != DoAfterStatus.Finished) return;
|
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;
|
return;
|
||||||
|
|
||||||
hands.Drop(hand, false);
|
handSys.TryDrop(Owner, hand, checkActionBlocker: false, handsComp: hands);
|
||||||
userHands.PutInHandOrDrop(entity.Value);
|
handSys.PickupOrDrop(user, held, handsComp: userHands);
|
||||||
// hand update will trigger strippable update
|
// hand update will trigger strippable update
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,14 +305,14 @@ namespace Content.Server.Strip
|
|||||||
!_entities.TryGetComponent(user, out HandsComponent? userHands))
|
!_entities.TryGetComponent(user, out HandsComponent? userHands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var placingItem = userHands.GetActiveHandItem != null;
|
var placingItem = userHands.ActiveHandEntity != null;
|
||||||
|
|
||||||
switch (obj.Message)
|
switch (obj.Message)
|
||||||
{
|
{
|
||||||
case StrippingInventoryButtonPressed inventoryMessage:
|
case StrippingInventoryButtonPressed inventoryMessage:
|
||||||
if (_entities.TryGetComponent<InventoryComponent?>(Owner, out var inventory))
|
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;
|
placingItem = false;
|
||||||
|
|
||||||
if (placingItem)
|
if (placingItem)
|
||||||
@@ -336,7 +326,7 @@ namespace Content.Server.Strip
|
|||||||
|
|
||||||
if (_entities.TryGetComponent<HandsComponent?>(Owner, out var hands))
|
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;
|
placingItem = false;
|
||||||
|
|
||||||
if (placingItem)
|
if (placingItem)
|
||||||
|
|||||||
@@ -76,17 +76,15 @@ namespace Content.Server.Strip
|
|||||||
|
|
||||||
if (TryComp(uid, out HandsComponent? handsComp))
|
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 (hand.HeldEntity == null || HasComp<HandVirtualItemComponent>(hand.HeldEntity))
|
||||||
|
|
||||||
if (!owner.HasValue || HasComp<HandVirtualItemComponent>(owner.Value))
|
|
||||||
{
|
{
|
||||||
hands[hand] = "None";
|
hands[hand.Name] = "None";
|
||||||
continue;
|
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.Server.UserInterface;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
@@ -28,6 +29,7 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
private readonly UplinkListingSytem _listing = default!;
|
private readonly UplinkListingSytem _listing = default!;
|
||||||
|
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -123,11 +125,7 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(player, out HandsComponent? hands) &&
|
_handsSystem.PickupOrDrop(player, entity.Value);
|
||||||
EntityManager.TryGetComponent(entity.Value, out SharedItemComponent? item))
|
|
||||||
{
|
|
||||||
hands.PutInHandOrDrop(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
SoundSystem.Play(Filter.SinglePlayer(message.Session), uplink.BuySuccessSound.GetSound(),
|
SoundSystem.Play(Filter.SinglePlayer(message.Session), uplink.BuySuccessSound.GetSound(),
|
||||||
uplink.Owner, AudioParams.Default.WithVolume(-8f));
|
uplink.Owner, AudioParams.Default.WithVolume(-8f));
|
||||||
@@ -149,8 +147,7 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// try to put it into players hands
|
// try to put it into players hands
|
||||||
if (EntityManager.TryGetComponent(player, out SharedHandsComponent? hands))
|
_handsSystem.PickupOrDrop(player, tcUid.Value);
|
||||||
hands.TryPutInAnyHand(tcUid.Value);
|
|
||||||
|
|
||||||
// play buying sound
|
// play buying sound
|
||||||
SoundSystem.Play(Filter.SinglePlayer(args.Session), uplink.BuySuccessSound.GetSound(),
|
SoundSystem.Play(Filter.SinglePlayer(args.Session), uplink.BuySuccessSound.GetSound(),
|
||||||
@@ -217,14 +214,10 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also check hands
|
// Also check hands
|
||||||
if (EntityManager.TryGetComponent(user, out HandsComponent? hands))
|
foreach (var item in _handsSystem.EnumerateHeld(user))
|
||||||
{
|
{
|
||||||
var heldItems = hands.GetAllHeldItems();
|
if (HasComp<PDAComponent>(item))
|
||||||
foreach (var item in heldItems)
|
return item;
|
||||||
{
|
|
||||||
if (EntityManager.HasComponent<PDAComponent>(item.Owner))
|
|
||||||
return item.Owner;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace Content.Server.Verbs
|
|||||||
// first get the held item. again.
|
// first get the held item. again.
|
||||||
EntityUid? holding = null;
|
EntityUid? holding = null;
|
||||||
if (TryComp(user, out SharedHandsComponent? hands) &&
|
if (TryComp(user, out SharedHandsComponent? hands) &&
|
||||||
hands.TryGetActiveHeldEntity(out var heldEntity))
|
hands.ActiveHandEntity is EntityUid heldEntity)
|
||||||
{
|
{
|
||||||
holding = heldEntity;
|
holding = heldEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,15 +152,10 @@ public sealed partial class GunSystem
|
|||||||
return false;
|
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;
|
||||||
TryInsertAmmo(user, ammo, ammoBox);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
handsComponent.PutInHand(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAmmoBoxAppearance(ammoBox.Owner, ammoBox);
|
UpdateAmmoBoxAppearance(ammoBox.Owner, ammoBox);
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public sealed partial class GunSystem
|
|||||||
{
|
{
|
||||||
if (!TryComp(gun.Owner, out ServerRangedBarrelComponent? barrel)) return;
|
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) ||
|
if (!TryComp(user, out CombatModeComponent? combat) ||
|
||||||
!combat.IsInCombatMode ||
|
!combat.IsInCombatMode ||
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ public sealed partial class GunSystem
|
|||||||
if (args.Hands == null ||
|
if (args.Hands == null ||
|
||||||
!args.CanAccess ||
|
!args.CanAccess ||
|
||||||
!args.CanInteract ||
|
!args.CanInteract ||
|
||||||
!component.HasMagazine ||
|
component.MagazineContainer.ContainedEntity is not EntityUid mag ||
|
||||||
!_blocker.CanPickup(args.User))
|
!_blocker.CanPickup(args.User, mag))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (component.MagNeedsOpenBolt && !component.BoltOpen)
|
if (component.MagNeedsOpenBolt && !component.BoltOpen)
|
||||||
@@ -37,7 +37,7 @@ public sealed partial class GunSystem
|
|||||||
|
|
||||||
AlternativeVerb verb = new()
|
AlternativeVerb verb = new()
|
||||||
{
|
{
|
||||||
Text = MetaData(component.MagazineContainer.ContainedEntity!.Value).EntityName,
|
Text = MetaData(mag).EntityName,
|
||||||
Category = VerbCategory.Eject,
|
Category = VerbCategory.Eject,
|
||||||
Act = () => RemoveMagazine(args.User, component)
|
Act = () => RemoveMagazine(args.User, component)
|
||||||
};
|
};
|
||||||
@@ -325,10 +325,7 @@ public sealed partial class GunSystem
|
|||||||
component.MagazineContainer.Remove(mag.Value);
|
component.MagazineContainer.Remove(mag.Value);
|
||||||
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundMagEject.GetSound(), component.Owner, AudioParams.Default.WithVolume(-2));
|
SoundSystem.Play(Filter.Pvs(component.Owner), component.SoundMagEject.GetSound(), component.Owner, AudioParams.Default.WithVolume(-2));
|
||||||
|
|
||||||
if (TryComp(user, out HandsComponent? handsComponent))
|
_handsSystem.PickupOrDrop(user, mag.Value);
|
||||||
{
|
|
||||||
handsComponent.PutInHandOrDrop(EntityManager.GetComponent<SharedItemComponent>(mag.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
component.Dirty(EntityManager);
|
component.Dirty(EntityManager);
|
||||||
UpdateMagazineAppearance(component);
|
UpdateMagazineAppearance(component);
|
||||||
|
|||||||
@@ -70,16 +70,8 @@ public sealed partial class GunSystem
|
|||||||
if (TakeAmmo(component) is not {Valid: true} ammo)
|
if (TakeAmmo(component) is not {Valid: true} ammo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var itemComponent = EntityManager.GetComponent<SharedItemComponent>(ammo);
|
_handsSystem.PickupOrDrop(args.User, ammo, handsComp: handsComponent);
|
||||||
if (!handsComponent.CanPutInHand(itemComponent))
|
EjectCasing(ammo);
|
||||||
{
|
|
||||||
Transform(ammo).Coordinates = Transform(args.User).Coordinates;
|
|
||||||
EjectCasing(ammo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handsComponent.PutInHand(itemComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,15 +75,10 @@ public sealed partial class GunSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemComponent = EntityManager.GetComponent<SharedItemComponent>(ammo.Value);
|
if (!_handsSystem.TryPickup(args.User, ammo.Value, handsComp: handsComponent))
|
||||||
if (!handsComponent.CanPutInHand(itemComponent))
|
|
||||||
{
|
{
|
||||||
EjectCasing(ammo.Value);
|
EjectCasing(ammo.Value);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
handsComponent.PutInHand(itemComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateSpeedLoaderAppearance(component);
|
UpdateSpeedLoaderAppearance(component);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Shared.ActionBlocker;
|
|||||||
using Content.Shared.Camera;
|
using Content.Shared.Camera;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -47,6 +48,7 @@ public sealed partial class GunSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly StunSystem _stun = default!;
|
[Dependency] private readonly StunSystem _stun = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many sounds are allowed to be played on ejecting multiple casings.
|
/// How many sounds are allowed to be played on ejecting multiple casings.
|
||||||
@@ -141,7 +143,7 @@ public sealed partial class GunSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: Not exactly robust
|
// TODO: Not exactly robust
|
||||||
var gun = handsComponent.GetActiveHand()?.HeldEntity;
|
var gun = handsComponent.ActiveHand?.HeldEntity;
|
||||||
|
|
||||||
if (gun == null || !TryComp(gun, out ServerRangedWeaponComponent? weapon))
|
if (gun == null || !TryComp(gun, out ServerRangedWeaponComponent? weapon))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ using Content.Server.Hands.Systems;
|
|||||||
using Content.Server.Weapon.Melee;
|
using Content.Server.Weapon.Melee;
|
||||||
using Content.Server.Wieldable.Components;
|
using Content.Server.Wieldable.Components;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Server.Wieldable
|
namespace Content.Server.Wieldable
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,7 @@ namespace Content.Server.Wieldable
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||||
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -75,7 +76,8 @@ namespace Content.Server.Wieldable
|
|||||||
return false;
|
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
|
// TODO FLUENT need function to change 'hands' to 'hand' when there's only 1 required
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
@@ -89,7 +91,7 @@ namespace Content.Server.Wieldable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Is it.. actually in one of their hands?
|
// Is it.. actually in one of their hands?
|
||||||
if (!hands.TryGetHandHoldingEntity(uid, out _))
|
if (!_handsSystem.IsHolding(user, uid, out _, hands))
|
||||||
{
|
{
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ namespace Content.Server.WireHacking
|
|||||||
return false;
|
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))
|
!_entities.TryGetComponent(activeHandEntity, out tool))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Server.Clothing.Components;
|
|
||||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
|
||||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
||||||
@@ -9,6 +8,7 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
|
|||||||
public sealed class SpawnArtifactSystem : EntitySystem
|
public sealed class SpawnArtifactSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
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
|
// if there is an user - try to put spawned item in their hands
|
||||||
// doesn't work for spawners
|
// doesn't work for spawners
|
||||||
if (args.Activator != null &&
|
_handsSystem.PickupOrDrop(args.Activator, spawned);
|
||||||
EntityManager.TryGetComponent(args.Activator.Value, out SharedHandsComponent? hands) &&
|
|
||||||
EntityManager.HasComponent<ItemComponent>(spawned))
|
|
||||||
{
|
|
||||||
hands.TryPutInAnyHand(spawned);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChooseRandomPrototype(EntityUid uid, SpawnArtifactComponent? component = null)
|
private void ChooseRandomPrototype(EntityUid uid, SpawnArtifactComponent? component = null)
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Hands.Components;
|
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
|
||||||
namespace Content.Shared.Access.Systems
|
namespace Content.Shared.Access.Systems
|
||||||
{
|
{
|
||||||
@@ -18,6 +13,7 @@ namespace Content.Shared.Access.Systems
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -54,7 +50,7 @@ namespace Content.Shared.Access.Systems
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If no access is found, an empty set is used instead.
|
/// If no access is found, an empty set is used instead.
|
||||||
/// </remarks>
|
/// </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)
|
public bool IsAllowed(AccessReaderComponent reader, EntityUid entity)
|
||||||
{
|
{
|
||||||
var tags = FindAccessTags(entity);
|
var tags = FindAccessTags(entity);
|
||||||
@@ -78,14 +74,10 @@ namespace Content.Shared.Access.Systems
|
|||||||
if (FindAccessTagsItem(uid, out var tags))
|
if (FindAccessTagsItem(uid, out var tags))
|
||||||
return tags;
|
return tags;
|
||||||
|
|
||||||
// maybe access component inside its hands?
|
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||||
if (EntityManager.TryGetComponent(uid, out SharedHandsComponent? hands))
|
|
||||||
{
|
{
|
||||||
if (hands.TryGetActiveHeldEntity(out var heldItem) &&
|
if (FindAccessTagsItem(item, out tags))
|
||||||
FindAccessTagsItem(heldItem.Value, out tags))
|
|
||||||
{
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe its inside an inventory slot?
|
// maybe its inside an inventory slot?
|
||||||
|
|||||||
@@ -95,12 +95,18 @@ namespace Content.Shared.ActionBlocker
|
|||||||
return !ev.Cancelled;
|
return !ev.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanPickup(EntityUid uid)
|
public bool CanPickup(EntityUid user, EntityUid item)
|
||||||
{
|
{
|
||||||
var ev = new PickupAttemptEvent(uid);
|
var userEv = new PickupAttemptEvent(user, item);
|
||||||
RaiseLocalEvent(uid, ev);
|
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)
|
public bool CanEmote(EntityUid uid)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Acts;
|
using Content.Shared.Acts;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -8,14 +9,9 @@ using Content.Shared.Sound;
|
|||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Content.Shared.Containers.ItemSlots
|
namespace Content.Shared.Containers.ItemSlots
|
||||||
@@ -27,6 +23,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -175,11 +172,11 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Drop the held item onto the floor. Return if the user cannot drop.
|
// 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;
|
return;
|
||||||
|
|
||||||
if (slot.Item != null)
|
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);
|
Insert(uid, slot, args.Used, args.User, excludeUserAudio: args.Predicted);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
@@ -287,18 +284,17 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (!Resolve(user, ref hands, false))
|
if (!Resolve(user, ref hands, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!hands.TryGetActiveHeldEntity(out var item))
|
if (hands.ActiveHand?.HeldEntity is not EntityUid held)
|
||||||
return false;
|
return false;
|
||||||
var heldItem = item.Value;
|
|
||||||
|
|
||||||
if (!CanInsert(uid, item.Value, slot))
|
if (!CanInsert(uid, held, slot))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// hands.Drop(item) checks CanDrop action blocker
|
// hands.Drop(item) checks CanDrop action blocker
|
||||||
if (hands.Drop(heldItem))
|
if (_handsSystem.TryDrop(user, hands.ActiveHand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Insert(uid, slot, heldItem, user);
|
Insert(uid, slot, held, user);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@@ -374,8 +370,8 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (!TryEject(uid, slot, user, out var item, excludeUserAudio))
|
if (!TryEject(uid, slot, user, out var item, excludeUserAudio))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (user != null && EntityManager.TryGetComponent(user.Value, out SharedHandsComponent? hands))
|
if (user != null)
|
||||||
hands.PutInHand(item.Value);
|
_handsSystem.PickupOrDrop(user.Value, item.Value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -384,25 +380,27 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
#region Verbs
|
#region Verbs
|
||||||
private void AddEjectVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent<AlternativeVerb> args)
|
private void AddEjectVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (args.Hands == null || !args.CanAccess ||!args.CanInteract ||
|
if (args.Hands == null || !args.CanAccess ||!args.CanInteract)
|
||||||
!_actionBlockerSystem.CanPickup(args.User))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var slot in itemSlots.Slots.Values)
|
foreach (var slot in itemSlots.Slots.Values)
|
||||||
{
|
{
|
||||||
if (!CanEject(slot))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (slot.EjectOnInteract)
|
if (slot.EjectOnInteract)
|
||||||
// For this item slot, ejecting/inserting is a primary interaction. Instead of an eject category
|
// 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.
|
// alt-click verb, there will be a "Take item" primary interaction verb.
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!CanEject(slot))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!_actionBlockerSystem.CanPickup(args.User, slot.Item!.Value))
|
||||||
|
continue;
|
||||||
|
|
||||||
var verbSubject = slot.Name != string.Empty
|
var verbSubject = slot.Name != string.Empty
|
||||||
? Loc.GetString(slot.Name)
|
? 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();
|
AlternativeVerb verb = new();
|
||||||
verb.IconEntity = slot.Item;
|
verb.IconEntity = slot.Item;
|
||||||
@@ -428,28 +426,28 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// If there are any slots that eject on left-click, add a "Take <item>" verb.
|
// 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
|
if (!_actionBlockerSystem.CanPickup(args.User, slot.Item!.Value))
|
||||||
? Loc.GetString(slot.Name)
|
continue;
|
||||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
|
|
||||||
|
|
||||||
InteractionVerb takeVerb = new();
|
var verbSubject = slot.Name != string.Empty
|
||||||
takeVerb.IconEntity = slot.Item;
|
? Loc.GetString(slot.Name)
|
||||||
takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
|
: EntityManager.GetComponent<MetaDataComponent>(slot.Item!.Value).EntityName ?? string.Empty;
|
||||||
|
|
||||||
if (slot.EjectVerbText == null)
|
InteractionVerb takeVerb = new();
|
||||||
takeVerb.Text = Loc.GetString("take-item-verb-text", ("subject", verbSubject));
|
takeVerb.IconEntity = slot.Item;
|
||||||
else
|
takeVerb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
|
||||||
takeVerb.Text = Loc.GetString(slot.EjectVerbText);
|
|
||||||
|
|
||||||
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
|
// 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.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
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;
|
||||||
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]
|
/// <summary>
|
||||||
public abstract class SharedHandsComponent : Component
|
/// The currently active hand.
|
||||||
{
|
/// </summary>
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[ViewVariables]
|
||||||
|
public Hand? ActiveHand;
|
||||||
/// <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>
|
/// <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>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
[ViewVariables]
|
||||||
public sealed class UseInHandMsg : EntityEventArgs
|
public EntityUid? ActiveHandEntity => ActiveHand?.HeldEntity;
|
||||||
{
|
|
||||||
}
|
[ViewVariables]
|
||||||
|
public Dictionary<string, Hand> Hands = new();
|
||||||
|
|
||||||
|
public int Count => Hands.Count;
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
public List<string> SortedHands = new();
|
||||||
public sealed class ActivateInHandMsg : EntityEventArgs
|
|
||||||
{
|
|
||||||
public string HandName { get; }
|
|
||||||
|
|
||||||
public ActivateInHandMsg(string handName)
|
|
||||||
{
|
|
||||||
HandName = handName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
[DataField("throwForceMultiplier")]
|
||||||
public sealed class ClientInteractUsingInHandMsg : EntityEventArgs
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
{
|
public float ThrowForceMultiplier { get; set; } = 10f; //should be tuned so that a thrown item lands about under the player's cursor
|
||||||
public string HandName { get; }
|
|
||||||
|
|
||||||
public ClientInteractUsingInHandMsg(string handName)
|
|
||||||
{
|
|
||||||
HandName = handName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves an item from one hand to the active hand.
|
/// Distance after which longer throw targets stop increasing throw impulse.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
[DataField("throwRange")]
|
||||||
public sealed class MoveItemFromHandMsg : EntityEventArgs
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
{
|
public float ThrowRange { get; set; } = 8f;
|
||||||
public string HandName { get; }
|
}
|
||||||
|
|
||||||
public MoveItemFromHandMsg(string handName)
|
[Serializable, NetSerializable]
|
||||||
{
|
public sealed class Hand
|
||||||
HandName = handName;
|
{
|
||||||
}
|
[ViewVariables]
|
||||||
}
|
public string Name { get; }
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public HandLocation Location { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
public enum HandLocation : byte
|
[ViewVariables, NonSerialized]
|
||||||
{
|
public ContainerSlot? Container;
|
||||||
Left,
|
|
||||||
Middle,
|
|
||||||
Right
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class HandCountChangedEvent : EntityEventArgs
|
[ViewVariables]
|
||||||
{
|
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||||
public HandCountChangedEvent(EntityUid sender)
|
|
||||||
{
|
|
||||||
Sender = sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Content.Shared.Hands.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using static Robust.Shared.GameObjects.SharedSpriteComponent;
|
using static Robust.Shared.GameObjects.SharedSpriteComponent;
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
namespace Content.Shared.Hands
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -73,15 +70,9 @@ namespace Content.Shared.Hands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid User { get; }
|
public EntityUid User { get; }
|
||||||
|
|
||||||
/// <summary>
|
public HandDeselectedEvent(EntityUid user)
|
||||||
/// Item in the hand that was deselected.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Item { get; }
|
|
||||||
|
|
||||||
public HandDeselectedEvent(EntityUid user, EntityUid item)
|
|
||||||
{
|
{
|
||||||
User = user;
|
User = user;
|
||||||
Item = item;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,15 +87,9 @@ namespace Content.Shared.Hands
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid User { get; }
|
public EntityUid User { get; }
|
||||||
|
|
||||||
/// <summary>
|
public HandSelectedEvent(EntityUid user)
|
||||||
/// Item in the hand that was selected.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Item { get; }
|
|
||||||
|
|
||||||
public HandSelectedEvent(EntityUid user, EntityUid item)
|
|
||||||
{
|
{
|
||||||
User = 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) { }
|
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 class ContentKeyFunctions
|
||||||
{
|
{
|
||||||
public static readonly BoundKeyFunction WideAttack = "WideAttack";
|
public static readonly BoundKeyFunction WideAttack = "WideAttack";
|
||||||
public static readonly BoundKeyFunction ActivateItemInHand = "ActivateItemInHand";
|
public static readonly BoundKeyFunction UseItemInHand = "ActivateItemInHand";
|
||||||
public static readonly BoundKeyFunction AltActivateItemInHand = "AltActivateItemInHand";
|
public static readonly BoundKeyFunction AltUseItemInHand = "AltActivateItemInHand";
|
||||||
public static readonly BoundKeyFunction ActivateItemInWorld = "ActivateItemInWorld";
|
public static readonly BoundKeyFunction ActivateItemInWorld = "ActivateItemInWorld";
|
||||||
public static readonly BoundKeyFunction AltActivateItemInWorld = "AltActivateItemInWorld";
|
public static readonly BoundKeyFunction AltActivateItemInWorld = "AltActivateItemInWorld";
|
||||||
public static readonly BoundKeyFunction Drop = "Drop";
|
public static readonly BoundKeyFunction Drop = "Drop";
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
// Does the user have hands?
|
// Does the user have hands?
|
||||||
Hand? hand;
|
Hand? hand;
|
||||||
if (!TryComp(user, out SharedHandsComponent? hands) || !hands.TryGetActiveHand(out hand))
|
if (!TryComp(user, out SharedHandsComponent? hands) || hands.ActiveHand == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var inRangeUnobstructed = target == null
|
var inRangeUnobstructed = target == null
|
||||||
@@ -224,7 +224,7 @@ namespace Content.Shared.Interaction
|
|||||||
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
: !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities
|
||||||
|
|
||||||
// empty-hand interactions
|
// empty-hand interactions
|
||||||
if (hand.HeldEntity == null)
|
if (hands.ActiveHandEntity is not EntityUid held)
|
||||||
{
|
{
|
||||||
if (inRangeUnobstructed && target != null)
|
if (inRangeUnobstructed && target != null)
|
||||||
InteractHand(user, target.Value);
|
InteractHand(user, target.Value);
|
||||||
@@ -236,7 +236,7 @@ namespace Content.Shared.Interaction
|
|||||||
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
if (checkCanUse && !_actionBlockerSystem.CanUseHeldEntity(user))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (target == hand.HeldEntity)
|
if (target == held)
|
||||||
{
|
{
|
||||||
UseInHandInteraction(user, target.Value, checkCanUse: false, checkCanInteract: false);
|
UseInHandInteraction(user, target.Value, checkCanUse: false, checkCanInteract: false);
|
||||||
return;
|
return;
|
||||||
@@ -246,7 +246,7 @@ namespace Content.Shared.Interaction
|
|||||||
{
|
{
|
||||||
InteractUsing(
|
InteractUsing(
|
||||||
user,
|
user,
|
||||||
hand.HeldEntity.Value,
|
held,
|
||||||
target.Value,
|
target.Value,
|
||||||
coordinates,
|
coordinates,
|
||||||
checkCanInteract: false,
|
checkCanInteract: false,
|
||||||
@@ -257,7 +257,7 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
InteractUsingRanged(
|
InteractUsingRanged(
|
||||||
user,
|
user,
|
||||||
hand.HeldEntity.Value,
|
held,
|
||||||
target,
|
target,
|
||||||
coordinates,
|
coordinates,
|
||||||
inRangeUnobstructed);
|
inRangeUnobstructed);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
@@ -21,6 +22,7 @@ public abstract partial class InventorySystem
|
|||||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
|
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
|
||||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
|
|
||||||
private void InitializeEquip()
|
private void InitializeEquip()
|
||||||
@@ -52,7 +54,7 @@ public abstract partial class InventorySystem
|
|||||||
if (!TryEquip(args.User, uid, slotDef.Name, true, inventory: inv))
|
if (!TryEquip(args.User, uid, slotDef.Name, true, inventory: inv))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
hands.PutInHandOrDrop(slotEntity.Value);
|
_handsSystem.PickupOrDrop(args.User, slotEntity.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -104,7 +106,7 @@ public abstract partial class InventorySystem
|
|||||||
if (!TryComp(actor, out InventoryComponent? inventory) || !TryComp<SharedHandsComponent>(actor, out var hands))
|
if (!TryComp(actor, out InventoryComponent? inventory) || !TryComp<SharedHandsComponent>(actor, out var hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hands.TryGetActiveHeldEntity(out var held);
|
var held = hands.ActiveHandEntity;
|
||||||
TryGetSlotEntity(actor, ev.Slot, out var itemUid, inventory);
|
TryGetSlotEntity(actor, ev.Slot, out var itemUid, inventory);
|
||||||
|
|
||||||
// attempt to perform some interaction
|
// attempt to perform some interaction
|
||||||
@@ -118,8 +120,8 @@ public abstract partial class InventorySystem
|
|||||||
// un-equip to hands
|
// un-equip to hands
|
||||||
if (itemUid != null)
|
if (itemUid != null)
|
||||||
{
|
{
|
||||||
if (hands.CanPickupEntityToActiveHand(itemUid.Value) && TryUnequip(actor, ev.Slot, inventory: inventory))
|
if (_handsSystem.CanPickupAnyHand(actor, itemUid.Value, handsComp: hands) && TryUnequip(actor, ev.Slot, inventory: inventory))
|
||||||
hands.PutInHand(itemUid.Value, false);
|
_handsSystem.TryPickup(actor, itemUid.Value, checkActionBlocker: false, handsComp: hands);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +137,7 @@ public abstract partial class InventorySystem
|
|||||||
return;
|
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);
|
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>
|
public PickupAttemptEvent(EntityUid user, EntityUid item) : base(user, item) { }
|
||||||
/// Raised on a *mob* when it tries to pickup something
|
}
|
||||||
/// </summary>
|
|
||||||
public sealed class PickupAttemptEvent : CancellableEntityEventArgs
|
|
||||||
{
|
|
||||||
public PickupAttemptEvent(EntityUid uid)
|
|
||||||
{
|
|
||||||
Uid = uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
[Virtual]
|
||||||
/// Raised on the *item* when tried to be picked up
|
public class BasePickupAttemptEvent : CancellableEntityEventArgs
|
||||||
/// </summary>
|
{
|
||||||
/// <remarks>
|
public readonly EntityUid User;
|
||||||
/// Doesn't just handle "items" but calling it "PickedUpAttempt" is too close to "Pickup" for the sleep deprived brain.
|
public readonly EntityUid Item;
|
||||||
/// </remarks>
|
|
||||||
public sealed class AttemptItemPickupEvent : CancellableEntityEventArgs
|
public BasePickupAttemptEvent(EntityUid user, EntityUid item)
|
||||||
{
|
{
|
||||||
|
User = user;
|
||||||
|
Item = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Content.Shared.Item
|
namespace Content.Shared.Item
|
||||||
{
|
{
|
||||||
public abstract class SharedItemSystem : EntitySystem
|
public abstract class SharedItemSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -30,13 +30,7 @@ namespace Content.Shared.Item
|
|||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryComp(args.User, out SharedHandsComponent? hands))
|
args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false);
|
||||||
return;
|
|
||||||
|
|
||||||
if (hands.ActiveHand == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
args.Handled = hands.TryPickupEntity(hands.ActiveHand, uid, false, animateUser: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHandleState(EntityUid uid, SharedItemComponent component, ref ComponentHandleState args)
|
private void OnHandleState(EntityUid uid, SharedItemComponent component, ref ComponentHandleState args)
|
||||||
@@ -74,11 +68,11 @@ namespace Content.Shared.Item
|
|||||||
args.Using != null ||
|
args.Using != null ||
|
||||||
!args.CanAccess ||
|
!args.CanAccess ||
|
||||||
!args.CanInteract ||
|
!args.CanInteract ||
|
||||||
!args.Hands.CanPickupEntityToActiveHand(args.Target))
|
!_handsSystem.CanPickupAnyHand(args.User, args.Target, handsComp: args.Hands, item: component))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InteractionVerb verb = new();
|
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";
|
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.
|
// 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.Components;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
|
|
||||||
namespace Content.Shared.Placeable
|
namespace Content.Shared.Placeable
|
||||||
{
|
{
|
||||||
public sealed class PlaceableSurfaceSystem : EntitySystem
|
public sealed class PlaceableSurfaceSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -52,16 +52,13 @@ namespace Content.Shared.Placeable
|
|||||||
if (!surface.IsPlaceable)
|
if (!surface.IsPlaceable)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(!EntityManager.TryGetComponent<SharedHandsComponent?>(args.User, out var handComponent))
|
if (!_handsSystem.TryDrop(args.User, args.Used))
|
||||||
return;
|
|
||||||
|
|
||||||
if(!handComponent.TryDropEntity(args.Used, EntityManager.GetComponent<TransformComponent>(surface.Owner).Coordinates))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (surface.PlaceCentered)
|
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
|
else
|
||||||
EntityManager.GetComponent<TransformComponent>(args.Used).Coordinates = args.ClickLocation;
|
Transform(args.Used).Coordinates = args.ClickLocation;
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace Content.Shared.Verbs
|
|||||||
EntityUid? @using = null;
|
EntityUid? @using = null;
|
||||||
if (TryComp(user, out SharedHandsComponent? hands) && (force || _actionBlockerSystem.CanUseHeldEntity(user)))
|
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".
|
// 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
|
// 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