HandsSystem Refactor (#38438)
* checkpoint * pt 2 * pt... i forgot * pt 4 * patch * More test fixes * optimization!!! * the REAL hand system * fix RetractableItemActionSystem.cs oversight * the review * test * remove test usage of body prototype * Update Content.IntegrationTests/Tests/Interaction/InteractionTest.cs Co-authored-by: Tayrtahn <tayrtahn@gmail.com> * hellcode * hellcode 2 * Minor cleanup * test * Chasing the last of the bugs * changes --------- Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ using Content.Shared.Tag;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Hands.EntitySystems;
|
||||
|
||||
@@ -28,10 +29,10 @@ public abstract partial class SharedHandsSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var gotUnequipped = new GotUnequippedHandEvent(uid, args.Entity, hand);
|
||||
var gotUnequipped = new GotUnequippedHandEvent(uid, args.Entity, hand.Value);
|
||||
RaiseLocalEvent(args.Entity, gotUnequipped);
|
||||
|
||||
var didUnequip = new DidUnequipHandEvent(uid, args.Entity, hand);
|
||||
var didUnequip = new DidUnequipHandEvent(uid, args.Entity, hand.Value);
|
||||
RaiseLocalEvent(uid, didUnequip);
|
||||
|
||||
if (TryComp(args.Entity, out VirtualItemComponent? @virtual))
|
||||
@@ -47,26 +48,29 @@ public abstract partial class SharedHandsSystem
|
||||
/// <summary>
|
||||
/// Checks whether an entity can drop a given entity. Will return false if they are not holding the entity.
|
||||
/// </summary>
|
||||
public bool CanDrop(EntityUid uid, EntityUid entity, HandsComponent? handsComp = null, bool checkActionBlocker = true)
|
||||
public bool CanDrop(Entity<HandsComponent?> ent, EntityUid entity, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
if (!IsHolding(ent, entity, out var hand))
|
||||
return false;
|
||||
|
||||
return CanDropHeld(uid, hand, checkActionBlocker);
|
||||
return CanDropHeld(ent, hand, checkActionBlocker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the contents of a hand is able to be removed from its container.
|
||||
/// </summary>
|
||||
public bool CanDropHeld(EntityUid uid, Hand hand, bool checkActionBlocker = true)
|
||||
public bool CanDropHeld(EntityUid uid, string handId, bool checkActionBlocker = true)
|
||||
{
|
||||
if (hand.Container?.ContainedEntity is not {} held)
|
||||
if (!ContainerSystem.TryGetContainer(uid, handId, out var container))
|
||||
return false;
|
||||
|
||||
if (!ContainerSystem.CanRemove(held, hand.Container))
|
||||
if (container.ContainedEntities.FirstOrNull() is not {} held)
|
||||
return false;
|
||||
|
||||
if (!ContainerSystem.CanRemove(held, container))
|
||||
return false;
|
||||
|
||||
if (checkActionBlocker && !_actionBlocker.CanDrop(uid))
|
||||
@@ -78,98 +82,100 @@ public abstract partial class SharedHandsSystem
|
||||
/// <summary>
|
||||
/// Attempts to drop the item in the currently active hand.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, HandsComponent? handsComp = null)
|
||||
public bool TryDrop(Entity<HandsComponent?> ent, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (handsComp.ActiveHand == null)
|
||||
if (ent.Comp.ActiveHandId == null)
|
||||
return false;
|
||||
|
||||
return TryDrop(uid, handsComp.ActiveHand, targetDropLocation, checkActionBlocker, doDropInteraction, handsComp);
|
||||
return TryDrop(ent, ent.Comp.ActiveHandId, targetDropLocation, checkActionBlocker, doDropInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops an item at the target location.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, EntityUid entity, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, HandsComponent? handsComp = null)
|
||||
public bool TryDrop(Entity<HandsComponent?> ent, EntityUid entity, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
if (!IsHolding(ent, entity, out var hand))
|
||||
return false;
|
||||
|
||||
return TryDrop(uid, hand, targetDropLocation, checkActionBlocker, doDropInteraction, handsComp);
|
||||
return TryDrop(ent, hand, targetDropLocation, checkActionBlocker, doDropInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops a hands contents at the target location.
|
||||
/// </summary>
|
||||
public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true, HandsComponent? handsComp = null)
|
||||
public bool TryDrop(Entity<HandsComponent?> ent, string handId, EntityCoordinates? targetDropLocation = null, bool checkActionBlocker = true, bool doDropInteraction = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!CanDropHeld(uid, hand, checkActionBlocker))
|
||||
if (!CanDropHeld(ent, handId, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
var entity = hand.HeldEntity!.Value;
|
||||
if (!TryGetHeldItem(ent, handId, out var entity))
|
||||
return false;
|
||||
|
||||
// if item is a fake item (like with pulling), just delete it rather than bothering with trying to drop it into the world
|
||||
if (TryComp(entity, out VirtualItemComponent? @virtual))
|
||||
_virtualSystem.DeleteVirtualItem((entity, @virtual), uid);
|
||||
_virtualSystem.DeleteVirtualItem((entity.Value, @virtual), ent);
|
||||
|
||||
if (TerminatingOrDeleted(entity))
|
||||
return true;
|
||||
|
||||
var itemXform = Transform(entity);
|
||||
var itemXform = Transform(entity.Value);
|
||||
if (itemXform.MapUid == null)
|
||||
return true;
|
||||
|
||||
var userXform = Transform(uid);
|
||||
var isInContainer = ContainerSystem.IsEntityOrParentInContainer(uid, xform: userXform);
|
||||
var userXform = Transform(ent);
|
||||
var isInContainer = ContainerSystem.IsEntityOrParentInContainer(ent, xform: userXform);
|
||||
|
||||
// if the user is in a container, drop the item inside the container
|
||||
if (isInContainer) {
|
||||
TransformSystem.DropNextTo((entity, itemXform), (uid, userXform));
|
||||
if (isInContainer)
|
||||
{
|
||||
TransformSystem.DropNextTo((entity.Value, itemXform), (ent, userXform));
|
||||
return true;
|
||||
}
|
||||
|
||||
// drop the item with heavy calculations from their hands and place it at the calculated interaction range position
|
||||
// The DoDrop is handle if there's no drop target
|
||||
DoDrop(uid, hand, doDropInteraction: doDropInteraction, handsComp);
|
||||
DoDrop(ent, handId, doDropInteraction: doDropInteraction);
|
||||
|
||||
// if there's no drop location stop here
|
||||
if (targetDropLocation == null)
|
||||
return true;
|
||||
|
||||
// otherwise, also move dropped item and rotate it properly according to grid/map
|
||||
var (itemPos, itemRot) = TransformSystem.GetWorldPositionRotation(entity);
|
||||
var (itemPos, itemRot) = TransformSystem.GetWorldPositionRotation(entity.Value);
|
||||
var origin = new MapCoordinates(itemPos, itemXform.MapID);
|
||||
var target = TransformSystem.ToMapCoordinates(targetDropLocation.Value);
|
||||
TransformSystem.SetWorldPositionRotation(entity, GetFinalDropCoordinates(uid, origin, target, entity), itemRot);
|
||||
TransformSystem.SetWorldPositionRotation(entity.Value, GetFinalDropCoordinates(ent, origin, target, entity.Value), itemRot);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move a held item from a hand into a container that is not another hand, without dropping it on the floor in-between.
|
||||
/// </summary>
|
||||
public bool TryDropIntoContainer(EntityUid uid, EntityUid entity, BaseContainer targetContainer, bool checkActionBlocker = true, HandsComponent? handsComp = null)
|
||||
public bool TryDropIntoContainer(Entity<HandsComponent?> ent, EntityUid entity, BaseContainer targetContainer, bool checkActionBlocker = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!IsHolding(uid, entity, out var hand, handsComp))
|
||||
if (!IsHolding(ent, entity, out var hand))
|
||||
return false;
|
||||
|
||||
if (!CanDropHeld(uid, hand, checkActionBlocker))
|
||||
if (!CanDropHeld(ent, hand, checkActionBlocker))
|
||||
return false;
|
||||
|
||||
if (!ContainerSystem.CanInsert(entity, targetContainer))
|
||||
return false;
|
||||
|
||||
DoDrop(uid, hand, false, handsComp);
|
||||
DoDrop(ent, hand, false);
|
||||
ContainerSystem.Insert(entity, targetContainer);
|
||||
return true;
|
||||
}
|
||||
@@ -202,34 +208,38 @@ public abstract partial class SharedHandsSystem
|
||||
/// <summary>
|
||||
/// Removes the contents of a hand from its container. Assumes that the removal is allowed. In general, you should not be calling this directly.
|
||||
/// </summary>
|
||||
public virtual void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? handsComp = null, bool log = true)
|
||||
public virtual void DoDrop(Entity<HandsComponent?> ent,
|
||||
string handId,
|
||||
bool doDropInteraction = true,
|
||||
bool log = true)
|
||||
{
|
||||
if (!Resolve(uid, ref handsComp))
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return;
|
||||
|
||||
if (hand.Container?.ContainedEntity == null)
|
||||
if (!ContainerSystem.TryGetContainer(ent, handId, out var container))
|
||||
return;
|
||||
|
||||
var entity = hand.Container.ContainedEntity.Value;
|
||||
|
||||
if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(entity))
|
||||
if (!TryGetHeldItem(ent, handId, out var entity))
|
||||
return;
|
||||
|
||||
if (!ContainerSystem.Remove(entity, hand.Container))
|
||||
if (TerminatingOrDeleted(ent) || TerminatingOrDeleted(entity))
|
||||
return;
|
||||
|
||||
if (!ContainerSystem.Remove(entity.Value, container))
|
||||
{
|
||||
Log.Error($"Failed to remove {ToPrettyString(entity)} from users hand container when dropping. User: {ToPrettyString(uid)}. Hand: {hand.Name}.");
|
||||
Log.Error($"Failed to remove {ToPrettyString(entity)} from users hand container when dropping. User: {ToPrettyString(ent)}. Hand: {handId}.");
|
||||
return;
|
||||
}
|
||||
|
||||
Dirty(uid, handsComp);
|
||||
Dirty(ent);
|
||||
|
||||
if (doDropInteraction)
|
||||
_interactionSystem.DroppedInteraction(uid, entity);
|
||||
_interactionSystem.DroppedInteraction(ent, entity.Value);
|
||||
|
||||
if (log)
|
||||
_adminLogger.Add(LogType.Drop, LogImpact.Low, $"{ToPrettyString(uid):user} dropped {ToPrettyString(entity):entity}");
|
||||
_adminLogger.Add(LogType.Drop, LogImpact.Low, $"{ToPrettyString(ent):user} dropped {ToPrettyString(entity):entity}");
|
||||
|
||||
if (hand == handsComp.ActiveHand)
|
||||
RaiseLocalEvent(entity, new HandDeselectedEvent(uid));
|
||||
if (handId == ent.Comp.ActiveHandId)
|
||||
RaiseLocalEvent(entity.Value, new HandDeselectedEvent(ent));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user