Storage Component ECS (#7530)

Co-authored-by: fishfish458 <fishfish458>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
Fishfish458
2022-04-28 06:11:15 -06:00
committed by GitHub
parent f403311641
commit 4c9e45a480
38 changed files with 892 additions and 1163 deletions

View File

@@ -1,23 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.Animations;
using Content.Client.Hands;
using Content.Client.Items.Components;
using Content.Client.Items.Managers;
using Content.Client.UserInterface.Controls;
using Content.Shared.DragDrop;
using Content.Shared.Storage;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Input;
using static Robust.Client.UserInterface.Control;
using static Robust.Client.UserInterface.Controls.BaseButton;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Storage
{
@@ -27,71 +10,10 @@ namespace Content.Client.Storage
[RegisterComponent]
public sealed class ClientStorageComponent : SharedStorageComponent, IDraggable
{
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
private List<EntityUid> _storedEntities = new();
private int StorageSizeUsed;
private int StorageCapacityMax;
private StorageWindow? _window;
public bool UIOpen => _window?.IsOpen ?? false;
public override IReadOnlyList<EntityUid> StoredEntities => _storedEntities;
private StorageWindow GetOrCreateWindow()
{
if (_window == null)
{
_window = new StorageWindow(this, _playerManager, _entityManager)
{
Title = _entityManager.GetComponent<MetaDataComponent>(Owner).EntityName
};
_window.EntityList.GenerateItem += GenerateButton;
_window.EntityList.ItemPressed += Interact;
}
return _window;
}
protected override void OnRemove()
{
if (_window is { Disposed: false })
{
_window.EntityList.GenerateItem -= GenerateButton;
_window.EntityList.ItemPressed -= Interact;
_window.Dispose();
}
_window = null;
base.OnRemove();
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
base.HandleComponentState(curState, nextState);
if (curState is not StorageComponentState state)
{
return;
}
_storedEntities = state.StoredEntities.ToList();
}
/// <summary>
/// Copies received values from server about contents of storage container
/// </summary>
/// <param name="storageState"></param>
public void HandleStorageMessage(StorageHeldItemsEvent storageState)
{
_storedEntities = storageState.StoredEntities.ToList();
StorageSizeUsed = storageState.StorageSizeUsed;
StorageCapacityMax = storageState.StorageSizeMax;
GetOrCreateWindow().BuildEntityList(storageState.StoredEntities.ToList());
}
/// <summary>
/// Animate the newly stored entities in <paramref name="msg"/> flying towards this storage's position
/// </summary>
@@ -110,190 +32,9 @@ namespace Content.Client.Storage
}
}
/// <summary>
/// Opens the storage UI if closed. Closes it if opened.
/// </summary>
public void ToggleUI()
{
var window = GetOrCreateWindow();
if (window.IsOpen)
window.Close();
else
window.OpenCentered();
}
public void CloseUI()
{
_window?.Close();
}
/// <summary>
/// Function for clicking one of the stored entity buttons in the UI, tells server to remove that entity
/// </summary>
/// <param name="entity"></param>
public void Interact(ButtonEventArgs args, EntityUid entity)
{
if (args.Event.Function == EngineKeyFunctions.UIClick)
{
_entityManager.EntityNetManager?.SendSystemNetworkMessage(new RemoveEntityEvent(Owner, entity));
args.Event.Handle();
}
else if (_entityManager.EntityExists(entity))
{
_itemSlotManager.OnButtonPressed(args.Event, entity);
}
}
public override bool Remove(EntityUid entity)
{
if (_storedEntities.Remove(entity))
{
Dirty();
return true;
}
return false;
}
/// <summary>
/// Button created for each entity that represents that item in the storage UI, with a texture, and name and size label
/// </summary>
public void GenerateButton(EntityUid entity, EntityContainerButton button)
{
if (!_entityManager.EntityExists(entity))
return;
_entityManager.TryGetComponent(entity, out ISpriteComponent? sprite);
_entityManager.TryGetComponent(entity, out ItemComponent? item);
button.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
SeparationOverride = 2,
Children =
{
new SpriteView
{
HorizontalAlignment = HAlignment.Left,
VerticalAlignment = VAlignment.Center,
MinSize = new Vector2(32.0f, 32.0f),
OverrideDirection = Direction.South,
Sprite = sprite
},
new Label
{
HorizontalExpand = true,
ClipText = true,
Text = _entityManager.GetComponent<MetaDataComponent>(entity).EntityName
},
new Label
{
Align = Label.AlignMode.Right,
Text = item?.Size.ToString() ?? Loc.GetString("no-item-size")
}
}
});
button.EnableAllKeybinds = true;
}
/// <summary>
/// GUI class for client storage component
/// </summary>
private sealed class StorageWindow : DefaultWindow
{
private Control _vBox;
private readonly Label _information;
public readonly EntityListDisplay EntityList;
public readonly ClientStorageComponent StorageEntity;
private readonly StyleBoxFlat _hoveredBox = new() { BackgroundColor = Color.Black.WithAlpha(0.35f) };
private readonly StyleBoxFlat _unHoveredBox = new() { BackgroundColor = Color.Black.WithAlpha(0.0f) };
public StorageWindow(ClientStorageComponent storageEntity, IPlayerManager players, IEntityManager entities)
{
StorageEntity = storageEntity;
SetSize = (200, 320);
Title = Loc.GetString("comp-storage-window-title");
RectClipContent = true;
var containerButton = new ContainerButton
{
Name = "StorageContainerButton",
MouseFilter = MouseFilterMode.Pass,
};
Contents.AddChild(containerButton);
var innerContainerButton = new PanelContainer
{
PanelOverride = _unHoveredBox,
};
containerButton.AddChild(innerContainerButton);
containerButton.OnPressed += args =>
{
var controlledEntity = players.LocalPlayer?.ControlledEntity;
if (entities.HasComponent<HandsComponent>(controlledEntity))
{
entities.EntityNetManager?.SendSystemNetworkMessage(new InsertEntityEvent(storageEntity.Owner));
}
};
_vBox = new BoxContainer()
{
Orientation = LayoutOrientation.Vertical,
MouseFilter = MouseFilterMode.Ignore,
};
containerButton.AddChild(_vBox);
_information = new Label
{
Text = Loc.GetString("comp-storage-window-volume", ("itemCount", 0), ("usedVolume", 0), ("maxVolume", 0)),
VerticalAlignment = VAlignment.Center
};
_vBox.AddChild(_information);
EntityList = new EntityListDisplay
{
Name = "EntityListContainer",
};
_vBox.AddChild(EntityList);
EntityList.OnMouseEntered += _ =>
{
innerContainerButton.PanelOverride = _hoveredBox;
};
EntityList.OnMouseExited += _ =>
{
innerContainerButton.PanelOverride = _unHoveredBox;
};
}
public override void Close()
{
IoCManager.Resolve<IEntityManager>().EntityNetManager?.SendSystemNetworkMessage(new CloseStorageUIEvent(StorageEntity.Owner));
base.Close();
}
/// <summary>
/// Loops through stored entities creating buttons for each, updates information labels
/// </summary>
public void BuildEntityList(List<EntityUid> entityUids)
{
EntityList.PopulateList(entityUids);
//Sets information about entire storage container current capacity
if (StorageEntity.StorageCapacityMax != 0)
{
_information.Text = Loc.GetString("comp-storage-window-volume", ("itemCount", entityUids.Count),
("usedVolume", StorageEntity.StorageSizeUsed), ("maxVolume", StorageEntity.StorageCapacityMax));
}
else
{
_information.Text = Loc.GetString("comp-storage-window-volume-unlimited", ("itemCount", entityUids.Count));
}
}
}
}
}

