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:
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects;
|
||||
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.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IHandsComponent))]
|
||||
public class HandsComponent : SharedHandsComponent, IHandsComponent
|
||||
{
|
||||
private HandsGui _gui;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud;
|
||||
#pragma warning restore 649
|
||||
|
||||
[ViewVariables] private readonly Dictionary<string, IEntity> _hands = new Dictionary<string, IEntity>();
|
||||
|
||||
[ViewVariables] public string ActiveIndex { get; private set; }
|
||||
|
||||
[ViewVariables] private ISpriteComponent _sprite;
|
||||
|
||||
[ViewVariables] public IEntity ActiveHand => GetEntity(ActiveIndex);
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
_gui?.Dispose();
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
if (Owner.TryGetComponent(out _sprite))
|
||||
{
|
||||
foreach (var slot in _hands.Keys)
|
||||
{
|
||||
_sprite.LayerMapReserveBlank($"hand-{slot}");
|
||||
_setHand(slot, _hands[slot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEntity GetEntity(string index)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(index) && _hands.TryGetValue(index, out var entity))
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
if (curState == null)
|
||||
return;
|
||||
|
||||
var cast = (HandsComponentState) curState;
|
||||
foreach (var (slot, uid) in cast.Hands)
|
||||
{
|
||||
IEntity entity = null;
|
||||
try
|
||||
{
|
||||
entity = Owner.EntityManager.GetEntity(uid);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
_hands[slot] = entity;
|
||||
_setHand(slot, entity);
|
||||
}
|
||||
|
||||
foreach (var slot in _hands.Keys.ToList())
|
||||
{
|
||||
if (!cast.Hands.ContainsKey(slot))
|
||||
{
|
||||
_hands[slot] = null;
|
||||
_setHand(slot, null);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveIndex = cast.ActiveIndex;
|
||||
|
||||
_gui?.UpdateHandIcons();
|
||||
RefreshInHands();
|
||||
}
|
||||
|
||||
private void _setHand(string hand, IEntity entity)
|
||||
{
|
||||
if (_sprite == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
_sprite.LayerSetVisible($"hand-{hand}", false);
|
||||
return;
|
||||
}
|
||||
|
||||
SetInHands(hand, entity);
|
||||
}
|
||||
|
||||
private void SetInHands(string hand, IEntity entity)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
_sprite.LayerSetVisible($"hand-{hand}", false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entity.TryGetComponent(out ItemComponent item)) return;
|
||||
var maybeInhands = item.GetInHandStateInfo(hand);
|
||||
if (!maybeInhands.HasValue)
|
||||
{
|
||||
_sprite.LayerSetVisible($"hand-{hand}", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var (rsi, state) = maybeInhands.Value;
|
||||
_sprite.LayerSetVisible($"hand-{hand}", true);
|
||||
_sprite.LayerSetState($"hand-{hand}", state, rsi);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshInHands()
|
||||
{
|
||||
if (!Initialized) return;
|
||||
|
||||
foreach (var (hand, entity) in _hands)
|
||||
{
|
||||
SetInHands(hand, entity);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataReadWriteFunction(
|
||||
"hands",
|
||||
new List<string>(),
|
||||
hands => hands.ForEach(slot => _hands.Add(slot, null)),
|
||||
() => _hands.Keys.ToList());
|
||||
|
||||
serializer.DataField(this, x => ActiveIndex, "defaultHand", _hands.Keys.LastOrDefault());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
namespace Content.Client.GameObjects.Components.Items
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IItemComponent))]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using Content.Client.Interfaces.GameObjects.Components.Interaction;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
@@ -137,7 +137,7 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
{
|
||||
var controlledEntity = IoCManager.Resolve<IPlayerManager>().LocalPlayer.ControlledEntity;
|
||||
|
||||
if (controlledEntity.TryGetComponent(out IHandsComponent hands))
|
||||
if (controlledEntity.TryGetComponent(out HandsComponent hands))
|
||||
{
|
||||
StorageEntity.SendNetworkMessage(new InsertEntityMessage());
|
||||
}
|
||||
@@ -250,7 +250,7 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
{
|
||||
var controlledEntity = IoCManager.Resolve<IPlayerManager>().LocalPlayer.ControlledEntity;
|
||||
|
||||
if (controlledEntity.TryGetComponent(out IHandsComponent hands))
|
||||
if (controlledEntity.TryGetComponent(out HandsComponent hands))
|
||||
{
|
||||
StorageEntity.SendNetworkMessage(new InsertEntityMessage());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Client.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
@@ -11,7 +11,6 @@ using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -58,7 +57,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
var entity = _playerManager.LocalPlayer.ControlledEntity;
|
||||
if (entity == null || !entity.TryGetComponent(out IHandsComponent hands))
|
||||
if (entity == null || !entity.TryGetComponent(out HandsComponent hands))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.Interfaces.GameObjects
|
||||
{
|
||||
// HYPER SIMPLE HANDS API CLIENT SIDE.
|
||||
// To allow for showing the HUD, mostly.
|
||||
public interface IHandsComponent
|
||||
{
|
||||
IEntity GetEntity(string index);
|
||||
string ActiveIndex { get; }
|
||||
IEntity ActiveHand { get; }
|
||||
|
||||
void SendChangeHand(string index);
|
||||
void AttackByInHand(string index);
|
||||
void UseActiveHand();
|
||||
void ActivateItemInHand(string handIndex);
|
||||
void RefreshInHands();
|
||||
}
|
||||
}
|
||||
15
Content.Client/UserInterface/HandButton.cs
Normal file
15
Content.Client/UserInterface/HandButton.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
public class HandButton : ItemSlotButton
|
||||
{
|
||||
public HandButton(Texture texture, Texture storageTexture, HandLocation location) : base(texture, storageTexture)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public HandLocation Location { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
using Content.Client.GameObjects;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -16,67 +17,140 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
public class HandsGui : Control
|
||||
{
|
||||
private const string HandNameLeft = "left";
|
||||
private const string HandNameRight = "right";
|
||||
|
||||
#pragma warning disable 0649
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager;
|
||||
#pragma warning restore 0649
|
||||
|
||||
private IEntity _leftHand;
|
||||
private IEntity _rightHand;
|
||||
private readonly TextureRect _activeHandRect;
|
||||
|
||||
private readonly TextureRect ActiveHandRect;
|
||||
private readonly Texture _leftHandTexture;
|
||||
private readonly Texture _middleHandTexture;
|
||||
private readonly Texture _rightHandTexture;
|
||||
|
||||
private readonly ItemSlotButton _leftButton;
|
||||
private readonly ItemSlotButton _rightButton;
|
||||
private readonly ItemStatusPanel _leftPanel;
|
||||
private readonly ItemStatusPanel _topPanel;
|
||||
private readonly ItemStatusPanel _rightPanel;
|
||||
|
||||
private readonly ItemStatusPanel _rightStatusPanel;
|
||||
private readonly ItemStatusPanel _leftStatusPanel;
|
||||
private readonly HBoxContainer _guiContainer;
|
||||
private readonly VBoxContainer _handsColumn;
|
||||
private readonly HBoxContainer _handsContainer;
|
||||
|
||||
private int _lastHands;
|
||||
|
||||
public HandsGui()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
var textureHandLeft = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
|
||||
var textureHandRight = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_r.png");
|
||||
var textureHandActive = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_active.png");
|
||||
var storageTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/back.png");
|
||||
|
||||
_rightStatusPanel = new ItemStatusPanel(true);
|
||||
_leftStatusPanel = new ItemStatusPanel(false);
|
||||
|
||||
_leftButton = new ItemSlotButton(textureHandLeft, storageTexture);
|
||||
_rightButton = new ItemSlotButton(textureHandRight, storageTexture);
|
||||
var hBox = new HBoxContainer
|
||||
AddChild(_guiContainer = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 0,
|
||||
Children = {_rightStatusPanel, _rightButton, _leftButton, _leftStatusPanel}
|
||||
};
|
||||
Children =
|
||||
{
|
||||
(_rightPanel = ItemStatusPanel.FromSide(HandLocation.Right)),
|
||||
(_handsColumn = new VBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(_topPanel = ItemStatusPanel.FromSide(HandLocation.Middle)),
|
||||
(_handsContainer = new HBoxContainer {SeparationOverride = 0})
|
||||
}
|
||||
}),
|
||||
(_leftPanel = ItemStatusPanel.FromSide(HandLocation.Left))
|
||||
}
|
||||
});
|
||||
|
||||
AddChild(hBox);
|
||||
|
||||
_leftButton.OnPressed += args => HandKeyBindDown(args, HandNameLeft);
|
||||
_leftButton.OnStoragePressed += args => _OnStoragePressed(args, HandNameLeft);
|
||||
_rightButton.OnPressed += args => HandKeyBindDown(args, HandNameRight);
|
||||
_rightButton.OnStoragePressed += args => _OnStoragePressed(args, HandNameRight);
|
||||
var textureHandActive = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_active.png");
|
||||
|
||||
// Active hand
|
||||
_leftButton.AddChild(ActiveHandRect = new TextureRect
|
||||
_activeHandRect = new TextureRect
|
||||
{
|
||||
Texture = textureHandActive,
|
||||
TextureScale = (2, 2)
|
||||
});
|
||||
};
|
||||
|
||||
_leftHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
|
||||
_middleHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_middle.png");
|
||||
_rightHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_r.png");
|
||||
}
|
||||
|
||||
private ItemStatusPanel GetItemPanel(Hand hand)
|
||||
{
|
||||
return hand.Location switch
|
||||
{
|
||||
HandLocation.Left => _rightPanel,
|
||||
HandLocation.Middle => _topPanel,
|
||||
HandLocation.Right => _leftPanel,
|
||||
_ => throw new IndexOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
private Texture HandTexture(HandLocation location)
|
||||
{
|
||||
switch (location)
|
||||
{
|
||||
case HandLocation.Left:
|
||||
return _leftHandTexture;
|
||||
case HandLocation.Middle:
|
||||
return _middleHandTexture;
|
||||
case HandLocation.Right:
|
||||
return _rightHandTexture;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(location), location, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hands component controling this gui, returns true if successful and false if failure
|
||||
/// Adds a new hand to this control
|
||||
/// </summary>
|
||||
/// <param name="hand">The hand to add to this control</param>
|
||||
/// <param name="buttonLocation">
|
||||
/// The actual location of the button. The right hand is drawn
|
||||
/// on the LEFT of the screen.
|
||||
/// </param>
|
||||
private void AddHand(Hand hand, HandLocation buttonLocation)
|
||||
{
|
||||
var buttonTexture = HandTexture(buttonLocation);
|
||||
var storageTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/back.png");
|
||||
var button = new HandButton(buttonTexture, storageTexture, buttonLocation);
|
||||
var slot = hand.Name;
|
||||
|
||||
button.OnPressed += args => HandKeyBindDown(args, slot);
|
||||
button.OnStoragePressed += args => _OnStoragePressed(args, slot);
|
||||
|
||||
_handsContainer.AddChild(button);
|
||||
|
||||
if (_activeHandRect.Parent == null)
|
||||
{
|
||||
button.AddChild(_activeHandRect);
|
||||
_activeHandRect.SetPositionInParent(1);
|
||||
}
|
||||
|
||||
hand.Button = button;
|
||||
}
|
||||
|
||||
public void RemoveHand(Hand hand)
|
||||
{
|
||||
var button = hand.Button;
|
||||
|
||||
if (button != null)
|
||||
{
|
||||
if (button.Children.Contains(_activeHandRect))
|
||||
{
|
||||
button.RemoveChild(_activeHandRect);
|
||||
}
|
||||
|
||||
_handsContainer.RemoveChild(button);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hands component controlling this gui
|
||||
/// </summary>
|
||||
/// <param name="hands"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryGetHands(out IHandsComponent hands)
|
||||
/// <returns>true if successful and false if failure</returns>
|
||||
private bool TryGetHands(out HandsComponent hands)
|
||||
{
|
||||
hands = default;
|
||||
|
||||
@@ -93,50 +167,63 @@ namespace Content.Client.UserInterface
|
||||
|
||||
UpdateDraw();
|
||||
|
||||
if (!TryGetHands(out var hands))
|
||||
if (!TryGetHands(out var component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var left = hands.GetEntity(HandNameLeft);
|
||||
var right = hands.GetEntity(HandNameRight);
|
||||
// TODO: Remove button on remove hand
|
||||
|
||||
ActiveHandRect.Parent.RemoveChild(ActiveHandRect);
|
||||
var parent = hands.ActiveIndex == HandNameLeft ? _leftButton : _rightButton;
|
||||
parent.AddChild(ActiveHandRect);
|
||||
ActiveHandRect.SetPositionInParent(1);
|
||||
|
||||
if (left != _leftHand)
|
||||
var hands = component.Hands.OrderByDescending(x => x.Location).ToArray();
|
||||
for (var i = 0; i < hands.Length; i++)
|
||||
{
|
||||
_leftHand = left;
|
||||
_itemSlotManager.SetItemSlot(_leftButton, _leftHand);
|
||||
}
|
||||
var hand = hands[i];
|
||||
|
||||
if (right != _rightHand)
|
||||
if (hand.Button == null)
|
||||
{
|
||||
_rightHand = right;
|
||||
_itemSlotManager.SetItemSlot(_rightButton, _rightHand);
|
||||
}
|
||||
AddHand(hand, hand.Location);
|
||||
}
|
||||
|
||||
private void HandKeyBindDown(GUIBoundKeyEventArgs args, string handIndex)
|
||||
hand.Button!.Button.Texture = HandTexture(hand.Location);
|
||||
hand.Button!.SetPositionInParent(i);
|
||||
_itemSlotManager.SetItemSlot(hand.Button, hand.Entity);
|
||||
}
|
||||
|
||||
_activeHandRect.Parent?.RemoveChild(_activeHandRect);
|
||||
component.GetHand(component.ActiveIndex)?.Button?.AddChild(_activeHandRect);
|
||||
|
||||
if (hands.Length > 0)
|
||||
{
|
||||
_activeHandRect.SetPositionInParent(1);
|
||||
}
|
||||
|
||||
_leftPanel.SetPositionFirst();
|
||||
_rightPanel.SetPositionLast();
|
||||
}
|
||||
|
||||
private void HandKeyBindDown(GUIBoundKeyEventArgs args, string slotName)
|
||||
{
|
||||
if (!TryGetHands(out var hands))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Function == ContentKeyFunctions.MouseMiddle)
|
||||
{
|
||||
hands.SendChangeHand(handIndex);
|
||||
hands.SendChangeHand(slotName);
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = hands.GetEntity(handIndex);
|
||||
var entity = hands.GetEntity(slotName);
|
||||
if (entity == null)
|
||||
{
|
||||
if (args.Function == EngineKeyFunctions.UIClick && hands.ActiveIndex != handIndex)
|
||||
if (args.Function == EngineKeyFunctions.UIClick && hands.ActiveIndex != slotName)
|
||||
{
|
||||
hands.SendChangeHand(handIndex);
|
||||
hands.SendChangeHand(slotName);
|
||||
args.Handle();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -148,37 +235,131 @@ namespace Content.Client.UserInterface
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
if (hands.ActiveIndex == handIndex)
|
||||
if (hands.ActiveIndex == slotName)
|
||||
{
|
||||
hands.UseActiveHand();
|
||||
}
|
||||
else
|
||||
{
|
||||
hands.AttackByInHand(handIndex);
|
||||
hands.AttackByInHand(slotName);
|
||||
}
|
||||
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void _OnStoragePressed(GUIBoundKeyEventArgs args, string handIndex)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
if (!TryGetHands(out var hands))
|
||||
if (args.Function != EngineKeyFunctions.UIClick || !TryGetHands(out var hands))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hands.ActivateItemInHand(handIndex);
|
||||
}
|
||||
|
||||
private void UpdatePanels()
|
||||
{
|
||||
if (!TryGetHands(out var component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var hand in component.Hands)
|
||||
{
|
||||
_itemSlotManager.UpdateCooldown(hand.Button, hand.Entity);
|
||||
}
|
||||
|
||||
switch (component.Hands.Count)
|
||||
{
|
||||
case var n when n == 0 && _lastHands != 0:
|
||||
_guiContainer.Visible = false;
|
||||
|
||||
_topPanel.Update(null);
|
||||
_leftPanel.Update(null);
|
||||
_rightPanel.Update(null);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
if (_lastHands != 1)
|
||||
{
|
||||
_guiContainer.Visible = true;
|
||||
|
||||
_topPanel.Update(null);
|
||||
_topPanel.Visible = false;
|
||||
|
||||
_leftPanel.Update(null);
|
||||
_leftPanel.Visible = false;
|
||||
|
||||
_rightPanel.Visible = true;
|
||||
|
||||
if (!_guiContainer.Children.Contains(_rightPanel))
|
||||
{
|
||||
_rightPanel.AddChild(_rightPanel);
|
||||
_rightPanel.SetPositionFirst();
|
||||
}
|
||||
}
|
||||
|
||||
_rightPanel.Update(component.Hands[0].Entity);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
if (_lastHands != 2)
|
||||
{
|
||||
_guiContainer.Visible = true;
|
||||
_topPanel.Update(null);
|
||||
_topPanel.Visible = false;
|
||||
|
||||
_leftPanel.Visible = true;
|
||||
_rightPanel.Visible = true;
|
||||
|
||||
if (_handsColumn.Children.Contains(_topPanel))
|
||||
{
|
||||
_handsColumn.RemoveChild(_topPanel);
|
||||
}
|
||||
}
|
||||
|
||||
_leftPanel.Update(component.Hands[0].Entity);
|
||||
_rightPanel.Update(component.Hands[1].Entity);
|
||||
|
||||
// Order is left, right
|
||||
foreach (var hand in component.Hands)
|
||||
{
|
||||
var tooltip = GetItemPanel(hand);
|
||||
tooltip.Update(hand.Entity);
|
||||
}
|
||||
|
||||
break;
|
||||
case var n when n > 2:
|
||||
if (_lastHands <= 2)
|
||||
{
|
||||
_guiContainer.Visible = true;
|
||||
|
||||
_topPanel.Visible = true;
|
||||
_leftPanel.Visible = false;
|
||||
_rightPanel.Visible = false;
|
||||
|
||||
if (!_handsColumn.Children.Contains(_topPanel))
|
||||
{
|
||||
_handsColumn.AddChild(_topPanel);
|
||||
_topPanel.SetPositionFirst();
|
||||
}
|
||||
}
|
||||
|
||||
_topPanel.Update(component.ActiveHand);
|
||||
_leftPanel.Update(null);
|
||||
_rightPanel.Update(null);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_lastHands = component.Hands.Count;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
_itemSlotManager.UpdateCooldown(_leftButton, _leftHand);
|
||||
_itemSlotManager.UpdateCooldown(_rightButton, _rightHand);
|
||||
|
||||
_rightStatusPanel.Update(_rightHand);
|
||||
_leftStatusPanel.Update(_leftHand);
|
||||
UpdatePanels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
public sealed class ItemSlotButton : MarginContainer
|
||||
public class ItemSlotButton : MarginContainer
|
||||
{
|
||||
public TextureRect Button { get; }
|
||||
public SpriteView SpriteView { get; }
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -26,22 +30,17 @@ namespace Content.Client.UserInterface
|
||||
private readonly PanelContainer _panel;
|
||||
|
||||
[ViewVariables]
|
||||
private IEntity _entity;
|
||||
private IEntity? _entity;
|
||||
|
||||
public ItemStatusPanel(bool isRightHand)
|
||||
public ItemStatusPanel(Texture texture, StyleBox.Margin margin)
|
||||
{
|
||||
// isRightHand means on the LEFT of the screen.
|
||||
// Keep that in mind.
|
||||
var panel = new StyleBoxTexture
|
||||
{
|
||||
Texture = ResC.GetTexture(isRightHand
|
||||
? "/Textures/Interface/Nano/item_status_right.svg.96dpi.png"
|
||||
: "/Textures/Interface/Nano/item_status_left.svg.96dpi.png")
|
||||
Texture = texture
|
||||
};
|
||||
panel.SetContentMarginOverride(StyleBox.Margin.Vertical, 4);
|
||||
panel.SetContentMarginOverride(StyleBox.Margin.Horizontal, 6);
|
||||
panel.SetPatchMargin((isRightHand ? StyleBox.Margin.Left : StyleBox.Margin.Right) | StyleBox.Margin.Top,
|
||||
13);
|
||||
panel.SetPatchMargin(margin, 13);
|
||||
|
||||
AddChild(_panel = new PanelContainer
|
||||
{
|
||||
@@ -67,7 +66,42 @@ namespace Content.Client.UserInterface
|
||||
SizeFlagsVertical = SizeFlags.ShrinkEnd;
|
||||
}
|
||||
|
||||
public void Update(IEntity entity)
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="ItemStatusPanel"/>
|
||||
/// based on whether or not it is being created for the right
|
||||
/// or left hand.
|
||||
/// </summary>
|
||||
/// <param name="location">
|
||||
/// The location of the hand that this panel is for
|
||||
/// </param>
|
||||
/// <returns>the new <see cref="ItemStatusPanel"/> instance</returns>
|
||||
public static ItemStatusPanel FromSide(HandLocation location)
|
||||
{
|
||||
string texture;
|
||||
StyleBox.Margin margin;
|
||||
|
||||
switch (location)
|
||||
{
|
||||
case HandLocation.Left:
|
||||
texture = "/Textures/Interface/Nano/item_status_right.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Left | StyleBox.Margin.Top;
|
||||
break;
|
||||
case HandLocation.Middle:
|
||||
texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
break;
|
||||
case HandLocation.Right:
|
||||
texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(location), location, null);
|
||||
}
|
||||
|
||||
return new ItemStatusPanel(ResC.GetTexture(texture), margin);
|
||||
}
|
||||
|
||||
public void Update(IEntity? entity)
|
||||
{
|
||||
if (entity == null)
|
||||
{
|
||||
@@ -105,7 +139,7 @@ namespace Content.Client.UserInterface
|
||||
|
||||
ClearOldStatus();
|
||||
|
||||
foreach (var statusComponent in _entity.GetAllComponents<IItemStatus>())
|
||||
foreach (var statusComponent in _entity!.GetAllComponents<IItemStatus>())
|
||||
{
|
||||
var control = statusComponent.MakeControl();
|
||||
_statusContents.AddChild(control);
|
||||
@@ -114,9 +148,10 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Depending on if its a two-hand panel or not
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return Vector2.ComponentMax(base.CalculateMinimumSize(), (150, 00));
|
||||
return Vector2.ComponentMax(base.CalculateMinimumSize(), (150, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Weapon.Melee;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
@@ -21,7 +22,8 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
/// <returns></returns>
|
||||
public override Outcome Execute(float frameTime)
|
||||
{
|
||||
if (!_owner.TryGetComponent(out HandsComponent handsComponent) || handsComponent.FindHand(_entity) == null)
|
||||
if (!_owner.TryGetComponent(out HandsComponent handsComponent) ||
|
||||
!handsComponent.TryHand(_entity, out _))
|
||||
{
|
||||
return Outcome.Failed;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Server.AI.Operators.Inventory
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Server.AI.Operators.Inventory
|
||||
@@ -22,9 +23,9 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
// TODO: If in clothing then click on it
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetHand(hand)?.Owner == _entity)
|
||||
if (handsComponent.GetItem(hand)?.Owner == _entity)
|
||||
{
|
||||
handsComponent.ActiveIndex = hand;
|
||||
handsComponent.ActiveHand = hand;
|
||||
return Outcome.Success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Shared.Containers;
|
||||
@@ -41,11 +41,11 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetHand(hand) == null)
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
if (handsComponent.ActiveIndex != hand)
|
||||
if (handsComponent.ActiveHand != hand)
|
||||
{
|
||||
handsComponent.ActiveIndex = hand;
|
||||
handsComponent.ActiveHand = hand;
|
||||
}
|
||||
|
||||
emptyHands = true;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Server.AI.Operators.Inventory
|
||||
@@ -38,8 +38,8 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
|
||||
foreach (var slot in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetHand(slot) != itemComponent) continue;
|
||||
handsComponent.ActiveIndex = slot;
|
||||
if (handsComponent.GetItem(slot) != itemComponent) continue;
|
||||
handsComponent.ActiveHand = slot;
|
||||
handsComponent.ActivateItem();
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
|
||||
namespace Content.Server.AI.Utility.Considerations.Hands
|
||||
{
|
||||
@@ -21,7 +22,7 @@ namespace Content.Server.AI.Utility.Considerations.Hands
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
handCount++;
|
||||
if (handsComponent.GetHand(hand) == null)
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
freeCount += 1;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.AI.WorldState;
|
||||
using Content.Server.AI.WorldState.States;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
|
||||
namespace Content.Server.AI.Utility.Considerations.Hands
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Hands
|
||||
@@ -16,7 +17,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetHand(hand) == null)
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.AI.WorldState.States.Hands
|
||||
@@ -20,7 +21,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
if (handsComponent.GetHand(hand) == null)
|
||||
if (handsComponent.GetItem(hand) == null)
|
||||
{
|
||||
result.Add(hand);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace Content.Server.AI.WorldState.States.Hands
|
||||
|
||||
foreach (var hand in handsComponent.ActivePriorityEnumerable())
|
||||
{
|
||||
var item = handsComponent.GetHand(hand);
|
||||
var item = handsComponent.GetItem(hand);
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using Content.Server.Interfaces.Chat;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Server.Console;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.Enums;
|
||||
@@ -13,6 +12,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
|
||||
namespace Content.Server.Chat
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.GameObjects.Components.Access;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
@@ -132,7 +132,7 @@ namespace Content.Server.GameObjects.Components.Access
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!hands.Drop(hands.ActiveIndex, container))
|
||||
if(!hands.Drop(hands.ActiveHand, container))
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, user, _localizationManager.GetString("You can't let go of the ID card!"));
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Strap;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
@@ -19,6 +20,7 @@ using Robust.Shared.ViewVariables;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
@@ -21,6 +21,7 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Doors;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Shared.BodySystem;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Server.GameObjects.EntitySystemMessages;
|
||||
@@ -18,72 +21,67 @@ using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
namespace Content.Server.GameObjects.Components.GUI
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IHandsComponent))]
|
||||
public class HandsComponent : SharedHandsComponent, IHandsComponent
|
||||
public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
#pragma warning restore 649
|
||||
|
||||
private string _activeIndex;
|
||||
private string? _activeHand;
|
||||
private uint _nextHand;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string ActiveIndex
|
||||
public string? ActiveHand
|
||||
{
|
||||
get => _activeIndex;
|
||||
get => _activeHand;
|
||||
set
|
||||
{
|
||||
if (!_hands.ContainsKey(value))
|
||||
if (value != null && GetHand(value) == null)
|
||||
{
|
||||
throw new ArgumentException($"No hand '{value}'");
|
||||
}
|
||||
|
||||
_activeIndex = value;
|
||||
_activeHand = value;
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables] private readonly Dictionary<string, ContainerSlot> _hands = new Dictionary<string, ContainerSlot>();
|
||||
[ViewVariables] private List<string> _orderedHands = new List<string>();
|
||||
[ViewVariables] private readonly List<Hand> _hands = new List<Hand>();
|
||||
|
||||
// Mostly arbitrary.
|
||||
public const float PickupRange = 2;
|
||||
|
||||
[ViewVariables] public int Count => _orderedHands.Count;
|
||||
[ViewVariables] public int Count => _hands.Count;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
// TODO: This does not serialize what objects are held.
|
||||
protected override void Startup()
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataReadWriteFunction("hands",
|
||||
new List<string>(0),
|
||||
hands => hands.ForEach(AddHand),
|
||||
() => _orderedHands);
|
||||
serializer.DataField(ref _activeIndex, "defaultHand", _orderedHands.LastOrDefault());
|
||||
base.Startup();
|
||||
ActiveHand = _hands.LastOrDefault()?.Name;
|
||||
}
|
||||
|
||||
public IEnumerable<ItemComponent> GetAllHeldItems()
|
||||
{
|
||||
foreach (var slot in _hands.Values)
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
if (slot.ContainedEntity != null)
|
||||
if (hand.Entity != null)
|
||||
{
|
||||
yield return slot.ContainedEntity.GetComponent<ItemComponent>();
|
||||
yield return hand.Entity.GetComponent<ItemComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHolding(IEntity entity)
|
||||
{
|
||||
foreach (var slot in _hands.Values)
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
if (slot.ContainedEntity == entity)
|
||||
if (hand.Entity == entity)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -91,28 +89,38 @@ namespace Content.Server.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
public ItemComponent GetHand(string index)
|
||||
private Hand? GetHand(string name)
|
||||
{
|
||||
var slot = _hands[index];
|
||||
return slot.ContainedEntity?.GetComponent<ItemComponent>();
|
||||
return _hands.FirstOrDefault(hand => hand.Name == name);
|
||||
}
|
||||
|
||||
public ItemComponent GetActiveHand => GetHand(ActiveIndex);
|
||||
public ItemComponent? GetItem(string handName)
|
||||
{
|
||||
return GetHand(handName)?.Entity?.GetComponent<ItemComponent>();
|
||||
}
|
||||
|
||||
public ItemComponent? GetActiveHand => ActiveHand == null
|
||||
? null
|
||||
: GetItem(ActiveHand);
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over the hand keys, returning the active hand first.
|
||||
/// </summary>
|
||||
public IEnumerable<string> ActivePriorityEnumerable()
|
||||
{
|
||||
yield return ActiveIndex;
|
||||
foreach (var hand in _hands.Keys)
|
||||
if (ActiveHand != null)
|
||||
{
|
||||
if (hand == ActiveIndex)
|
||||
yield return ActiveHand;
|
||||
}
|
||||
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
if (hand.Name == ActiveHand)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return hand;
|
||||
yield return hand.Name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +128,7 @@ namespace Content.Server.GameObjects
|
||||
{
|
||||
foreach (var hand in ActivePriorityEnumerable())
|
||||
{
|
||||
if (PutInHand(item, hand, fallback: false))
|
||||
if (PutInHand(item, hand, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -131,14 +139,14 @@ namespace Content.Server.GameObjects
|
||||
|
||||
public bool PutInHand(ItemComponent item, string index, bool fallback = true)
|
||||
{
|
||||
if (!CanPutInHand(item, index))
|
||||
var hand = GetHand(index);
|
||||
if (!CanPutInHand(item, index) || hand == null)
|
||||
{
|
||||
return fallback && PutInHand(item);
|
||||
}
|
||||
|
||||
var slot = _hands[index];
|
||||
Dirty();
|
||||
var success = slot.Insert(item.Owner);
|
||||
var success = hand.Container.Insert(item.Owner);
|
||||
if (success)
|
||||
{
|
||||
item.Owner.Transform.LocalPosition = Vector2.Zero;
|
||||
@@ -152,14 +160,16 @@ namespace Content.Server.GameObjects
|
||||
public void PutInHandOrDrop(ItemComponent item)
|
||||
{
|
||||
if (!PutInHand(item))
|
||||
{
|
||||
item.Owner.Transform.GridPosition = Owner.Transform.GridPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanPutInHand(ItemComponent item)
|
||||
{
|
||||
foreach (var hand in ActivePriorityEnumerable())
|
||||
foreach (var handName in ActivePriorityEnumerable())
|
||||
{
|
||||
if (CanPutInHand(item, hand))
|
||||
if (CanPutInHand(item, handName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -170,43 +180,42 @@ namespace Content.Server.GameObjects
|
||||
|
||||
public bool CanPutInHand(ItemComponent item, string index)
|
||||
{
|
||||
var slot = _hands[index];
|
||||
return slot.CanInsert(item.Owner);
|
||||
return GetHand(index)?.Container.CanInsert(item.Owner) == true;
|
||||
}
|
||||
|
||||
public string FindHand(IEntity entity)
|
||||
public bool TryHand(IEntity entity, [MaybeNullWhen(false)] out string handName)
|
||||
{
|
||||
foreach (var (index, slot) in _hands)
|
||||
handName = null;
|
||||
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
if (slot.ContainedEntity == entity)
|
||||
if (hand.Entity == entity)
|
||||
{
|
||||
return index;
|
||||
handName = hand.Name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Drop(string slot, GridCoordinates coords, bool doMobChecks = true)
|
||||
{
|
||||
if (!CanDrop(slot))
|
||||
var hand = GetHand(slot);
|
||||
if (!CanDrop(slot) || hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var inventorySlot = _hands[slot];
|
||||
var item = inventorySlot.ContainedEntity.GetComponent<ItemComponent>();
|
||||
var item = hand.Entity.GetComponent<ItemComponent>();
|
||||
|
||||
if (!inventorySlot.Remove(inventorySlot.ContainedEntity))
|
||||
if (!hand.Container.Remove(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (doMobChecks && !_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(Owner, item.Owner))
|
||||
return false;
|
||||
|
||||
if (ContainerHelpers.TryGetContainer(Owner, out var container) &&
|
||||
!container.Insert(item.Owner))
|
||||
if (doMobChecks &&
|
||||
!_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(Owner, item.Owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -214,6 +223,11 @@ namespace Content.Server.GameObjects
|
||||
item.RemovedFromSlot();
|
||||
item.Owner.Transform.GridPosition = coords;
|
||||
|
||||
if (ContainerHelpers.TryGetContainer(Owner, out var container))
|
||||
{
|
||||
container.Insert(item.Owner);
|
||||
}
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
@@ -225,8 +239,7 @@ namespace Content.Server.GameObjects
|
||||
throw new ArgumentNullException(nameof(entity));
|
||||
}
|
||||
|
||||
var slot = FindHand(entity);
|
||||
if (slot == null)
|
||||
if (!TryHand(entity, out var slot))
|
||||
{
|
||||
throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity));
|
||||
}
|
||||
@@ -236,24 +249,21 @@ namespace Content.Server.GameObjects
|
||||
|
||||
public bool Drop(string slot, bool doMobChecks = true)
|
||||
{
|
||||
if (!CanDrop(slot))
|
||||
var hand = GetHand(slot);
|
||||
if (!CanDrop(slot) || hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var inventorySlot = _hands[slot];
|
||||
var item = inventorySlot.ContainedEntity.GetComponent<ItemComponent>();
|
||||
var item = hand.Entity.GetComponent<ItemComponent>();
|
||||
|
||||
if (doMobChecks && !_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(Owner, item.Owner))
|
||||
return false;
|
||||
|
||||
if (!inventorySlot.Remove(inventorySlot.ContainedEntity))
|
||||
if (doMobChecks &&
|
||||
!_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(Owner, item.Owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ContainerHelpers.TryGetContainer(Owner, out var container) &&
|
||||
!container.Insert(item.Owner))
|
||||
if (!hand.Container.Remove(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -266,6 +276,11 @@ namespace Content.Server.GameObjects
|
||||
spriteComponent.RenderOrder = item.Owner.EntityManager.CurrentTick.Value;
|
||||
}
|
||||
|
||||
if (ContainerHelpers.TryGetContainer(Owner, out var container))
|
||||
{
|
||||
container.Insert(item.Owner);
|
||||
}
|
||||
|
||||
Dirty();
|
||||
return true;
|
||||
}
|
||||
@@ -277,8 +292,7 @@ namespace Content.Server.GameObjects
|
||||
throw new ArgumentNullException(nameof(entity));
|
||||
}
|
||||
|
||||
var slot = FindHand(entity);
|
||||
if (slot == null)
|
||||
if (!TryHand(entity, out var slot))
|
||||
{
|
||||
throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity));
|
||||
}
|
||||
@@ -298,31 +312,30 @@ namespace Content.Server.GameObjects
|
||||
throw new ArgumentNullException(nameof(targetContainer));
|
||||
}
|
||||
|
||||
if (!CanDrop(slot))
|
||||
var hand = GetHand(slot);
|
||||
if (!CanDrop(slot) || hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var inventorySlot = _hands[slot];
|
||||
var item = inventorySlot.ContainedEntity.GetComponent<ItemComponent>();
|
||||
var item = hand.Entity.GetComponent<ItemComponent>();
|
||||
|
||||
if (doMobChecks && !_entitySystemManager.GetEntitySystem<InteractionSystem>().TryDroppedInteraction(Owner, item.Owner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!inventorySlot.CanRemove(inventorySlot.ContainedEntity))
|
||||
if (!hand.Container.CanRemove(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetContainer.CanInsert(inventorySlot.ContainedEntity))
|
||||
if (!targetContainer.CanInsert(hand.Entity))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!inventorySlot.Remove(inventorySlot.ContainedEntity))
|
||||
if (!hand.Container.Remove(hand.Entity))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
@@ -345,8 +358,7 @@ namespace Content.Server.GameObjects
|
||||
throw new ArgumentNullException(nameof(entity));
|
||||
}
|
||||
|
||||
var slot = FindHand(entity);
|
||||
if (slot == null)
|
||||
if (!TryHand(entity, out var slot))
|
||||
{
|
||||
throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity));
|
||||
}
|
||||
@@ -357,94 +369,103 @@ namespace Content.Server.GameObjects
|
||||
/// <summary>
|
||||
/// Checks whether an item can be dropped from the specified slot.
|
||||
/// </summary>
|
||||
/// <param name="slot">The slot to check for.</param>
|
||||
/// <param name="name">The slot to check for.</param>
|
||||
/// <returns>
|
||||
/// True if there is an item in the slot and it can be dropped, false otherwise.
|
||||
/// </returns>
|
||||
public bool CanDrop(string slot)
|
||||
public bool CanDrop(string name)
|
||||
{
|
||||
var inventorySlot = _hands[slot];
|
||||
|
||||
if (ContainerHelpers.TryGetContainer(Owner, out var container) &&
|
||||
!container.CanInsert(inventorySlot.ContainedEntity))
|
||||
var hand = GetHand(name);
|
||||
if (hand?.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return inventorySlot.CanRemove(inventorySlot.ContainedEntity);
|
||||
return hand.Container.CanRemove(hand.Entity);
|
||||
}
|
||||
|
||||
public void AddHand(string index)
|
||||
public void AddHand(string name)
|
||||
{
|
||||
if (HasHand(index))
|
||||
if (HasHand(name))
|
||||
{
|
||||
throw new InvalidOperationException($"Hand '{index}' already exists.");
|
||||
throw new InvalidOperationException($"Hand '{name}' already exists.");
|
||||
}
|
||||
|
||||
var slot = ContainerManagerComponent.Create<ContainerSlot>(Name + "_" + index, Owner);
|
||||
_hands[index] = slot;
|
||||
if (!_orderedHands.Contains(index))
|
||||
{
|
||||
_orderedHands.Add(index);
|
||||
}
|
||||
var container = ContainerManagerComponent.Create<ContainerSlot>($"hand {_nextHand++}", Owner);
|
||||
var hand = new Hand(name, container);
|
||||
|
||||
_hands.Add(hand);
|
||||
|
||||
ActiveHand ??= name;
|
||||
|
||||
ActiveIndex ??= index;
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public void RemoveHand(string index)
|
||||
public void RemoveHand(string name)
|
||||
{
|
||||
if (!HasHand(index))
|
||||
var hand = GetHand(name);
|
||||
if (hand == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Hand '{index}' does not exist.");
|
||||
throw new InvalidOperationException($"Hand '{name}' does not exist.");
|
||||
}
|
||||
|
||||
_hands[index].Shutdown(); //TODO verify this
|
||||
_hands.Remove(index);
|
||||
_orderedHands.Remove(index);
|
||||
Drop(hand.Name, false);
|
||||
hand!.Dispose();
|
||||
_hands.Remove(hand);
|
||||
|
||||
if (index == ActiveIndex)
|
||||
if (name == ActiveHand)
|
||||
{
|
||||
_activeIndex = _orderedHands.Count == 0 ? null : _orderedHands[0];
|
||||
_activeHand = _hands.FirstOrDefault()?.Name;
|
||||
}
|
||||
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public bool HasHand(string index)
|
||||
public bool HasHand(string name)
|
||||
{
|
||||
return _hands.ContainsKey(index);
|
||||
return _hands.Any(hand => hand.Name == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of the slot passed to the inventory component.
|
||||
/// </summary>
|
||||
private string HandSlotName(string index) => $"_hand_{index}";
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
var dict = new Dictionary<string, EntityUid>(_hands.Count);
|
||||
foreach (var hand in _hands)
|
||||
var hands = new SharedHand[_hands.Count];
|
||||
|
||||
for (var i = 0; i < _hands.Count; i++)
|
||||
{
|
||||
if (hand.Value.ContainedEntity != null)
|
||||
{
|
||||
dict[hand.Key] = hand.Value.ContainedEntity.Uid;
|
||||
}
|
||||
var location = i == 0
|
||||
? HandLocation.Right
|
||||
: i == _hands.Count - 1
|
||||
? HandLocation.Left
|
||||
: HandLocation.Middle;
|
||||
|
||||
var hand = _hands[i].ToShared(i, location);
|
||||
hands[i] = hand;
|
||||
}
|
||||
|
||||
return new HandsComponentState(dict, ActiveIndex);
|
||||
return new HandsComponentState(hands, ActiveHand);
|
||||
}
|
||||
|
||||
public void SwapHands()
|
||||
{
|
||||
var index = _orderedHands.FindIndex(x => x == ActiveIndex);
|
||||
if (ActiveHand == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hand = GetHand(ActiveHand);
|
||||
if (hand == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No hand found with name {ActiveHand}");
|
||||
}
|
||||
|
||||
var index = _hands.IndexOf(hand);
|
||||
index++;
|
||||
if (index >= _orderedHands.Count)
|
||||
if (index == _hands.Count)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
ActiveIndex = _orderedHands[index];
|
||||
ActiveHand = _hands[index].Name;
|
||||
}
|
||||
|
||||
public void ActivateItem()
|
||||
@@ -469,7 +490,7 @@ namespace Content.Server.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, channel, session);
|
||||
|
||||
@@ -485,15 +506,19 @@ namespace Content.Server.GameObjects
|
||||
var playerEntity = session.AttachedEntity;
|
||||
|
||||
if (playerEntity == Owner && HasHand(msg.Index))
|
||||
ActiveIndex = msg.Index;
|
||||
{
|
||||
ActiveHand = msg.Index;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ClientAttackByInHandMsg msg:
|
||||
{
|
||||
if (!_hands.TryGetValue(msg.Index, out var slot))
|
||||
var hand = GetHand(msg.Index);
|
||||
if (hand == null)
|
||||
{
|
||||
Logger.WarningS("go.comp.hands", "Got a ClientAttackByInHandMsg with invalid hand index '{0}'",
|
||||
Logger.WarningS("go.comp.hands", "Got a ClientAttackByInHandMsg with invalid hand name '{0}'",
|
||||
msg.Index);
|
||||
return;
|
||||
}
|
||||
@@ -501,19 +526,22 @@ namespace Content.Server.GameObjects
|
||||
var playerEntity = session.AttachedEntity;
|
||||
var used = GetActiveHand?.Owner;
|
||||
|
||||
if (playerEntity == Owner && slot.ContainedEntity != null)
|
||||
if (playerEntity == Owner && hand.Entity != null)
|
||||
{
|
||||
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
||||
if (used != null)
|
||||
{
|
||||
interactionSystem.Interaction(Owner, used, slot.ContainedEntity,
|
||||
interactionSystem.Interaction(Owner, used, hand.Entity,
|
||||
GridCoordinates.InvalidGrid);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entity = slot.ContainedEntity;
|
||||
var entity = hand.Entity;
|
||||
if (!Drop(entity))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
interactionSystem.Interaction(Owner, entity);
|
||||
}
|
||||
}
|
||||
@@ -521,7 +549,7 @@ namespace Content.Server.GameObjects
|
||||
break;
|
||||
}
|
||||
|
||||
case UseInHandMsg msg:
|
||||
case UseInHandMsg _:
|
||||
{
|
||||
var playerEntity = session.AttachedEntity;
|
||||
var used = GetActiveHand?.Owner;
|
||||
@@ -538,7 +566,7 @@ namespace Content.Server.GameObjects
|
||||
case ActivateInHandMsg msg:
|
||||
{
|
||||
var playerEntity = session.AttachedEntity;
|
||||
var used = GetHand(msg.Index)?.Owner;
|
||||
var used = GetItem(msg.Index)?.Owner;
|
||||
|
||||
if (playerEntity == Owner && used != null)
|
||||
{
|
||||
@@ -552,9 +580,9 @@ namespace Content.Server.GameObjects
|
||||
|
||||
public void HandleSlotModifiedMaybe(ContainerModifiedMessage message)
|
||||
{
|
||||
foreach (var container in _hands.Values)
|
||||
foreach (var hand in _hands)
|
||||
{
|
||||
if (container != message.Container)
|
||||
if (hand.Container != message.Container)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -571,5 +599,48 @@ namespace Content.Server.GameObjects
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void IBodyPartAdded.BodyPartAdded(BodyPartAddedEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.Part.PartType != BodyPartType.Hand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddHand(eventArgs.SlotName);
|
||||
}
|
||||
|
||||
void IBodyPartRemoved.BodyPartRemoved(BodyPartRemovedEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.Part.PartType != BodyPartType.Hand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveHand(eventArgs.SlotName);
|
||||
}
|
||||
}
|
||||
|
||||
public class Hand : IDisposable
|
||||
{
|
||||
public Hand(string name, ContainerSlot container)
|
||||
{
|
||||
Name = name;
|
||||
Container = container;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public IEntity? Entity => Container.ContainedEntity;
|
||||
public ContainerSlot Container { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Container.Shutdown(); // TODO verify this
|
||||
}
|
||||
|
||||
public SharedHand ToShared(int index, HandLocation location)
|
||||
{
|
||||
return new SharedHand(index, Name, Entity?.Uid, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
@@ -326,7 +327,7 @@ namespace Content.Server.GameObjects
|
||||
var activeHand = hands.GetActiveHand;
|
||||
if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing))
|
||||
{
|
||||
hands.Drop(hands.ActiveIndex);
|
||||
hands.Drop(hands.ActiveHand);
|
||||
if (!Equip(msg.Inventoryslot, clothing, out var reason))
|
||||
{
|
||||
hands.PutInHand(clothing);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
@@ -16,7 +18,6 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Interactable
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Throw;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
@@ -100,7 +102,7 @@ namespace Content.Server.GameObjects.Components
|
||||
if (!CanPickup(eventArgs.User)) return false;
|
||||
|
||||
var hands = eventArgs.User.GetComponent<IHandsComponent>();
|
||||
hands.PutInHand(this, hands.ActiveIndex, fallback: false);
|
||||
hands.PutInHand(this, hands.ActiveHand, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.BodySystem;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -22,10 +24,10 @@ using Content.Server.Interfaces;
|
||||
using Robust.Shared.Audio;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.Chat;
|
||||
using Content.Server.BodySystem;
|
||||
using Content.Shared.BodySystem;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Kitchen
|
||||
@@ -211,7 +213,13 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
||||
return false;
|
||||
}
|
||||
|
||||
var itemEntity = eventArgs.User.GetComponent<HandsComponent>().GetActiveHand.Owner;
|
||||
var itemEntity = eventArgs.User.GetComponent<HandsComponent>().GetActiveHand?.Owner;
|
||||
|
||||
if (itemEntity == null)
|
||||
{
|
||||
eventArgs.User.PopupMessage(eventArgs.User, Loc.GetString("You have no active hand!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (itemEntity.TryGetComponent<PourableComponent>(out var attackPourable))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Utensil;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -54,8 +55,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
|
||||
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.User.TryGetComponent(out HandsComponent handsComponent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var hands = eventArgs.User.TryGetComponent(out HandsComponent handsComponent);
|
||||
var itemToSpawn = _entityManager.SpawnEntity(GetRandomPrototype(), Owner.Transform.GridPosition);
|
||||
handsComponent.PutInHandOrDrop(itemToSpawn.GetComponent<ItemComponent>());
|
||||
_count--;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.PDA;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -17,6 +18,7 @@ namespace Content.Server.GameObjects.Components
|
||||
|
||||
serializer.DataField(ref _isPlaceable, "IsPlaceable", true);
|
||||
}
|
||||
|
||||
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
||||
{
|
||||
if (!IsPlaceable)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.Interfaces;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels;
|
||||
using Content.Shared.Interfaces;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.Components.Projectiles;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Shared.GameObjects;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Server.GameObjects.EntitySystems.Click;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Timing;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.Construction;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems.Click;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Throw;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.Input;
|
||||
@@ -15,6 +16,8 @@ using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Players;
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
@@ -74,11 +77,10 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
|
||||
var ent = session.AttachedEntity;
|
||||
|
||||
if (ent == null || !ent.IsValid())
|
||||
return false;
|
||||
|
||||
if (!ent.TryGetComponent(out T comp))
|
||||
if (ent == null || !ent.IsValid() || !ent.TryGetComponent(out T comp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
component = comp;
|
||||
return true;
|
||||
@@ -87,9 +89,11 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
private static void HandleSwapHands(ICommonSession session)
|
||||
{
|
||||
if (!TryGetAttachedComponent(session as IPlayerSession, out HandsComponent handsComp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var interactionSystem = EntitySystem.Get<InteractionSystem>();
|
||||
var interactionSystem = Get<InteractionSystem>();
|
||||
|
||||
var oldItem = handsComp.GetActiveHand;
|
||||
|
||||
@@ -98,11 +102,15 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
var newItem = handsComp.GetActiveHand;
|
||||
|
||||
if (oldItem != null)
|
||||
{
|
||||
interactionSystem.HandDeselectedInteraction(handsComp.Owner, oldItem.Owner);
|
||||
}
|
||||
|
||||
if (newItem != null)
|
||||
{
|
||||
interactionSystem.HandSelectedInteraction(handsComp.Owner, newItem.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleDrop(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||
{
|
||||
@@ -119,11 +127,11 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
|
||||
var entCoords = ent.Transform.GridPosition.Position;
|
||||
var entToDesiredDropCoords = coords.Position - entCoords;
|
||||
var targetLength = Math.Min(entToDesiredDropCoords.Length, InteractionSystem.InteractionRange - 0.001f); // InteractionRange is reduced due to InRange not dealing with floating point error
|
||||
var targetLength = Math.Min(entToDesiredDropCoords.Length, SharedInteractionSystem.InteractionRange - 0.001f); // InteractionRange is reduced due to InRange not dealing with floating point error
|
||||
var newCoords = new GridCoordinates((entToDesiredDropCoords.Normalized * targetLength) + entCoords, coords.GridID);
|
||||
var rayLength = EntitySystem.Get<SharedInteractionSystem>().UnobstructedRayLength(ent.Transform.MapPosition, newCoords.ToMap(_mapManager), ignoredEnt: ent);
|
||||
var rayLength = Get<SharedInteractionSystem>().UnobstructedRayLength(ent.Transform.MapPosition, newCoords.ToMap(_mapManager), ignoredEnt: ent);
|
||||
|
||||
handsComp.Drop(handsComp.ActiveIndex, new GridCoordinates(entCoords + (entToDesiredDropCoords.Normalized * rayLength), coords.GridID));
|
||||
handsComp.Drop(handsComp.ActiveHand, new GridCoordinates(entCoords + (entToDesiredDropCoords.Normalized * rayLength), coords.GridID));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -146,10 +154,10 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
if (!plyEnt.TryGetComponent(out HandsComponent handsComp))
|
||||
return false;
|
||||
|
||||
if (!handsComp.CanDrop(handsComp.ActiveIndex))
|
||||
if (!handsComp.CanDrop(handsComp.ActiveHand))
|
||||
return false;
|
||||
|
||||
var throwEnt = handsComp.GetHand(handsComp.ActiveIndex).Owner;
|
||||
var throwEnt = handsComp.GetItem(handsComp.ActiveHand).Owner;
|
||||
|
||||
if (!handsComp.ThrowItem())
|
||||
return false;
|
||||
@@ -157,7 +165,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
// throw the item, split off from a stack if it's meant to be thrown individually
|
||||
if (!throwEnt.TryGetComponent(out StackComponent stackComp) || stackComp.Count < 2 || !stackComp.ThrowIndividually)
|
||||
{
|
||||
handsComp.Drop(handsComp.ActiveIndex);
|
||||
handsComp.Drop(handsComp.ActiveHand);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -201,7 +209,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
return;
|
||||
}
|
||||
|
||||
var heldItem = handsComp.GetHand(handsComp.ActiveIndex)?.Owner;
|
||||
var heldItem = handsComp.GetItem(handsComp.ActiveHand)?.Owner;
|
||||
|
||||
if (heldItem != null)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Markers;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Observer;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.BodySystem;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared.BodySystem;
|
||||
using Content.Shared.Jobs;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
@@ -321,4 +324,56 @@ namespace Content.Server.GameTicking
|
||||
shell.SendText(player, $"Created unloaded map from file {args[1]} with id {args[0]}. Use \"savebp 4 foo.yml\" to save it.");
|
||||
}
|
||||
}
|
||||
|
||||
class AddHandCommand : IClientCommand
|
||||
{
|
||||
public string Command => "addhand";
|
||||
public string Description => "Adds a hand to your entity.";
|
||||
public string Help => $"Usage: {Command}";
|
||||
|
||||
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
shell.SendText(player, "Only a player can run this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity == null)
|
||||
{
|
||||
shell.SendText(player, "You have no entity.");
|
||||
return;
|
||||
}
|
||||
|
||||
var manager = player.AttachedEntity.GetComponent<BodyManagerComponent>();
|
||||
var hand = manager.PartDictionary.First(x => x.Key == string.Join(" ", args));
|
||||
manager.InstallBodyPart(hand.Value, hand.Key + new Random());
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveHandCommand : IClientCommand
|
||||
{
|
||||
public string Command => "removehand";
|
||||
public string Description => "Removes a hand from your entity.";
|
||||
public string Help => $"Usage: {Command}";
|
||||
|
||||
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||
{
|
||||
if (player == null)
|
||||
{
|
||||
shell.SendText(player, "Only a player can run this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity == null)
|
||||
{
|
||||
shell.SendText(player, "You have no entity.");
|
||||
return;
|
||||
}
|
||||
|
||||
var manager = player.AttachedEntity.GetComponent<BodyManagerComponent>();
|
||||
var hand = manager.PartDictionary.First(x => x.Value.PartType == BodyPartType.Hand);
|
||||
manager.DisconnectBodyPart(hand.Value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.BodySystem;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using System.Linq;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Interaction;
|
||||
|
||||
namespace Content.Server.BodySystem {
|
||||
|
||||
@@ -178,8 +179,7 @@ namespace Content.Server.BodySystem {
|
||||
///////// Server-specific stuff
|
||||
/////////
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
public override void ExposeData(ObjectSerializer serializer) {
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataReadWriteFunction(
|
||||
@@ -225,8 +225,16 @@ namespace Content.Server.BodySystem {
|
||||
if (!_prototypeManager.TryIndex(partID, out BodyPartPrototype newPartData)) { //Get the BodyPartPrototype corresponding to the BodyPart ID we grabbed.
|
||||
throw new InvalidOperationException("BodyPart prototype with ID " + partID + " could not be found!");
|
||||
}
|
||||
_partDictionary.Remove(slotName); //Try and remove an existing limb if that exists.
|
||||
_partDictionary.Add(slotName, new BodyPart(newPartData)); //Add a new BodyPart with the BodyPartPrototype as a baseline to our BodyComponent.
|
||||
|
||||
//Try and remove an existing limb if that exists.
|
||||
if (_partDictionary.Remove(slotName, out var removedPart))
|
||||
{
|
||||
BodyPartRemoved(removedPart, slotName);
|
||||
}
|
||||
|
||||
var addedPart = new BodyPart(newPartData);
|
||||
_partDictionary.Add(slotName, addedPart); //Add a new BodyPart with the BodyPartPrototype as a baseline to our BodyComponent.
|
||||
BodyPartAdded(addedPart, slotName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +272,8 @@ namespace Content.Server.BodySystem {
|
||||
if (TryGetBodyPart(slotName, out BodyPart result)) //And that nothing is in it
|
||||
return false;
|
||||
_partDictionary.Add(slotName, part);
|
||||
BodyPartAdded(part, slotName);
|
||||
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
@@ -316,7 +326,11 @@ namespace Content.Server.BodySystem {
|
||||
return;
|
||||
if (part != null) {
|
||||
string slotName = _partDictionary.FirstOrDefault(x => x.Value == part).Key;
|
||||
_partDictionary.Remove(slotName);
|
||||
if (_partDictionary.Remove(slotName, out var partRemoved))
|
||||
{
|
||||
BodyPartRemoved(partRemoved, slotName);
|
||||
}
|
||||
|
||||
if (TryGetBodyPartConnections(slotName, out List<string> connections)) //Call disconnect on all limbs that were hanging off this limb.
|
||||
{
|
||||
foreach (string connectionName in connections) //This loop is an unoptimized travesty. TODO: optimize to be less shit
|
||||
@@ -340,7 +354,11 @@ namespace Content.Server.BodySystem {
|
||||
if (!TryGetBodyPart(name, out BodyPart part))
|
||||
return;
|
||||
if (part != null) {
|
||||
_partDictionary.Remove(name);
|
||||
if (_partDictionary.Remove(name, out var partRemoved))
|
||||
{
|
||||
BodyPartRemoved(partRemoved, name);
|
||||
}
|
||||
|
||||
if (TryGetBodyPartConnections(name, out List<string> connections)) {
|
||||
foreach (string connectionName in connections) {
|
||||
if (TryGetBodyPart(connectionName, out BodyPart result) && !ConnectedToCenterPart(result)) {
|
||||
@@ -355,5 +373,24 @@ namespace Content.Server.BodySystem {
|
||||
}
|
||||
}
|
||||
|
||||
private void BodyPartAdded(BodyPart part, string slotName)
|
||||
{
|
||||
var argsAdded = new BodyPartAddedEventArgs(part, slotName);
|
||||
|
||||
foreach (var component in Owner.GetAllComponents<IBodyPartAdded>().ToArray())
|
||||
{
|
||||
component.BodyPartAdded(argsAdded);
|
||||
}
|
||||
}
|
||||
|
||||
private void BodyPartRemoved(BodyPart part, string slotName)
|
||||
{
|
||||
var args = new BodyPartRemovedEventArgs(part, slotName);
|
||||
|
||||
foreach (var component in Owner.GetAllComponents<IBodyPartRemoved>())
|
||||
{
|
||||
component.BodyPartRemoved(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Content.Server.BodySystem;
|
||||
|
||||
namespace Content.Server.Interfaces.GameObjects.Components.Interaction
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when a body part
|
||||
/// is added to their owning entity.
|
||||
/// </summary>
|
||||
public interface IBodyPartAdded
|
||||
{
|
||||
void BodyPartAdded(BodyPartAddedEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class BodyPartAddedEventArgs : EventArgs
|
||||
{
|
||||
public BodyPartAddedEventArgs(BodyPart part, string slotName)
|
||||
{
|
||||
Part = part;
|
||||
SlotName = slotName;
|
||||
}
|
||||
|
||||
public BodyPart Part { get; }
|
||||
|
||||
public string SlotName { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when a body part
|
||||
/// is removed from their owning entity.
|
||||
/// </summary>
|
||||
public interface IBodyPartRemoved
|
||||
{
|
||||
void BodyPartRemoved(BodyPartRemovedEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class BodyPartRemovedEventArgs : EventArgs
|
||||
{
|
||||
public BodyPartRemovedEventArgs(BodyPart part, string slotName)
|
||||
{
|
||||
Part = part;
|
||||
SlotName = slotName;
|
||||
}
|
||||
|
||||
public BodyPart Part { get; }
|
||||
|
||||
public string SlotName { get; }
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,14 @@ using Robust.Server.GameObjects.EntitySystemMessages;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Interfaces.GameObjects
|
||||
namespace Content.Server.Interfaces.GameObjects.Components.Items
|
||||
{
|
||||
public interface IHandsComponent : IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// The hand index of the currently active hand.
|
||||
/// The hand name of the currently active hand.
|
||||
/// </summary>
|
||||
string ActiveIndex { get; set; }
|
||||
string ActiveHand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates over every held item.
|
||||
@@ -24,9 +24,9 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// <summary>
|
||||
/// Gets the item held by a hand.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the hand to get.</param>
|
||||
/// <param name="handName">The name of the hand to get.</param>
|
||||
/// <returns>The item in the held, null if no item is held</returns>
|
||||
ItemComponent GetHand(string index);
|
||||
ItemComponent GetItem(string handName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets item held by the current active hand
|
||||
@@ -44,7 +44,7 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// Puts an item into a specific hand.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to put in the hand.</param>
|
||||
/// <param name="index">The index of the hand to put the item into.</param>
|
||||
/// <param name="index">The name of the hand to put the item into.</param>
|
||||
/// <param name="fallback">
|
||||
/// If true and the provided hand is full, the method will fall back to <see cref="PutInHand(ItemComponent)" />
|
||||
/// </param>
|
||||
@@ -62,20 +62,22 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// Checks to see if an item can be put in the specified hand.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to check for.</param>
|
||||
/// <param name="index">The index for the hand to check for.</param>
|
||||
/// <param name="index">The name for the hand to check for.</param>
|
||||
/// <returns>True if the item can be inserted, false otherwise.</returns>
|
||||
bool CanPutInHand(ItemComponent item, string index);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the hand slot holding the specified entity, if any.
|
||||
/// </summary>
|
||||
/// <param name="entity">
|
||||
/// The entity to look for in our hands.
|
||||
/// <param name="entity">The entity to look for in our hands.</param>
|
||||
/// <param name="handName">
|
||||
/// The name of the hand slot if the entity is indeed held,
|
||||
/// <see langword="null" /> otherwise.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The index of the hand slot if the entity is indeed held, <see langword="null" /> otherwise.
|
||||
/// true if the entity is held, false otherwise
|
||||
/// </returns>
|
||||
string FindHand(IEntity entity);
|
||||
bool TryHand(IEntity entity, out string handName);
|
||||
|
||||
/// <summary>
|
||||
/// Drops the item contained in the slot to the same position as our entity.
|
||||
@@ -135,7 +137,7 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// </summary>
|
||||
/// <param name="slot">The slot of which to drop the entity.</param>
|
||||
/// <param name="targetContainer">The container to drop into.</param>
|
||||
/// <param name="doMobChecks">Whether to check the <see cref="ActionBlockerSystem.CanDrop()"/> for the mob or not.</param>
|
||||
/// <param name="doMobChecks">Whether to check the <see cref="ActionBlockerSystem.CanDrop(IEntity)"/> for the mob or not.</param>
|
||||
/// <returns>True on success, false if something was blocked (insertion or removal).</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if dry-run checks reported OK to remove and insert,
|
||||
@@ -167,20 +169,20 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// <summary>
|
||||
/// Checks whether the item in the specified hand can be dropped.
|
||||
/// </summary>
|
||||
/// <param name="index">The hand to check for.</param>
|
||||
/// <param name="name">The hand to check for.</param>
|
||||
/// <returns>
|
||||
/// True if the item can be dropped, false if the hand is empty or the item in the hand cannot be dropped.
|
||||
/// </returns>
|
||||
bool CanDrop(string index);
|
||||
bool CanDrop(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new hand to this hands component.
|
||||
/// </summary>
|
||||
/// <param name="index">The name of the hand to add.</param>
|
||||
/// <param name="name">The name of the hand to add.</param>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if a hand with specified name already exists.
|
||||
/// </exception>
|
||||
void AddHand(string index);
|
||||
void AddHand(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Removes a hand from this hands component.
|
||||
@@ -188,15 +190,15 @@ namespace Content.Server.Interfaces.GameObjects
|
||||
/// <remarks>
|
||||
/// If the hand contains an item, the item is dropped.
|
||||
/// </remarks>
|
||||
/// <param name="index">The name of the hand to remove.</param>
|
||||
void RemoveHand(string index);
|
||||
/// <param name="name">The name of the hand to remove.</param>
|
||||
void RemoveHand(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a hand with the specified name exists.
|
||||
/// </summary>
|
||||
/// <param name="index">The hand name to check.</param>
|
||||
/// <param name="name">The hand name to check.</param>
|
||||
/// <returns>True if the hand exists, false otherwise.</returns>
|
||||
bool HasHand(string index);
|
||||
bool HasHand(string name);
|
||||
|
||||
void HandleSlotModifiedMaybe(ContainerModifiedMessage message);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.Interfaces.PDA;
|
||||
using Content.Shared.GameObjects.Components.PDA;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Shared.Sandbox;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.GameObjects
|
||||
namespace Content.Shared.GameObjects.Components.Items
|
||||
{
|
||||
public abstract class SharedHandsComponent : Component
|
||||
{
|
||||
@@ -11,14 +13,31 @@ namespace Content.Shared.GameObjects
|
||||
public sealed override uint? NetID => ContentNetIDs.HANDS;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SharedHand
|
||||
{
|
||||
public readonly int Index;
|
||||
public readonly string Name;
|
||||
public readonly EntityUid? EntityUid;
|
||||
public readonly HandLocation Location;
|
||||
|
||||
public SharedHand(int index, string name, EntityUid? entityUid, HandLocation location)
|
||||
{
|
||||
Index = index;
|
||||
Name = name;
|
||||
EntityUid = entityUid;
|
||||
Location = location;
|
||||
}
|
||||
}
|
||||
|
||||
// The IDs of the items get synced over the network.
|
||||
[Serializable, NetSerializable]
|
||||
public class HandsComponentState : ComponentState
|
||||
{
|
||||
public readonly Dictionary<string, EntityUid> Hands;
|
||||
public readonly SharedHand[] Hands;
|
||||
public readonly string ActiveIndex;
|
||||
|
||||
public HandsComponentState(Dictionary<string, EntityUid> hands, string activeIndex) : base(ContentNetIDs.HANDS)
|
||||
public HandsComponentState(SharedHand[] hands, string activeIndex) : base(ContentNetIDs.HANDS)
|
||||
{
|
||||
Hands = hands;
|
||||
ActiveIndex = activeIndex;
|
||||
@@ -75,4 +94,11 @@ namespace Content.Shared.GameObjects
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
public enum HandLocation : byte
|
||||
{
|
||||
Left,
|
||||
Middle,
|
||||
Right
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@
|
||||
- deleteewc
|
||||
- asay
|
||||
- mapping
|
||||
- addhand
|
||||
- removehand
|
||||
CanViewVar: true
|
||||
CanAdminPlace: true
|
||||
|
||||
@@ -159,6 +161,8 @@
|
||||
- sudo
|
||||
- asay
|
||||
- mapping
|
||||
- addhand
|
||||
- removehand
|
||||
CanViewVar: true
|
||||
CanAdminPlace: true
|
||||
CanScript: true
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
- type: AiController
|
||||
logic: Mimic
|
||||
- type: Hands
|
||||
hands:
|
||||
- left
|
||||
- right
|
||||
- type: MovementSpeedModifier
|
||||
- type: InteractionOutline
|
||||
- type: Sprite
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
- type: AiController
|
||||
logic: Xeno
|
||||
- type: Hands
|
||||
hands:
|
||||
- left
|
||||
- right
|
||||
- type: MovementSpeedModifier
|
||||
- type: InteractionOutline
|
||||
- type: Sprite
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
components:
|
||||
- type: Flashable
|
||||
- type: Hands
|
||||
hands:
|
||||
- left
|
||||
- right
|
||||
- type: MovementSpeedModifier
|
||||
- type: Hunger
|
||||
- type: Thirst
|
||||
@@ -150,10 +147,6 @@
|
||||
description: A dummy human meant to be used in character setup
|
||||
components:
|
||||
- type: Hands
|
||||
hands:
|
||||
- left
|
||||
- right
|
||||
|
||||
- type: Inventory
|
||||
- type: Sprite
|
||||
netsync: false
|
||||
|
||||
BIN
Resources/Textures/Interface/Inventory/hand_l_no_letter.png
Normal file
BIN
Resources/Textures/Interface/Inventory/hand_l_no_letter.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Resources/Textures/Interface/Inventory/hand_middle.png
Normal file
BIN
Resources/Textures/Interface/Inventory/hand_middle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Resources/Textures/Interface/Inventory/hand_r_no_letter.png
Normal file
BIN
Resources/Textures/Interface/Inventory/hand_r_no_letter.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Reference in New Issue
Block a user