using Content.Shared.GameObjects; using SS14.Client.Interfaces.GameObjects.Components; using SS14.Client.UserInterface; using SS14.Client.UserInterface.Controls; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.IoC; using SS14.Shared.Serialization; using SS14.Shared.Utility; using System; using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.Components.Clothing; using SS14.Shared.Interfaces.Reflection; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventoryMessage; using Content.Client.GameObjects.Components.Mobs; using Content.Client.GameObjects.Components.Actor; namespace Content.Client.GameObjects { /// /// A character UI which shows items the user has equipped within his inventory /// public class ClientInventoryComponent : SharedInventoryComponent, ICharacterUI { private Dictionary _slots = new Dictionary(); /// /// Holds the godot control for the inventory window /// private InventoryWindow _window; private string _templateName = "HumanInventory"; //stored for serialization purposes /// /// Inventory template after being loaded from instance creator and string name /// private Inventory _inventory; private ISpriteComponent _sprite; //Relevant interface implementation for the character UI controller public Control Scene => _window; public UIPriority Priority => UIPriority.Inventory; public override void OnRemove() { base.OnRemove(); _window.Dispose(); } public override void Initialize() { base.Initialize(); //Loads inventory template var reflectionManager = IoCManager.Resolve(); var type = reflectionManager.LooseGetType(_templateName); DebugTools.Assert(type != null); _inventory = (Inventory)Activator.CreateInstance(type); //Creates godot control class for inventory _window = new InventoryWindow(this); _window.CreateInventory(_inventory); if (Owner.TryGetComponent(out _sprite)) { foreach (var mask in _inventory.SlotMasks.OrderBy(s => _inventory.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 void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _templateName, "Template", "HumanInventory"); } public override void HandleComponentState(ComponentState state) { base.HandleComponentState(state); var cast = (InventoryComponentState) state; var doneSlots = new HashSet(); var entityManager = IoCManager.Resolve(); foreach (var (slot, entityUid) in cast.Entities) { if (_slots.ContainsKey(slot)) { _slots.Remove(slot); _clearSlot(slot); } var entity = entityManager.GetEntity(entityUid); _slots[slot] = entity; _setSlot(slot, entity); doneSlots.Add(slot); } foreach (var slot in _slots.Keys.ToList()) { if (!doneSlots.Contains(slot)) { _clearSlot(slot); _slots.Remove(slot); } } } private void _setSlot(Slots slot, IEntity entity) { if (_sprite != null && entity.TryGetComponent(out ClothingComponent clothing)) { var flag = SlotMasks[slot]; var data = clothing.GetEquippedStateInfo(flag); if (data == null) { _sprite.LayerSetVisible(slot, false); } else { var (rsi, state) = data.Value; _sprite.LayerSetVisible(slot, true); _sprite.LayerSetRSI(slot, rsi); _sprite.LayerSetState(slot, state); } } _window?.AddToSlot(slot, entity); } private void _clearSlot(Slots slot) { _window?.RemoveFromSlot(slot); _sprite?.LayerSetVisible(slot, false); } public void SendUnequipMessage(Slots slot) { var unequipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Unequip); SendNetworkMessage(unequipmessage); } public void SendEquipMessage(Slots slot) { var equipmessage = new ClientInventoryMessage(slot, ClientInventoryUpdate.Equip); SendNetworkMessage(equipmessage); } /// /// Temporary window to hold the basis for inventory hud /// private class InventoryWindow : PanelContainer { private int elements_x; private GridContainer GridContainer; private List IndexedSlots; private Dictionary InventorySlots = new Dictionary(); //ordered dictionary? private ClientInventoryComponent InventoryComponent; protected override ResourcePath ScenePath => new ResourcePath("/Scenes/Mobs/HumanInventory.tscn"); public InventoryWindow(ClientInventoryComponent inventory) { InventoryComponent = inventory; } /// /// Creates a grid container filled with slot buttons loaded from an inventory template /// public void CreateInventory(Inventory inventory) { elements_x = inventory.Columns; GridContainer = (GridContainer)GetChild("CenterContainer").GetChild("GridContainer"); GridContainer.Columns = elements_x; IndexedSlots = new List(inventory.SlotMasks); foreach (Slots slot in IndexedSlots) { InventoryButton newbutton = new InventoryButton(slot); if (slot == Slots.NONE) { //TODO: Re-enable when godot grid container maintains grid with invisible elements //newbutton.Visible = false; } else { //Store slot button and give it the default onpress behavior for empty elements newbutton.GetChild