View File

@@ -0,0 +1,87 @@
using Content.Client.Storage.UI;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Content.Client.Items.Managers;
using JetBrains.Annotations;
using static Content.Shared.Storage.SharedStorageComponent;
namespace Content.Client.Storage
{
[UsedImplicitly]
public sealed class StorageBoundUserInterface : BoundUserInterface
{
[ViewVariables] private StorageWindow? _window;
public StorageBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
if (_window == null)
{
var entMan = IoCManager.Resolve<IEntityManager>();
_window = new StorageWindow(entMan) {Title = entMan.GetComponent<MetaDataComponent>(Owner.Owner).EntityName};
_window.EntityList.GenerateItem += _window.GenerateButton;
_window.EntityList.ItemPressed += InteractWithItem;
_window.StorageContainerButton.OnPressed += TouchedContainerButton;
_window.OnClose += Close;
_window.OpenCentered();
}
else
{
_window.Open();
}
}
public void InteractWithItem(BaseButton.ButtonEventArgs args, EntityUid entity)
{
if (args.Event.Function == EngineKeyFunctions.UIClick)
{
SendMessage(new StorageRemoveItemMessage(entity));
}
else if (IoCManager.Resolve<IEntityManager>().EntityExists(entity))
{
IoCManager.Resolve<IItemSlotManager>().OnButtonPressed(args.Event, entity);
}
}
public void TouchedContainerButton(BaseButton.ButtonEventArgs args)
{
SendMessage(new StorageInsertItemMessage());
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_window == null || state is not StorageBoundUserInterfaceState cast)
return;
_window?.BuildEntityList(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_window != null)
{
_window.EntityList.GenerateItem -= _window.GenerateButton;
_window.EntityList.ItemPressed -= InteractWithItem;
_window.StorageContainerButton.OnPressed -= TouchedContainerButton;
_window.OnClose -= Close;
}
_window?.Dispose();
_window = null;
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.Storage;
using Content.Client.Animations;
namespace Content.Client.Storage;
@@ -9,41 +10,28 @@ public sealed class StorageSystem : EntitySystem
{
base.Initialize();
SubscribeNetworkEvent<StorageHeldItemsEvent>(OnStorageHeldItems);
SubscribeNetworkEvent<OpenStorageUIEvent>(OnOpenStorageUI);
SubscribeNetworkEvent<CloseStorageUIEvent>(OnCloseStorageUI);
SubscribeNetworkEvent<AnimateInsertingEntitiesEvent>(OnAnimateInsertingEntities);
SubscribeNetworkEvent<AnimateInsertingEntitiesEvent>(HandleAnimatingInsertingEntities);
}
private void OnStorageHeldItems(StorageHeldItemsEvent ev)
/// <summary>
/// Animate the newly stored entities in <paramref name="msg"/> flying towards this storage's position
/// </summary>
/// <param name="msg"></param>
public void HandleAnimatingInsertingEntities(AnimateInsertingEntitiesEvent msg)
{
if (TryComp<ClientStorageComponent>(ev.Storage, out var storage))
{
storage.HandleStorageMessage(ev);
}
}
if (!TryComp(msg.Storage, out ClientStorageComponent? storage))
return;
private void OnOpenStorageUI(OpenStorageUIEvent ev)
{
if (TryComp<ClientStorageComponent>(ev.Storage, out var storage))
{
storage.ToggleUI();
}
}
TryComp(msg.Storage, out TransformComponent? transformComp);
private void OnCloseStorageUI(CloseStorageUIEvent ev)
{
if (TryComp<ClientStorageComponent>(ev.Storage, out var storage))
for (var i = 0; msg.StoredEntities.Count > i; i++)
{
storage.CloseUI();
}
}
private void OnAnimateInsertingEntities(AnimateInsertingEntitiesEvent ev)
{
if (TryComp<ClientStorageComponent>(ev.Storage, out var storage))
{
storage.HandleAnimatingInsertingEntities(ev);
var entity = msg.StoredEntities[i];
var initialPosition = msg.EntityPositions[i];
if (EntityManager.EntityExists(entity) && transformComp != null)
{
ReusableAnimations.AnimateEntityPickup(entity, initialPosition, transformComp.LocalPosition, EntityManager);
}
}
}
}

