From f6e265bccb2df35d62d12caa5b09b7a102694ac8 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 24 Sep 2017 21:09:26 +0200 Subject: [PATCH 01/12] Inventories WiP --- Content.Server/Content.Server.csproj | 6 + .../Components/Items/HandsComponent.cs | 11 ++ .../Components/Items/InventoryComponent.cs | 105 ++++++++++++++++++ .../Components/Items/ItemComponent.cs | 35 ++++++ .../Components/Items/IHandsComponent.cs | 50 +++++++++ .../Components/Items/IInventoryComponent.cs | 84 ++++++++++++++ .../Components/Items/IItemComponent.cs | 22 ++++ 7 files changed, 313 insertions(+) create mode 100644 Content.Server/GameObjects/Components/Items/HandsComponent.cs create mode 100644 Content.Server/GameObjects/Components/Items/InventoryComponent.cs create mode 100644 Content.Server/GameObjects/Components/Items/ItemComponent.cs create mode 100644 Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs create mode 100644 Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs create mode 100644 Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 07b85bcc33..d2cdb12b80 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -56,6 +56,12 @@ + + + + + + diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs new file mode 100644 index 0000000000..0dc7a00e86 --- /dev/null +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -0,0 +1,11 @@ +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using System.Collections.Generic; + +namespace Content.Server.Interfaces.GameObjects +{ + public class HandsComponent : Component, IHandsComponent + { + public override string Name => "Hands"; + } +} diff --git a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs new file mode 100644 index 0000000000..2374532b95 --- /dev/null +++ b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs @@ -0,0 +1,105 @@ +using Content.Server.Interfaces.GameObjects; +using SS14.Server.GameObjects; +using SS14.Server.Interfaces.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using System; +using System.Collections.Generic; + +namespace Content.Server.Interfaces.GameObjects +{ + public class InventoryComponent : Component, IInventoryComponent + { + public override string Name => "Inventory"; + + private Dictionary slots = new Dictionary(); + private TransformComponent transform; + // TODO: Make this container unique per-slot. + private IContainer container; + + public override void Initialize() + { + transform = Owner.GetComponent(); + base.Initialize(); + } + + public override void OnRemove() + { + transform = null; + base.OnRemove(); + } + + public IItemComponent Get(string slot) + { + return _GetSlot(slot).Item; + } + + public IInventorySlot GetSlot(string slot) + { + return slots[slot]; + } + + // Private version that returns our concrete implementation. + private InventorySlot _GetSlot(string slot) + { + return slots[slot]; + } + + public bool PutInSlot(string slot, IItemComponent item) + { + var inventorySlot = _GetSlot(slot); + if (inventorySlot.Item != null) + { + return false; + } + + inventorySlot.Item = item; + item.EquippedToSlot(inventorySlot); + return true; + } + + public bool DropSlot(string slot) + { + var inventorySlot = _GetSlot(slot); + var item = inventorySlot.Item; + if (item == null || !container.Remove(item.Owner)) + { + return false; + } + + item.RemovedFromSlot(); + inventorySlot.Item = null; + + // TODO: The item should be dropped to the container our owner is in, if any. + var itemTransform = item.Owner.GetComponent(); + itemTransform.LocalPosition = transform.LocalPosition; + return true; + } + + public void AddSlot(string slot) + { + if (slots.ContainsKey(slot)) + { + + } + } + + public void RemoveSlot(string slot) + { + throw new NotImplementedException(); + } + + private class InventorySlot : IInventorySlot + { + public IItemComponent Item { get; set; } + public string Name { get; } + public IInventoryComponent Owner { get; } + + public InventorySlot(string name, IInventoryComponent owner) + { + Name = name; + Owner = owner; + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Items/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/ItemComponent.cs new file mode 100644 index 0000000000..0571ab8492 --- /dev/null +++ b/Content.Server/GameObjects/Components/Items/ItemComponent.cs @@ -0,0 +1,35 @@ +using Content.Server.Interfaces.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using System; + +namespace Content.Server.Interfaces.GameObjects +{ + public class ItemComponent : Component, IItemComponent + { + public override string Name => "Item"; + + /// + public IInventorySlot ContainingSlot { get; private set; } + + public void RemovedFromSlot() + { + if (ContainingSlot == null) + { + throw new InvalidOperationException("Item is not in a slot."); + } + + ContainingSlot = null; + } + + public void EquippedToSlot(IInventorySlot slot) + { + if (ContainingSlot != null) + { + throw new InvalidOperationException("Item is already in a slot."); + } + + ContainingSlot = slot; + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs new file mode 100644 index 0000000000..881f30328b --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -0,0 +1,50 @@ +using SS14.Shared.Interfaces.GameObjects; +using System.Collections.Generic; + +namespace Content.Server.Interfaces.GameObjects +{ + public interface IHandsComponent : IComponent + { + /// + /// The hand index of the currently active hand. + /// + string ActiveIndex { get; } + + /// + /// Enumerates over every held item. + /// + IEnumerable GetAllHands(); + + /// + /// Gets the item held by a hand. + /// + /// The index of the hand to get. + /// The item in the held, null if no item is held + IItemComponent GetHand(string index); + + /// + /// Puts an item into any empty hand, preferring the active hand. + /// + /// The item to put in a hand. + /// True if the item was inserted, false otherwise. + bool PutInHand(IItemComponent item); + + /// + /// Puts an item into a specific hand. + /// + /// The item to put in the hand. + /// The index of the hand to put the item into. + /// + /// If true and the provided hand is full, the method will fall back to + /// + /// True if the item was inserted into a hand, false otherwise. + bool PutInHand(IItemComponent item, string index, bool fallback=true); + + /// + /// Drops an item on the ground, removing it from the hand. + /// + /// The hand to drop from. + /// True if an item was successfully dropped, false otherwise. + bool Drop(string index); + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs new file mode 100644 index 0000000000..4f3247ecdf --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs @@ -0,0 +1,84 @@ +using SS14.Server.Interfaces.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using System; + +namespace Content.Server.Interfaces.GameObjects +{ + public interface IInventoryComponent : IComponent + { + /// + /// Gets the item in the specified slot. + /// + /// The slot to get the item for. + /// Null if the slot is empty, otherwise the item. + IItemComponent Get(string slot); + + /// + /// Gets the slot with specified name. + /// This gets the slot, NOT the item contained therein. + /// + /// The name of the slot to get. + IInventorySlot GetSlot(string slot); + + /// + /// Puts an item in a slot. + /// + /// + /// This will fail if there is already an item in the specified slot. + /// + /// The slot to put the item in. + /// The item to insert into the slot. + /// True if the item was successfully inserted, false otherwise. + bool PutInSlot(string slot, IItemComponent item); + + /// + /// Drops the item in a slot. + /// + /// The slot to drop the item from. + /// True if an item was dropped, false otherwise. + bool DropSlot(string slot); + + /// + /// Adds a new slot to this inventory component. + /// + /// The name of the slot to add. + /// + /// Thrown if the slot with specified name already exists. + /// + void AddSlot(string slot); + + /// + /// Removes a slot from this inventory component. + /// + /// + /// If the slot contains an item, the item is dropped. + /// + /// The name of the slot to remove. + void RemoveSlot(string slot); + + /// + /// + /// + /// + /// + bool HasSlot(string slot); + } + + public interface IInventorySlot + { + /// + /// The name of the slot. + /// + string Name { get; } + + /// + /// The item contained in the slot, can be null. + /// + IItemComponent Item { get; } + + /// + /// The component owning us. + /// + IInventoryComponent Owner { get; } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs new file mode 100644 index 0000000000..cd54ef375c --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs @@ -0,0 +1,22 @@ +using SS14.Shared.Interfaces.GameObjects; + +namespace Content.Server.Interfaces.GameObjects +{ + public interface IItemComponent : IComponent + { + /// + /// The inventory slot this item is stored in, if any. + /// + IInventorySlot ContainingSlot { get; } + + /// + /// Called when the item is removed from its inventory slot. + /// + void RemovedFromSlot(); + + /// + /// Called when the item is inserted into a new inventory slot. + /// + void EquippedToSlot(IInventorySlot slot); + } +} From 66483bdd7252b02c8d60905d8390879281a8ef01 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 24 Sep 2017 22:24:54 +0200 Subject: [PATCH 02/12] Can* API functions by Yota's request. --- .../Components/Items/InventoryComponent.cs | 55 ++++++++++++++++--- .../Components/Items/IHandsComponent.cs | 24 ++++++++ .../Components/Items/IInventoryComponent.cs | 27 +++++++-- 3 files changed, 94 insertions(+), 12 deletions(-) diff --git a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs index 2374532b95..db4f994636 100644 --- a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs @@ -45,10 +45,15 @@ namespace Content.Server.Interfaces.GameObjects return slots[slot]; } - public bool PutInSlot(string slot, IItemComponent item) + public bool Insert(string slot, IItemComponent item) { + if (item == null) + { + throw new ArgumentNullException(nameof(item), "An item must be passed. To remove an item from a slot, use Drop()"); + } + var inventorySlot = _GetSlot(slot); - if (inventorySlot.Item != null) + if (!CanInsert(slot, item)) { return false; } @@ -58,11 +63,22 @@ namespace Content.Server.Interfaces.GameObjects return true; } - public bool DropSlot(string slot) + public bool CanInsert(string slot, IItemComponent item) { + var inventorySlot = _GetSlot(slot); + return inventorySlot.Item == null; + } + + public bool Drop(string slot) + { + if (!CanDrop(slot)) + { + return false; + } + var inventorySlot = _GetSlot(slot); var item = inventorySlot.Item; - if (item == null || !container.Remove(item.Owner)) + if (!container.Remove(item.Owner)) { return false; } @@ -76,17 +92,42 @@ namespace Content.Server.Interfaces.GameObjects return true; } + public bool CanDrop(string slot) + { + var inventorySlot = _GetSlot(slot); + var item = inventorySlot.Item; + return item != null && container.CanRemove(item.Owner); + } + public void AddSlot(string slot) { - if (slots.ContainsKey(slot)) + if (HasSlot(slot)) { - + throw new InvalidOperationException($"Slot '{slot}' already exists."); } + + slots[slot] = new InventorySlot(slot, this); } public void RemoveSlot(string slot) { - throw new NotImplementedException(); + if (!HasSlot(slot)) + { + throw new InvalidOperationException($"Slow '{slot}' does not exist."); + } + + if (Get(slot) != null && !Drop(slot)) + { + // TODO: Handle this potential failiure better. + throw new InvalidOperationException("Unable to remove slot as the contained item could not be dropped"); + } + + slots.Remove(slot); + } + + public bool HasSlot(string slot) + { + return slots.ContainsKey(slot); } private class InventorySlot : IInventorySlot diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 881f30328b..d5ff2c1bec 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -40,11 +40,35 @@ namespace Content.Server.Interfaces.GameObjects /// True if the item was inserted into a hand, false otherwise. bool PutInHand(IItemComponent item, string index, bool fallback=true); + /// + /// Checks to see if an item can be put in any hand. + /// + /// The item to check for. + /// True if the item can be inserted, false otherwise. + bool CanPutInHand(IItemComponent item); + + /// + /// Checks to see if an item can be put in the specified hand. + /// + /// The item to check for. + /// The index for the hand to check for. + /// True if the item can be inserted, false otherwise. + bool CanPutInHand(IItemComponent item, string index); + /// /// Drops an item on the ground, removing it from the hand. /// /// The hand to drop from. /// True if an item was successfully dropped, false otherwise. bool Drop(string index); + + /// + /// Checks whether the item in the specified hand can be dropped. + /// + /// The hand to check for. + /// + /// True if the item can be dropped, false if the hand is empty or the item in the hand cannot be dropped. + /// + bool CanDrop(string index); } } diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs index 4f3247ecdf..62fab52d9d 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs @@ -29,14 +29,31 @@ namespace Content.Server.Interfaces.GameObjects /// The slot to put the item in. /// The item to insert into the slot. /// True if the item was successfully inserted, false otherwise. - bool PutInSlot(string slot, IItemComponent item); + bool Insert(string slot, IItemComponent item); + + /// + /// Checks whether an item can be put in the specified slot. + /// + /// The slot to check for. + /// The item to check for. + /// True if the item can be inserted into the specified slot. + bool CanInsert(string slot, IItemComponent item); /// /// Drops the item in a slot. /// /// The slot to drop the item from. /// True if an item was dropped, false otherwise. - bool DropSlot(string slot); + bool Drop(string slot); + + /// + /// Checks whether an item can be dropped from the specified slot. + /// + /// The slot to check for. + /// + /// True if there is an item in the slot and it can be dropped, false otherwise. + /// + bool CanDrop(string slot); /// /// Adds a new slot to this inventory component. @@ -57,10 +74,10 @@ namespace Content.Server.Interfaces.GameObjects void RemoveSlot(string slot); /// - /// + /// Checks whether a slot with the specified name exists. /// - /// - /// + /// The slot name to check. + /// True if the slot exists, false otherwise. bool HasSlot(string slot); } From 73ae408e205fe22aee038f1575e1d75715275d08 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 24 Sep 2017 23:19:47 +0200 Subject: [PATCH 03/12] More inventory work. APIs implemented. Still need to do prototype loading and test cases. --- Content.Server/EntryPoint.cs | 17 ++- .../Components/Items/HandsComponent.cs | 122 +++++++++++++++++- .../Components/Items/InventoryComponent.cs | 13 +- .../Components/Items/ItemComponent.cs | 2 +- .../Components/Items/IHandsComponent.cs | 2 +- 5 files changed, 148 insertions(+), 8 deletions(-) diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 6483e6b6f4..c8c527c982 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -1,4 +1,8 @@ -using SS14.Shared.ContentPack; +using Content.Server.GameObjects; +using Content.Server.Interfaces.GameObjects; +using SS14.Shared.ContentPack; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.IoC; namespace Content.Server { @@ -6,7 +10,16 @@ namespace Content.Server { public override void Init() { - // TODO: Anything at all. + var factory = IoCManager.Resolve(); + + factory.Register(); + factory.RegisterReference(); + + factory.Register(); + factory.RegisterReference(); + + factory.Register(); + factory.RegisterReference(); } } } diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index 0dc7a00e86..371cab4818 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -1,11 +1,131 @@ +using Content.Server.Interfaces.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using System.Collections.Generic; +using System; +using System.Linq; -namespace Content.Server.Interfaces.GameObjects +namespace Content.Server.GameObjects { public class HandsComponent : Component, IHandsComponent { public override string Name => "Hands"; + + private string activeIndex; + public string ActiveIndex + { + get => activeIndex; + set + { + if (!hands.ContainsKey(value)) + { + throw new ArgumentException($"No hand '{value}'"); + } + + activeIndex = value; + } + } + + private Dictionary hands = new Dictionary(); + private IInventoryComponent inventory; + + public override void Initialize() + { + inventory = Owner.GetComponent(); + } + + public IEnumerable GetAllHands() + { + foreach (var slot in hands.Values) + { + if (slot.Item != null) + { + yield return slot.Item; + } + } + } + + public IItemComponent GetHand(string index) + { + var slot = hands[index]; + return slot.Item; + } + + /// + /// Enumerates over the hand keys, returning the active hand first. + /// + private IEnumerable ActivePriorityEnumerable() + { + yield return ActiveIndex; + foreach (var hand in hands.Keys) + { + if (hand == ActiveIndex) + { + continue; + } + + yield return hand; + } + } + + public bool PutInHand(IItemComponent item) + { + foreach (var hand in ActivePriorityEnumerable()) + { + if (PutInHand(item, hand, fallback: false)) + { + return true; + } + } + + return false; + } + + public bool PutInHand(IItemComponent item, string index, bool fallback = true) + { + if (!CanPutInHand(item, index)) + { + return fallback && PutInHand(item); + } + + var slot = hands[index]; + return slot.Owner.Insert(slot.Name, item); + } + + public bool CanPutInHand(IItemComponent item) + { + foreach (var hand in ActivePriorityEnumerable()) + { + if (CanPutInHand(item, hand)) + { + return true; + } + } + + return false; + } + + public bool CanPutInHand(IItemComponent item, string index) + { + var slot = hands[index]; + return slot.Owner.CanInsert(slot.Name, item); + } + + public bool Drop(string index) + { + if (!CanDrop(index)) + { + return false; + } + + var slot = hands[index]; + return slot.Owner.Drop(slot.Name); + } + + public bool CanDrop(string index) + { + var slot = hands[index]; + return slot.Item != null && slot.Owner.CanDrop(slot.Name); + } } } diff --git a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs index db4f994636..6e206d311a 100644 --- a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs @@ -1,12 +1,13 @@ using Content.Server.Interfaces.GameObjects; using SS14.Server.GameObjects; +using SS14.Server.GameObjects.Components.Container; using SS14.Server.Interfaces.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using System; using System.Collections.Generic; -namespace Content.Server.Interfaces.GameObjects +namespace Content.Server.GameObjects { public class InventoryComponent : Component, IInventoryComponent { @@ -20,12 +21,18 @@ namespace Content.Server.Interfaces.GameObjects public override void Initialize() { transform = Owner.GetComponent(); + container = Container.Create("inventory", Owner); base.Initialize(); } public override void OnRemove() { + foreach (var slot in slots.Keys) + { + RemoveSlot(slot); + } transform = null; + container = null; base.OnRemove(); } @@ -53,7 +60,7 @@ namespace Content.Server.Interfaces.GameObjects } var inventorySlot = _GetSlot(slot); - if (!CanInsert(slot, item)) + if (!CanInsert(slot, item) || !container.Insert(item.Owner)) { return false; } @@ -66,7 +73,7 @@ namespace Content.Server.Interfaces.GameObjects public bool CanInsert(string slot, IItemComponent item) { var inventorySlot = _GetSlot(slot); - return inventorySlot.Item == null; + return inventorySlot.Item == null && container.CanInsert(item.Owner); } public bool Drop(string slot) diff --git a/Content.Server/GameObjects/Components/Items/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/ItemComponent.cs index 0571ab8492..efebe59f4c 100644 --- a/Content.Server/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ItemComponent.cs @@ -3,7 +3,7 @@ using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using System; -namespace Content.Server.Interfaces.GameObjects +namespace Content.Server.GameObjects { public class ItemComponent : Component, IItemComponent { diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index d5ff2c1bec..52a63baf05 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Interfaces.GameObjects /// /// The hand index of the currently active hand. /// - string ActiveIndex { get; } + string ActiveIndex { get; set; } /// /// Enumerates over every held item. From 3e0bcddd4db965bc32638b67558ab0ab1f524fa5 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 25 Sep 2017 20:52:39 +0200 Subject: [PATCH 04/12] Done I hope. Needs testing and type checker updates. waiting on https://github.com/space-wizards/space-station-14/pull/422 --- .../Components/Items/HandsComponent.cs | 58 ++++++++++++++++++- .../Components/Items/InventoryComponent.cs | 18 +++++- .../Components/Items/IHandsComponent.cs | 27 ++++++++- .../Components/Items/IInventoryComponent.cs | 2 +- 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index 371cab4818..997e57bcba 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -1,9 +1,11 @@ using Content.Server.Interfaces.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Utility; using System.Collections.Generic; using System; using System.Linq; +using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects { @@ -32,10 +34,28 @@ namespace Content.Server.GameObjects public override void Initialize() { inventory = Owner.GetComponent(); + base.Initialize(); } - public IEnumerable GetAllHands() + public override void OnRemove() { + inventory = null; + base.OnRemove(); + } + + public override void LoadParameters(YamlMappingNode mapping) + { + foreach (var node in mapping.GetNode("hands")) + { + AddHand(node.AsString()); + } + base.LoadParameters(mapping); + } + + public IEnumerable GetAllHeldItems() + { + throw new NotImplementedException(); + /* foreach (var slot in hands.Values) { if (slot.Item != null) @@ -43,6 +63,7 @@ namespace Content.Server.GameObjects yield return slot.Item; } } + */ } public IItemComponent GetHand(string index) @@ -56,6 +77,8 @@ namespace Content.Server.GameObjects /// private IEnumerable ActivePriorityEnumerable() { + throw new NotImplementedException(); + /* yield return ActiveIndex; foreach (var hand in hands.Keys) { @@ -66,6 +89,7 @@ namespace Content.Server.GameObjects yield return hand; } + */ } public bool PutInHand(IItemComponent item) @@ -127,5 +151,37 @@ namespace Content.Server.GameObjects var slot = hands[index]; return slot.Item != null && slot.Owner.CanDrop(slot.Name); } + + public void AddHand(string index) + { + if (HasHand(index)) + { + throw new InvalidOperationException($"Hand '{index}' already exists."); + } + + var slot = inventory.AddSlot(HandSlotName(index)); + hands[index] = slot; + } + + public void RemoveHand(string index) + { + if (!HasHand(index)) + { + throw new InvalidOperationException($"Hand '{index}' does not exist."); + } + + inventory.RemoveSlot(HandSlotName(index)); + hands.Remove(index); + } + + public bool HasHand(string index) + { + return hands.ContainsKey(index); + } + + /// + /// Get the name of the slot passed to the inventory component. + /// + private string HandSlotName(string index) => $"_hand_{index}"; } } diff --git a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs index 6e206d311a..585235d948 100644 --- a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs @@ -2,10 +2,12 @@ using Content.Server.Interfaces.GameObjects; using SS14.Server.GameObjects; using SS14.Server.GameObjects.Components.Container; using SS14.Server.Interfaces.GameObjects; +using SS14.Shared.Utility; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using System; using System.Collections.Generic; +using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects { @@ -36,6 +38,18 @@ namespace Content.Server.GameObjects base.OnRemove(); } + public override void LoadParameters(YamlMappingNode mapping) + { + if (mapping.TryGetNode("slots", out var slotsNode)) + { + foreach (var node in slotsNode) + { + AddSlot(node.AsString()); + } + } + base.LoadParameters(mapping); + } + public IItemComponent Get(string slot) { return _GetSlot(slot).Item; @@ -106,14 +120,14 @@ namespace Content.Server.GameObjects return item != null && container.CanRemove(item.Owner); } - public void AddSlot(string slot) + public IInventorySlot AddSlot(string slot) { if (HasSlot(slot)) { throw new InvalidOperationException($"Slot '{slot}' already exists."); } - slots[slot] = new InventorySlot(slot, this); + return slots[slot] = new InventorySlot(slot, this); } public void RemoveSlot(string slot) diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 52a63baf05..0d8fc902d4 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -13,7 +13,7 @@ namespace Content.Server.Interfaces.GameObjects /// /// Enumerates over every held item. /// - IEnumerable GetAllHands(); + IEnumerable GetAllHeldItems(); /// /// Gets the item held by a hand. @@ -70,5 +70,30 @@ namespace Content.Server.Interfaces.GameObjects /// True if the item can be dropped, false if the hand is empty or the item in the hand cannot be dropped. /// bool CanDrop(string index); + + /// + /// Adds a new hand to this hands component. + /// + /// The name of the hand to add. + /// + /// Thrown if a hand with specified name already exists. + /// + void AddHand(string index); + + /// + /// Removes a hand from this hands component. + /// + /// + /// If the hand contains an item, the item is dropped. + /// + /// The name of the hand to remove. + void RemoveHand(string index); + + /// + /// Checks whether a hand with the specified name exists. + /// + /// The hand name to check. + /// True if the hand exists, false otherwise. + bool HasHand(string index); } } diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs index 62fab52d9d..6fe70fc1b6 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs @@ -62,7 +62,7 @@ namespace Content.Server.Interfaces.GameObjects /// /// Thrown if the slot with specified name already exists. /// - void AddSlot(string slot); + IInventorySlot AddSlot(string slot); /// /// Removes a slot from this inventory component. From c85436118a49e9ba97b0e3479b878b97b578e670 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 25 Sep 2017 21:00:53 +0200 Subject: [PATCH 05/12] Basic example prototype that manages not to crash. --- Resources/Prototypes/Entities/hands.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Resources/Prototypes/Entities/hands.yml diff --git a/Resources/Prototypes/Entities/hands.yml b/Resources/Prototypes/Entities/hands.yml new file mode 100644 index 0000000000..4879b96150 --- /dev/null +++ b/Resources/Prototypes/Entities/hands.yml @@ -0,0 +1,14 @@ +- type: entity + name: IT HAS HANDS + id: thing_with_hands + components: + - type: Transform + - type: Hands + hands: + - left + - right + - type: Inventory + slots: + - head + - shoes + - uniform From a464acf354fb84af35b5b6faef7ac4fbf9774d37 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 26 Sep 2017 19:59:31 +0200 Subject: [PATCH 06/12] Ignore item and inventory client side. --- Content.Client/EntryPoint.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 23c31b9e9b..d2ff4e773f 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -1,4 +1,6 @@ using SS14.Shared.ContentPack; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.IoC; namespace Content.Client { @@ -6,7 +8,10 @@ namespace Content.Client { public override void Init() { - // TODO: Anything at all. + var factory = IoCManager.Resolve(); + + factory.RegisterIgnore("Inventory"); + factory.RegisterIgnore("Item"); } } } From 4f2d059de4b9f1d7545fa065f95c998bae34405f Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 26 Sep 2017 21:27:48 +0200 Subject: [PATCH 07/12] Simple network replication for hands, untested. --- Content.Client/Content.Client.csproj | 2 ++ Content.Client/EntryPoint.cs | 7 +++- .../Components/Items/HandsComponent.cs | 34 +++++++++++++++++++ .../Components/Items/IHandsComponent.cs | 16 +++++++++ .../Components/Items/HandsComponent.cs | 24 ++++++++----- Content.Shared/Content.Shared.csproj | 2 ++ .../Components/Items/HandsComponent.cs | 25 ++++++++++++++ .../GameObjects/Components/NetIDs.cs | 7 ++++ 8 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 Content.Client/GameObjects/Components/Items/HandsComponent.cs create mode 100644 Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs create mode 100644 Content.Shared/GameObjects/Components/Items/HandsComponent.cs create mode 100644 Content.Shared/GameObjects/Components/NetIDs.cs diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 6fad7de4a6..4927d2da9e 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -62,6 +62,8 @@ + + diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index d2ff4e773f..cd7fc67701 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -1,4 +1,6 @@ -using SS14.Shared.ContentPack; +using Content.Client.GameObjects; +using Content.Client.Interfaces.GameObjects; +using SS14.Shared.ContentPack; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.IoC; @@ -12,6 +14,9 @@ namespace Content.Client factory.RegisterIgnore("Inventory"); factory.RegisterIgnore("Item"); + + factory.Register(); + factory.RegisterReference(); } } } diff --git a/Content.Client/GameObjects/Components/Items/HandsComponent.cs b/Content.Client/GameObjects/Components/Items/HandsComponent.cs new file mode 100644 index 0000000000..315b9aa7d2 --- /dev/null +++ b/Content.Client/GameObjects/Components/Items/HandsComponent.cs @@ -0,0 +1,34 @@ +using Content.Client.Interfaces.GameObjects; +using Content.Shared.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.IoC; +using System.Collections.Generic; + +namespace Content.Client.GameObjects +{ + public class HandsComponent : SharedHandsComponent, IHandsComponent + { + private readonly Dictionary hands = new Dictionary(); + + public IEntity GetEntity(string index) + { + if (hands.TryGetValue(index, out var entity)) + { + return entity; + } + + return null; + } + + public override void HandleComponentState(ComponentState state) + { + var cast = (HandsComponentState)state; + hands.Clear(); + foreach (var hand in cast.Hands) + { + hands[hand.Key] = Owner.EntityManager.GetEntity(hand.Value); + } + } + } +} diff --git a/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs new file mode 100644 index 0000000000..06a9f6c1c7 --- /dev/null +++ b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -0,0 +1,16 @@ +using Content.Client.Interfaces.GameObjects; +using Content.Shared.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.IoC; +using System.Collections.Generic; + +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); + } +} diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index 997e57bcba..28e5063ba6 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Interfaces.GameObjects; +using Content.Shared.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Utility; @@ -9,10 +10,8 @@ using YamlDotNet.RepresentationModel; namespace Content.Server.GameObjects { - public class HandsComponent : Component, IHandsComponent + public class HandsComponent : SharedHandsComponent, IHandsComponent { - public override string Name => "Hands"; - private string activeIndex; public string ActiveIndex { @@ -54,8 +53,6 @@ namespace Content.Server.GameObjects public IEnumerable GetAllHeldItems() { - throw new NotImplementedException(); - /* foreach (var slot in hands.Values) { if (slot.Item != null) @@ -63,7 +60,6 @@ namespace Content.Server.GameObjects yield return slot.Item; } } - */ } public IItemComponent GetHand(string index) @@ -77,8 +73,6 @@ namespace Content.Server.GameObjects /// private IEnumerable ActivePriorityEnumerable() { - throw new NotImplementedException(); - /* yield return ActiveIndex; foreach (var hand in hands.Keys) { @@ -89,7 +83,6 @@ namespace Content.Server.GameObjects yield return hand; } - */ } public bool PutInHand(IItemComponent item) @@ -183,5 +176,18 @@ namespace Content.Server.GameObjects /// Get the name of the slot passed to the inventory component. /// private string HandSlotName(string index) => $"_hand_{index}"; + + public override ComponentState GetComponentState() + { + var dict = new Dictionary(hands.Count); + foreach (var hand in hands) + { + if (hand.Value.Item != null) + { + dict[hand.Key] = hand.Value.Item.Owner.Uid; + } + } + return new HandsComponentState(dict); + } } } diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index af0cea6ca3..7618413325 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -56,6 +56,8 @@ + + diff --git a/Content.Shared/GameObjects/Components/Items/HandsComponent.cs b/Content.Shared/GameObjects/Components/Items/HandsComponent.cs new file mode 100644 index 0000000000..bac1c58156 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Items/HandsComponent.cs @@ -0,0 +1,25 @@ +using SS14.Shared.GameObjects; +using System; +using System.Collections.Generic; + +namespace Content.Shared.GameObjects +{ + public abstract class SharedHandsComponent : Component + { + public sealed override string Name => "Hands"; + public sealed override uint? NetID => ContentNetIDs.HANDS; + public sealed override Type StateType => typeof(HandsComponentState); + } + + // The IDs of the items get synced over the network. + [Serializable] + public class HandsComponentState : ComponentState + { + public readonly Dictionary Hands; + + public HandsComponentState(Dictionary hands) + { + Hands = hands; + } + } +} diff --git a/Content.Shared/GameObjects/Components/NetIDs.cs b/Content.Shared/GameObjects/Components/NetIDs.cs new file mode 100644 index 0000000000..da323846c2 --- /dev/null +++ b/Content.Shared/GameObjects/Components/NetIDs.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.GameObjects +{ + public static class ContentNetIDs + { + public const uint HANDS = 0; + } +} From d345316db8d7c6e35268aaf4252a08a5c6718c46 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 26 Sep 2017 21:58:45 +0200 Subject: [PATCH 08/12] Make NetID use 1000+ range --- Content.Shared/GameObjects/Components/NetIDs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/GameObjects/Components/NetIDs.cs b/Content.Shared/GameObjects/Components/NetIDs.cs index da323846c2..fe77227233 100644 --- a/Content.Shared/GameObjects/Components/NetIDs.cs +++ b/Content.Shared/GameObjects/Components/NetIDs.cs @@ -2,6 +2,6 @@ namespace Content.Shared.GameObjects { public static class ContentNetIDs { - public const uint HANDS = 0; + public const uint HANDS = 1000; } } From f40cffa746ed8d99f2ebe9751c1be25118d15db9 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 26 Sep 2017 23:10:10 +0200 Subject: [PATCH 09/12] Fix init ordering issue with hands. --- .../GameObjects/Components/Items/HandsComponent.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index 28e5063ba6..d03bdf9c91 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -29,10 +29,19 @@ namespace Content.Server.GameObjects private Dictionary hands = new Dictionary(); private IInventoryComponent inventory; + private YamlMappingNode tempParametersMapping; public override void Initialize() { inventory = Owner.GetComponent(); + if (tempParametersMapping != null) + { + foreach (var node in tempParametersMapping.GetNode("hands")) + { + AddHand(node.AsString()); + } + } + base.Initialize(); } @@ -44,10 +53,7 @@ namespace Content.Server.GameObjects public override void LoadParameters(YamlMappingNode mapping) { - foreach (var node in mapping.GetNode("hands")) - { - AddHand(node.AsString()); - } + tempParametersMapping = mapping; base.LoadParameters(mapping); } From b0b220f085b5cee5123c906927aadd065b986705 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Fri, 29 Sep 2017 18:38:27 +0200 Subject: [PATCH 10/12] Hand switching works! --- .../Components/Items/HandsComponent.cs | 37 +++++++++++++++++++ Resources/Prototypes/Entities/Mobs.yml | 10 +++++ Resources/Prototypes/Entities/hands.yml | 14 ------- 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 Resources/Prototypes/Entities/Mobs.yml delete mode 100644 Resources/Prototypes/Entities/hands.yml diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index d03bdf9c91..f384741ae1 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -1,5 +1,7 @@ using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; +using SS14.Server.GameObjects.Events; +using SS14.Shared; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Utility; @@ -28,6 +30,7 @@ namespace Content.Server.GameObjects } private Dictionary hands = new Dictionary(); + private List orderedHands = new List(); private IInventoryComponent inventory; private YamlMappingNode tempParametersMapping; @@ -42,6 +45,7 @@ namespace Content.Server.GameObjects } } + Owner.SubscribeEvent(OnKeyChange, this); base.Initialize(); } @@ -160,6 +164,7 @@ namespace Content.Server.GameObjects var slot = inventory.AddSlot(HandSlotName(index)); hands[index] = slot; + orderedHands.Add(index); } public void RemoveHand(string index) @@ -171,6 +176,19 @@ namespace Content.Server.GameObjects inventory.RemoveSlot(HandSlotName(index)); hands.Remove(index); + orderedHands.Remove(index); + + if (index == ActiveIndex) + { + if (orderedHands.Count == 0) + { + activeIndex = null; + } + else + { + activeIndex = orderedHands[0]; + } + } } public bool HasHand(string index) @@ -195,5 +213,24 @@ namespace Content.Server.GameObjects } return new HandsComponentState(dict); } + + // Game logic goes here. + public void OnKeyChange(object sender, EntityEventArgs uncast) + { + var cast = (BoundKeyChangeEventArgs)uncast; + if (cast.Actor != Owner || cast.KeyFunction != BoundKeyFunctions.SwitchHands || cast.KeyState != BoundKeyState.Down) + { + return; + } + + var index = orderedHands.FindIndex(x => x == ActiveIndex); + index++; + if (index >= orderedHands.Count) + { + index = 0; + } + + ActiveIndex = orderedHands[index]; + } } } diff --git a/Resources/Prototypes/Entities/Mobs.yml b/Resources/Prototypes/Entities/Mobs.yml new file mode 100644 index 0000000000..6e829fec7e --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs.yml @@ -0,0 +1,10 @@ +- type: entity + name: Urist McHands + id: HumanMob_Content + parent: HumanMob + components: + - type: Hands + hands: + - left + - right + - type: Inventory diff --git a/Resources/Prototypes/Entities/hands.yml b/Resources/Prototypes/Entities/hands.yml deleted file mode 100644 index 4879b96150..0000000000 --- a/Resources/Prototypes/Entities/hands.yml +++ /dev/null @@ -1,14 +0,0 @@ -- type: entity - name: IT HAS HANDS - id: thing_with_hands - components: - - type: Transform - - type: Hands - hands: - - left - - right - - type: Inventory - slots: - - head - - shoes - - uniform From c7de99418304bd14af310bab826680a7508ca22a Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 30 Sep 2017 12:17:45 +0200 Subject: [PATCH 11/12] Item pickup seems to work, crash due to netcode. --- .../Components/Items/HandsComponent.cs | 48 ++++++++++++++++++- Resources/Prototypes/Entities/Items.yml | 7 +++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 Resources/Prototypes/Entities/Items.yml diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs index f384741ae1..f5f20970b9 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs @@ -1,6 +1,7 @@ -using Content.Server.Interfaces.GameObjects; +using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; using SS14.Server.GameObjects.Events; +using SS14.Server.Interfaces.GameObjects; using SS14.Shared; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; @@ -32,11 +33,16 @@ namespace Content.Server.GameObjects private Dictionary hands = new Dictionary(); private List orderedHands = new List(); private IInventoryComponent inventory; + private IServerTransformComponent transform; private YamlMappingNode tempParametersMapping; + // Mostly arbitrary. + public const float PICKUP_RANGE = 2; + public override void Initialize() { inventory = Owner.GetComponent(); + transform = Owner.GetComponent(); if (tempParametersMapping != null) { foreach (var node in tempParametersMapping.GetNode("hands")) @@ -46,12 +52,15 @@ namespace Content.Server.GameObjects } Owner.SubscribeEvent(OnKeyChange, this); + Owner.SubscribeEvent(OnClick, this); base.Initialize(); } public override void OnRemove() { inventory = null; + Owner.UnsubscribeEvent(this); + Owner.UnsubscribeEvent(this); base.OnRemove(); } @@ -165,6 +174,10 @@ namespace Content.Server.GameObjects var slot = inventory.AddSlot(HandSlotName(index)); hands[index] = slot; orderedHands.Add(index); + if (ActiveIndex == null) + { + ActiveIndex = index; + } } public void RemoveHand(string index) @@ -218,11 +231,24 @@ namespace Content.Server.GameObjects public void OnKeyChange(object sender, EntityEventArgs uncast) { var cast = (BoundKeyChangeEventArgs)uncast; - if (cast.Actor != Owner || cast.KeyFunction != BoundKeyFunctions.SwitchHands || cast.KeyState != BoundKeyState.Down) + if (cast.Actor != Owner || cast.KeyState != BoundKeyState.Down) { return; } + switch (cast.KeyFunction) + { + case BoundKeyFunctions.SwitchHands: + SwapHands(); + break; + case BoundKeyFunctions.Drop: + Drop(ActiveIndex); + break; + } + } + + private void SwapHands() + { var index = orderedHands.FindIndex(x => x == ActiveIndex); index++; if (index >= orderedHands.Count) @@ -232,5 +258,23 @@ namespace Content.Server.GameObjects ActiveIndex = orderedHands[index]; } + + public void OnClick(object sender, EntityEventArgs uncast) + { + var cast = (ClickedOnEntityEventArgs)uncast; + if (cast.MouseButton != MouseClickType.Left || Owner.EntityManager.GetEntity(cast.Clicker) != Owner) + { + return; + } + + var target = Owner.EntityManager.GetEntity(cast.Clicked); + var targetTransform = target.GetComponent(); + if (!target.TryGetComponent(out var item) || (targetTransform.WorldPosition - transform.WorldPosition).Length > PICKUP_RANGE) + { + return; + } + + PutInHand(item, ActiveIndex, fallback: false); + } } } diff --git a/Resources/Prototypes/Entities/Items.yml b/Resources/Prototypes/Entities/Items.yml new file mode 100644 index 0000000000..c531503e36 --- /dev/null +++ b/Resources/Prototypes/Entities/Items.yml @@ -0,0 +1,7 @@ +- type: entity + name: "Toolbox 2: Handle edition" + parent: Toolbox + id: ToolboxItem + components: + - type: Item + From 26e9c37be1b4b34f86682f26f0fb3deb6a8261e6 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 30 Sep 2017 16:56:19 +0200 Subject: [PATCH 12/12] Functional GUI! --- Content.Client/Content.Client.csproj | 9 +- ...dsComponent.cs => ClientHandsComponent.cs} | 23 ++- .../Components/Items/IHandsComponent.cs | 10 +- Content.Client/UserInterface/HandsGui.cs | 192 ++++++++++++++++++ Content.Server/Content.Server.csproj | 4 +- .../Components/Items/ItemComponent.cs | 13 +- ...dsComponent.cs => ServerHandsComponent.cs} | 21 +- Content.Shared/Content.Shared.csproj | 4 +- ...dsComponent.cs => SharedHandsComponent.cs} | 6 +- Resources/Prototypes/Entities/Items.yml | 7 + 10 files changed, 269 insertions(+), 20 deletions(-) rename Content.Client/GameObjects/Components/Items/{HandsComponent.cs => ClientHandsComponent.cs} (53%) create mode 100644 Content.Client/UserInterface/HandsGui.cs rename Content.Server/GameObjects/Components/Items/{HandsComponent.cs => ServerHandsComponent.cs} (93%) rename Content.Shared/GameObjects/Components/Items/{HandsComponent.cs => SharedHandsComponent.cs} (80%) diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 4927d2da9e..8dbc915a17 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -62,8 +62,9 @@ - + + @@ -82,6 +83,10 @@ {31d24303-f6a9-4d53-bb03-a73edcb3186d} sfml-system + + {d17de83d-a592-461f-8af2-53f9e22e1d0f} + sfml-window + {302b877e-0000-0000-0000-000000000000} SS14.Client.Graphics @@ -105,4 +110,4 @@ - + \ No newline at end of file diff --git a/Content.Client/GameObjects/Components/Items/HandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs similarity index 53% rename from Content.Client/GameObjects/Components/Items/HandsComponent.cs rename to Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs index 315b9aa7d2..3688198afe 100644 --- a/Content.Client/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs @@ -1,5 +1,10 @@ -using Content.Client.Interfaces.GameObjects; +using Content.Client.Interfaces.GameObjects; +using Content.Client.UserInterface; using Content.Shared.GameObjects; +using Lidgren.Network; +using SS14.Client.Interfaces.UserInterface; +using SS14.Client.UserInterface; +using SS14.Shared; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.IoC; @@ -10,6 +15,7 @@ namespace Content.Client.GameObjects public class HandsComponent : SharedHandsComponent, IHandsComponent { private readonly Dictionary hands = new Dictionary(); + public string ActiveIndex { get; private set; } public IEntity GetEntity(string index) { @@ -29,6 +35,21 @@ namespace Content.Client.GameObjects { hands[hand.Key] = Owner.EntityManager.GetEntity(hand.Value); } + + ActiveIndex = cast.ActiveIndex; + + var uiMgr = (UserInterfaceManager)IoCManager.Resolve(); + + if (uiMgr.GetSingleComponentByGuiComponentType(GuiComponentType.HandsUi) == null) + { + uiMgr.AddComponent(new HandsGui()); + } + uiMgr.ComponentUpdate(GuiComponentType.HandsUi, this); + } + + public void SendChangeHand(string index) + { + Owner.SendComponentNetworkMessage(this, NetDeliveryMethod.ReliableUnordered, index); } } } diff --git a/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 06a9f6c1c7..91002b3cc9 100644 --- a/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -1,9 +1,4 @@ -using Content.Client.Interfaces.GameObjects; -using Content.Shared.GameObjects; -using SS14.Shared.GameObjects; -using SS14.Shared.Interfaces.GameObjects; -using SS14.Shared.IoC; -using System.Collections.Generic; +using SS14.Shared.Interfaces.GameObjects; namespace Content.Client.Interfaces.GameObjects { @@ -12,5 +7,8 @@ namespace Content.Client.Interfaces.GameObjects public interface IHandsComponent { IEntity GetEntity(string index); + string ActiveIndex { get; } + + void SendChangeHand(string index); } } diff --git a/Content.Client/UserInterface/HandsGui.cs b/Content.Client/UserInterface/HandsGui.cs new file mode 100644 index 0000000000..92eb8be029 --- /dev/null +++ b/Content.Client/UserInterface/HandsGui.cs @@ -0,0 +1,192 @@ +using Content.Client.Interfaces.GameObjects; +using OpenTK.Graphics; +using SFML.Graphics; +using SFML.Window; +using SS14.Client.GameObjects; +using SS14.Client.Graphics; +using SS14.Client.Graphics.Utility; +using SS14.Client.Interfaces.Player; +using SS14.Client.Interfaces.Resource; +using SS14.Client.Interfaces.UserInterface; +using SS14.Client.UserInterface.Components; +using SS14.Shared; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.IoC; +using SS14.Shared.Maths; + +namespace Content.Client.UserInterface +{ + public class HandsGui : GuiComponent + { + private readonly Color4 _inactiveColor = new Color4(90, 90, 90, 255); + + private readonly IPlayerManager _playerManager = IoCManager.Resolve(); + private readonly IUserInterfaceManager _userInterfaceManager = IoCManager.Resolve(); + private readonly Sprite handSlot; + private readonly int spacing = 1; + + private UiHandInfo LeftHand; + private UiHandInfo RightHand; + private Box2i handL; + private Box2i handR; + + public HandsGui() + { + var _resMgr = IoCManager.Resolve(); + ComponentClass = GuiComponentType.HandsUi; + handSlot = _resMgr.GetSprite("hand"); + ZDepth = 5; + } + + public override void ComponentUpdate(params object[] args) + { + base.ComponentUpdate(args); + UpdateHandIcons(); + } + + public override void Update(float frameTime) + { + var slotBounds = handSlot.GetLocalBounds(); + var width = (int)((slotBounds.Width * 2) + spacing); + var height = (int)slotBounds.Height; + Position = new Vector2i((int)(CluwneLib.Window.Viewport.Width - width) / 2, (int)CluwneLib.Window.Viewport.Height - height - 10); + handL = Box2i.FromDimensions(Position.X, Position.Y, (int)slotBounds.Width, (int)slotBounds.Height); + handR = Box2i.FromDimensions(Position.X + (int)slotBounds.Width + spacing, Position.Y, (int)slotBounds.Width, (int)slotBounds.Height); + ClientArea = Box2i.FromDimensions(Position.X, Position.Y, width, (int)slotBounds.Height); + } + + public override void Render() + { + if (_playerManager?.ControlledEntity == null) + { + return; + } + + IEntity entity = _playerManager.ControlledEntity; + if (!entity.TryGetComponent(out var hands)) + { + return; + } + + var leftActive = hands.ActiveIndex == "left"; + + handSlot.Color = Color.White; + handSlot.SetTransformToRect(leftActive ? handL : handR); + handSlot.Draw(); + + handSlot.Color = _inactiveColor.Convert(); + handSlot.SetTransformToRect(leftActive ? handR : handL); + handSlot.Draw(); + + if (LeftHand.Entity != null && LeftHand.HeldSprite != null) + { + var bounds = LeftHand.HeldSprite.GetLocalBounds(); + LeftHand.HeldSprite.SetTransformToRect( + Box2i.FromDimensions(handL.Left + (int)(handL.Width / 2f - bounds.Width / 2f), + handL.Top + (int)(handL.Height / 2f - bounds.Height / 2f), + (int)bounds.Width, (int)bounds.Height)); + LeftHand.HeldSprite.Draw(); + } + + if (RightHand.Entity != null && RightHand.HeldSprite != null) + { + var bounds = RightHand.HeldSprite.GetLocalBounds(); + RightHand.HeldSprite.SetTransformToRect( + Box2i.FromDimensions(handR.Left + (int)(handR.Width / 2f - bounds.Width / 2f), + handR.Top + (int)(handR.Height / 2f - bounds.Height / 2f), + (int)bounds.Width, (int)bounds.Height)); + RightHand.HeldSprite.Draw(); + } + } + + public void UpdateHandIcons() + { + if (_playerManager?.ControlledEntity == null) + { + return; + } + + IEntity entity = _playerManager.ControlledEntity; + if (!entity.TryGetComponent(out var hands)) + { + return; + } + + var left = hands.GetEntity("left"); + var right = hands.GetEntity("right"); + + if (left != null) + { + if (left != LeftHand.Entity) + { + LeftHand.Entity = left; + LeftHand.HeldSprite = GetIconSprite(left); + } + } + else + { + LeftHand.Entity = null; + LeftHand.HeldSprite = null; + } + + if (right != null) + { + if (right != RightHand.Entity) + { + RightHand.Entity = right; + RightHand.HeldSprite = GetIconSprite(right); + } + } + else + { + RightHand.Entity = null; + RightHand.HeldSprite = null; + } + } + + private void SendSwitchHandTo(string index) + { + IEntity entity = _playerManager.ControlledEntity; + if (!entity.TryGetComponent(out var hands)) + { + return; + } + hands.SendChangeHand(index); + } + + public override bool MouseDown(MouseButtonEventArgs e) + { + if (e.Button != Mouse.Button.Right) + { + return false; + } + if (handL.Contains(e.X, e.Y)) + { + SendSwitchHandTo("left"); + return true; + } + if (handR.Contains(e.X, e.Y)) + { + SendSwitchHandTo("right"); + return true; + } + return false; + } + + private static Sprite GetIconSprite(IEntity entity) + { + Sprite icon = null; + if (entity.TryGetComponent(out var component)) + { + icon = component.Icon; + } + return icon ?? IoCManager.Resolve().DefaultSprite(); + } + + private struct UiHandInfo + { + public IEntity Entity { get; set; } + public Sprite HeldSprite { get; set; } + } + } +} diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index d2cdb12b80..da2735d7f1 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -59,7 +59,7 @@ - + @@ -91,4 +91,4 @@ - + \ No newline at end of file diff --git a/Content.Server/GameObjects/Components/Items/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/ItemComponent.cs index efebe59f4c..113fc2c6ef 100644 --- a/Content.Server/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ItemComponent.cs @@ -1,6 +1,7 @@ -using Content.Server.Interfaces.GameObjects; +using Content.Server.Interfaces.GameObjects; using SS14.Shared.GameObjects; using SS14.Shared.Interfaces.GameObjects; +using SS14.Server.Interfaces.GameObjects; using System; namespace Content.Server.GameObjects @@ -20,6 +21,11 @@ namespace Content.Server.GameObjects } ContainingSlot = null; + + foreach (var component in Owner.GetComponents()) + { + component.Visible = true; + } } public void EquippedToSlot(IInventorySlot slot) @@ -30,6 +36,11 @@ namespace Content.Server.GameObjects } ContainingSlot = slot; + + foreach (var component in Owner.GetComponents()) + { + component.Visible = false; + } } } } diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs similarity index 93% rename from Content.Server/GameObjects/Components/Items/HandsComponent.cs rename to Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs index f5f20970b9..e5ea4c9572 100644 --- a/Content.Server/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs @@ -4,12 +4,11 @@ using SS14.Server.GameObjects.Events; using SS14.Server.Interfaces.GameObjects; using SS14.Shared; using SS14.Shared.GameObjects; -using SS14.Shared.Interfaces.GameObjects; using SS14.Shared.Utility; -using System.Collections.Generic; using System; -using System.Linq; +using System.Collections.Generic; using YamlDotNet.RepresentationModel; +using Lidgren.Network; namespace Content.Server.GameObjects { @@ -224,7 +223,7 @@ namespace Content.Server.GameObjects dict[hand.Key] = hand.Value.Item.Owner.Uid; } } - return new HandsComponentState(dict); + return new HandsComponentState(dict, ActiveIndex); } // Game logic goes here. @@ -276,5 +275,19 @@ namespace Content.Server.GameObjects PutInHand(item, ActiveIndex, fallback: false); } + + public override void HandleNetworkMessage(IncomingEntityComponentMessage message, NetConnection sender) + { + if (message.MessageParameters.Count != 1) + { + return; + } + var index = message.MessageParameters[0]; + if (index is string newIndex && HasHand(newIndex)) + { + ActiveIndex = newIndex; + } + base.HandleNetworkMessage(message, sender); + } } } diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 7618413325..c200d1c88f 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -56,7 +56,7 @@ - + @@ -97,4 +97,4 @@ - + \ No newline at end of file diff --git a/Content.Shared/GameObjects/Components/Items/HandsComponent.cs b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs similarity index 80% rename from Content.Shared/GameObjects/Components/Items/HandsComponent.cs rename to Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs index bac1c58156..a6bd76d5d4 100644 --- a/Content.Shared/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs @@ -1,4 +1,4 @@ -using SS14.Shared.GameObjects; +using SS14.Shared.GameObjects; using System; using System.Collections.Generic; @@ -16,10 +16,12 @@ namespace Content.Shared.GameObjects public class HandsComponentState : ComponentState { public readonly Dictionary Hands; + public readonly string ActiveIndex; - public HandsComponentState(Dictionary hands) + public HandsComponentState(Dictionary hands, string activeIndex) : base(ContentNetIDs.HANDS) { Hands = hands; + ActiveIndex = activeIndex; } } } diff --git a/Resources/Prototypes/Entities/Items.yml b/Resources/Prototypes/Entities/Items.yml index c531503e36..28667c3eba 100644 --- a/Resources/Prototypes/Entities/Items.yml +++ b/Resources/Prototypes/Entities/Items.yml @@ -5,3 +5,10 @@ components: - type: Item +- type: entity + name: "Mop 2: Handle edition" + parent: Mop + id: MopItem + components: + - type: Item +