From 7597cd917271d494dce302d0ce162ad8112950d3 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 6 Oct 2017 21:05:21 +0200 Subject: [PATCH] Interactable component system. (#9) * InteractableComponent v1. Broken edition * It works! --- Content.Client/EntryPoint.cs | 1 + Content.Server/Content.Server.csproj | 2 + Content.Server/EntryPoint.cs | 3 + .../Interactable/InteractableComponent.cs | 80 +++++++++++++++++++ .../Components/Items/ItemComponent.cs | 40 +++++++++- .../Components/Items/ServerHandsComponent.cs | 19 ----- .../Interactable/IInteractableComponent.cs | 48 +++++++++++ Resources/Prototypes/Entities/Items.yml | 3 +- 8 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Interactable/InteractableComponent.cs create mode 100644 Content.Server/Interfaces/GameObjects/Components/Interactable/IInteractableComponent.cs diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index cd7fc67701..438bb87a86 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -14,6 +14,7 @@ namespace Content.Client factory.RegisterIgnore("Inventory"); factory.RegisterIgnore("Item"); + factory.RegisterIgnore("Interactable"); factory.Register(); factory.RegisterReference(); diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index da2735d7f1..1ff7d0523d 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -56,6 +56,8 @@ + + diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index c8c527c982..2c9b03ec3b 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -20,6 +20,9 @@ namespace Content.Server factory.Register(); factory.RegisterReference(); + + factory.Register(); + factory.RegisterReference(); } } } diff --git a/Content.Server/GameObjects/Components/Interactable/InteractableComponent.cs b/Content.Server/GameObjects/Components/Interactable/InteractableComponent.cs new file mode 100644 index 0000000000..8a4c50cc19 --- /dev/null +++ b/Content.Server/GameObjects/Components/Interactable/InteractableComponent.cs @@ -0,0 +1,80 @@ +using Content.Server.Interfaces.GameObjects; +using SS14.Server.Interfaces.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects.Components; +using SS14.Shared.Log; +using System; + +namespace Content.Server.GameObjects +{ + public class InteractableComponent : Component, IInteractableComponent + { + public override string Name => "Interactable"; + + /// + public event EventHandler OnAttackHand; + + /// + public event EventHandler OnAttackBy; + + private IClickableComponent clickableComponent; + private IServerTransformComponent transform; + private const float INTERACTION_RANGE = 2; + private const float INTERACTION_RANGE_SQUARED = INTERACTION_RANGE * INTERACTION_RANGE; + + public override void Initialize() + { + transform = Owner.GetComponent(); + if (Owner.TryGetComponent(out var component)) + { + clickableComponent = component; + clickableComponent.OnClick += ClickableComponent_OnClick; + } + else + { + Logger.Error($"Interactable component must also have a clickable component to function! Prototype: {Owner.Prototype.ID}"); + } + base.Initialize(); + } + + public override void Shutdown() + { + if (clickableComponent != null) + { + clickableComponent.OnClick -= ClickableComponent_OnClick; + clickableComponent = null; + } + transform = null; + base.Shutdown(); + } + + private void ClickableComponent_OnClick(object sender, ClickEventArgs e) + { + if (!e.User.TryGetComponent(out var userTransform)) + { + return; + } + + var distance = (userTransform.WorldPosition - transform.WorldPosition).LengthSquared; + if (distance > INTERACTION_RANGE_SQUARED) + { + return; + } + + if (!e.User.TryGetComponent(out var hands)) + { + return; + } + + var item = hands.GetHand(hands.ActiveIndex); + if (item != null) + { + OnAttackBy?.Invoke(this, new AttackByEventArgs(Owner, e.User, item, hands.ActiveIndex)); + } + else + { + OnAttackHand?.Invoke(this, new AttackHandEventArgs(Owner, e.User, hands.ActiveIndex)); + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Items/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/ItemComponent.cs index 113fc2c6ef..af9980906d 100644 --- a/Content.Server/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ItemComponent.cs @@ -1,7 +1,8 @@ using Content.Server.Interfaces.GameObjects; -using SS14.Shared.GameObjects; -using SS14.Shared.Interfaces.GameObjects; using SS14.Server.Interfaces.GameObjects; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects.Components; +using SS14.Shared.Log; using System; namespace Content.Server.GameObjects @@ -12,6 +13,7 @@ namespace Content.Server.GameObjects /// public IInventorySlot ContainingSlot { get; private set; } + private IInteractableComponent interactableComponent; public void RemovedFromSlot() { @@ -42,5 +44,39 @@ namespace Content.Server.GameObjects component.Visible = false; } } + + public override void Initialize() + { + if (Owner.TryGetComponent(out var interactable)) + { + interactableComponent = interactable; + interactableComponent.OnAttackHand += InteractableComponent_OnAttackHand; + } + else + { + Logger.Error($"Item component must have an interactable component to function! Prototype: {Owner.Prototype.ID}"); + } + base.Initialize(); + } + + private void InteractableComponent_OnAttackHand(object sender, AttackHandEventArgs e) + { + if (ContainingSlot != null) + { + return; + } + var hands = e.User.GetComponent(); + hands.PutInHand(this, e.HandIndex, fallback: false); + } + + public override void Shutdown() + { + if (interactableComponent != null) + { + interactableComponent.OnAttackHand -= InteractableComponent_OnAttackHand; + interactableComponent = null; + } + base.Shutdown(); + } } } diff --git a/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs index e5ea4c9572..6c5e3b8447 100644 --- a/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/Items/ServerHandsComponent.cs @@ -51,7 +51,6 @@ namespace Content.Server.GameObjects } Owner.SubscribeEvent(OnKeyChange, this); - Owner.SubscribeEvent(OnClick, this); base.Initialize(); } @@ -258,24 +257,6 @@ 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); - } - public override void HandleNetworkMessage(IncomingEntityComponentMessage message, NetConnection sender) { if (message.MessageParameters.Count != 1) diff --git a/Content.Server/Interfaces/GameObjects/Components/Interactable/IInteractableComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Interactable/IInteractableComponent.cs new file mode 100644 index 0000000000..9c63dc4a0c --- /dev/null +++ b/Content.Server/Interfaces/GameObjects/Components/Interactable/IInteractableComponent.cs @@ -0,0 +1,48 @@ +using SS14.Shared.Interfaces.GameObjects; +using System; + +namespace Content.Server.Interfaces.GameObjects +{ + public interface IInteractableComponent : IComponent + { + /// + /// Invoked when an entity is clicked with an empty hand. + /// + event EventHandler OnAttackHand; + + /// + /// Invoked when an entity is clicked with an item. + /// + event EventHandler OnAttackBy; + } + + public class AttackByEventArgs : EventArgs + { + public readonly IEntity Target; + public readonly IEntity User; + public readonly IItemComponent Item; + public readonly string HandIndex; + + public AttackByEventArgs(IEntity target, IEntity user, IItemComponent item, string handIndex) + { + Target = target; + User = user; + Item = item; + HandIndex = handIndex; + } + } + + public class AttackHandEventArgs : EventArgs + { + public readonly IEntity Target; + public readonly IEntity User; + public readonly string HandIndex; + + public AttackHandEventArgs(IEntity target, IEntity user, string handIndex) + { + Target = target; + User = user; + HandIndex = handIndex; + } + } +} diff --git a/Resources/Prototypes/Entities/Items.yml b/Resources/Prototypes/Entities/Items.yml index 28667c3eba..56a416333d 100644 --- a/Resources/Prototypes/Entities/Items.yml +++ b/Resources/Prototypes/Entities/Items.yml @@ -4,6 +4,7 @@ id: ToolboxItem components: - type: Item + - type: Interactable - type: entity name: "Mop 2: Handle edition" @@ -11,4 +12,4 @@ id: MopItem components: - type: Item - + - type: Interactable