Add changing the amount of hands on the GUI depending on your body parts (#1406)
* Multiple hands in gui first pass * Remove IHandsComponent interface * Create hand class and more hand textures * Refactor ServerHandsComponent to use a single list of hands * Seal SharedHand * Fix picked up items not showing on top of the hand buttons * Remove HandsGui buttons and panels dictionaries * Fix items in hands rendering * Fix wrong hand container comparison * Fix not updating the location of duplicate hands * Change ClientHandsComponent to use a SortedList instead of a dictionary * More merge conflict fixes * Change SortedList to List * Fix hand button order * Add item tooltip for more than 2 hands and updating when removing hands * Add add hand and remove hand command * Merge conflict fixes * Remove nullable reference type from ContainerSlot * Fix texture errors * Fix error when reaching 0 hands * Fix error when swapping hands with no hands * Merged remove hand methods * Fix item panel texture errors * Merge conflict fixes * Fix addhand and removehand command descriptions * Add properly displaying tooltips for 2 hands * Make hand indexes and locations consistent across the client and server * Add dropping held entity if a hand is removed * Change hand location to be calculated by index * Made different hand gui updates more consistent * Remove human body yml testing changes * Sanitize addhand and removehand commands * Merge conflict fixes * Remove testing changes * Revert body system changes * Add missing imports * Remove obsolete hands parameter in yml files * Fix broken import * Fix startup error and adding and removing hands on the same tick * Make hand container id use an uint In case someone gets more than 2 billion hands * Rename hand component files * Make hands state use an array
This commit is contained in:
256
Content.Client/GameObjects/Components/Items/HandsComponent.cs
Normal file
256
Content.Client/GameObjects/Components/Items/HandsComponent.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Items
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class HandsComponent : SharedHandsComponent
|
||||
{
|
||||
private HandsGui? _gui;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
#pragma warning restore 649
|
||||
|
||||
private readonly List<Hand> _hands = new List<Hand>();
|
||||
|
||||
[ViewVariables] public IReadOnlyList<Hand> Hands => _hands;
|
||||
|
||||
[ViewVariables] public string? ActiveIndex { get; private set; }
|
||||
|
||||
[ViewVariables] private ISpriteComponent? _sprite;
|
||||
|
||||
[ViewVariables] public IEntity? ActiveHand => GetEntity(ActiveIndex);
|
||||
|
||||
private void AddHand(Hand hand)
|
||||
{
|
||||
_hands.Insert(hand.Index, hand);
|
||||
}
|
||||
|
||||
public Hand? GetHand(string? name)
|
||||
{
|
||||
return Hands.FirstOrDefault(hand => hand.Name == name);
|
||||
}
|
||||
|
||||
private bool TryHand(string name, [MaybeNullWhen(false)] out Hand hand)
|
||||
{
|
||||
return (hand = GetHand(name)) != null;
|
||||
}
|
||||
|
||||
public IEntity? GetEntity(string? handName)
|
||||
{
|
||||
if (handName == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetHand(handName)?.Entity;
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
_gui?.Dispose();
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
if (Owner.TryGetComponent(out _sprite))
|
||||
{
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
_sprite.LayerMapReserveBlank($"hand-{hand.Name}");
|
||||
UpdateHandSprites(hand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
if (curState == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cast = (HandsComponentState) curState;
|
||||
foreach (var sharedHand in cast.Hands)
|
||||
{
|
||||
if (!TryHand(sharedHand.Name, out var hand))
|
||||
{
|
||||
hand = new Hand(sharedHand, Owner.EntityManager);
|
||||
AddHand(hand);
|
||||
}
|
||||
else
|
||||
{
|
||||
hand.Location = sharedHand.Location;
|
||||
|
||||
hand.Entity = sharedHand.EntityUid.HasValue
|
||||
? Owner.EntityManager.GetEntity(sharedHand.EntityUid.Value)
|
||||
: null;
|
||||
}
|
||||
|
||||
UpdateHandSprites(hand);
|
||||
}
|
||||
|
||||
foreach (var currentHand in _hands.ToList())
|
||||
{
|
||||
if (cast.Hands.All(newHand => newHand.Name != currentHand.Name))
|
||||
{
|
||||
_hands.Remove(currentHand);
|
||||
_gui?.RemoveHand(currentHand);
|
||||
HideHand(currentHand);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveIndex = cast.ActiveIndex;
|
||||
|
||||
_gui?.UpdateHandIcons();
|
||||
RefreshInHands();
|
||||
}
|
||||
|
||||
private void HideHand(Hand hand)
|
||||
{
|
||||
_sprite?.LayerSetVisible($"hand-{hand.Name}", false);
|
||||
}
|
||||
|
||||
private void UpdateHandSprites(Hand hand)
|
||||
{
|
||||
if (_sprite == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = hand.Entity;
|
||||
var name = hand.Name;
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
_sprite.LayerSetVisible($"hand-{name}", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entity.TryGetComponent(out ItemComponent item)) return;
|
||||
|
||||
var maybeInHands = item.GetInHandStateInfo(name);
|
||||
|
||||
if (!maybeInHands.HasValue)
|
||||
{
|
||||
_sprite.LayerSetVisible($"hand-{name}", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var (rsi, state) = maybeInHands.Value;
|
||||
_sprite.LayerSetVisible($"hand-{name}", true);
|
||||
_sprite.LayerSetState($"hand-{name}", state, rsi);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshInHands()
|
||||
{
|
||||
if (!Initialized) return;
|
||||
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
UpdateHandSprites(hand);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
ActiveIndex = _hands.LastOrDefault()?.Name;
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case PlayerAttachedMsg _:
|
||||
if (_gui == null)
|
||||
{
|
||||
_gui = new HandsGui();
|
||||
}
|
||||
else
|
||||
{
|
||||
_gui.Parent?.RemoveChild(_gui);
|
||||
}
|
||||
|
||||
_gameHud.HandsContainer.AddChild(_gui);
|
||||
_gui.UpdateHandIcons();
|
||||
break;
|
||||
|
||||
case PlayerDetachedMsg _:
|
||||
_gui?.Parent?.RemoveChild(_gui);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendChangeHand(string index)
|
||||
{
|
||||
SendNetworkMessage(new ClientChangedHandMsg(index));
|
||||
}
|
||||
|
||||
public void AttackByInHand(string index)
|
||||
{
|
||||
SendNetworkMessage(new ClientAttackByInHandMsg(index));
|
||||
}
|
||||
|
||||
public void UseActiveHand()
|
||||
{
|
||||
if (GetEntity(ActiveIndex) != null)
|
||||
{
|
||||
SendNetworkMessage(new UseInHandMsg());
|
||||
}
|
||||
}
|
||||
|
||||
public void ActivateItemInHand(string handIndex)
|
||||
{
|
||||
if (GetEntity(handIndex) == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendNetworkMessage(new ActivateInHandMsg(handIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public class Hand
|
||||
{
|
||||
// TODO: Separate into server hand and client hand
|
||||
public Hand(SharedHand hand, IEntityManager manager, HandButton? button = null)
|
||||
{
|
||||
Index = hand.Index;
|
||||
Name = hand.Name;
|
||||
Location = hand.Location;
|
||||
Button = button;
|
||||
|
||||
if (!hand.EntityUid.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
manager.TryGetEntity(hand.EntityUid.Value, out var entity);
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
public int Index { get; }
|
||||
public string Name { get; }
|
||||
public HandLocation Location { get; set; }
|
||||
public IEntity? Entity { get; set; }
|
||||
public HandButton? Button { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user