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:
@@ -27,43 +27,14 @@ namespace Content.Shared.Hands.Components
|
||||
|
||||
public sealed override string Name => "Hands";
|
||||
|
||||
public event Action? OnItemChanged; //TODO: Try to replace C# event
|
||||
|
||||
/// <summary>
|
||||
/// The name of the currently active hand.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
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]
|
||||
public string? ActiveHand;
|
||||
|
||||
[ViewVariables]
|
||||
public readonly List<Hand> Hands = new();
|
||||
public List<Hand> Hands = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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)]
|
||||
public float ThrowRange { get; set; } = 8f;
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
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));
|
||||
}
|
||||
private bool PlayerCanDrop => EntitySystem.Get<ActionBlockerSystem>().CanDrop(Owner);
|
||||
private bool PlayerCanPickup => EntitySystem.Get<ActionBlockerSystem>().CanPickup(Owner);
|
||||
|
||||
public void AddHand(string handName, HandLocation handLocation)
|
||||
{
|
||||
if (HasHand(handName))
|
||||
return;
|
||||
|
||||
var container = Owner.CreateContainer<ContainerSlot>(handName);
|
||||
var container = Owner.EnsureContainer<ContainerSlot>(handName);
|
||||
container.OccludesLight = false;
|
||||
|
||||
Hands.Add(new Hand(handName, handLocation, container));
|
||||
|
||||
ActiveHand ??= handName;
|
||||
if (ActiveHand == null)
|
||||
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, handName, this);
|
||||
|
||||
HandCountChanged();
|
||||
|
||||
HandsModified();
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void RemoveHand(string handName)
|
||||
@@ -156,14 +86,14 @@ namespace Content.Shared.Hands.Components
|
||||
Hands.Remove(hand);
|
||||
|
||||
if (ActiveHand == hand.Name)
|
||||
ActiveHand = Hands.FirstOrDefault()?.Name;
|
||||
EntitySystem.Get<SharedHandsSystem>().TrySetActiveHand(Owner, Hands.FirstOrDefault()?.Name, this);
|
||||
|
||||
HandCountChanged();
|
||||
|
||||
HandsModified();
|
||||
Dirty();
|
||||
}
|
||||
|
||||
private Hand? GetActiveHand()
|
||||
public Hand? GetActiveHand()
|
||||
{
|
||||
if (ActiveHand == null)
|
||||
return null;
|
||||
@@ -220,7 +150,7 @@ namespace Content.Shared.Hands.Components
|
||||
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;
|
||||
|
||||
@@ -228,7 +158,7 @@ namespace Content.Shared.Hands.Components
|
||||
return false;
|
||||
|
||||
heldEntity = hand.HeldEntity;
|
||||
return hand.HeldEntity != null;
|
||||
return heldEntity != null;
|
||||
}
|
||||
|
||||
public bool TryGetActiveHeldEntity([NotNullWhen(true)] out EntityUid? heldEntity)
|
||||
@@ -251,7 +181,7 @@ namespace Content.Shared.Hands.Components
|
||||
{
|
||||
foreach (var hand in Hands)
|
||||
{
|
||||
if (hand.HeldEntity.HasValue)
|
||||
if (hand.HeldEntity != null)
|
||||
yield return hand.HeldEntity.Value;
|
||||
}
|
||||
}
|
||||
@@ -302,7 +232,7 @@ namespace Content.Shared.Hands.Components
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop())
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -406,7 +336,7 @@ namespace Content.Shared.Hands.Components
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
RemoveHeldEntityFromHand(hand);
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -418,62 +348,27 @@ namespace Content.Shared.Hands.Components
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
|
||||
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))
|
||||
if (!hand.Container!.CanRemove(hand.HeldEntity.Value))
|
||||
return false;
|
||||
|
||||
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>
|
||||
/// Drops a hands contents to the target location.
|
||||
/// </summary>
|
||||
public void DropHeldEntity(Hand hand, EntityCoordinates targetDropLocation)
|
||||
{
|
||||
if (hand.HeldEntity is not { } heldEntity)
|
||||
if (hand.HeldEntity == null)
|
||||
return;
|
||||
|
||||
RemoveHeldEntityFromHand(hand);
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
|
||||
EntitySystem.Get<SharedInteractionSystem>().DroppedInteraction(Owner, heldEntity);
|
||||
|
||||
_entMan.GetComponent<TransformComponent>(heldEntity).WorldPosition = GetFinalDropCoordinates(targetDropLocation);
|
||||
|
||||
OnItemChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -508,7 +403,7 @@ namespace Content.Shared.Hands.Components
|
||||
if (!CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop())
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
DropHeldEntity(hand, location);
|
||||
@@ -525,10 +420,12 @@ namespace Content.Shared.Hands.Components
|
||||
|
||||
private bool CanPutHeldEntityIntoContainer(Hand hand, IContainer targetContainer, bool checkActionBlocker)
|
||||
{
|
||||
if (hand.HeldEntity is not { } heldEntity)
|
||||
if (hand.HeldEntity == null)
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop())
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanDrop)
|
||||
return false;
|
||||
|
||||
if (!targetContainer.CanInsert(heldEntity))
|
||||
@@ -542,10 +439,12 @@ namespace Content.Shared.Hands.Components
|
||||
/// </summary>
|
||||
private void PutHeldEntityIntoContainer(Hand hand, IContainer targetContainer)
|
||||
{
|
||||
if (hand.HeldEntity is not { } heldEntity)
|
||||
if (hand.HeldEntity == null)
|
||||
return;
|
||||
|
||||
RemoveHeldEntityFromHand(hand);
|
||||
var heldEntity = hand.HeldEntity.Value;
|
||||
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
|
||||
if (!targetContainer.Insert(heldEntity))
|
||||
{
|
||||
@@ -563,7 +462,7 @@ namespace Content.Shared.Hands.Components
|
||||
if (!TryGetHand(handName, out var hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanPickup())
|
||||
if (checkActionBlocker && !PlayerCanPickup)
|
||||
return false;
|
||||
|
||||
if (!CanInsertEntityIntoHand(hand, entity))
|
||||
@@ -580,17 +479,17 @@ namespace Content.Shared.Hands.Components
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity to a specific hand.
|
||||
/// </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))
|
||||
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>
|
||||
@@ -598,6 +497,9 @@ namespace Content.Shared.Hands.Components
|
||||
/// </summary>
|
||||
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
|
||||
{
|
||||
if (!_entMan.HasComponent<SharedItemComponent>(entity))
|
||||
return false;
|
||||
|
||||
var handContainer = hand.Container;
|
||||
if (handContainer == null) return false;
|
||||
|
||||
@@ -611,56 +513,23 @@ namespace Content.Shared.Hands.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
private bool TryPickupEntity(Hand hand, EntityUid entity, bool checkActionBlocker = true, bool animateUser = false)
|
||||
{
|
||||
if (!CanInsertEntityIntoHand(hand, entity))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !PlayerCanPickup())
|
||||
if (checkActionBlocker && !PlayerCanPickup)
|
||||
return false;
|
||||
|
||||
HandlePickupAnimation(entity);
|
||||
PutEntityIntoHand(hand, entity);
|
||||
EntitySystem.Get<SharedAdminLogSystem>().Add(LogType.Pickup, LogImpact.Low, $"{_entMan.ToPrettyString(Owner):user} picked up {_entMan.ToPrettyString(entity):entity}");
|
||||
// animation
|
||||
var handSys = EntitySystem.Get<SharedHandsSystem>();
|
||||
var coordinateEntity = _entMan.GetComponent<TransformComponent>(Owner).Parent?.Owner ?? Owner;
|
||||
var initialPosition = EntityCoordinates.FromMap(coordinateEntity, _entMan.GetComponent<TransformComponent>(entity).MapPosition);
|
||||
var finalPosition = _entMan.GetComponent<TransformComponent>(Owner).LocalPosition;
|
||||
|
||||
handSys.PickupAnimation(entity, initialPosition, finalPosition, animateUser ? null : Owner);
|
||||
handSys.PutEntityIntoHand(Owner, hand, entity, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -740,28 +609,16 @@ namespace Content.Shared.Hands.Components
|
||||
if (!CanInsertEntityIntoHand(activeHand, heldEntity.Value) || !CanRemoveHeldEntityFromHand(hand))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && (!PlayerCanDrop() || !PlayerCanPickup()))
|
||||
if (checkActionBlocker && (!PlayerCanDrop || !PlayerCanPickup))
|
||||
return false;
|
||||
|
||||
RemoveHeldEntityFromHand(hand);
|
||||
PutEntityIntoHand(activeHand, heldEntity.Value);
|
||||
EntitySystem.Get<SharedHandsSystem>().RemoveHeldEntityFromHand(Owner, hand, this);
|
||||
EntitySystem.Get<SharedHandsSystem>().PutEntityIntoHand(Owner, activeHand, heldEntity.Value, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
_entMan.EventBus.RaiseEvent(EventSource.Local, new HandCountChangedEvent(Owner));
|
||||
@@ -772,36 +629,30 @@ namespace Content.Shared.Hands.Components
|
||||
/// </summary>
|
||||
public bool PutInHand(SharedItemComponent item, bool checkActionBlocker = true)
|
||||
{
|
||||
return TryPutInActiveHandOrAny(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);
|
||||
return PutInHand(item.Owner, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts an item any hand, prefering the active hand, or puts it on the floor under the player.
|
||||
/// </summary>
|
||||
public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true) =>
|
||||
PutInHandOrDrop(item.Owner, checkActionBlocker);
|
||||
|
||||
public void PutInHandOrDrop(EntityUid uid, bool checkActionBlocker = true)
|
||||
public void PutInHandOrDrop(EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!TryPutInActiveHandOrAny(uid, checkActionBlocker))
|
||||
_entMan.GetComponent<TransformComponent>(uid).Coordinates = _entMan.GetComponent<TransformComponent>(Owner).Coordinates;
|
||||
|
||||
if (!PutInHand(entity, checkActionBlocker))
|
||||
_entMan.GetComponent<TransformComponent>(entity).Coordinates = _entMan.GetComponent<TransformComponent>(Owner).Coordinates;
|
||||
}
|
||||
|
||||
public void PutInHandOrDrop(SharedItemComponent item, bool checkActionBlocker = true)
|
||||
{
|
||||
PutInHandOrDrop(item.Owner, checkActionBlocker);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the active hand. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
public bool 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>
|
||||
@@ -814,13 +665,13 @@ namespace Content.Shared.Hands.Components
|
||||
if (priorityHandName != null)
|
||||
priorityHand = GetHandOrNull(priorityHandName);
|
||||
|
||||
return TryPutInAnyHand(entity, priorityHand, checkActionBlocker);
|
||||
return PutInHand(entity, priorityHand, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pick up an entity into the priority hand, if provided. If it cannot, tries to pick up the entity into each other hand.
|
||||
/// </summary>
|
||||
private bool TryPutInAnyHand(EntityUid entity, Hand? priorityHand = null, bool checkActionBlocker = true)
|
||||
private bool PutInHand(EntityUid entity, Hand? priorityHand = null, bool checkActionBlocker = true)
|
||||
{
|
||||
if (priorityHand != null)
|
||||
{
|
||||
@@ -836,9 +687,23 @@ namespace Content.Shared.Hands.Components
|
||||
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
|
||||
@@ -877,6 +742,7 @@ namespace Content.Shared.Hands.Components
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class Hand
|
||||
{
|
||||
[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"/>,
|
||||
/// which may not be synced with the server when the client hands are created.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public IContainer? Container { get; set; }
|
||||
[ViewVariables, NonSerialized]
|
||||
public ContainerSlot? Container;
|
||||
|
||||
[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;
|
||||
Location = location;
|
||||
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]
|
||||
public sealed class HandsComponentState : ComponentState
|
||||
{
|
||||
public HandState[] Hands { get; }
|
||||
public List<Hand> Hands { get; }
|
||||
public string? ActiveHand { get; }
|
||||
|
||||
public HandsComponentState(HandState[] hands, string? activeHand = null)
|
||||
public HandsComponentState(List<Hand> hands, string? activeHand = null)
|
||||
{
|
||||
Hands = hands;
|
||||
ActiveHand = activeHand;
|
||||
@@ -1004,25 +853,4 @@ namespace Content.Shared.Hands.Components
|
||||
|
||||
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.Input;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Containers;
|
||||
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
|
||||
{
|
||||
public abstract class SharedHandsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeAllEvent<RequestSetHandEvent>(HandleSetHand);
|
||||
|
||||
SubscribeLocalEvent<SharedHandsComponent, EntRemovedFromContainerMessage>(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)
|
||||
{
|
||||
var entity = eventArgs.SenderSession.AttachedEntity;
|
||||
|
||||
if (entity == null || !EntityManager.TryGetComponent(entity, out SharedHandsComponent? hands))
|
||||
if (eventArgs.SenderSession.AttachedEntity == null)
|
||||
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.
|
||||
/// Set the currently active hand and raise hand (de)selection events directed at the held entities.
|
||||
/// </summary>
|
||||
public string HandName { get; }
|
||||
|
||||
public RequestSetHandEvent(string handName)
|
||||
/// <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)
|
||||
{
|
||||
HandName = handName;
|
||||
}
|
||||
}
|
||||
if (!Resolve(uid, ref handComp))
|
||||
return false;
|
||||
|
||||
/// <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;
|
||||
if (value == handComp.ActiveHand)
|
||||
return false;
|
||||
|
||||
public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user)
|
||||
{
|
||||
BlockingEntity = blockingEntity;
|
||||
User = user;
|
||||
if (value != null && !handComp.HasHand(value))
|
||||
{
|
||||
Logger.Warning($"{nameof(SharedHandsComponent)} on {handComp.Owner} tried to set its active hand to {value}, which was not a hand.");
|
||||
return false;
|
||||
}
|
||||
if (value == null && handComp.Hands.Count != 0)
|
||||
{
|
||||
Logger.Error($"{nameof(SharedHandsComponent)} on {handComp.Owner} tried to set its active hand to null, when it still had another hand.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handComp.TryGetActiveHeldEntity(out var entity))
|
||||
RaiseLocalEvent(entity.Value, new HandDeselectedEvent(uid, entity.Value), false);
|
||||
|
||||
handComp.ActiveHand = value;
|
||||
|
||||
if (handComp.TryGetActiveHeldEntity(out entity))
|
||||
RaiseLocalEvent(entity.Value, new HandSelectedEvent(uid, entity.Value), false);
|
||||
|
||||
handComp.Dirty();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user