Partial hand ECS (#5634)
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Co-authored-by: Paul Ritter <ritter.paul1@googlemail.com> Co-authored-by: Paul <ritter.paul1@googlemail.com>
This commit is contained in:
@@ -30,6 +30,7 @@ namespace Content.Client.Animations
|
|||||||
}
|
}
|
||||||
var sprite = entMan.GetComponent<SpriteComponent>(animatableClone);
|
var sprite = entMan.GetComponent<SpriteComponent>(animatableClone);
|
||||||
sprite.CopyFrom(sprite0);
|
sprite.CopyFrom(sprite0);
|
||||||
|
sprite.Visible = true;
|
||||||
|
|
||||||
var animations = entMan.GetComponent<AnimationPlayerComponent>(animatableClone);
|
var animations = entMan.GetComponent<AnimationPlayerComponent>(animatableClone);
|
||||||
animations.AnimationCompleted += (_) => {
|
animations.AnimationCompleted += (_) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Analyzers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
@@ -7,48 +7,9 @@ namespace Content.Client.Hands
|
|||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(SharedHandsComponent))]
|
[ComponentReference(typeof(SharedHandsComponent))]
|
||||||
|
[Friend(typeof(HandsSystem))]
|
||||||
public class HandsComponent : SharedHandsComponent
|
public class HandsComponent : SharedHandsComponent
|
||||||
{
|
{
|
||||||
public HandsGui? Gui { get; set; }
|
public HandsGui? Gui { get; set; }
|
||||||
|
|
||||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
|
||||||
{
|
|
||||||
if (curState is not HandsComponentState state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Hands.Clear();
|
|
||||||
|
|
||||||
foreach (var handState in state.Hands)
|
|
||||||
{
|
|
||||||
var newHand = new Hand(handState.Name, handState.Location);
|
|
||||||
Hands.Add(newHand);
|
|
||||||
}
|
|
||||||
|
|
||||||
ActiveHand = state.ActiveHand;
|
|
||||||
|
|
||||||
HandsModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void HandsModified()
|
|
||||||
{
|
|
||||||
UpdateHandContainers();
|
|
||||||
|
|
||||||
base.HandsModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateHandContainers()
|
|
||||||
{
|
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent<ContainerManagerComponent?>(Owner, out var containerMan))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var hand in Hands)
|
|
||||||
{
|
|
||||||
if (hand.Container == null)
|
|
||||||
{
|
|
||||||
containerMan.TryGetContainer(hand.Name, out var container);
|
|
||||||
hand.Container = container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,24 +59,18 @@ namespace Content.Client.Hands
|
|||||||
{
|
{
|
||||||
base.EnteredTree();
|
base.EnteredTree();
|
||||||
|
|
||||||
_handsSystem.GuiStateUpdated += HandsSystemOnGuiStateUpdated;
|
|
||||||
_configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
_configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
||||||
|
|
||||||
HandsSystemOnGuiStateUpdated();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ExitedTree()
|
protected override void ExitedTree()
|
||||||
{
|
{
|
||||||
base.ExitedTree();
|
base.ExitedTree();
|
||||||
|
|
||||||
_handsSystem.GuiStateUpdated -= HandsSystemOnGuiStateUpdated;
|
|
||||||
_configManager.UnsubValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
_configManager.UnsubValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandsSystemOnGuiStateUpdated()
|
public void Update(HandsGuiState state)
|
||||||
{
|
{
|
||||||
var state = _handsSystem.GetGuiState();
|
|
||||||
|
|
||||||
ActiveHand = state.ActiveHand;
|
ActiveHand = state.ActiveHand;
|
||||||
_hands = state.GuiHands;
|
_hands = state.GuiHands;
|
||||||
Array.Sort(_hands, HandOrderComparer.Instance);
|
Array.Sort(_hands, HandOrderComparer.Instance);
|
||||||
@@ -97,7 +91,7 @@ namespace Content.Client.Hands
|
|||||||
newButton.OnPressed += args => OnHandPressed(args, handName);
|
newButton.OnPressed += args => OnHandPressed(args, handName);
|
||||||
newButton.OnStoragePressed += _ => OnStoragePressed(handName);
|
newButton.OnStoragePressed += _ => OnStoragePressed(handName);
|
||||||
|
|
||||||
_itemSlotManager.SetItemSlot(newButton, hand.HeldItem ?? EntityUid.Invalid);
|
_itemSlotManager.SetItemSlot(newButton, hand.HeldItem);
|
||||||
|
|
||||||
// Show blocked overlay if hand is blocked.
|
// Show blocked overlay if hand is blocked.
|
||||||
newButton.Blocked.Visible =
|
newButton.Blocked.Visible =
|
||||||
@@ -107,7 +101,7 @@ namespace Content.Client.Hands
|
|||||||
if (TryGetActiveHand(out var activeHand))
|
if (TryGetActiveHand(out var activeHand))
|
||||||
{
|
{
|
||||||
activeHand.HandButton.SetActiveHand(true);
|
activeHand.HandButton.SetActiveHand(true);
|
||||||
StatusPanel.Update(activeHand.HeldItem ?? EntityUid.Invalid);
|
StatusPanel.Update(activeHand.HeldItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +113,7 @@ namespace Content.Client.Hands
|
|||||||
}
|
}
|
||||||
else if (TryGetHand(handName, out var hand))
|
else if (TryGetHand(handName, out var hand))
|
||||||
{
|
{
|
||||||
_itemSlotManager.OnButtonPressed(args, hand.HeldItem ?? EntityUid.Invalid);
|
_itemSlotManager.OnButtonPressed(args, hand.HeldItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +150,7 @@ namespace Content.Client.Hands
|
|||||||
|
|
||||||
foreach (var hand in _hands)
|
foreach (var hand in _hands)
|
||||||
{
|
{
|
||||||
_itemSlotManager.UpdateCooldown(hand.HandButton, hand.HeldItem ?? EntityUid.Invalid);
|
_itemSlotManager.UpdateCooldown(hand.HandButton, hand.HeldItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Client.Animations;
|
using Content.Client.Animations;
|
||||||
using Content.Client.HUD;
|
using Content.Client.HUD;
|
||||||
@@ -9,8 +9,10 @@ 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.GameObjects;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Client.Hands
|
namespace Content.Client.Hands
|
||||||
@@ -22,8 +24,6 @@ namespace Content.Client.Hands
|
|||||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
||||||
public event Action? GuiStateUpdated;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -31,70 +31,107 @@ namespace Content.Client.Hands
|
|||||||
SubscribeLocalEvent<HandsComponent, PlayerAttachedEvent>(HandlePlayerAttached);
|
SubscribeLocalEvent<HandsComponent, PlayerAttachedEvent>(HandlePlayerAttached);
|
||||||
SubscribeLocalEvent<HandsComponent, PlayerDetachedEvent>(HandlePlayerDetached);
|
SubscribeLocalEvent<HandsComponent, PlayerDetachedEvent>(HandlePlayerDetached);
|
||||||
SubscribeLocalEvent<HandsComponent, ComponentRemove>(HandleCompRemove);
|
SubscribeLocalEvent<HandsComponent, ComponentRemove>(HandleCompRemove);
|
||||||
SubscribeLocalEvent<HandsModifiedMessage>(HandleHandsModified);
|
SubscribeLocalEvent<HandsComponent, ComponentHandleState>(HandleComponentState);
|
||||||
|
|
||||||
SubscribeNetworkEvent<PickupAnimationMessage>(HandlePickupAnimation);
|
SubscribeNetworkEvent<PickupAnimationEvent>(HandlePickupAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
#region StateHandling
|
||||||
|
private void HandleComponentState(EntityUid uid, HandsComponent component, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
CommandBinds.Unregister<HandsSystem>();
|
if (args.Current is not HandsComponentState state)
|
||||||
base.Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleHandsModified(HandsModifiedMessage ev)
|
|
||||||
{
|
|
||||||
if (ev.Hands.Owner == _playerManager.LocalPlayer?.ControlledEntity)
|
|
||||||
GuiStateUpdated?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void HandleContainerModified(EntityUid uid, SharedHandsComponent component, ContainerModifiedMessage args)
|
|
||||||
{
|
|
||||||
if (uid == _playerManager.LocalPlayer?.ControlledEntity)
|
|
||||||
GuiStateUpdated?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandlePickupAnimation(PickupAnimationMessage msg)
|
|
||||||
{
|
|
||||||
if (!EntityManager.EntityExists(msg.EntityUid))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Do we have a NEW hand?
|
||||||
|
var handsModified = component.Hands.Count != state.Hands.Count;
|
||||||
|
if (!handsModified)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < state.Hands.Count; i++)
|
||||||
|
{
|
||||||
|
if (component.Hands[i].Name != state.Hands[i].Name ||
|
||||||
|
component.Hands[i].Location != state.Hands[i].Location)
|
||||||
|
{
|
||||||
|
handsModified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handsModified)
|
||||||
|
{
|
||||||
|
// we have new hands, get the new containers.
|
||||||
|
component.Hands = state.Hands;
|
||||||
|
UpdateHandContainers(uid, 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)
|
||||||
|
UpdateGui();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region PickupAnimation
|
||||||
|
private void HandlePickupAnimation(PickupAnimationEvent msg)
|
||||||
|
{
|
||||||
|
PickupAnimation(msg.ItemUid, msg.InitialPosition, msg.FinalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||||
|
EntityUid? exclude)
|
||||||
|
{
|
||||||
|
PickupAnimation(item, initialPosition, finalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition)
|
||||||
|
{
|
||||||
if (!_gameTiming.IsFirstTimePredicted)
|
if (!_gameTiming.IsFirstTimePredicted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ReusableAnimations.AnimateEntityPickup(msg.EntityUid, msg.InitialPosition, msg.FinalPosition, EntityManager);
|
if (finalPosition.EqualsApprox(initialPosition.Position, tolerance: 0.1f))
|
||||||
}
|
return;
|
||||||
|
|
||||||
public HandsGuiState GetGuiState()
|
ReusableAnimations.AnimateEntityPickup(item, initialPosition, finalPosition);
|
||||||
{
|
|
||||||
if (GetPlayerHandsComponent() is not { } hands)
|
|
||||||
return new HandsGuiState(Array.Empty<GuiHand>());
|
|
||||||
|
|
||||||
var states = hands.Hands
|
|
||||||
.Select(hand => new GuiHand(hand.Name, hand.Location, hand.HeldEntity))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return new HandsGuiState(states, hands.ActiveHand);
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public EntityUid? GetActiveHandEntity()
|
public EntityUid? GetActiveHandEntity()
|
||||||
{
|
{
|
||||||
if (GetPlayerHandsComponent() is not { ActiveHand: { } active } hands)
|
return TryGetPlayerHands(out var hands) && hands.TryGetActiveHeldEntity(out var entity)
|
||||||
return null;
|
? entity
|
||||||
|
: null;
|
||||||
return hands.GetHand(active).HeldEntity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HandsComponent? GetPlayerHandsComponent()
|
/// <summary>
|
||||||
|
/// Get the hands component of the local player
|
||||||
|
/// </summary>
|
||||||
|
public bool TryGetPlayerHands([NotNullWhen(true)] out HandsComponent? hands)
|
||||||
{
|
{
|
||||||
var player = _playerManager.LocalPlayer?.ControlledEntity;
|
var player = _playerManager.LocalPlayer?.ControlledEntity;
|
||||||
|
hands = null;
|
||||||
if (player is not {Valid: true} || !EntityManager.TryGetComponent(player.Value, out HandsComponent? hands))
|
return player != null && TryComp(player.Value, out hands);
|
||||||
return null;
|
|
||||||
|
|
||||||
return hands;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a user clicked on their hands GUI
|
||||||
|
/// </summary>
|
||||||
public void UIHandClick(HandsComponent hands, string handName)
|
public void UIHandClick(HandsComponent hands, string handName)
|
||||||
{
|
{
|
||||||
if (!hands.TryGetHand(handName, out var pressedHand))
|
if (!hands.TryGetHand(handName, out var pressedHand))
|
||||||
@@ -117,7 +154,7 @@ namespace Content.Client.Hands
|
|||||||
if (pressedHand != activeHand && pressedEntity == null)
|
if (pressedHand != activeHand && pressedEntity == null)
|
||||||
{
|
{
|
||||||
// change active hand
|
// change active hand
|
||||||
RaiseNetworkEvent(new RequestSetHandEvent(handName));
|
EntityManager.RaisePredictiveEvent(new RequestSetHandEvent(handName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,9 +172,44 @@ namespace Content.Client.Hands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a user clicks on an item in their hands GUI.
|
||||||
|
/// </summary>
|
||||||
public void UIHandActivate(string handName)
|
public void UIHandActivate(string handName)
|
||||||
{
|
{
|
||||||
RaiseNetworkEvent (new ActivateInHandMsg(handName));
|
RaiseNetworkEvent(new ActivateInHandMsg(handName));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Gui
|
||||||
|
public void UpdateGui(HandsComponent? hands = null)
|
||||||
|
{
|
||||||
|
if (hands == null && !TryGetPlayerHands(out hands) || hands.Gui == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var states = hands.Hands
|
||||||
|
.Select(hand => new GuiHand(hand.Name, hand.Location, hand.HeldEntity))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
hands.Gui.Update(new HandsGuiState(states, hands.ActiveHand));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void HandleContainerModified(EntityUid uid, SharedHandsComponent component, ContainerModifiedMessage args)
|
||||||
|
{
|
||||||
|
base.HandleContainerModified(uid, component, args);
|
||||||
|
|
||||||
|
if (uid == _playerManager.LocalPlayer?.ControlledEntity)
|
||||||
|
UpdateGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TrySetActiveHand(EntityUid uid, string? value, SharedHandsComponent? handComp = null)
|
||||||
|
{
|
||||||
|
if (!base.TrySetActiveHand(uid, value, handComp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (uid == _playerManager.LocalPlayer?.ControlledEntity)
|
||||||
|
UpdateGui();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePlayerAttached(EntityUid uid, HandsComponent component, PlayerAttachedEvent args)
|
private void HandlePlayerAttached(EntityUid uid, HandsComponent component, PlayerAttachedEvent args)
|
||||||
@@ -145,6 +217,7 @@ namespace Content.Client.Hands
|
|||||||
component.Gui = new HandsGui(component, this);
|
component.Gui = new HandsGui(component, this);
|
||||||
_gameHud.HandsContainer.AddChild(component.Gui);
|
_gameHud.HandsContainer.AddChild(component.Gui);
|
||||||
component.Gui.SetPositionFirst();
|
component.Gui.SetPositionFirst();
|
||||||
|
UpdateGui(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void HandlePlayerDetached(EntityUid uid, HandsComponent component, PlayerDetachedEvent args)
|
private static void HandlePlayerDetached(EntityUid uid, HandsComponent component, PlayerDetachedEvent args)
|
||||||
@@ -162,5 +235,6 @@ namespace Content.Client.Hands
|
|||||||
comp.Gui?.Orphan();
|
comp.Gui?.Orphan();
|
||||||
comp.Gui = null;
|
comp.Gui = null;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Content.Client.Hands;
|
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
@@ -8,15 +6,5 @@ namespace Content.Client.Items.Components
|
|||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(SharedItemComponent))]
|
[ComponentReference(typeof(SharedItemComponent))]
|
||||||
public class ItemComponent : SharedItemComponent
|
public class ItemComponent : SharedItemComponent { }
|
||||||
{
|
|
||||||
protected override void OnEquippedPrefixChange()
|
|
||||||
{
|
|
||||||
if (!Owner.TryGetContainer(out var container))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent(container.Owner, out HandsComponent? hands))
|
|
||||||
hands.UpdateHandVisualizer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Client.Items.UI;
|
using Content.Client.Items.UI;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -7,10 +7,10 @@ namespace Content.Client.Items.Managers
|
|||||||
{
|
{
|
||||||
public interface IItemSlotManager
|
public interface IItemSlotManager
|
||||||
{
|
{
|
||||||
bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid item);
|
bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid? item);
|
||||||
void UpdateCooldown(ItemSlotButton? cooldownTexture, EntityUid entity);
|
void UpdateCooldown(ItemSlotButton? cooldownTexture, EntityUid? entity);
|
||||||
bool SetItemSlot(ItemSlotButton button, EntityUid? entity);
|
bool SetItemSlot(ItemSlotButton button, EntityUid? entity);
|
||||||
void HoverInSlot(ItemSlotButton button, EntityUid entity, bool fits);
|
void HoverInSlot(ItemSlotButton button, EntityUid? entity, bool fits);
|
||||||
event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
|
event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
|
||||||
bool IsHighlighted(EntityUid? uid);
|
bool IsHighlighted(EntityUid? uid);
|
||||||
|
|
||||||
|
|||||||
@@ -53,34 +53,34 @@ namespace Content.Client.Items.Managers
|
|||||||
button.StorageButton.Visible = _entityManager.HasComponent<ClientStorageComponent>(entity);
|
button.StorageButton.Visible = _entityManager.HasComponent<ClientStorageComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.Entity = entity;
|
button.Entity = entity ?? default;
|
||||||
|
|
||||||
// im lazy
|
// im lazy
|
||||||
button.UpdateSlotHighlighted();
|
button.UpdateSlotHighlighted();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid item)
|
public bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid? item)
|
||||||
{
|
{
|
||||||
if (item == default)
|
if (item == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (args.Function == ContentKeyFunctions.ExamineEntity)
|
if (args.Function == ContentKeyFunctions.ExamineEntity)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<ExamineSystem>()
|
_entitySystemManager.GetEntitySystem<ExamineSystem>()
|
||||||
.DoExamine(item);
|
.DoExamine(item.Value);
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.OpenContextMenu)
|
else if (args.Function == ContentKeyFunctions.OpenContextMenu)
|
||||||
{
|
{
|
||||||
_entitySystemManager.GetEntitySystem<VerbSystem>().VerbMenu.OpenVerbMenu(item);
|
_entitySystemManager.GetEntitySystem<VerbSystem>().VerbMenu.OpenVerbMenu(item.Value);
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
||||||
{
|
{
|
||||||
_entityManager.EntityNetManager?.SendSystemNetworkMessage(new InteractInventorySlotEvent(item, altInteract: false));
|
_entityManager.EntityNetManager?.SendSystemNetworkMessage(new InteractInventorySlotEvent(item.Value, altInteract: false));
|
||||||
}
|
}
|
||||||
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
||||||
{
|
{
|
||||||
_entityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(item, altInteract: true));
|
_entityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(item.Value, altInteract: true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -90,7 +90,7 @@ namespace Content.Client.Items.Managers
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCooldown(ItemSlotButton? button, EntityUid entity)
|
public void UpdateCooldown(ItemSlotButton? button, EntityUid? entity)
|
||||||
{
|
{
|
||||||
var cooldownDisplay = button?.CooldownDisplay;
|
var cooldownDisplay = button?.CooldownDisplay;
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ namespace Content.Client.Items.Managers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity == default || _entityManager.Deleted(entity) ||
|
if (entity == null || _entityManager.Deleted(entity) ||
|
||||||
!_entityManager.TryGetComponent(entity, out ItemCooldownComponent? cooldown) ||
|
!_entityManager.TryGetComponent(entity, out ItemCooldownComponent? cooldown) ||
|
||||||
!cooldown.CooldownStart.HasValue ||
|
!cooldown.CooldownStart.HasValue ||
|
||||||
!cooldown.CooldownEnd.HasValue)
|
!cooldown.CooldownEnd.HasValue)
|
||||||
@@ -119,9 +119,9 @@ namespace Content.Client.Items.Managers
|
|||||||
cooldownDisplay.Visible = ratio > -1f;
|
cooldownDisplay.Visible = ratio > -1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HoverInSlot(ItemSlotButton button, EntityUid entity, bool fits)
|
public void HoverInSlot(ItemSlotButton button, EntityUid? entity, bool fits)
|
||||||
{
|
{
|
||||||
if (entity == default || !button.MouseIsHovering)
|
if (entity == null || !button.MouseIsHovering)
|
||||||
{
|
{
|
||||||
button.ClearHover();
|
button.ClearHover();
|
||||||
return;
|
return;
|
||||||
@@ -135,7 +135,7 @@ namespace Content.Client.Items.Managers
|
|||||||
// Set green / red overlay at 50% transparency
|
// Set green / red overlay at 50% transparency
|
||||||
var hoverEntity = _entityManager.SpawnEntity("hoverentity", MapCoordinates.Nullspace);
|
var hoverEntity = _entityManager.SpawnEntity("hoverentity", MapCoordinates.Nullspace);
|
||||||
var hoverSprite = _entityManager.GetComponent<SpriteComponent>(hoverEntity);
|
var hoverSprite = _entityManager.GetComponent<SpriteComponent>(hoverEntity);
|
||||||
hoverSprite.CopyFrom(_entityManager.GetComponent<SpriteComponent>(entity));
|
hoverSprite.CopyFrom(_entityManager.GetComponent<SpriteComponent>(entity.Value));
|
||||||
hoverSprite.Color = fits ? new Color(0, 255, 0, 127) : new Color(255, 0, 0, 127);
|
hoverSprite.Color = fits ? new Color(0, 255, 0, 127) : new Color(255, 0, 0, 127);
|
||||||
|
|
||||||
button.HoverSpriteView.Sprite = hoverSprite;
|
button.HoverSpriteView.Sprite = hoverSprite;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace Content.Client.Items.UI
|
|||||||
private readonly PanelContainer _panel;
|
private readonly PanelContainer _panel;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private EntityUid _entity;
|
private EntityUid? _entity;
|
||||||
|
|
||||||
public ItemStatusPanel(Texture texture, StyleBox.Margin cutout, StyleBox.Margin flat, Label.AlignMode textAlign)
|
public ItemStatusPanel(Texture texture, StyleBox.Margin cutout, StyleBox.Margin flat, Label.AlignMode textAlign)
|
||||||
{
|
{
|
||||||
@@ -130,19 +130,19 @@ namespace Content.Client.Items.UI
|
|||||||
UpdateItemName();
|
UpdateItemName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(EntityUid entity)
|
public void Update(EntityUid? entity)
|
||||||
{
|
{
|
||||||
if (entity == default)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
ClearOldStatus();
|
ClearOldStatus();
|
||||||
_entity = default;
|
_entity = null;
|
||||||
_panel.Visible = false;
|
_panel.Visible = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity != _entity)
|
if (entity != _entity)
|
||||||
{
|
{
|
||||||
_entity = entity;
|
_entity = entity.Value;
|
||||||
BuildNewEntityStatus();
|
BuildNewEntityStatus();
|
||||||
|
|
||||||
UpdateItemName();
|
UpdateItemName();
|
||||||
@@ -153,7 +153,7 @@ namespace Content.Client.Items.UI
|
|||||||
|
|
||||||
private void UpdateItemName()
|
private void UpdateItemName()
|
||||||
{
|
{
|
||||||
if (_entity == default)
|
if (_entity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_entityManager.TryGetComponent(_entity, out HandVirtualItemComponent? virtualItem)
|
if (_entityManager.TryGetComponent(_entity, out HandVirtualItemComponent? virtualItem)
|
||||||
@@ -163,7 +163,7 @@ namespace Content.Client.Items.UI
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_itemNameLabel.Text = _entityManager.GetComponent<MetaDataComponent>(_entity).EntityName;
|
_itemNameLabel.Text = _entityManager.GetComponent<MetaDataComponent>(_entity.Value).EntityName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ namespace Content.Client.Items.UI
|
|||||||
|
|
||||||
ClearOldStatus();
|
ClearOldStatus();
|
||||||
|
|
||||||
foreach (var statusComponent in _entityManager.GetComponents<IItemStatus>(_entity))
|
foreach (var statusComponent in _entityManager.GetComponents<IItemStatus>(_entity!.Value))
|
||||||
{
|
{
|
||||||
var control = statusComponent.MakeControl();
|
var control = statusComponent.MakeControl();
|
||||||
_statusContents.AddChild(control);
|
_statusContents.AddChild(control);
|
||||||
@@ -194,7 +194,7 @@ namespace Content.Client.Items.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
var collectMsg = new ItemStatusCollectMessage();
|
var collectMsg = new ItemStatusCollectMessage();
|
||||||
_entityManager.EventBus.RaiseLocalEvent(_entity, collectMsg);
|
_entityManager.EventBus.RaiseLocalEvent(_entity!.Value, collectMsg);
|
||||||
|
|
||||||
foreach (var control in collectMsg.Controls)
|
foreach (var control in collectMsg.Controls)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -332,9 +332,8 @@ 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)
|
||||||
EntityManager.TryGetComponent(item, out SharedItemComponent? itemComp))
|
hands.PutInHandOrDrop(item);
|
||||||
hands.PutInHandOrDrop(itemComp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LEGACY CODE. See warning at the top of the file!
|
// LEGACY CODE. See warning at the top of the file!
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
@@ -31,7 +31,7 @@ namespace Content.Server.DoAfter
|
|||||||
doAfter.EventArgs.BreakOnUserMove,
|
doAfter.EventArgs.BreakOnUserMove,
|
||||||
doAfter.EventArgs.BreakOnTargetMove,
|
doAfter.EventArgs.BreakOnTargetMove,
|
||||||
doAfter.EventArgs.MovementThreshold,
|
doAfter.EventArgs.MovementThreshold,
|
||||||
doAfter.EventArgs.Target ?? EntityUid.Invalid);
|
doAfter.EventArgs.Target);
|
||||||
|
|
||||||
toAdd.Add(clientDoAfter);
|
toAdd.Add(clientDoAfter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Act;
|
using Content.Server.Act;
|
||||||
using Content.Server.Interaction;
|
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Pulling;
|
using Content.Server.Pulling;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
@@ -13,12 +12,10 @@ using Content.Shared.Item;
|
|||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Pulling.Components;
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
@@ -37,32 +34,6 @@ namespace Content.Server.Hands.Components
|
|||||||
|
|
||||||
int IDisarmedAct.Priority => int.MaxValue; // We want this to be the last disarm act to run.
|
int IDisarmedAct.Priority => int.MaxValue; // We want this to be the last disarm act to run.
|
||||||
|
|
||||||
protected override void OnHeldEntityRemovedFromHand(EntityUid heldEntity, HandState handState)
|
|
||||||
{
|
|
||||||
if (_entities.TryGetComponent(heldEntity, out SharedItemComponent? item))
|
|
||||||
{
|
|
||||||
item.RemovedFromSlot();
|
|
||||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().UnequippedHandInteraction(Owner, heldEntity, handState);
|
|
||||||
}
|
|
||||||
if (_entities.TryGetComponent(heldEntity, out SpriteComponent? sprite))
|
|
||||||
{
|
|
||||||
sprite.RenderOrder = _entities.CurrentTick.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void HandlePickupAnimation(EntityUid entity)
|
|
||||||
{
|
|
||||||
var initialPosition = EntityCoordinates.FromMap(_entities.GetComponent<TransformComponent>(Owner).Parent?.Owner ?? Owner, _entities.GetComponent<TransformComponent>(entity).MapPosition);
|
|
||||||
|
|
||||||
var finalPosition = _entities.GetComponent<TransformComponent>(Owner).LocalPosition;
|
|
||||||
|
|
||||||
if (finalPosition.EqualsApprox(initialPosition.Position))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_entities.EntityNetManager!.SendSystemNetworkMessage(
|
|
||||||
new PickupAnimationMessage(entity, finalPosition, initialPosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Pull/Disarm
|
#region Pull/Disarm
|
||||||
|
|
||||||
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs args)
|
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs args)
|
||||||
@@ -198,24 +169,6 @@ namespace Content.Server.Hands.Components
|
|||||||
yield return item;
|
yield return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Hands.Systems
|
namespace Content.Server.Hands.Systems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class HandVirtualItemSystem : SharedHandVirtualItemSystem
|
public sealed class HandVirtualItemSystem : SharedHandVirtualItemSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -34,7 +37,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
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;
|
||||||
hands.PutEntityIntoHand(hand, virtualItem);
|
_handsSystem.PutEntityIntoHand(user, hand, virtualItem, hands);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Interaction;
|
|
||||||
using Content.Server.Inventory;
|
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Server.Storage.Components;
|
using Content.Server.Storage.Components;
|
||||||
|
using Content.Server.Strip;
|
||||||
using Content.Server.Throwing;
|
using Content.Server.Throwing;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
@@ -16,14 +17,17 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.Physics.Pull;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Input.Binding;
|
using Robust.Shared.Input.Binding;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -36,6 +40,8 @@ namespace Content.Server.Hands.Systems
|
|||||||
[Dependency] private readonly StackSystem _stackSystem = default!;
|
[Dependency] private readonly StackSystem _stackSystem = default!;
|
||||||
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
[Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!;
|
||||||
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
|
[Dependency] private readonly AdminLogSystem _logSystem = default!;
|
||||||
|
[Dependency] private readonly StrippableSystem _strippableSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -51,27 +57,78 @@ namespace Content.Server.Hands.Systems
|
|||||||
SubscribeLocalEvent<HandsComponent, PullStartedMessage>(HandlePullStarted);
|
SubscribeLocalEvent<HandsComponent, PullStartedMessage>(HandlePullStarted);
|
||||||
SubscribeLocalEvent<HandsComponent, PullStoppedMessage>(HandlePullStopped);
|
SubscribeLocalEvent<HandsComponent, PullStoppedMessage>(HandlePullStopped);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<HandsComponent, ComponentGetState>(GetComponentState);
|
||||||
|
|
||||||
CommandBinds.Builder
|
CommandBinds.Builder
|
||||||
.Bind(ContentKeyFunctions.ActivateItemInHand, InputCmdHandler.FromDelegate(HandleActivateItem))
|
.Bind(ContentKeyFunctions.ActivateItemInHand, InputCmdHandler.FromDelegate(s => HandleActivateItem(s)))
|
||||||
.Bind(ContentKeyFunctions.AltActivateItemInHand, InputCmdHandler.FromDelegate(HandleAltActivateItem))
|
.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))
|
||||||
.Bind(ContentKeyFunctions.SwapHands, InputCmdHandler.FromDelegate(SwapHandsPressed, handle: false))
|
|
||||||
.Bind(ContentKeyFunctions.Drop, new PointerInputCmdHandler(DropPressed))
|
|
||||||
.Register<HandsSystem>();
|
.Register<HandsSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
|
||||||
|
CommandBinds.Unregister<HandsSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetComponentState(EntityUid uid, HandsComponent hands, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new HandsComponentState(hands.Hands, hands.ActiveHand);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region EntityInsertRemove
|
||||||
|
public override void RemoveHeldEntityFromHand(EntityUid uid, Hand hand, SharedHandsComponent? hands = null)
|
||||||
|
{
|
||||||
|
base.RemoveHeldEntityFromHand(uid, hand, hands);
|
||||||
|
|
||||||
|
// update gui of anyone stripping this entity.
|
||||||
|
_strippableSystem.SendUpdate(uid);
|
||||||
|
|
||||||
|
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
|
||||||
|
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PutEntityIntoHand(EntityUid uid, Hand hand, EntityUid entity, SharedHandsComponent? hands = null)
|
||||||
|
{
|
||||||
|
base.PutEntityIntoHand(uid, hand, entity, hands);
|
||||||
|
|
||||||
|
// update gui of anyone stripping this entity.
|
||||||
|
_strippableSystem.SendUpdate(uid);
|
||||||
|
|
||||||
|
_logSystem.Add(LogType.Pickup, LogImpact.Low, $"{uid} picked up {entity}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PickupAnimation(EntityUid item, EntityCoordinates initialPosition, Vector2 finalPosition,
|
||||||
|
EntityUid? exclude)
|
||||||
|
{
|
||||||
|
if (finalPosition.EqualsApprox(initialPosition.Position, tolerance: 0.1f))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var filter = Filter.Pvs(item);
|
||||||
|
|
||||||
|
if (exclude != null)
|
||||||
|
filter = filter.RemoveWhereAttachedEntity(entity => entity == exclude);
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new PickupAnimationEvent(item, initialPosition, finalPosition), filter);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region pulling
|
||||||
private static void HandlePullAttempt(EntityUid uid, HandsComponent component, PullAttemptMessage args)
|
private static void HandlePullAttempt(EntityUid uid, HandsComponent component, PullAttemptMessage args)
|
||||||
{
|
{
|
||||||
if (args.Puller.Owner != uid)
|
if (args.Puller.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Cancel pull if all hands full.
|
// Cancel pull if all hands full.
|
||||||
if (component.Hands.All(hand => hand.HeldEntity != null))
|
if (component.Hands.All(hand => !hand.IsEmpty))
|
||||||
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)
|
||||||
@@ -93,132 +150,43 @@ namespace Content.Server.Hands.Systems
|
|||||||
foreach (var hand in component.Hands)
|
foreach (var hand in component.Hands)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity == null
|
if (hand.HeldEntity == null
|
||||||
|| !EntityManager.TryGetComponent(hand.HeldEntity, out HandVirtualItemComponent? virtualItem)
|
|| !TryComp(hand.HeldEntity, out HandVirtualItemComponent? virtualItem)
|
||||||
|| virtualItem.BlockingEntity != args.Pulled.Owner)
|
|| virtualItem.BlockingEntity != args.Pulled.Owner)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
EntityManager.DeleteEntity(hand.HeldEntity.Value);
|
QueueDel(hand.HeldEntity.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
private void SwapHandsPressed(ICommonSession? session)
|
#region interactions
|
||||||
{
|
|
||||||
var player = session?.AttachedEntity;
|
|
||||||
|
|
||||||
if (!player.HasValue || !player.Value.IsValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(player.Value, out SharedHandsComponent? hands))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!hands.TryGetSwapHandsResult(out var nextHand))
|
|
||||||
return;
|
|
||||||
|
|
||||||
hands.ActiveHand = nextHand;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool DropPressed(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
|
||||||
{
|
|
||||||
var player = session?.AttachedEntity;
|
|
||||||
|
|
||||||
if (!player.HasValue || !player.Value.IsValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(player.Value, out SharedHandsComponent? hands))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var activeHand = hands.ActiveHand;
|
|
||||||
|
|
||||||
if (activeHand == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
hands.TryDropHand(activeHand, coords);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleMoveItemFromHand(MoveItemFromHandMsg msg, EntitySessionEventArgs args)
|
private void HandleMoveItemFromHand(MoveItemFromHandMsg msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (!TryGetHandsComp(args.SenderSession, out var hands))
|
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||||
return;
|
|
||||||
|
|
||||||
hands.TryMoveHeldEntityToActiveHand(msg.HandName);
|
hands.TryMoveHeldEntityToActiveHand(msg.HandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUseInHand(UseInHandMsg msg, EntitySessionEventArgs args)
|
private void HandleUseInHand(UseInHandMsg msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (!TryGetHandsComp(args.SenderSession, out var hands))
|
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||||
return;
|
|
||||||
|
|
||||||
hands.ActivateItem();
|
hands.ActivateItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleInteractUsingInHand(ClientInteractUsingInHandMsg msg, EntitySessionEventArgs args)
|
private void HandleInteractUsingInHand(ClientInteractUsingInHandMsg msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (!TryGetHandsComp(args.SenderSession, out var hands))
|
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||||
return;
|
|
||||||
|
|
||||||
hands.InteractHandWithActiveHand(msg.HandName);
|
hands.InteractHandWithActiveHand(msg.HandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
|
|
||||||
CommandBinds.Unregister<HandsSystem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleActivateInHand(ActivateInHandMsg msg, EntitySessionEventArgs args)
|
private void HandleActivateInHand(ActivateInHandMsg msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (!TryGetHandsComp(args.SenderSession, out var hands))
|
if (TryComp(args.SenderSession.AttachedEntity, out SharedHandsComponent? hands))
|
||||||
return;
|
|
||||||
|
|
||||||
hands.ActivateHeldEntity(msg.HandName);
|
hands.ActivateHeldEntity(msg.HandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Actually shows all items/clothing/etc.
|
private void HandleActivateItem(ICommonSession? session, bool altInteract = false)
|
||||||
private void HandleExamined(EntityUid uid, HandsComponent component, ExaminedEvent args)
|
|
||||||
{
|
{
|
||||||
foreach (var inhand in component.GetAllHeldItems())
|
if (TryComp(session?.AttachedEntity, out SharedHandsComponent? hands))
|
||||||
{
|
hands.ActivateItem(altInteract);
|
||||||
if (EntityManager.HasComponent<HandVirtualItemComponent>(inhand.Owner))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
args.PushText(Loc.GetString("comp-hands-examine", ("user", component.Owner), ("item", inhand.Owner)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetHandsComp(
|
|
||||||
ICommonSession? session,
|
|
||||||
[NotNullWhen(true)] out SharedHandsComponent? hands)
|
|
||||||
{
|
|
||||||
hands = default;
|
|
||||||
|
|
||||||
if (session is not IPlayerSession playerSession)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var player = playerSession.AttachedEntity;
|
|
||||||
|
|
||||||
if (player is not {Valid: true})
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return EntityManager.TryGetComponent(player, out hands);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleActivateItem(ICommonSession? session)
|
|
||||||
{
|
|
||||||
if (!TryGetHandsComp(session, out var hands))
|
|
||||||
return;
|
|
||||||
|
|
||||||
hands.ActivateItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleAltActivateItem(ICommonSession? session)
|
|
||||||
{
|
|
||||||
if (!TryGetHandsComp(session, out var hands))
|
|
||||||
return;
|
|
||||||
|
|
||||||
hands.ActivateItem(altInteract: true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||||
@@ -227,9 +195,9 @@ namespace Content.Server.Hands.Systems
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (playerSession.AttachedEntity is not {Valid: true} player ||
|
if (playerSession.AttachedEntity is not {Valid: true} player ||
|
||||||
!EntityManager.EntityExists(player) ||
|
!Exists(player) ||
|
||||||
player.IsInContainer() ||
|
player.IsInContainer() ||
|
||||||
!EntityManager.TryGetComponent(player, out SharedHandsComponent? hands) ||
|
!TryComp(player, out SharedHandsComponent? hands) ||
|
||||||
!hands.TryGetActiveHeldEntity(out var throwEnt) ||
|
!hands.TryGetActiveHeldEntity(out var throwEnt) ||
|
||||||
!_actionBlockerSystem.CanThrow(player))
|
!_actionBlockerSystem.CanThrow(player))
|
||||||
return false;
|
return false;
|
||||||
@@ -246,7 +214,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
else if (!hands.Drop(throwEnt.Value))
|
else if (!hands.Drop(throwEnt.Value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var direction = coords.ToMapPos(EntityManager) - EntityManager.GetComponent<TransformComponent>(player).WorldPosition;
|
var direction = coords.ToMapPos(EntityManager) - Transform(player).WorldPosition;
|
||||||
if (direction == Vector2.Zero)
|
if (direction == Vector2.Zero)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -273,14 +241,14 @@ namespace Content.Server.Hands.Systems
|
|||||||
if (session is not IPlayerSession playerSession)
|
if (session is not IPlayerSession playerSession)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (playerSession.AttachedEntity is not {Valid: true} plyEnt || !EntityManager.EntityExists(plyEnt))
|
if (playerSession.AttachedEntity is not {Valid: true} plyEnt || !Exists(plyEnt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands))
|
if (!EntityManager.TryGetComponent(plyEnt, out SharedHandsComponent? hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_inventorySystem.TryGetSlotEntity(plyEnt, equipmentSlot, out var slotEntity) ||
|
if (!_inventorySystem.TryGetSlotEntity(plyEnt, equipmentSlot, out var slotEntity) ||
|
||||||
!EntityManager.TryGetComponent(slotEntity, out ServerStorageComponent? storageComponent))
|
!TryComp(slotEntity, out ServerStorageComponent? storageComponent))
|
||||||
{
|
{
|
||||||
plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", equipmentSlot)));
|
plyEnt.PopupMessage(Loc.GetString("hands-system-missing-equipment-slot", ("slotName", equipmentSlot)));
|
||||||
return;
|
return;
|
||||||
@@ -301,11 +269,24 @@ 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))
|
if (!hands.TryPickupEntityToActiveHand(lastStoredEntity, animateUser: true))
|
||||||
EntityManager.GetComponent<TransformComponent>(lastStoredEntity).Coordinates = EntityManager.GetComponent<TransformComponent>(plyEnt).Coordinates;
|
Transform(lastStoredEntity).Coordinates = Transform(plyEnt).Coordinates;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ namespace Content.Server.Inventory
|
|||||||
{
|
{
|
||||||
hands.PutInHand(itemUid.Value);
|
hands.PutInHand(itemUid.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev)
|
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev)
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ namespace Content.Server.Light.EntitySystems
|
|||||||
if (userUid != null)
|
if (userUid != null)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent(userUid.Value, out SharedHandsComponent? hands))
|
if (EntityManager.TryGetComponent(userUid.Value, out SharedHandsComponent? hands))
|
||||||
hands.TryPutInActiveHandOrAny(bulb);
|
hands.PutInHand(bulb);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateLight(uid, light);
|
UpdateLight(uid, light);
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ namespace Content.Server.PneumaticCannon
|
|||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent<HandsComponent?>(user, out var hands))
|
if (EntityManager.TryGetComponent<HandsComponent?>(user, out var hands))
|
||||||
{
|
{
|
||||||
hands.TryPutInActiveHandOrAny(contained);
|
hands.PutInHand(contained);
|
||||||
}
|
}
|
||||||
|
|
||||||
user.PopupMessage(Loc.GetString("pneumatic-cannon-component-gas-tank-remove",
|
user.PopupMessage(Loc.GetString("pneumatic-cannon-component-gas-tank-remove",
|
||||||
|
|||||||
@@ -47,18 +47,14 @@ namespace Content.Server.Strip
|
|||||||
|
|
||||||
_strippableSystem = EntitySystem.Get<StrippableSystem>();
|
_strippableSystem = EntitySystem.Get<StrippableSystem>();
|
||||||
Owner.EnsureComponentWarn<ServerInventoryComponent>();
|
Owner.EnsureComponentWarn<ServerInventoryComponent>();
|
||||||
var hands = Owner.EnsureComponentWarn<HandsComponent>();
|
|
||||||
var cuffed = Owner.EnsureComponentWarn<CuffableComponent>();
|
var cuffed = Owner.EnsureComponentWarn<CuffableComponent>();
|
||||||
cuffed.OnCuffedStateChanged += UpdateState;
|
cuffed.OnCuffedStateChanged += UpdateState;
|
||||||
hands.OnItemChanged += UpdateState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Shutdown()
|
protected override void Shutdown()
|
||||||
{
|
{
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
|
||||||
if(_entities.TryGetComponent<HandsComponent>(Owner, out var hands))
|
|
||||||
hands.OnItemChanged -= UpdateState;
|
|
||||||
if(_entities.TryGetComponent<CuffableComponent>(Owner, out var cuffed))
|
if(_entities.TryGetComponent<CuffableComponent>(Owner, out var cuffed))
|
||||||
cuffed.OnCuffedStateChanged -= UpdateState;
|
cuffed.OnCuffedStateChanged -= UpdateState;
|
||||||
}
|
}
|
||||||
@@ -208,8 +204,8 @@ namespace Content.Server.Strip
|
|||||||
if (result != DoAfterStatus.Finished) return;
|
if (result != DoAfterStatus.Finished) return;
|
||||||
|
|
||||||
userHands.Drop(hand);
|
userHands.Drop(hand);
|
||||||
hands.TryPickupEntity(hand, item!.Owner, checkActionBlocker: false);
|
hands.TryPickupEntity(hand, item!.Owner, checkActionBlocker: false, animateUser: true);
|
||||||
UpdateState();
|
// hand update will trigger strippable update
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -314,10 +310,12 @@ 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;
|
||||||
|
|
||||||
var item = hands.GetItem(hand);
|
if (!hands.TryGetHeldEntity(hand, out var entity))
|
||||||
|
return;
|
||||||
|
|
||||||
hands.Drop(hand, false);
|
hands.Drop(hand, false);
|
||||||
userHands.PutInHandOrDrop(item!);
|
userHands.PutInHandOrDrop(entity.Value);
|
||||||
UpdateState();
|
// hand update will trigger strippable update
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj)
|
private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace Content.Server.Strip
|
|||||||
|
|
||||||
public void SendUpdate(EntityUid uid, StrippableComponent? strippableComponent = null)
|
public void SendUpdate(EntityUid uid, StrippableComponent? strippableComponent = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref strippableComponent) || strippableComponent.UserInterface == null)
|
if (!Resolve(uid, ref strippableComponent, false) || strippableComponent.UserInterface == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
23
Content.Server/Weapon/Ranged/RangedWeaponSystem.cs
Normal file
23
Content.Server/Weapon/Ranged/RangedWeaponSystem.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Content.Shared.Hands;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Weapon.Ranged
|
||||||
|
{
|
||||||
|
public sealed class RangedWeaponSysten : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ServerRangedWeaponComponent, HandSelectedEvent>(OnHandSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandSelected(EntityUid uid, ServerRangedWeaponComponent component, HandSelectedEvent args)
|
||||||
|
{
|
||||||
|
// Instead of dirtying on hand-select this component should probably by dirtied whenever it needs to be.
|
||||||
|
// I take no responsibility for this code. It was like this when I got here.
|
||||||
|
|
||||||
|
component.Dirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ using Robust.Shared.ViewVariables;
|
|||||||
namespace Content.Server.Weapon.Ranged
|
namespace Content.Server.Weapon.Ranged
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class ServerRangedWeaponComponent : SharedRangedWeaponComponent, IHandSelected
|
public sealed class ServerRangedWeaponComponent : SharedRangedWeaponComponent
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
@@ -195,11 +195,5 @@ namespace Content.Server.Weapon.Ranged
|
|||||||
}
|
}
|
||||||
FireHandler?.Invoke(user, targetPos);
|
FireHandler?.Invoke(user, targetPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probably a better way to do this.
|
|
||||||
void IHandSelected.HandSelected(HandSelectedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace Content.Shared.Actions.Components
|
|||||||
/// Currently only maintained server side and not synced to client, as are all the equip/unequip events.
|
/// Currently only maintained server side and not synced to client, as are all the equip/unequip events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class ItemActionsComponent : Component, IEquippedHand, IUnequippedHand
|
public class ItemActionsComponent : Component
|
||||||
{
|
{
|
||||||
public override string Name => "ItemActions";
|
public override string Name => "ItemActions";
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ namespace Content.Shared.Actions.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// hand it's currently in, null if not in a hand.
|
/// hand it's currently in, null if not in a hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HandState? InHand;
|
public Hand? InHand;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Entity currently holding this in hand or equip slot. Null if not held.
|
/// Entity currently holding this in hand or equip slot. Null if not held.
|
||||||
@@ -179,19 +179,19 @@ namespace Content.Shared.Actions.Components
|
|||||||
GrantOrUpdate(actionType, toggleOn: toggleOn);
|
GrantOrUpdate(actionType, toggleOn: toggleOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEquippedHand.EquippedHand(EquippedHandEventArgs eventArgs)
|
public void EquippedHand(EntityUid user, Hand hand)
|
||||||
{
|
{
|
||||||
// this entity cannot be granted actions if no actions component
|
// this entity cannot be granted actions if no actions component
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent<SharedActionsComponent?>(eventArgs.User, out var actionsComponent))
|
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent<SharedActionsComponent?>(user, out var actionsComponent))
|
||||||
return;
|
return;
|
||||||
Holder = eventArgs.User;
|
Holder = user;
|
||||||
HolderActionsComponent = actionsComponent;
|
HolderActionsComponent = actionsComponent;
|
||||||
IsEquipped = true;
|
IsEquipped = true;
|
||||||
InHand = eventArgs.Hand;
|
InHand = hand;
|
||||||
GrantOrUpdateAllToHolder();
|
GrantOrUpdateAllToHolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IUnequippedHand.UnequippedHand(UnequippedHandEventArgs eventArgs)
|
public void UnequippedHand()
|
||||||
{
|
{
|
||||||
RevokeAllFromHolder();
|
RevokeAllFromHolder();
|
||||||
Holder = null;
|
Holder = null;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Content.Shared.Actions.Components;
|
using Content.Shared.Actions.Components;
|
||||||
|
using Content.Shared.Hands;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Content.Shared.Actions
|
namespace Content.Shared.Actions
|
||||||
{
|
{
|
||||||
@@ -16,6 +18,18 @@ namespace Content.Shared.Actions
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
UpdatesOutsidePrediction = true;
|
UpdatesOutsidePrediction = true;
|
||||||
|
SubscribeLocalEvent<ItemActionsComponent, UnequippedHandEvent>(OnHandUnequipped);
|
||||||
|
SubscribeLocalEvent<ItemActionsComponent, EquippedHandEvent>(OnHandEquipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandEquipped(EntityUid uid, ItemActionsComponent component, EquippedHandEvent args)
|
||||||
|
{
|
||||||
|
component.EquippedHand(args.User, args.Hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandUnequipped(EntityUid uid, ItemActionsComponent component, UnequippedHandEvent args)
|
||||||
|
{
|
||||||
|
component.UnequippedHand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
if (args.Handled)
|
if (args.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(args.User, out SharedHandsComponent? hands))
|
if (!EntityManager.TryGetComponent(args.User, out SharedHandsComponent hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var slot in itemSlots.Slots.Values)
|
foreach (var slot in itemSlots.Slots.Values)
|
||||||
@@ -370,7 +370,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (user != null && EntityManager.TryGetComponent(user.Value, out SharedHandsComponent? hands))
|
if (user != null && EntityManager.TryGetComponent(user.Value, out SharedHandsComponent? hands))
|
||||||
hands.TryPutInActiveHandOrAny(item.Value);
|
hands.PutInHand(item.Value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -458,7 +458,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
|
|
||||||
var verbSubject = slot.Name != string.Empty
|
var verbSubject = slot.Name != string.Empty
|
||||||
? Loc.GetString(slot.Name)
|
? Loc.GetString(slot.Name)
|
||||||
: EntityManager.GetComponent<MetaDataComponent>(args.Using.Value).EntityName ?? string.Empty;
|
: Name(args.Using.Value) ?? string.Empty;
|
||||||
|
|
||||||
Verb insertVerb = new();
|
Verb insertVerb = new();
|
||||||
insertVerb.Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true);
|
insertVerb.Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true);
|
||||||
|
|||||||
@@ -27,43 +27,14 @@ namespace Content.Shared.Hands.Components
|
|||||||
|
|
||||||
public sealed override string Name => "Hands";
|
public sealed override string Name => "Hands";
|
||||||
|
|
||||||
public event Action? OnItemChanged; //TODO: Try to replace C# event
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the currently active hand.
|
/// The name of the currently active hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables]
|
||||||
public string? ActiveHand
|
public string? ActiveHand;
|
||||||
{
|
|
||||||
get => _activeHand;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value != null && !HasHand(value))
|
|
||||||
{
|
|
||||||
Logger.Warning($"{nameof(SharedHandsComponent)} on {Owner} tried to set its active hand to {value}, which was not a hand.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (value == null && Hands.Count != 0)
|
|
||||||
{
|
|
||||||
Logger.Error($"{nameof(SharedHandsComponent)} on {Owner} tried to set its active hand to null, when it still had another hand.");
|
|
||||||
_activeHand = Hands[0].Name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (value != ActiveHand)
|
|
||||||
{
|
|
||||||
DeselectActiveHeldEntity();
|
|
||||||
_activeHand = value;
|
|
||||||
SelectActiveHeldEntity();
|
|
||||||
|
|
||||||
HandsModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string? _activeHand;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public readonly List<Hand> Hands = new();
|
public List<Hand> Hands = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of throw impulse per distance the player is from the throw target.
|
/// The amount of throw impulse per distance the player is from the throw target.
|
||||||
@@ -79,66 +50,25 @@ namespace Content.Shared.Hands.Components
|
|||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float ThrowRange { get; set; } = 8f;
|
public float ThrowRange { get; set; } = 8f;
|
||||||
|
|
||||||
public override ComponentState GetComponentState()
|
private bool PlayerCanDrop => EntitySystem.Get<ActionBlockerSystem>().CanDrop(Owner);
|
||||||
{
|
private bool PlayerCanPickup => EntitySystem.Get<ActionBlockerSystem>().CanPickup(Owner);
|
||||||
var hands = new HandState[Hands.Count];
|
|
||||||
|
|
||||||
for (var i = 0; i < Hands.Count; i++)
|
|
||||||
{
|
|
||||||
var hand = Hands[i].ToHandState();
|
|
||||||
hands[i] = hand;
|
|
||||||
}
|
|
||||||
return new HandsComponentState(hands, ActiveHand);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void HandsModified()
|
|
||||||
{
|
|
||||||
// todo axe all this for ECS.
|
|
||||||
// todo burn it all down.
|
|
||||||
UpdateHandVisualizer();
|
|
||||||
Dirty();
|
|
||||||
|
|
||||||
_entMan.EventBus.RaiseEvent(EventSource.Local, new HandsModifiedMessage { Hands = this });
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateHandVisualizer()
|
|
||||||
{
|
|
||||||
var entMan = _entMan;
|
|
||||||
|
|
||||||
if (!entMan.TryGetComponent(Owner, out AppearanceComponent? appearance))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var hands = new List<HandVisualState>();
|
|
||||||
foreach (var hand in Hands)
|
|
||||||
{
|
|
||||||
if (hand.HeldEntity == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!entMan.TryGetComponent(hand.HeldEntity, out SharedItemComponent? item) || item.RsiPath == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var handState = new HandVisualState(item.RsiPath, item.EquippedPrefix, hand.Location, item.Color);
|
|
||||||
hands.Add(handState);
|
|
||||||
}
|
|
||||||
|
|
||||||
appearance.SetData(HandsVisuals.VisualState, new HandsVisualState(hands));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddHand(string handName, HandLocation handLocation)
|
public void AddHand(string handName, HandLocation handLocation)
|
||||||
{
|
{
|
||||||
if (HasHand(handName))
|
if (HasHand(handName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var container = Owner.CreateContainer<ContainerSlot>(handName);
|
var container = Owner.EnsureContainer<ContainerSlot>(handName);
|
||||||
container.OccludesLight = false;
|
container.OccludesLight = false;
|
||||||
|
|
||||||
Hands.Add(new Hand(handName, handLocation, container));
|
Hands.Add(new Hand(handName, handLocation, container));
|
||||||
|
|
||||||
ActiveHand ??= handName;
|
if (ActiveHand == null)
|
||||||
|
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, handName, this);
|
||||||
|
|
||||||
HandCountChanged();
|
HandCountChanged();
|
||||||
|
|
||||||
HandsModified();
|
Dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveHand(string handName)
|
public void RemoveHand(string handName)
|
||||||
@@ -156,14 +86,14 @@ namespace Content.Shared.Hands.Components
|
|||||||
Hands.Remove(hand);
|
Hands.Remove(hand);
|
||||||
|
|
||||||
if (ActiveHand == hand.Name)
|
if (ActiveHand == hand.Name)
|
||||||
ActiveHand = Hands.FirstOrDefault()?.Name;
|
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, Hands.FirstOrDefault()?.Name, this);
|
||||||
|
|
||||||
HandCountChanged();
|
HandCountChanged();
|
||||||
|
|
||||||
HandsModified();
|
Dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Hand? GetActiveHand()
|
public Hand? GetActiveHand()
|
||||||
{
|
{
|
||||||
if (ActiveHand == null)
|
if (ActiveHand == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -220,7 +150,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
return hand.HeldEntity != null;
|
return hand.HeldEntity != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetHeldEntity(string handName,[NotNullWhen(true)] out EntityUid? heldEntity)
|
public bool TryGetHeldEntity(string handName, [NotNullWhen(true)] out EntityUid? heldEntity)
|
||||||
{
|
{
|
||||||
heldEntity = null;
|
heldEntity = null;
|
||||||
|
|
||||||
@@ -228,7 +158,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
heldEntity = hand.HeldEntity;
|
heldEntity = hand.HeldEntity;
|
||||||
return hand.HeldEntity != null;
|
return heldEntity != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetActiveHeldEntity([NotNullWhen(true)] out EntityUid? heldEntity)
|
public bool TryGetActiveHeldEntity([NotNullWhen(true)] out EntityUid? heldEntity)
|
||||||
@@ -251,7 +181,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
{
|
{
|
||||||
foreach (var hand in Hands)
|
foreach (var hand in Hands)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity.HasValue)
|
if (hand.HeldEntity != null)
|
||||||
yield return hand.HeldEntity.Value;
|
yield return hand.HeldEntity.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,7 +232,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (!CanRemoveHeldEntityFromHand(hand))
|
if (!CanRemoveHeldEntityFromHand(hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && !PlayerCanDrop())
|
if (checkActionBlocker && !PlayerCanDrop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -406,7 +336,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (!CanRemoveHeldEntityFromHand(hand))
|
if (!CanRemoveHeldEntityFromHand(hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RemoveHeldEntityFromHand(hand);
|
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,62 +348,27 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (hand.HeldEntity == null)
|
if (hand.HeldEntity == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!hand.Container!.CanRemove(hand.HeldEntity.Value))
|
||||||
return hand.Container?.CanRemove(hand.HeldEntity.Value) ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the player is allowed to perform drops.
|
|
||||||
/// </summary>
|
|
||||||
private bool PlayerCanDrop()
|
|
||||||
{
|
|
||||||
if (!IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ActionBlockerSystem>().CanDrop(Owner))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the contents of a hand from its container. Assumes that the removal is allowed.
|
|
||||||
/// </summary>
|
|
||||||
private void RemoveHeldEntityFromHand(Hand hand)
|
|
||||||
{
|
|
||||||
if (hand.HeldEntity is not { } heldEntity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var handContainer = hand.Container;
|
|
||||||
if (handContainer == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (hand.Name == ActiveHand)
|
|
||||||
DeselectActiveHeldEntity();
|
|
||||||
|
|
||||||
if (!handContainer.Remove(heldEntity))
|
|
||||||
{
|
|
||||||
Logger.Error($"{nameof(SharedHandsComponent)} on {Owner} could not remove {heldEntity} from {handContainer}.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnHeldEntityRemovedFromHand(heldEntity, hand.ToHandState());
|
|
||||||
|
|
||||||
HandsModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drops a hands contents to the target location.
|
/// Drops a hands contents to the target location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void DropHeldEntity(Hand hand, EntityCoordinates targetDropLocation)
|
public void DropHeldEntity(Hand hand, EntityCoordinates targetDropLocation)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity is not { } heldEntity)
|
if (hand.HeldEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RemoveHeldEntityFromHand(hand);
|
var heldEntity = hand.HeldEntity.Value;
|
||||||
|
|
||||||
|
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||||
|
|
||||||
EntitySystem.Get<SharedInteractionSystem>().DroppedInteraction(Owner, heldEntity);
|
EntitySystem.Get<SharedInteractionSystem>().DroppedInteraction(Owner, heldEntity);
|
||||||
|
|
||||||
_entMan.GetComponent<TransformComponent>(heldEntity).WorldPosition = GetFinalDropCoordinates(targetDropLocation);
|
_entMan.GetComponent<TransformComponent>(heldEntity).WorldPosition = GetFinalDropCoordinates(targetDropLocation);
|
||||||
|
|
||||||
OnItemChanged?.Invoke();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -508,7 +403,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (!CanRemoveHeldEntityFromHand(hand))
|
if (!CanRemoveHeldEntityFromHand(hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && !PlayerCanDrop())
|
if (checkActionBlocker && !PlayerCanDrop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DropHeldEntity(hand, location);
|
DropHeldEntity(hand, location);
|
||||||
@@ -525,10 +420,12 @@ namespace Content.Shared.Hands.Components
|
|||||||
|
|
||||||
private bool CanPutHeldEntityIntoContainer(Hand hand, IContainer targetContainer, bool checkActionBlocker)
|
private bool CanPutHeldEntityIntoContainer(Hand hand, IContainer targetContainer, bool checkActionBlocker)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity is not { } heldEntity)
|
if (hand.HeldEntity == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && !PlayerCanDrop())
|
var heldEntity = hand.HeldEntity.Value;
|
||||||
|
|
||||||
|
if (checkActionBlocker && !PlayerCanDrop)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!targetContainer.CanInsert(heldEntity))
|
if (!targetContainer.CanInsert(heldEntity))
|
||||||
@@ -542,10 +439,12 @@ namespace Content.Shared.Hands.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void PutHeldEntityIntoContainer(Hand hand, IContainer targetContainer)
|
private void PutHeldEntityIntoContainer(Hand hand, IContainer targetContainer)
|
||||||
{
|
{
|
||||||
if (hand.HeldEntity is not { } heldEntity)
|
if (hand.HeldEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RemoveHeldEntityFromHand(hand);
|
var heldEntity = hand.HeldEntity.Value;
|
||||||
|
|
||||||
|
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||||
|
|
||||||
if (!targetContainer.Insert(heldEntity))
|
if (!targetContainer.Insert(heldEntity))
|
||||||
{
|
{
|
||||||
@@ -563,7 +462,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (!TryGetHand(handName, out var hand))
|
if (!TryGetHand(handName, out var hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && !PlayerCanPickup())
|
if (checkActionBlocker && !PlayerCanPickup)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!CanInsertEntityIntoHand(hand, entity))
|
if (!CanInsertEntityIntoHand(hand, entity))
|
||||||
@@ -580,17 +479,17 @@ namespace Content.Shared.Hands.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to pick up an entity to a specific hand.
|
/// Tries to pick up an entity to a specific hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryPickupEntity(string handName, EntityUid entity, bool checkActionBlocker = true)
|
public bool TryPickupEntity(string handName, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||||
{
|
{
|
||||||
if (!TryGetHand(handName, out var hand))
|
if (!TryGetHand(handName, out var hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return TryPickupEntity(hand, entity, checkActionBlocker);
|
return TryPickupEntity(hand, entity, checkActionBlocker, animateUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryPickupEntityToActiveHand(EntityUid entity, bool checkActionBlocker = true)
|
public bool TryPickupEntityToActiveHand(EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||||
{
|
{
|
||||||
return ActiveHand != null && TryPickupEntity(ActiveHand, entity, checkActionBlocker);
|
return ActiveHand != null && TryPickupEntity(ActiveHand, entity, checkActionBlocker, animateUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -598,6 +497,9 @@ namespace Content.Shared.Hands.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
||||||
{
|
{
|
||||||
|
if (!_entMan.HasComponent<SharedItemComponent>(entity))
|
||||||
|
return false;
|
||||||
|
|
||||||
var handContainer = hand.Container;
|
var handContainer = hand.Container;
|
||||||
if (handContainer == null) return false;
|
if (handContainer == null) return false;
|
||||||
|
|
||||||
@@ -611,56 +513,23 @@ namespace Content.Shared.Hands.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private bool TryPickupEntity(Hand hand, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||||
/// Checks if the player is allowed to perform pickup actions.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected bool PlayerCanPickup()
|
|
||||||
{
|
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanPickup(Owner))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Puts an entity into the player's hand, assumes that the insertion is allowed.
|
|
||||||
/// </summary>
|
|
||||||
public void PutEntityIntoHand(Hand hand, EntityUid entity)
|
|
||||||
{
|
|
||||||
var handContainer = hand.Container;
|
|
||||||
if (handContainer == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!handContainer.Insert(entity))
|
|
||||||
{
|
|
||||||
Logger.Error($"{nameof(SharedHandsComponent)} on {Owner} could not insert {entity} into {handContainer}.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntitySystem.Get<SharedInteractionSystem>().EquippedHandInteraction(Owner, entity, hand.ToHandState());
|
|
||||||
|
|
||||||
if (hand.Name == ActiveHand)
|
|
||||||
SelectActiveHeldEntity();
|
|
||||||
|
|
||||||
_entMan.GetComponent<TransformComponent>(entity).LocalPosition = Vector2.Zero;
|
|
||||||
|
|
||||||
OnItemChanged?.Invoke();
|
|
||||||
|
|
||||||
HandsModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryPickupEntity(Hand hand, EntityUid entity, bool checkActionBlocker = true)
|
|
||||||
{
|
{
|
||||||
if (!CanInsertEntityIntoHand(hand, entity))
|
if (!CanInsertEntityIntoHand(hand, entity))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && !PlayerCanPickup())
|
if (checkActionBlocker && !PlayerCanPickup)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
HandlePickupAnimation(entity);
|
// animation
|
||||||
PutEntityIntoHand(hand, entity);
|
var handSys = EntitySystem.Get<SharedHandsSystem>();
|
||||||
EntitySystem.Get<SharedAdminLogSystem>().Add(LogType.Pickup, LogImpact.Low, $"{_entMan.ToPrettyString(Owner):user} picked up {_entMan.ToPrettyString(entity):entity}");
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,28 +609,16 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (!CanInsertEntityIntoHand(activeHand, heldEntity.Value) || !CanRemoveHeldEntityFromHand(hand))
|
if (!CanInsertEntityIntoHand(activeHand, heldEntity.Value) || !CanRemoveHeldEntityFromHand(hand))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (checkActionBlocker && (!PlayerCanDrop() || !PlayerCanPickup()))
|
if (checkActionBlocker && (!PlayerCanDrop || !PlayerCanPickup))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RemoveHeldEntityFromHand(hand);
|
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||||
PutEntityIntoHand(activeHand, heldEntity.Value);
|
EntitySystem.Get<SharedHandsSystem>().PutEntityIntoHand(Owner, activeHand, heldEntity.Value, this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void DeselectActiveHeldEntity()
|
|
||||||
{
|
|
||||||
if (TryGetActiveHeldEntity(out var entity))
|
|
||||||
EntitySystem.Get<SharedInteractionSystem>().HandDeselectedInteraction(Owner, entity.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectActiveHeldEntity()
|
|
||||||
{
|
|
||||||
if (TryGetActiveHeldEntity(out var entity))
|
|
||||||
EntitySystem.Get<SharedInteractionSystem>().HandSelectedInteraction(Owner, entity.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandCountChanged()
|
private void HandCountChanged()
|
||||||
{
|
{
|
||||||
_entMan.EventBus.RaiseEvent(EventSource.Local, new HandCountChangedEvent(Owner));
|
_entMan.EventBus.RaiseEvent(EventSource.Local, new HandCountChangedEvent(Owner));
|
||||||
@@ -772,36 +629,30 @@ namespace Content.Shared.Hands.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PutInHand(SharedItemComponent item, bool checkActionBlocker = true)
|
public bool PutInHand(SharedItemComponent item, bool checkActionBlocker = true)
|
||||||
{
|
{
|
||||||
return TryPutInActiveHandOrAny(item.Owner, checkActionBlocker);
|
return PutInHand(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 uid, bool checkActionBlocker = true)
|
|
||||||
{
|
|
||||||
return TryPutInActiveHandOrAny(uid, checkActionBlocker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Puts an item any hand, prefering the active hand, or puts it on the floor under the player.
|
/// Puts an item any hand, prefering the active hand, or puts it on the floor under the player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true) =>
|
public void PutInHandOrDrop(EntityUid entity, bool checkActionBlocker = true)
|
||||||
PutInHandOrDrop(item.Owner, checkActionBlocker);
|
|
||||||
|
|
||||||
public void PutInHandOrDrop(EntityUid uid, bool checkActionBlocker = true)
|
|
||||||
{
|
{
|
||||||
if (!TryPutInActiveHandOrAny(uid, checkActionBlocker))
|
if (!PutInHand(entity, checkActionBlocker))
|
||||||
_entMan.GetComponent<TransformComponent>(uid).Coordinates = _entMan.GetComponent<TransformComponent>(Owner).Coordinates;
|
_entMan.GetComponent<TransformComponent>(entity).Coordinates = _entMan.GetComponent<TransformComponent>(Owner).Coordinates;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true)
|
||||||
|
{
|
||||||
|
PutInHandOrDrop(item.Owner, checkActionBlocker);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand.
|
/// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TryPutInActiveHandOrAny(EntityUid entity, bool checkActionBlocker = true)
|
public bool PutInHand(EntityUid entity, bool checkActionBlocker = true)
|
||||||
{
|
{
|
||||||
return TryPutInAnyHand(entity, GetActiveHand(), checkActionBlocker);
|
return PutInHand(entity, GetActiveHand(), checkActionBlocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -814,13 +665,13 @@ namespace Content.Shared.Hands.Components
|
|||||||
if (priorityHandName != null)
|
if (priorityHandName != null)
|
||||||
priorityHand = GetHandOrNull(priorityHandName);
|
priorityHand = GetHandOrNull(priorityHandName);
|
||||||
|
|
||||||
return TryPutInAnyHand(entity, priorityHand, checkActionBlocker);
|
return PutInHand(entity, priorityHand, checkActionBlocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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.
|
/// 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>
|
/// </summary>
|
||||||
private bool TryPutInAnyHand(EntityUid entity, Hand? priorityHand = null, bool checkActionBlocker = true)
|
private bool PutInHand(EntityUid entity, Hand? priorityHand = null, bool checkActionBlocker = true)
|
||||||
{
|
{
|
||||||
if (priorityHand != null)
|
if (priorityHand != null)
|
||||||
{
|
{
|
||||||
@@ -836,9 +687,23 @@ namespace Content.Shared.Hands.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnHeldEntityRemovedFromHand(EntityUid heldEntity, HandState handState) { }
|
/// <summary>
|
||||||
|
/// Checks if any hand can pick up an item.
|
||||||
|
/// </summary>
|
||||||
|
public bool CanPutInHand(SharedItemComponent item, bool mobCheck = true)
|
||||||
|
{
|
||||||
|
var entity = item.Owner;
|
||||||
|
|
||||||
protected virtual void HandlePickupAnimation(EntityUid entity) { }
|
if (mobCheck && !PlayerCanPickup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var hand in Hands)
|
||||||
|
{
|
||||||
|
if (CanInsertEntityIntoHand(hand, entity))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region visualizerData
|
#region visualizerData
|
||||||
@@ -877,6 +742,7 @@ namespace Content.Shared.Hands.Components
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
public class Hand
|
public class Hand
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
@@ -889,46 +755,29 @@ namespace Content.Shared.Hands.Components
|
|||||||
/// The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
|
/// 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.
|
/// which may not be synced with the server when the client hands are created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables, NonSerialized]
|
||||||
public IContainer? Container { get; set; }
|
public ContainerSlot? Container;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public EntityUid? HeldEntity => Container?.ContainedEntities?.Count > 0 ? Container.ContainedEntities[0] : null;
|
public EntityUid? HeldEntity => Container?.ContainedEntity;
|
||||||
|
|
||||||
|
public bool IsEmpty => HeldEntity == null;
|
||||||
|
|
||||||
public Hand(string name, HandLocation location, IContainer? container = null)
|
public Hand(string name, HandLocation location, ContainerSlot? container = null)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Location = location;
|
Location = location;
|
||||||
Container = container;
|
Container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HandState ToHandState()
|
|
||||||
{
|
|
||||||
return new(Name, Location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public struct HandState
|
|
||||||
{
|
|
||||||
public string Name { get; }
|
|
||||||
public HandLocation Location { get; }
|
|
||||||
|
|
||||||
public HandState(string name, HandLocation location)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
Location = location;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class HandsComponentState : ComponentState
|
public sealed class HandsComponentState : ComponentState
|
||||||
{
|
{
|
||||||
public HandState[] Hands { get; }
|
public List<Hand> Hands { get; }
|
||||||
public string? ActiveHand { get; }
|
public string? ActiveHand { get; }
|
||||||
|
|
||||||
public HandsComponentState(HandState[] hands, string? activeHand = null)
|
public HandsComponentState(List<Hand> hands, string? activeHand = null)
|
||||||
{
|
{
|
||||||
Hands = hands;
|
Hands = hands;
|
||||||
ActiveHand = activeHand;
|
ActiveHand = activeHand;
|
||||||
@@ -1004,25 +853,4 @@ namespace Content.Shared.Hands.Components
|
|||||||
|
|
||||||
public EntityUid Sender { get; }
|
public EntityUid Sender { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class PickupAnimationMessage : EntityEventArgs
|
|
||||||
{
|
|
||||||
public EntityUid EntityUid { get; }
|
|
||||||
public EntityCoordinates InitialPosition { get; }
|
|
||||||
public Vector2 FinalPosition { get; }
|
|
||||||
|
|
||||||
public PickupAnimationMessage(EntityUid entityUid, Vector2 finalPosition, EntityCoordinates initialPosition)
|
|
||||||
{
|
|
||||||
EntityUid = entityUid;
|
|
||||||
FinalPosition = finalPosition;
|
|
||||||
InitialPosition = initialPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public struct HandsModifiedMessage
|
|
||||||
{
|
|
||||||
public SharedHandsComponent Hands;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
160
Content.Shared/Hands/HandEvents.cs
Normal file
160
Content.Shared/Hands/HandEvents.cs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Hands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when an entity item in a hand is deselected.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class HandDeselectedEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entity that owns the deselected hand.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item in the hand that was deselected.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid Item { get; }
|
||||||
|
|
||||||
|
public HandDeselectedEvent(EntityUid user, EntityUid item)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when an item entity held by a hand is selected.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class HandSelectedEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entity that owns the selected hand.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item in the hand that was selected.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid Item { get; }
|
||||||
|
|
||||||
|
public HandSelectedEvent(EntityUid user, EntityUid item)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Item = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class RequestSetHandEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The hand to be swapped to.
|
||||||
|
/// </summary>
|
||||||
|
public string HandName { get; }
|
||||||
|
|
||||||
|
public RequestSetHandEvent(string handName)
|
||||||
|
{
|
||||||
|
HandName = handName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class PickupAnimationEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid ItemUid { get; }
|
||||||
|
public EntityCoordinates InitialPosition { get; }
|
||||||
|
public Vector2 FinalPosition { get; }
|
||||||
|
|
||||||
|
public PickupAnimationEvent(EntityUid itemUid, EntityCoordinates initialPosition,
|
||||||
|
Vector2 finalPosition)
|
||||||
|
{
|
||||||
|
ItemUid = itemUid;
|
||||||
|
FinalPosition = finalPosition;
|
||||||
|
InitialPosition = initialPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised directed on both the blocking entity and user when
|
||||||
|
/// a virtual hand item is deleted.
|
||||||
|
/// </summary>
|
||||||
|
public class VirtualItemDeletedEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid BlockingEntity;
|
||||||
|
public EntityUid User;
|
||||||
|
|
||||||
|
public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user)
|
||||||
|
{
|
||||||
|
BlockingEntity = blockingEntity;
|
||||||
|
User = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when putting an entity into a hand slot
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class EquippedHandEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entity that equipped the item.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that was equipped.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid Equipped { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hand that the item was placed into.
|
||||||
|
/// </summary>
|
||||||
|
public Hand Hand { get; }
|
||||||
|
|
||||||
|
public EquippedHandEvent(EntityUid user, EntityUid equipped, Hand hand)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Equipped = equipped;
|
||||||
|
Hand = hand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when removing an entity from an inventory slot.
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public class UnequippedHandEvent : HandledEntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entity that equipped the item.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid User { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that was unequipped.
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid Unequipped { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hand that the item is removed from.
|
||||||
|
/// </summary>
|
||||||
|
public Hand Hand { get; }
|
||||||
|
|
||||||
|
public UnequippedHandEvent(EntityUid user, EntityUid unequipped, Hand hand)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
Unequipped = unequipped;
|
||||||
|
Hand = hand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Shared.Hands.Components;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Analyzers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This interface gives components behavior when their entity is put in a hand inventory slot,
|
|
||||||
/// even if it came from another hand slot (which would also fire <see cref="IUnequippedHand"/>).
|
|
||||||
/// This includes moving the entity from a non-hand slot into a hand slot
|
|
||||||
/// (which would also fire <see cref="IUnequipped"/>).
|
|
||||||
/// </summary>
|
|
||||||
[RequiresExplicitImplementation]
|
|
||||||
public interface IEquippedHand
|
|
||||||
{
|
|
||||||
[Obsolete("Use EquippedHandMessage instead")]
|
|
||||||
void EquippedHand(EquippedHandEventArgs eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EquippedHandEventArgs : EntityEventArgs
|
|
||||||
{
|
|
||||||
public EquippedHandEventArgs(EntityUid user, HandState hand)
|
|
||||||
{
|
|
||||||
Hand = hand;
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly HandState Hand;
|
|
||||||
public readonly EntityUid User;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when putting an entity into a hand slot
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public class EquippedHandEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Entity that equipped the item.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid User { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Item that was equipped.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Equipped { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hand that the item was placed into.
|
|
||||||
/// </summary>
|
|
||||||
public HandState Hand { get; }
|
|
||||||
|
|
||||||
public EquippedHandEvent(EntityUid user, EntityUid equipped, HandState hand)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
Equipped = equipped;
|
|
||||||
Hand = hand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Analyzers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This interface gives components behavior when they're held on a deselected hand.
|
|
||||||
/// </summary>
|
|
||||||
[RequiresExplicitImplementation]
|
|
||||||
public interface IHandDeselected
|
|
||||||
{
|
|
||||||
[Obsolete("Use HandDeselectedMessage instead")]
|
|
||||||
void HandDeselected(HandDeselectedEventArgs eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HandDeselectedEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public HandDeselectedEventArgs(EntityUid user)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityUid User { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when an entity item in a hand is deselected.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public class HandDeselectedEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Entity that owns the deselected hand.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid User { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Item in the hand that was deselected.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Item { get; }
|
|
||||||
|
|
||||||
public HandDeselectedEvent(EntityUid user, EntityUid item)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
Item = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Analyzers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This interface gives components behavior when they're held on the selected hand.
|
|
||||||
/// </summary>
|
|
||||||
[RequiresExplicitImplementation]
|
|
||||||
public interface IHandSelected
|
|
||||||
{
|
|
||||||
[Obsolete("Use HandSelectedMessage instead")]
|
|
||||||
void HandSelected(HandSelectedEventArgs eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HandSelectedEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public HandSelectedEventArgs(EntityUid user)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityUid User { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when an item entity held by a hand is selected.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public class HandSelectedEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Entity that owns the selected hand.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid User { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Item in the hand that was selected.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Item { get; }
|
|
||||||
|
|
||||||
public HandSelectedEvent(EntityUid user, EntityUid item)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
Item = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Shared.Hands.Components;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Analyzers;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This interface gives components behavior when their entity is removed from a hand slot,
|
|
||||||
/// even if it is going into another hand slot (which would also fire <see cref="IEquippedHand"/>).
|
|
||||||
/// This includes moving the entity from a hand slot into a non-hand slot (which would also fire <see cref="IEquipped"/>).
|
|
||||||
/// </summary>
|
|
||||||
[RequiresExplicitImplementation]
|
|
||||||
public interface IUnequippedHand
|
|
||||||
{
|
|
||||||
[Obsolete("Use UnequippedHandMessage instead")]
|
|
||||||
void UnequippedHand(UnequippedHandEventArgs eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UnequippedHandEventArgs : EntityEventArgs
|
|
||||||
{
|
|
||||||
public UnequippedHandEventArgs(EntityUid user, HandState hand)
|
|
||||||
{
|
|
||||||
Hand = hand;
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly HandState Hand;
|
|
||||||
public readonly EntityUid User;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when removing an entity from an inventory slot.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI]
|
|
||||||
public class UnequippedHandEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Entity that equipped the item.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid User { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Item that was unequipped.
|
|
||||||
/// </summary>
|
|
||||||
public EntityUid Unequipped { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hand that the item is removed from.
|
|
||||||
/// </summary>
|
|
||||||
public HandState Hand { get; }
|
|
||||||
|
|
||||||
public UnequippedHandEvent(EntityUid user, EntityUid unequipped, HandState hand)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
Unequipped = unequipped;
|
|
||||||
Hand = hand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +1,213 @@
|
|||||||
using System;
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Input;
|
||||||
|
using Content.Shared.Item;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Serialization;
|
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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Content.Shared.Hands
|
namespace Content.Shared.Hands
|
||||||
{
|
{
|
||||||
public abstract class SharedHandsSystem : EntitySystem
|
public abstract class SharedHandsSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeAllEvent<RequestSetHandEvent>(HandleSetHand);
|
||||||
|
|
||||||
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(HandleContainerModified);
|
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(HandleContainerModified);
|
||||||
SubscribeLocalEvent<SharedHandsComponent, EntInsertedIntoContainerMessage>(HandleContainerModified);
|
SubscribeLocalEvent<SharedHandsComponent, EntInsertedIntoContainerMessage>(HandleContainerModified);
|
||||||
|
|
||||||
SubscribeAllEvent<RequestSetHandEvent>(HandleSetHand);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryComp(entity, out SharedSpriteComponent? component))
|
||||||
|
component.Visible = true;
|
||||||
|
|
||||||
|
hands.Dirty();
|
||||||
|
|
||||||
|
var unequippedHandMessage = new UnequippedHandEvent(uid, entity, hand);
|
||||||
|
RaiseLocalEvent(entity, unequippedHandMessage);
|
||||||
|
if (unequippedHandMessage.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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}");
|
||||||
|
|
||||||
|
if (TryComp(entity, out SharedSpriteComponent? component))
|
||||||
|
component.Visible = false;
|
||||||
|
|
||||||
|
hands.Dirty();
|
||||||
|
|
||||||
|
var equippedHandMessage = new EquippedHandEvent(uid, entity, hand);
|
||||||
|
RaiseLocalEvent(entity, equippedHandMessage);
|
||||||
|
|
||||||
|
// If one of the interactions resulted in the item being dropped, return early.
|
||||||
|
if (equippedHandMessage.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
|
||||||
|
|
||||||
|
#region visuals
|
||||||
|
protected virtual void HandleContainerModified(EntityUid uid, SharedHandsComponent hands, ContainerModifiedMessage args)
|
||||||
|
{
|
||||||
|
UpdateHandVisualizer(uid, hands);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the In-Hand sprites
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateHandVisualizer(EntityUid uid, SharedHandsComponent? handComp = null, AppearanceComponent? appearance = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref handComp, ref appearance, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var handsVisuals = new List<HandVisualState>();
|
||||||
|
foreach (var hand in handComp.Hands)
|
||||||
|
{
|
||||||
|
if (hand.HeldEntity == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!TryComp(hand.HeldEntity.Value, out SharedItemComponent? item) || item.RsiPath == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var handState = new HandVisualState(item.RsiPath, item.EquippedPrefix, hand.Location, item.Color);
|
||||||
|
handsVisuals.Add(handState);
|
||||||
|
}
|
||||||
|
|
||||||
|
appearance.SetData(HandsVisuals.VisualState, new HandsVisualState(handsVisuals));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
private void HandleSetHand(RequestSetHandEvent msg, EntitySessionEventArgs eventArgs)
|
private void HandleSetHand(RequestSetHandEvent msg, EntitySessionEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
var entity = eventArgs.SenderSession.AttachedEntity;
|
if (eventArgs.SenderSession.AttachedEntity == null)
|
||||||
|
|
||||||
if (entity == null || !EntityManager.TryGetComponent(entity, out SharedHandsComponent? hands))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hands.ActiveHand = msg.HandName;
|
TrySetActiveHand(eventArgs.SenderSession.AttachedEntity.Value, msg.HandName);
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void HandleContainerModified(
|
|
||||||
EntityUid uid,
|
|
||||||
SharedHandsComponent component,
|
|
||||||
ContainerModifiedMessage args)
|
|
||||||
{
|
|
||||||
component.Dirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class RequestSetHandEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The hand to be swapped to.
|
|
||||||
/// </summary>
|
|
||||||
public string HandName { get; }
|
|
||||||
|
|
||||||
public RequestSetHandEvent(string handName)
|
|
||||||
{
|
|
||||||
HandName = handName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised directed on both the blocking entity and user when
|
/// Set the currently active hand and raise hand (de)selection events directed at the held entities.
|
||||||
/// a virtual hand item is deleted.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VirtualItemDeletedEvent : EntityEventArgs
|
/// <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)
|
||||||
{
|
{
|
||||||
public EntityUid BlockingEntity;
|
if (!Resolve(uid, ref handComp))
|
||||||
public EntityUid User;
|
return false;
|
||||||
|
|
||||||
public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user)
|
if (value == handComp.ActiveHand)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (value != null && !handComp.HasHand(value))
|
||||||
{
|
{
|
||||||
BlockingEntity = blockingEntity;
|
Logger.Warning($"{nameof(SharedHandsComponent)} on {handComp.Owner} tried to set its active hand to {value}, which was not a hand.");
|
||||||
User = user;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ namespace Content.Shared.Interaction
|
|||||||
if (!TryComp(user, out SharedHandsComponent? hands))
|
if (!TryComp(user, out SharedHandsComponent? hands))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// TODO: Replace with body interaction range when we get something like arm length or telekinesis or something.
|
// TODO: Replace with body interaction range when we get something like arm length or telekinesis or something.
|
||||||
var inRangeUnobstructed = user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true);
|
var inRangeUnobstructed = user.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true);
|
||||||
if (target == null || !inRangeUnobstructed)
|
if (target == null || !inRangeUnobstructed)
|
||||||
@@ -734,46 +733,6 @@ namespace Content.Shared.Interaction
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Equip Hand
|
|
||||||
/// <summary>
|
|
||||||
/// Calls EquippedHand on all components that implement the IEquippedHand interface
|
|
||||||
/// on an item.
|
|
||||||
/// </summary>
|
|
||||||
public void EquippedHandInteraction(EntityUid user, EntityUid item, HandState hand)
|
|
||||||
{
|
|
||||||
var equippedHandMessage = new EquippedHandEvent(user, item, hand);
|
|
||||||
RaiseLocalEvent(item, equippedHandMessage);
|
|
||||||
if (equippedHandMessage.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var comps = AllComps<IEquippedHand>(item).ToList();
|
|
||||||
|
|
||||||
foreach (var comp in comps)
|
|
||||||
{
|
|
||||||
comp.EquippedHand(new EquippedHandEventArgs(user, hand));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calls UnequippedHand on all components that implement the IUnequippedHand interface
|
|
||||||
/// on an item.
|
|
||||||
/// </summary>
|
|
||||||
public void UnequippedHandInteraction(EntityUid user, EntityUid item, HandState hand)
|
|
||||||
{
|
|
||||||
var unequippedHandMessage = new UnequippedHandEvent(user, item, hand);
|
|
||||||
RaiseLocalEvent(item, unequippedHandMessage);
|
|
||||||
if (unequippedHandMessage.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var comps = AllComps<IUnequippedHand>(item).ToList();
|
|
||||||
|
|
||||||
foreach (var comp in comps)
|
|
||||||
{
|
|
||||||
comp.UnequippedHand(new UnequippedHandEventArgs(user, hand));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Drop
|
#region Drop
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activates the Dropped behavior of an object
|
/// Activates the Dropped behavior of an object
|
||||||
@@ -813,47 +772,6 @@ namespace Content.Shared.Interaction
|
|||||||
_adminLogSystem.Add(LogType.Drop, LogImpact.Low, $"{ToPrettyString(user):user} dropped {ToPrettyString(item):entity}");
|
_adminLogSystem.Add(LogType.Drop, LogImpact.Low, $"{ToPrettyString(user):user} dropped {ToPrettyString(item):entity}");
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Hand Selected
|
|
||||||
/// <summary>
|
|
||||||
/// Calls HandSelected on all components that implement the IHandSelected interface
|
|
||||||
/// on an item entity on a hand that has just been selected.
|
|
||||||
/// </summary>
|
|
||||||
public void HandSelectedInteraction(EntityUid user, EntityUid item)
|
|
||||||
{
|
|
||||||
var handSelectedMsg = new HandSelectedEvent(user, item);
|
|
||||||
RaiseLocalEvent(item, handSelectedMsg);
|
|
||||||
if (handSelectedMsg.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var comps = AllComps<IHandSelected>(item).ToList();
|
|
||||||
|
|
||||||
// Call Land on all components that implement the interface
|
|
||||||
foreach (var comp in comps)
|
|
||||||
{
|
|
||||||
comp.HandSelected(new HandSelectedEventArgs(user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calls HandDeselected on all components that implement the IHandDeselected interface
|
|
||||||
/// on an item entity on a hand that has just been deselected.
|
|
||||||
/// </summary>
|
|
||||||
public void HandDeselectedInteraction(EntityUid user, EntityUid item)
|
|
||||||
{
|
|
||||||
var handDeselectedMsg = new HandDeselectedEvent(user, item);
|
|
||||||
RaiseLocalEvent(item, handDeselectedMsg);
|
|
||||||
if (handDeselectedMsg.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var comps = AllComps<IHandDeselected>(item).ToList();
|
|
||||||
|
|
||||||
// Call Land on all components that implement the interface
|
|
||||||
foreach (var comp in comps)
|
|
||||||
{
|
|
||||||
comp.HandDeselected(new HandDeselectedEventArgs(user));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -891,8 +809,6 @@ namespace Content.Shared.Interaction
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace Content.Shared.Item
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Verb verb = new();
|
Verb verb = new();
|
||||||
verb.Act = () => args.Hands.TryPutInActiveHandOrAny(args.Target);
|
verb.Act = () => args.Hands.PutInHand(args.Target);
|
||||||
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,10 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Sound;
|
using Content.Shared.Sound;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -123,7 +125,7 @@ namespace Content.Shared.Item
|
|||||||
if (!CanPickup(user))
|
if (!CanPickup(user))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!_entMan.TryGetComponent(user, out SharedHandsComponent? hands))
|
if (!_entMan.TryGetComponent(user, out SharedHandsComponent hands))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var activeHand = hands.ActiveHand;
|
var activeHand = hands.ActiveHand;
|
||||||
@@ -131,15 +133,27 @@ namespace Content.Shared.Item
|
|||||||
if (activeHand == null)
|
if (activeHand == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
hands.TryPickupEntityToActiveHand(Owner);
|
hands.TryPickupEntityToActiveHand(Owner, animateUser: true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnEquippedPrefixChange() { }
|
private void OnEquippedPrefixChange()
|
||||||
|
{
|
||||||
|
if (Owner.TryGetContainer(out var container))
|
||||||
|
EntitySystem.Get<SharedHandsSystem>().UpdateHandVisualizer(container.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void RemovedFromSlot() { }
|
public void RemovedFromSlot()
|
||||||
|
{
|
||||||
|
if (_entMan.TryGetComponent(Owner, out SharedSpriteComponent component))
|
||||||
|
component.Visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void EquippedToSlot() { }
|
public virtual void EquippedToSlot()
|
||||||
|
{
|
||||||
|
if (_entMan.TryGetComponent(Owner, out SharedSpriteComponent component))
|
||||||
|
component.Visible = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
|
|||||||
@@ -67,14 +67,13 @@ namespace Content.Shared.Verbs
|
|||||||
EntityUid? @using = null;
|
EntityUid? @using = null;
|
||||||
if (TryComp(user, out SharedHandsComponent? hands) && (force || _actionBlockerSystem.CanUse(user)))
|
if (TryComp(user, out SharedHandsComponent? hands) && (force || _actionBlockerSystem.CanUse(user)))
|
||||||
{
|
{
|
||||||
// TODO Hands remove nullable (#5634)
|
hands.TryGetActiveHeldEntity(out @using);
|
||||||
hands.TryGetActiveHeldEntity(out var nonNullableUsing);
|
|
||||||
@using = nonNullableUsing;
|
|
||||||
|
|
||||||
// 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
|
||||||
// their sprite.
|
// their sprite.
|
||||||
if (@using != null && TryComp(@using, out HandVirtualItemComponent? pull))
|
|
||||||
|
if (TryComp(@using, out HandVirtualItemComponent? pull))
|
||||||
{
|
{
|
||||||
@using = pull.BlockingEntity;
|
@using = pull.BlockingEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user