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:
Nemanja
2025-06-25 09:13:03 -04:00
committed by GitHub
parent 6cffa8aabe
commit 524725d378
79 changed files with 849 additions and 897 deletions

View File

@@ -1,6 +1,5 @@
using Content.Shared.DisplacementMap;
using Content.Shared.Hands.EntitySystems;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
@@ -13,50 +12,50 @@ public sealed partial class HandsComponent : Component
/// <summary>
/// The currently active hand.
/// </summary>
[ViewVariables]
public Hand? ActiveHand;
[DataField]
public string? ActiveHandId;
/// <summary>
/// The item currently held in the active hand.
/// Dictionary relating a unique hand ID corresponding to a container slot on the attached entity to a class containing information about the Hand itself.
/// </summary>
[ViewVariables]
public EntityUid? ActiveHandEntity => ActiveHand?.HeldEntity;
[ViewVariables]
[DataField]
public Dictionary<string, Hand> Hands = new();
/// <summary>
/// The number of hands
/// </summary>
[ViewVariables]
public int Count => Hands.Count;
/// <summary>
/// List of hand-names. These are keys for <see cref="Hands"/>. The order of this list determines the order in which hands are iterated over.
/// </summary>
[DataField]
public List<string> SortedHands = new();
/// <summary>
/// If true, the items in the hands won't be affected by explosions.
/// </summary>
[DataField]
public bool DisableExplosionRecursion = false;
public bool DisableExplosionRecursion;
/// <summary>
/// Modifies the speed at which items are thrown.
/// </summary>
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float BaseThrowspeed { get; set; } = 11f;
public float BaseThrowspeed = 11f;
/// <summary>
/// Distance after which longer throw targets stop increasing throw impulse.
/// </summary>
[DataField("throwRange")]
[ViewVariables(VVAccess.ReadWrite)]
public float ThrowRange { get; set; } = 8f;
[DataField]
public float ThrowRange = 8f;
/// <summary>
/// Whether or not to add in-hand sprites for held items. Some entities (e.g., drones) don't want these.
/// Used by the client.
/// </summary>
[DataField("showInHands")]
[DataField]
public bool ShowInHands = true;
/// <summary>
@@ -68,14 +67,13 @@ public sealed partial class HandsComponent : Component
/// <summary>
/// The time at which throws will be allowed again.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[AutoPausedField]
[DataField, AutoPausedField]
public TimeSpan NextThrowTime;
/// <summary>
/// The minimum time inbetween throws.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[DataField]
public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(0.5f);
/// <summary>
@@ -103,48 +101,37 @@ public sealed partial class HandsComponent : Component
public bool CanBeStripped = true;
}
[DataDefinition]
[Serializable, NetSerializable]
public sealed class Hand //TODO: This should definitely be a struct - Jezi
public partial record struct Hand
{
[ViewVariables]
public string Name { get; }
[DataField]
public HandLocation Location = HandLocation.Right;
[ViewVariables]
public HandLocation Location { get; }
/// <summary>
/// The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
/// which may not be synced with the server when the client hands are created.
/// </summary>
[ViewVariables, NonSerialized]
public ContainerSlot? Container;
[ViewVariables]
public EntityUid? HeldEntity => Container?.ContainedEntity;
public bool IsEmpty => HeldEntity == null;
public Hand(string name, HandLocation location, ContainerSlot? container = null)
public Hand()
{
}
public Hand(HandLocation location)
{
Name = name;
Location = location;
Container = container;
}
}
[Serializable, NetSerializable]
public sealed class HandsComponentState : ComponentState
{
public readonly List<Hand> Hands;
public readonly List<string> HandNames;
public readonly string? ActiveHand;
public readonly Dictionary<string, Hand> Hands;
public readonly List<string> SortedHands;
public readonly string? ActiveHandId;
public HandsComponentState(HandsComponent handComp)
{
// cloning lists because of test networking.
Hands = new(handComp.Hands.Values);
HandNames = new(handComp.SortedHands);
ActiveHand = handComp.ActiveHand?.Name;
Hands = new(handComp.Hands);
SortedHands = new(handComp.SortedHands);
ActiveHandId = handComp.ActiveHandId;
}
}