get that crap outta here (completely rewrites inventorysystem) (#5807)
* some work * equip: done unequip: todo * unequipping done & refactored events * workin * movin * reee namespaces * stun * mobstate * fixes * some work on events * removes serverside itemcomp & misc fixes * work * smol merge fix * ports template to prototype & finishes ui * moves relay & adds containerenumerator * actions & cuffs * my god what is actioncode * more fixes * im loosing my grasp on reality * more fixes * more work * explosions * yes * more work * more fixes * merge master & misc fixed because i forgot to commit before merging master * more fixes * fixes * moar * more work * moar fixes * suffixmap * more work on client * motivation low * no. no containers * mirroring client to server * fixes * move serverinvcomp * serverinventorycomponent is dead * gaming * only strippable & ai left... * only ai and richtext left * fixes ai * fixes * fixes sprite layers * more fixes * resolves optional * yes * stable™️ * fixes * moar fixes * moar * fix some tests * lmao * no comment * good to merge™️ * fixes build but for real * adresses some reviews * adresses some more reviews * nullables, yo * fixes lobbyscreen * timid refactor to differentiate actor & target * adresses more reviews * more * my god what a mess * removed the rest of duplicates * removed duplicate slotflags and renamed shoes to feet * removes another unused one * yes * fixes lobby & makes tryunequip return unequipped item * fixes * some funny renames * fixes * misc improvements to attemptevents * fixes * merge fixes Co-authored-by: Paul Ritter <ritter.paul1@gmail.com>
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Client.Clothing;
|
||||
using Content.Shared.CharacterAppearance;
|
||||
using Content.Client.Items.UI;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Movement.EntitySystems;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.Inventory.EquipmentSlotDefines;
|
||||
using static Content.Shared.Inventory.SharedInventoryComponent.ClientInventoryMessage;
|
||||
|
||||
namespace Content.Client.Inventory
|
||||
{
|
||||
@@ -19,242 +15,21 @@ namespace Content.Client.Inventory
|
||||
/// A character UI which shows items the user has equipped within his inventory
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedInventoryComponent))]
|
||||
public class ClientInventoryComponent : SharedInventoryComponent
|
||||
[ComponentReference(typeof(InventoryComponent))]
|
||||
[Friend(typeof(ClientInventorySystem))]
|
||||
public class ClientInventoryComponent : InventoryComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
public Control BottomLeftButtons = default!;
|
||||
public Control BottomRightButtons = default!;
|
||||
public Control TopQuickButtons = default!;
|
||||
|
||||
private readonly Dictionary<Slots, EntityUid> _slots = new();
|
||||
public SS14Window InventoryWindow = default!;
|
||||
|
||||
public IReadOnlyDictionary<Slots, EntityUid> AllSlots => _slots;
|
||||
|
||||
[ViewVariables] public InventoryInterfaceController InterfaceController { get; private set; } = default!;
|
||||
|
||||
[ComponentDependency]
|
||||
private ISpriteComponent? _sprite;
|
||||
|
||||
private bool _playerAttached = false;
|
||||
public readonly Dictionary<string, List<ItemSlotButton>> SlotButtons = new();
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("speciesId")] public string? SpeciesId { get; set; }
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
if (_playerAttached)
|
||||
{
|
||||
InterfaceController?.PlayerDetached();
|
||||
}
|
||||
InterfaceController?.Dispose();
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
var controllerType = ReflectionManager.LooseGetType(InventoryInstance.InterfaceControllerTypeName);
|
||||
var args = new object[] {this};
|
||||
InterfaceController = DynamicTypeFactory.CreateInstance<InventoryInterfaceController>(controllerType, args);
|
||||
InterfaceController.Initialize();
|
||||
|
||||
if (_sprite != null)
|
||||
{
|
||||
foreach (var mask in InventoryInstance.SlotMasks.OrderBy(s => InventoryInstance.SlotDrawingOrder(s)))
|
||||
{
|
||||
if (mask == Slots.NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_sprite.LayerMapReserveBlank(mask);
|
||||
}
|
||||
}
|
||||
|
||||
// Component state already came in but we couldn't set anything visually because, well, we didn't initialize yet.
|
||||
foreach (var (slot, entity) in _slots)
|
||||
{
|
||||
_setSlot(slot, entity);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsEquipped(EntityUid item)
|
||||
{
|
||||
return item != default && _slots.Values.Any(e => e == item);
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
if (curState is not InventoryComponentState state)
|
||||
return;
|
||||
|
||||
var doneSlots = new HashSet<Slots>();
|
||||
|
||||
foreach (var (slot, entity) in state.Entities)
|
||||
{
|
||||
if (!_entMan.EntityExists(entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!_slots.ContainsKey(slot) || _slots[slot] != entity)
|
||||
{
|
||||
_slots[slot] = entity;
|
||||
_setSlot(slot, entity);
|
||||
}
|
||||
doneSlots.Add(slot);
|
||||
}
|
||||
|
||||
if (state.HoverEntity != null)
|
||||
{
|
||||
var (slot, (entity, fits)) = state.HoverEntity.Value;
|
||||
InterfaceController?.HoverInSlot(slot, entity, fits);
|
||||
}
|
||||
|
||||
foreach (var slot in _slots.Keys.ToList())
|
||||
{
|
||||
if (!doneSlots.Contains(slot))
|
||||
{
|
||||
_clearSlot(slot);
|
||||
_slots.Remove(slot);
|
||||
}
|
||||
}
|
||||
|
||||
EntitySystem.Get<MovementSpeedModifierSystem>().RefreshMovementSpeedModifiers(Owner);
|
||||
}
|
||||
|
||||
private void _setSlot(Slots slot, EntityUid entity)
|
||||
{
|
||||
SetSlotVisuals(slot, entity);
|
||||
|
||||
InterfaceController?.AddToSlot(slot, entity);
|
||||
}
|
||||
|
||||
internal void SetSlotVisuals(Slots slot, EntityUid entity)
|
||||
{
|
||||
if (_sprite == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_entMan.TryGetComponent(entity, out ClothingComponent? clothing))
|
||||
{
|
||||
var flag = SlotMasks[slot];
|
||||
var data = clothing.GetEquippedStateInfo(flag, SpeciesId);
|
||||
if (data != null)
|
||||
{
|
||||
var (rsi, state) = data.Value;
|
||||
_sprite.LayerSetVisible(slot, true);
|
||||
_sprite.LayerSetState(slot, state, rsi);
|
||||
_sprite.LayerSetAutoAnimated(slot, true);
|
||||
|
||||
if (slot == Slots.INNERCLOTHING && _sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
|
||||
{
|
||||
_sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch
|
||||
{
|
||||
FemaleClothingMask.NoMask => "female_none",
|
||||
FemaleClothingMask.UniformTop => "female_top",
|
||||
_ => "female_full",
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_sprite.LayerSetVisible(slot, false);
|
||||
}
|
||||
|
||||
internal void ClearAllSlotVisuals()
|
||||
{
|
||||
if (_sprite == null)
|
||||
return;
|
||||
|
||||
foreach (var slot in InventoryInstance.SlotMasks)
|
||||
{
|
||||
if (slot != Slots.NONE)
|
||||
{
|
||||
_sprite.LayerSetVisible(slot, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _clearSlot(Slots slot)
|
||||
{
|
||||
InterfaceController?.RemoveFromSlot(slot);
|
||||
_sprite?.LayerSetVisible(slot, false);
|
||||
}
|
||||
|
||||
public void SendEquipMessage(Slots slot)
|
||||
{
|
||||
var equipMessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip);
|
||||
#pragma warning disable 618
|
||||
SendNetworkMessage(equipMessage);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
public void SendUseMessage(Slots slot)
|
||||
{
|
||||
var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Use);
|
||||
#pragma warning disable 618
|
||||
SendNetworkMessage(equipmessage);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
public void SendHoverMessage(Slots slot)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
SendNetworkMessage(new ClientInventoryMessage(slot, ClientInventoryUpdate.Hover));
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
public void SendOpenStorageUIMessage(Slots slot)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
SendNetworkMessage(new OpenSlotStorageUIMessage(slot));
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
public void PlayerDetached()
|
||||
{
|
||||
InterfaceController.PlayerDetached();
|
||||
_playerAttached = false;
|
||||
}
|
||||
|
||||
public void PlayerAttached()
|
||||
{
|
||||
InterfaceController.PlayerAttached();
|
||||
_playerAttached = true;
|
||||
}
|
||||
|
||||
public override bool TryGetSlot(Slots slot, [NotNullWhen(true)] out EntityUid? item)
|
||||
{
|
||||
// dict TryGetValue uses default EntityUid, not null.
|
||||
if (!_slots.ContainsKey(slot))
|
||||
{
|
||||
item = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
item = _slots[slot];
|
||||
return item != null;
|
||||
}
|
||||
|
||||
public bool TryFindItemSlots(EntityUid item, [NotNullWhen(true)] out Slots? slots)
|
||||
{
|
||||
slots = null;
|
||||
|
||||
foreach (var (slot, entity) in _slots)
|
||||
{
|
||||
if (entity == item)
|
||||
{
|
||||
slots = slot;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public bool AttachedToGameHud;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Client.Clothing;
|
||||
using Content.Client.HUD;
|
||||
using Content.Shared.Input;
|
||||
using Content.Client.Items.Managers;
|
||||
using Content.Client.Items.UI;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Movement.EntitySystems;
|
||||
using Content.Shared.Slippery;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Item;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Inventory
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class ClientInventorySystem : EntitySystem
|
||||
public sealed class ClientInventorySystem : InventorySystem
|
||||
{
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _config = default!;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
|
||||
[Dependency] private readonly ClothingSystem _clothingSystem = default!;
|
||||
|
||||
public const int ButtonSize = 64;
|
||||
private const int ButtonSeparation = 4;
|
||||
private const int RightSeparation = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Stores delegates used to create controls for a given <see cref="InventoryTemplatePrototype"/>.
|
||||
/// </summary>
|
||||
private readonly
|
||||
Dictionary<string, Func<EntityUid, Dictionary<string, List<ItemSlotButton>>, (SS14Window window, Control bottomLeft, Control bottomRight, Control
|
||||
topQuick)>>
|
||||
_uiGenerateDelegates = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -25,29 +57,96 @@ namespace Content.Client.Inventory
|
||||
InputCmdHandler.FromDelegate(_ => HandleOpenInventoryMenu()))
|
||||
.Register<ClientInventorySystem>();
|
||||
|
||||
SubscribeLocalEvent<ClientInventoryComponent, PlayerAttachedEvent>((_, component, _) => component.PlayerAttached());
|
||||
SubscribeLocalEvent<ClientInventoryComponent, PlayerDetachedEvent>((_, component, _) => component.PlayerDetached());
|
||||
SubscribeLocalEvent<ClientInventoryComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||
SubscribeLocalEvent<ClientInventoryComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||
|
||||
SubscribeLocalEvent<ClientInventoryComponent, SlipAttemptEvent>(OnSlipAttemptEvent);
|
||||
SubscribeLocalEvent<ClientInventoryComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||
SubscribeLocalEvent<ClientInventoryComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<ClientInventoryComponent, ComponentShutdown>(OnShutdown);
|
||||
|
||||
SubscribeLocalEvent<ClientInventoryComponent, DidEquipEvent>(OnDidEquip);
|
||||
SubscribeLocalEvent<ClientInventoryComponent, DidUnequipEvent>(OnDidUnequip);
|
||||
|
||||
_config.OnValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
||||
}
|
||||
|
||||
// jesus christ, this is duplicated to server/client, should really just be shared..
|
||||
private void OnSlipAttemptEvent(EntityUid uid, ClientInventoryComponent component, SlipAttemptEvent args)
|
||||
public override bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, string slot, bool silent = false, bool force = false,
|
||||
InventoryComponent? inventory = null, SharedItemComponent? item = null)
|
||||
{
|
||||
if (component.TryGetSlot(EquipmentSlotDefines.Slots.SHOES, out EntityUid? shoes))
|
||||
if(!target.IsClientSide() && !actor.IsClientSide() && !itemUid.IsClientSide()) RaiseNetworkEvent(new TryEquipNetworkMessage(actor, target, itemUid, slot, silent, force));
|
||||
return base.TryEquip(actor, target, itemUid, slot, silent, force, inventory, item);
|
||||
}
|
||||
|
||||
public override bool TryUnequip(EntityUid actor, EntityUid target, string slot, [NotNullWhen(true)] out EntityUid? removedItem, bool silent = false, bool force = false,
|
||||
InventoryComponent? inventory = null)
|
||||
{
|
||||
if(!target.IsClientSide() && !actor.IsClientSide()) RaiseNetworkEvent(new TryUnequipNetworkMessage(actor, target, slot, silent, force));
|
||||
return base.TryUnequip(actor, target, slot, out removedItem, silent, force, inventory);
|
||||
}
|
||||
|
||||
private void OnDidUnequip(EntityUid uid, ClientInventoryComponent component, DidUnequipEvent args)
|
||||
{
|
||||
if (component.SlotButtons.TryGetValue(args.Slot, out var buttons))
|
||||
{
|
||||
RaiseLocalEvent(shoes.Value, args, false);
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
_itemSlotManager.SetItemSlot(button, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRefreshMovespeed(EntityUid uid, ClientInventoryComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
private void OnDidEquip(EntityUid uid, ClientInventoryComponent component, DidEquipEvent args)
|
||||
{
|
||||
foreach (var (_, ent) in component.AllSlots)
|
||||
if (component.SlotButtons.TryGetValue(args.Slot, out var buttons))
|
||||
{
|
||||
if (ent != default)
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
RaiseLocalEvent(ent, args, false);
|
||||
_itemSlotManager.SetItemSlot(button, args.Equipment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerDetached(EntityUid uid, ClientInventoryComponent component, PlayerDetachedEvent? args = null)
|
||||
{
|
||||
if(!component.AttachedToGameHud) return;
|
||||
|
||||
_gameHud.InventoryButtonVisible = false;
|
||||
_gameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(component.BottomLeftButtons);
|
||||
_gameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(component.BottomRightButtons);
|
||||
_gameHud.TopInventoryQuickButtonContainer.RemoveChild(component.TopQuickButtons);
|
||||
component.AttachedToGameHud = false;
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, ClientInventoryComponent component, ComponentShutdown args)
|
||||
{
|
||||
OnPlayerDetached(uid, component);
|
||||
}
|
||||
|
||||
private void OnPlayerAttached(EntityUid uid, ClientInventoryComponent component, PlayerAttachedEvent args)
|
||||
{
|
||||
if(component.AttachedToGameHud) return;
|
||||
|
||||
_gameHud.InventoryButtonVisible = true;
|
||||
_gameHud.BottomLeftInventoryQuickButtonContainer.AddChild(component.BottomLeftButtons);
|
||||
_gameHud.BottomRightInventoryQuickButtonContainer.AddChild(component.BottomRightButtons);
|
||||
_gameHud.TopInventoryQuickButtonContainer.AddChild(component.TopQuickButtons);
|
||||
component.AttachedToGameHud = true;
|
||||
}
|
||||
|
||||
private void UpdateHudTheme(int obj)
|
||||
{
|
||||
if (!_gameHud.ValidateHudTheme(obj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var inventoryComponent in EntityManager.EntityQuery<ClientInventoryComponent>(true))
|
||||
{
|
||||
foreach (var slotButton in inventoryComponent.SlotButtons)
|
||||
{
|
||||
foreach (var btn in slotButton.Value)
|
||||
{
|
||||
btn.RefreshTextures(_gameHud);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,9 +154,183 @@ namespace Content.Client.Inventory
|
||||
public override void Shutdown()
|
||||
{
|
||||
CommandBinds.Unregister<ClientInventorySystem>();
|
||||
_config.UnsubValueChanged(CCVars.HudTheme, UpdateHudTheme);
|
||||
base.Shutdown();
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, ClientInventoryComponent component, ComponentInit args)
|
||||
{
|
||||
_clothingSystem.InitClothing(uid, component);
|
||||
|
||||
if (!TryGetUIElements(uid, out var window, out var bottomLeft, out var bottomRight, out var topQuick,
|
||||
component))
|
||||
return;
|
||||
|
||||
component.InventoryWindow = window;
|
||||
component.BottomLeftButtons = bottomLeft;
|
||||
component.BottomRightButtons = bottomRight;
|
||||
component.TopQuickButtons = topQuick;
|
||||
}
|
||||
|
||||
private void HoverInSlotButton(EntityUid uid, string slot, ItemSlotButton button, InventoryComponent? inventoryComponent = null, SharedHandsComponent? hands = null)
|
||||
{
|
||||
if (!Resolve(uid, ref inventoryComponent))
|
||||
return;
|
||||
|
||||
if (!Resolve(uid, ref hands, false))
|
||||
return;
|
||||
|
||||
if (!hands.TryGetActiveHeldEntity(out var heldEntity))
|
||||
return;
|
||||
|
||||
if(!TryGetSlotContainer(uid, slot, out var containerSlot, out var slotDef, inventoryComponent))
|
||||
return;
|
||||
|
||||
_itemSlotManager.HoverInSlot(button, heldEntity,
|
||||
CanEquip(uid, heldEntity, slot, out _, slotDef, inventoryComponent) &&
|
||||
containerSlot.CanInsert(heldEntity, EntityManager));
|
||||
}
|
||||
|
||||
private void HandleSlotButtonPressed(EntityUid uid, string slot, ItemSlotButton button,
|
||||
GUIBoundKeyEventArgs args)
|
||||
{
|
||||
if (TryGetSlotEntity(uid, slot, out var itemUid))
|
||||
{
|
||||
if (!_itemSlotManager.OnButtonPressed(args, itemUid.Value) && args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
RaiseNetworkEvent(new UseSlotNetworkMessage(uid, slot));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Function != EngineKeyFunctions.UIClick) return;
|
||||
TryEquipActiveHandTo(uid, slot);
|
||||
}
|
||||
|
||||
private bool TryGetUIElements(EntityUid uid, [NotNullWhen(true)] out SS14Window? invWindow,
|
||||
[NotNullWhen(true)] out Control? invBottomLeft, [NotNullWhen(true)] out Control? invBottomRight,
|
||||
[NotNullWhen(true)] out Control? invTopQuick, ClientInventoryComponent? component = null)
|
||||
{
|
||||
invWindow = null;
|
||||
invBottomLeft = null;
|
||||
invBottomRight = null;
|
||||
invTopQuick = null;
|
||||
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if(!_prototypeManager.TryIndex<InventoryTemplatePrototype>(component.TemplateId, out var template))
|
||||
return false;
|
||||
|
||||
if (!_uiGenerateDelegates.TryGetValue(component.TemplateId, out var genfunc))
|
||||
{
|
||||
_uiGenerateDelegates[component.TemplateId] = genfunc = (entityUid, list) =>
|
||||
{
|
||||
var window = new SS14Window()
|
||||
{
|
||||
Title = Loc.GetString("human-inventory-window-title"),
|
||||
Resizable = false
|
||||
};
|
||||
window.OnClose += () => _gameHud.InventoryButtonDown = false;
|
||||
var windowContents = new LayoutContainer
|
||||
{
|
||||
MinSize = (ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation,
|
||||
ButtonSize * 4 + ButtonSeparation * 3)
|
||||
};
|
||||
window.Contents.AddChild(windowContents);
|
||||
|
||||
ItemSlotButton GetButton(SlotDefinition definition, string textureBack)
|
||||
{
|
||||
var btn = new ItemSlotButton(ButtonSize, $"{definition.TextureName}.png", textureBack,
|
||||
_gameHud)
|
||||
{
|
||||
OnStoragePressed = (e) =>
|
||||
{
|
||||
if (e.Function != EngineKeyFunctions.UIClick &&
|
||||
e.Function != ContentKeyFunctions.ActivateItemInWorld)
|
||||
return;
|
||||
RaiseNetworkEvent(new OpenSlotStorageNetworkMessage(entityUid, definition.Name));
|
||||
}
|
||||
};
|
||||
btn.OnHover = (_) =>
|
||||
{
|
||||
HoverInSlotButton(entityUid, definition.Name, btn);
|
||||
};
|
||||
btn.OnPressed = (e) =>
|
||||
{
|
||||
HandleSlotButtonPressed(entityUid, definition.Name, btn, e);
|
||||
};
|
||||
return btn;
|
||||
}
|
||||
|
||||
void AddButton(SlotDefinition definition, Vector2i position)
|
||||
{
|
||||
var button = GetButton(definition, "back.png");
|
||||
LayoutContainer.SetPosition(button, position);
|
||||
windowContents.AddChild(button);
|
||||
if (!list.ContainsKey(definition.Name))
|
||||
list[definition.Name] = new();
|
||||
list[definition.Name].Add(button);
|
||||
}
|
||||
|
||||
void AddHUDButton(BoxContainer container, SlotDefinition definition)
|
||||
{
|
||||
var button = GetButton(definition, "back.png");
|
||||
container.AddChild(button);
|
||||
if (!list.ContainsKey(definition.Name))
|
||||
list[definition.Name] = new();
|
||||
list[definition.Name].Add(button);
|
||||
}
|
||||
|
||||
var topQuick = new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||
SeparationOverride = 5
|
||||
};
|
||||
var bottomRight = new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||
SeparationOverride = 5
|
||||
};
|
||||
var bottomLeft = new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||
SeparationOverride = 5
|
||||
};
|
||||
|
||||
const int sizep = (ButtonSize + ButtonSeparation);
|
||||
|
||||
foreach (var slotDefinition in template.Slots)
|
||||
{
|
||||
switch (slotDefinition.UIContainer)
|
||||
{
|
||||
case SlotUIContainer.BottomLeft:
|
||||
AddHUDButton(bottomLeft, slotDefinition);
|
||||
break;
|
||||
case SlotUIContainer.BottomRight:
|
||||
AddHUDButton(bottomRight, slotDefinition);
|
||||
break;
|
||||
case SlotUIContainer.Top:
|
||||
AddHUDButton(topQuick, slotDefinition);
|
||||
break;
|
||||
}
|
||||
|
||||
AddButton(slotDefinition, slotDefinition.UIWindowPosition * sizep);
|
||||
}
|
||||
|
||||
return (window, bottomLeft, bottomRight, topQuick);
|
||||
};
|
||||
}
|
||||
|
||||
var res = genfunc(uid, component.SlotButtons);
|
||||
invWindow = res.window;
|
||||
invBottomLeft = res.bottomLeft;
|
||||
invBottomRight = res.bottomRight;
|
||||
invTopQuick = res.topQuick;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void HandleOpenInventoryMenu()
|
||||
{
|
||||
_gameHud.InventoryButtonDown = !_gameHud.InventoryButtonDown;
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.HUD;
|
||||
using Content.Client.Items.Managers;
|
||||
using Content.Client.Items.UI;
|
||||
using Content.Shared.CCVar;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.Inventory.EquipmentSlotDefines;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
|
||||
namespace Content.Client.Inventory
|
||||
{
|
||||
// Dynamically instantiated by ClientInventoryComponent.
|
||||
[UsedImplicitly]
|
||||
public class HumanInventoryInterfaceController : InventoryInterfaceController
|
||||
{
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
|
||||
[Dependency] private readonly INetConfigurationManager _configManager = default!;
|
||||
|
||||
private readonly Dictionary<Slots, List<ItemSlotButton>> _inventoryButtons
|
||||
= new();
|
||||
|
||||
private ItemSlotButton _hudButtonPocket1 = default!;
|
||||
private ItemSlotButton _hudButtonPocket2 = default!;
|
||||
private ItemSlotButton _hudButtonShoes = default!;
|
||||
private ItemSlotButton _hudButtonJumpsuit = default!;
|
||||
private ItemSlotButton _hudButtonGloves = default!;
|
||||
private ItemSlotButton _hudButtonNeck = default!;
|
||||
private ItemSlotButton _hudButtonHead = default!;
|
||||
private ItemSlotButton _hudButtonBelt = default!;
|
||||
private ItemSlotButton _hudButtonBack = default!;
|
||||
private ItemSlotButton _hudButtonOClothing = default!;
|
||||
private ItemSlotButton _hudButtonId = default!;
|
||||
private ItemSlotButton _hudButtonMask = default!;
|
||||
private ItemSlotButton _hudButtonEyes = default!;
|
||||
private ItemSlotButton _hudButtonEars = default!;
|
||||
|
||||
private Control _topQuickButtonsContainer = default!;
|
||||
private Control _bottomLeftQuickButtonsContainer = default!;
|
||||
private Control _bottomRightQuickButtonsContainer = default!;
|
||||
|
||||
public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme, invokeImmediately: true);
|
||||
|
||||
_window = new HumanInventoryWindow(_gameHud);
|
||||
_window.OnClose += () => GameHud.InventoryButtonDown = false;
|
||||
foreach (var (slot, button) in _window.Buttons)
|
||||
{
|
||||
button.OnPressed = (e) => AddToInventory(e, slot);
|
||||
button.OnStoragePressed = (e) => OpenStorage(e, slot);
|
||||
button.OnHover = (_) => RequestItemHover(slot);
|
||||
_inventoryButtons.Add(slot, new List<ItemSlotButton> {button});
|
||||
}
|
||||
|
||||
void AddButton(out ItemSlotButton variable, Slots slot, string textureName)
|
||||
{
|
||||
var texture = _gameHud.GetHudTexture($"{textureName}.png");
|
||||
var storageTexture = _gameHud.GetHudTexture("back.png");
|
||||
variable = new ItemSlotButton(texture, storageTexture, textureName)
|
||||
{
|
||||
OnPressed = (e) => AddToInventory(e, slot),
|
||||
OnStoragePressed = (e) => OpenStorage(e, slot),
|
||||
OnHover = (_) => RequestItemHover(slot)
|
||||
};
|
||||
_inventoryButtons[slot].Add(variable);
|
||||
}
|
||||
|
||||
AddButton(out _hudButtonPocket1, Slots.POCKET1, "pocket");
|
||||
AddButton(out _hudButtonPocket2, Slots.POCKET2, "pocket");
|
||||
AddButton(out _hudButtonId, Slots.IDCARD, "id");
|
||||
|
||||
AddButton(out _hudButtonBack, Slots.BACKPACK, "back");
|
||||
|
||||
AddButton(out _hudButtonBelt, Slots.BELT, "belt");
|
||||
|
||||
AddButton(out _hudButtonShoes, Slots.SHOES, "shoes");
|
||||
AddButton(out _hudButtonJumpsuit, Slots.INNERCLOTHING, "uniform");
|
||||
AddButton(out _hudButtonOClothing, Slots.OUTERCLOTHING, "suit");
|
||||
AddButton(out _hudButtonGloves, Slots.GLOVES, "gloves");
|
||||
AddButton(out _hudButtonNeck, Slots.NECK, "neck");
|
||||
AddButton(out _hudButtonMask, Slots.MASK, "mask");
|
||||
AddButton(out _hudButtonEyes, Slots.EYES, "glasses");
|
||||
AddButton(out _hudButtonEars, Slots.EARS, "ears");
|
||||
AddButton(out _hudButtonHead, Slots.HEAD, "head");
|
||||
|
||||
_topQuickButtonsContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
_hudButtonShoes,
|
||||
_hudButtonJumpsuit,
|
||||
_hudButtonOClothing,
|
||||
_hudButtonGloves,
|
||||
_hudButtonNeck,
|
||||
_hudButtonMask,
|
||||
_hudButtonEyes,
|
||||
_hudButtonEars,
|
||||
_hudButtonHead
|
||||
},
|
||||
SeparationOverride = 5
|
||||
};
|
||||
|
||||
_bottomRightQuickButtonsContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
_hudButtonPocket1,
|
||||
_hudButtonPocket2,
|
||||
_hudButtonId,
|
||||
},
|
||||
SeparationOverride = 5
|
||||
};
|
||||
_bottomLeftQuickButtonsContainer = new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
Children =
|
||||
{
|
||||
_hudButtonBelt,
|
||||
_hudButtonBack
|
||||
},
|
||||
SeparationOverride = 5
|
||||
};
|
||||
}
|
||||
|
||||
public override SS14Window? Window => _window;
|
||||
private HumanInventoryWindow? _window;
|
||||
|
||||
public override IEnumerable<ItemSlotButton> GetItemSlotButtons(Slots slot)
|
||||
{
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
{
|
||||
return Enumerable.Empty<ItemSlotButton>();
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public override void AddToSlot(Slots slot, EntityUid entity)
|
||||
{
|
||||
base.AddToSlot(slot, entity);
|
||||
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
return;
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
_itemSlotManager.SetItemSlot(button, entity);
|
||||
button.OnPressed = (e) => HandleInventoryKeybind(e, slot);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemoveFromSlot(Slots slot)
|
||||
{
|
||||
base.RemoveFromSlot(slot);
|
||||
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
ClearButton(button, slot);
|
||||
}
|
||||
}
|
||||
|
||||
public override void HoverInSlot(Slots slot, EntityUid entity, bool fits)
|
||||
{
|
||||
base.HoverInSlot(slot, entity, fits);
|
||||
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
_itemSlotManager.HoverInSlot(button, entity, fits);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleInventoryKeybind(GUIBoundKeyEventArgs args, Slots slot)
|
||||
{
|
||||
if (!_inventoryButtons.ContainsKey(slot))
|
||||
return;
|
||||
if (!Owner.TryGetSlot(slot, out var item))
|
||||
return;
|
||||
|
||||
if (!_itemSlotManager.OnButtonPressed(args, item.Value))
|
||||
base.HandleInventoryKeybind(args, slot);
|
||||
}
|
||||
|
||||
private void ClearButton(ItemSlotButton button, Slots slot)
|
||||
{
|
||||
button.OnPressed = (e) => AddToInventory(e, slot);
|
||||
_itemSlotManager.SetItemSlot(button, default);
|
||||
}
|
||||
|
||||
public override void PlayerAttached()
|
||||
{
|
||||
base.PlayerAttached();
|
||||
|
||||
GameHud.BottomLeftInventoryQuickButtonContainer.AddChild(_bottomLeftQuickButtonsContainer);
|
||||
GameHud.BottomRightInventoryQuickButtonContainer.AddChild(_bottomRightQuickButtonsContainer);
|
||||
GameHud.TopInventoryQuickButtonContainer.AddChild(_topQuickButtonsContainer);
|
||||
|
||||
// Update all the buttons to make sure they check out.
|
||||
|
||||
foreach (var (slot, buttons) in _inventoryButtons)
|
||||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
ClearButton(button, slot);
|
||||
}
|
||||
|
||||
if (Owner.TryGetSlot(slot, out var entity))
|
||||
{
|
||||
AddToSlot(slot, entity.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PlayerDetached()
|
||||
{
|
||||
base.PlayerDetached();
|
||||
|
||||
GameHud.BottomRightInventoryQuickButtonContainer.RemoveChild(_bottomRightQuickButtonsContainer);
|
||||
GameHud.BottomLeftInventoryQuickButtonContainer.RemoveChild(_bottomLeftQuickButtonsContainer);
|
||||
GameHud.TopInventoryQuickButtonContainer.RemoveChild(_topQuickButtonsContainer);
|
||||
|
||||
foreach (var (slot, list) in _inventoryButtons)
|
||||
{
|
||||
foreach (var button in list)
|
||||
{
|
||||
ClearButton(button, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateHudTheme(int idx)
|
||||
{
|
||||
if (!_gameHud.ValidateHudTheme(idx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (_, list) in _inventoryButtons)
|
||||
{
|
||||
foreach (var button in list)
|
||||
{
|
||||
button.Button.Texture = _gameHud.GetHudTexture($"{button.TextureName}.png");
|
||||
button.StorageButton.TextureNormal = _gameHud.GetHudTexture("back.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HumanInventoryWindow : SS14Window
|
||||
{
|
||||
private const int ButtonSize = 64;
|
||||
private const int ButtonSeparation = 4;
|
||||
private const int RightSeparation = 2;
|
||||
|
||||
public IReadOnlyDictionary<Slots, ItemSlotButton> Buttons { get; }
|
||||
|
||||
public HumanInventoryWindow(IGameHud gameHud)
|
||||
{
|
||||
Title = Loc.GetString("human-inventory-window-title");
|
||||
Resizable = false;
|
||||
|
||||
var buttonDict = new Dictionary<Slots, ItemSlotButton>();
|
||||
Buttons = buttonDict;
|
||||
|
||||
const int width = ButtonSize * 4 + ButtonSeparation * 3 + RightSeparation;
|
||||
const int height = ButtonSize * 4 + ButtonSeparation * 3;
|
||||
|
||||
var windowContents = new LayoutContainer {MinSize = (width, height)};
|
||||
Contents.AddChild(windowContents);
|
||||
|
||||
void AddButton(Slots slot, string textureName, Vector2 position)
|
||||
{
|
||||
var texture = gameHud.GetHudTexture($"{textureName}.png");
|
||||
var storageTexture = gameHud.GetHudTexture("back.png");
|
||||
var button = new ItemSlotButton(texture, storageTexture, textureName);
|
||||
|
||||
LayoutContainer.SetPosition(button, position);
|
||||
|
||||
windowContents.AddChild(button);
|
||||
buttonDict.Add(slot, button);
|
||||
}
|
||||
|
||||
const int sizep = (ButtonSize + ButtonSeparation);
|
||||
|
||||
// Left column.
|
||||
AddButton(Slots.EYES, "glasses", (0, 0));
|
||||
AddButton(Slots.NECK, "neck", (0, sizep));
|
||||
AddButton(Slots.INNERCLOTHING, "uniform", (0, 2 * sizep));
|
||||
AddButton(Slots.POCKET1, "pocket", (0, 3 * sizep));
|
||||
|
||||
// Middle column.
|
||||
AddButton(Slots.HEAD, "head", (sizep, 0));
|
||||
AddButton(Slots.MASK, "mask", (sizep, sizep));
|
||||
AddButton(Slots.OUTERCLOTHING, "suit", (sizep, 2 * sizep));
|
||||
AddButton(Slots.SHOES, "shoes", (sizep, 3 * sizep));
|
||||
|
||||
// Right column
|
||||
AddButton(Slots.EARS, "ears", (2 * sizep, 0));
|
||||
AddButton(Slots.IDCARD, "id", (2 * sizep, sizep));
|
||||
AddButton(Slots.GLOVES, "gloves", (2 * sizep, 2 * sizep));
|
||||
AddButton(Slots.POCKET2, "pocket", (2 * sizep, 3 * sizep));
|
||||
|
||||
// Far right column.
|
||||
AddButton(Slots.BACKPACK, "back", (3 * sizep, 0));
|
||||
AddButton(Slots.BELT, "belt", (3 * sizep, sizep));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.HUD;
|
||||
using Content.Client.Items.UI;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client.Inventory
|
||||
{
|
||||
public abstract class InventoryInterfaceController : IDisposable
|
||||
{
|
||||
[Dependency] protected readonly IGameHud GameHud = default!;
|
||||
|
||||
protected InventoryInterfaceController(ClientInventoryComponent owner)
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
public abstract SS14Window? Window { get; }
|
||||
protected ClientInventoryComponent Owner { get; }
|
||||
|
||||
public virtual void PlayerAttached()
|
||||
{
|
||||
GameHud.InventoryButtonVisible = true;
|
||||
}
|
||||
|
||||
public virtual void PlayerDetached()
|
||||
{
|
||||
GameHud.InventoryButtonVisible = false;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <returns>the button controls associated with the
|
||||
/// specified slot, if any. Empty if none.</returns>
|
||||
public abstract IEnumerable<ItemSlotButton> GetItemSlotButtons(EquipmentSlotDefines.Slots slot);
|
||||
|
||||
public virtual void AddToSlot(EquipmentSlotDefines.Slots slot, EntityUid entity)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void HoverInSlot(EquipmentSlotDefines.Slots slot, EntityUid entity, bool fits)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void RemoveFromSlot(EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void HandleInventoryKeybind(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
UseItemOnInventory(slot);
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddToInventory(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner.SendEquipMessage(slot);
|
||||
}
|
||||
|
||||
protected void UseItemOnInventory(EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
Owner.SendUseMessage(slot);
|
||||
}
|
||||
|
||||
protected void OpenStorage(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick && args.Function != ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner.SendOpenStorageUIMessage(slot);
|
||||
}
|
||||
|
||||
protected void RequestItemHover(EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
Owner.SendHoverMessage(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,13 @@ using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.Inventory.EquipmentSlotDefines;
|
||||
|
||||
namespace Content.Client.Inventory
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class StrippableBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
public Dictionary<Slots, string>? Inventory { get; private set; }
|
||||
public Dictionary<(string ID, string Name), string>? Inventory { get; private set; }
|
||||
public Dictionary<string, string>? Hands { get; private set; }
|
||||
public Dictionary<EntityUid, string>? Handcuffs { get; private set; }
|
||||
|
||||
@@ -55,9 +54,9 @@ namespace Content.Client.Inventory
|
||||
{
|
||||
foreach (var (slot, name) in Inventory)
|
||||
{
|
||||
_strippingMenu.AddButton(SlotNames[slot], name, (ev) =>
|
||||
_strippingMenu.AddButton(slot.Name, name, (ev) =>
|
||||
{
|
||||
SendMessage(new StrippingInventoryButtonPressed(slot));
|
||||
SendMessage(new StrippingInventoryButtonPressed(slot.ID));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user