View File

@@ -0,0 +1,142 @@
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Content.Client.Items.Components;
using Content.Client.UserInterface.Controls;
using Robust.Client.UserInterface;
using static Robust.Client.UserInterface.Controls.BoxContainer;
using static Content.Shared.Storage.SharedStorageComponent;
namespace Content.Client.Storage.UI
{
/// <summary>
/// GUI class for client storage component
/// </summary>
public sealed class StorageWindow : DefaultWindow
{
private IEntityManager _entityManager;
private readonly Label _information;
public readonly ContainerButton StorageContainerButton;
public readonly EntityListDisplay EntityList;
private readonly StyleBoxFlat _hoveredBox = new() { BackgroundColor = Color.Black.WithAlpha(0.35f) };
private readonly StyleBoxFlat _unHoveredBox = new() { BackgroundColor = Color.Black.WithAlpha(0.0f) };
public StorageWindow(IEntityManager entityManager)
{
_entityManager = entityManager;
SetSize = (200, 320);
Title = Loc.GetString("comp-storage-window-title");
RectClipContent = true;
StorageContainerButton = new ContainerButton
{
Name = "StorageContainerButton",
MouseFilter = MouseFilterMode.Pass,
};
Contents.AddChild(StorageContainerButton);
var innerContainerButton = new PanelContainer
{
PanelOverride = _unHoveredBox,
};
StorageContainerButton.AddChild(innerContainerButton);
Control vBox = new BoxContainer()
{
Orientation = LayoutOrientation.Vertical,
MouseFilter = MouseFilterMode.Ignore,
};
StorageContainerButton.AddChild(vBox);
_information = new Label
{
Text = Loc.GetString("comp-storage-window-volume", ("itemCount", 0), ("usedVolume", 0), ("maxVolume", 0)),
VerticalAlignment = VAlignment.Center
};
vBox.AddChild(_information);
EntityList = new EntityListDisplay
{
Name = "EntityListContainer",
};
vBox.AddChild(EntityList);
EntityList.OnMouseEntered += _ =>
{
innerContainerButton.PanelOverride = _hoveredBox;
};
EntityList.OnMouseExited += _ =>
{
innerContainerButton.PanelOverride = _unHoveredBox;
};
}
/// <summary>
/// Loops through stored entities creating buttons for each, updates information labels
/// </summary>
public void BuildEntityList(StorageBoundUserInterfaceState state)
{
EntityList.PopulateList(state.StoredEntities);
//Sets information about entire storage container current capacity
if (state.StorageCapacityMax != 0)
{
_information.Text = Loc.GetString("comp-storage-window-volume", ("itemCount", state.StoredEntities.Count),
("usedVolume", state.StorageSizeUsed), ("maxVolume", state.StorageCapacityMax));
}
else
{
_information.Text = Loc.GetString("comp-storage-window-volume-unlimited", ("itemCount", state.StoredEntities.Count));
}
}
/// <summary>
/// Button created for each entity that represents that item in the storage UI, with a texture, and name and size label
/// </summary>
public void GenerateButton(EntityUid entity, EntityContainerButton button)
{
if (!_entityManager.EntityExists(entity))
return;
_entityManager.TryGetComponent(entity, out ISpriteComponent? sprite);
_entityManager.TryGetComponent(entity, out ItemComponent? item);
button.AddChild(new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
SeparationOverride = 2,
Children =
{
new SpriteView
{
HorizontalAlignment = HAlignment.Left,
VerticalAlignment = VAlignment.Center,
MinSize = new Vector2(32.0f, 32.0f),
OverrideDirection = Direction.South,
Sprite = sprite
},
new Label
{
HorizontalExpand = true,
ClipText = true,
Text = _entityManager.GetComponent<MetaDataComponent>(entity).EntityName
},
new Label
{
Align = Label.AlignMode.Right,
Text = item?.Size.ToString() ?? Loc.GetString("no-item-size")
}
}
});
button.EnableAllKeybinds = true;
}
}
}