Interaction rework.

IActivate is now more used. IAttackHand falls back to IActivate.
This commit is contained in:
Pieter-Jan Briers
2019-05-16 15:51:26 +02:00
parent 1a5c4ad83c
commit c197278c6f
8 changed files with 200 additions and 175 deletions

View File

@@ -88,6 +88,7 @@ namespace Content.Server
factory.Register<DestructibleComponent>(); factory.Register<DestructibleComponent>();
factory.Register<TemperatureComponent>(); factory.Register<TemperatureComponent>();
factory.Register<ServerDoorComponent>(); factory.Register<ServerDoorComponent>();
factory.RegisterReference<ServerDoorComponent, IActivate>();
//Power Components //Power Components
factory.Register<PowerTransferComponent>(); factory.Register<PowerTransferComponent>();
@@ -127,6 +128,7 @@ namespace Content.Server
factory.RegisterReference<ServerStorageComponent, IActivate>(); factory.RegisterReference<ServerStorageComponent, IActivate>();
factory.Register<EntityStorageComponent>(); factory.Register<EntityStorageComponent>();
factory.RegisterReference<EntityStorageComponent, IStorageComponent>(); factory.RegisterReference<EntityStorageComponent, IStorageComponent>();
factory.RegisterReference<EntityStorageComponent, IActivate>();
factory.Register<ToolLockerFillComponent>(); factory.Register<ToolLockerFillComponent>();
factory.Register<ToolboxElectricalFillComponent>(); factory.Register<ToolboxElectricalFillComponent>();
@@ -135,6 +137,7 @@ namespace Content.Server
factory.Register<PoweredLightComponent>(); factory.Register<PoweredLightComponent>();
factory.Register<SmesComponent>(); factory.Register<SmesComponent>();
factory.Register<ApcComponent>(); factory.Register<ApcComponent>();
factory.RegisterReference<ApcComponent, IActivate>();
factory.Register<MaterialComponent>(); factory.Register<MaterialComponent>();
factory.Register<StackComponent>(); factory.Register<StackComponent>();
factory.Register<MaterialStorageComponent>(); factory.Register<MaterialStorageComponent>();
@@ -152,6 +155,7 @@ namespace Content.Server
factory.RegisterReference<SpawnPointComponent, SharedSpawnPointComponent>(); factory.RegisterReference<SpawnPointComponent, SharedSpawnPointComponent>();
factory.Register<LatheComponent>(); factory.Register<LatheComponent>();
factory.RegisterReference<LatheComponent, IActivate>();
factory.Register<LatheDatabaseComponent>(); factory.Register<LatheDatabaseComponent>();
factory.RegisterReference<LatheDatabaseComponent, SharedLatheDatabaseComponent>(); factory.RegisterReference<LatheDatabaseComponent, SharedLatheDatabaseComponent>();

View File

@@ -44,7 +44,7 @@ namespace Content.Server.GameObjects.Components.Construction
var prototype = _prototypeManager.Index<ConstructionPrototype>(prototypeName); var prototype = _prototypeManager.Index<ConstructionPrototype>(prototypeName);
var transform = Owner.Transform; var transform = Owner.Transform;
if (!loc.InRange(_mapManager, transform.GridPosition, InteractionSystem.INTERACTION_RANGE)) if (!loc.InRange(_mapManager, transform.GridPosition, InteractionSystem.InteractionRange))
{ {
return; return;
} }

View File

@@ -10,7 +10,7 @@ using Robust.Shared.Timers;
namespace Content.Server.GameObjects namespace Content.Server.GameObjects
{ {
public class ServerDoorComponent : Component, IAttackHand public class ServerDoorComponent : Component, IActivate
{ {
public override string Name => "Door"; public override string Name => "Door";
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects
base.OnRemove(); base.OnRemove();
} }
public bool AttackHand(AttackHandEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (_state == DoorState.Open) if (_state == DoorState.Open)
{ {
@@ -51,7 +51,6 @@ namespace Content.Server.GameObjects
{ {
Open(); Open();
} }
return true;
} }
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)

View File

@@ -14,7 +14,7 @@ using Robust.Server.GameObjects;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
public class EntityStorageComponent : Component, IAttackHand, IStorageComponent public class EntityStorageComponent : Component, IActivate, IStorageComponent
{ {
public override string Name => "EntityStorage"; public override string Name => "EntityStorage";
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components
[ViewVariables] [ViewVariables]
public bool Open { get; private set; } public bool Open { get; private set; }
public bool AttackHand(AttackHandEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (Open) if (Open)
{ {
@@ -51,7 +51,6 @@ namespace Content.Server.GameObjects.Components
{ {
OpenStorage(); OpenStorage();
} }
return true;
} }
private void CloseStorage() private void CloseStorage()

View File

@@ -12,7 +12,7 @@ using Robust.Shared.IoC;
namespace Content.Server.GameObjects.Components.Power namespace Content.Server.GameObjects.Components.Power
{ {
public sealed class ApcComponent : SharedApcComponent, IAttackHand public sealed class ApcComponent : SharedApcComponent, IActivate
{ {
PowerStorageComponent Storage; PowerStorageComponent Storage;
AppearanceComponent Appearance; AppearanceComponent Appearance;
@@ -106,15 +106,14 @@ namespace Content.Server.GameObjects.Components.Power
return net.Lack > 0 ? ApcExternalPowerState.Low : ApcExternalPowerState.Good; return net.Lack > 0 ? ApcExternalPowerState.Low : ApcExternalPowerState.Good;
} }
bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
{ {
return false; return;
} }
_userInterface.Open(actor.playerSession); _userInterface.Open(actor.playerSession);
return true;
} }
private void _clickSound() private void _clickSound()

View File

@@ -15,7 +15,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Research namespace Content.Server.GameObjects.Components.Research
{ {
public class LatheComponent : SharedLatheComponent, IAttackHand, IAttackBy, IActivate public class LatheComponent : SharedLatheComponent, IAttackBy, IActivate
{ {
public const int VolumePerSheet = 3750; public const int VolumePerSheet = 3750;
@@ -94,17 +94,6 @@ namespace Content.Server.GameObjects.Components.Research
_userInterface.Open(actor.playerSession); _userInterface.Open(actor.playerSession);
return; return;
} }
bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs)
{
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
return false;
_userInterface.Open(actor.playerSession);
return true;
}
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) bool IAttackBy.AttackBy(AttackByEventArgs eventArgs)
{ {
if (!Owner.TryGetComponent(out MaterialStorageComponent storage) if (!Owner.TryGetComponent(out MaterialStorageComponent storage)

View File

@@ -1,19 +1,19 @@
using System; using System;
using Content.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.Input; using Content.Shared.Input;
using Robust.Shared.Input; using JetBrains.Annotations;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Server.GameObjects.EntitySystems; using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Input;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Players; using Robust.Shared.Players;
namespace Content.Server.GameObjects.EntitySystems namespace Content.Server.GameObjects.EntitySystems
@@ -26,9 +26,6 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when using one object on another /// Called when using one object on another
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="attackwith"></param>
/// <returns></returns>
bool AttackBy(AttackByEventArgs eventArgs); bool AttackBy(AttackByEventArgs eventArgs);
} }
@@ -47,8 +44,6 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when a player directly interacts with an empty hand /// Called when a player directly interacts with an empty hand
/// </summary> /// </summary>
/// <param name="user"></param>
/// <returns></returns>
bool AttackHand(AttackHandEventArgs eventArgs); bool AttackHand(AttackHandEventArgs eventArgs);
} }
@@ -65,13 +60,11 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when we try to interact with an entity out of range /// Called when we try to interact with an entity out of range
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="attackwith"></param>
/// <param name="clicklocation"></param>
/// <returns></returns> /// <returns></returns>
bool RangedAttackBy(RangedAttackByEventArgs eventArgs); bool RangedAttackBy(RangedAttackByEventArgs eventArgs);
} }
[PublicAPI]
public class RangedAttackByEventArgs : EventArgs public class RangedAttackByEventArgs : EventArgs
{ {
public IEntity User { get; set; } public IEntity User { get; set; }
@@ -88,9 +81,6 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior /// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="clicklocation"></param>
/// <param name="attacked">The entity that was clicked on out of range. May be null if no entity was clicked on.true</param>
void AfterAttack(AfterAttackEventArgs eventArgs); void AfterAttack(AfterAttackEventArgs eventArgs);
} }
@@ -109,7 +99,6 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when we activate an object we are holding to use it /// Called when we activate an object we are holding to use it
/// </summary> /// </summary>
/// <param name="user"></param>
/// <returns></returns> /// <returns></returns>
bool UseEntity(UseEntityEventArgs eventArgs); bool UseEntity(UseEntityEventArgs eventArgs);
} }
@@ -127,7 +116,6 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Called when this component is activated by another entity. /// Called when this component is activated by another entity.
/// </summary> /// </summary>
/// <param name="user">Entity that activated this component.</param>
void Activate(ActivateEventArgs eventArgs); void Activate(ActivateEventArgs eventArgs);
} }
@@ -139,50 +127,66 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Governs interactions during clicking on entities /// Governs interactions during clicking on entities
/// </summary> /// </summary>
public class InteractionSystem : EntitySystem [UsedImplicitly]
public sealed class InteractionSystem : EntitySystem
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IMapManager _mapManager;
#pragma warning restore 649 #pragma warning restore 649
public const float INTERACTION_RANGE = 2; public const float InteractionRange = 2;
public const float INTERACTION_RANGE_SQUARED = INTERACTION_RANGE * INTERACTION_RANGE; public const float InteractionRangeSquared = InteractionRange * InteractionRange;
public override void Initialize() public override void Initialize()
{ {
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>(); var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
inputSys.BindMap.BindFunction(ContentKeyFunctions.UseItemInHand, new PointerInputCmdHandler(HandleUseItemInHand)); inputSys.BindMap.BindFunction(ContentKeyFunctions.UseItemInHand,
inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld, new PointerInputCmdHandler((HandleUseItemInWorld))); new PointerInputCmdHandler(HandleUseItemInHand));
inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld,
new PointerInputCmdHandler((HandleActivateItemInWorld)));
} }
private void HandleUseItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid) public void HandleActivateItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid)
{ {
if(!EntityManager.TryGetEntity(uid, out var used)) if (!EntityManager.TryGetEntity(uid, out var used))
return; return;
var playerEnt = ((IPlayerSession) session).AttachedEntity; var playerEnt = ((IPlayerSession) session).AttachedEntity;
if(playerEnt == null || !playerEnt.IsValid()) if (playerEnt == null || !playerEnt.IsValid())
{
return; return;
}
if (!playerEnt.Transform.GridPosition.InRange(_mapManager, used.Transform.GridPosition, INTERACTION_RANGE)) if (!playerEnt.Transform.GridPosition.InRange(_mapManager, used.Transform.GridPosition, InteractionRange))
{
return; return;
}
var activateMsg = new ActivateInWorldMessage(playerEnt, used); InteractionActivate(playerEnt, used);
}
private void InteractionActivate(IEntity user, IEntity used)
{
var activateMsg = new ActivateInWorldMessage(user, used);
RaiseEvent(activateMsg); RaiseEvent(activateMsg);
if(activateMsg.Handled) if (activateMsg.Handled)
{
return; return;
}
if (!used.TryGetComponent(out IActivate activateComp)) if (!used.TryGetComponent(out IActivate activateComp))
{
return; return;
}
activateComp.Activate(new ActivateEventArgs { User = playerEnt }); activateComp.Activate(new ActivateEventArgs {User = user});
} }
private void HandleUseItemInHand(ICommonSession session, GridCoordinates coords, EntityUid uid) private void HandleUseItemInHand(ICommonSession session, GridCoordinates coords, EntityUid uid)
{ {
// client sanitization // client sanitization
if(!_mapManager.GridExists(coords.GridID)) if (!_mapManager.GridExists(coords.GridID))
{ {
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}"); Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
return; return;
@@ -190,32 +194,37 @@ namespace Content.Server.GameObjects.EntitySystems
if (uid.IsClientSide()) if (uid.IsClientSide())
{ {
Logger.WarningS("system.interaction", $"Client sent interaction with client-side entity. Session={session}, Uid={uid}"); Logger.WarningS("system.interaction",
$"Client sent interaction with client-side entity. Session={session}, Uid={uid}");
return; return;
} }
UserInteraction(((IPlayerSession)session).AttachedEntity, coords, uid); UserInteraction(((IPlayerSession) session).AttachedEntity, coords, uid);
} }
private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid) private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
{ {
//Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null // Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
if (!EntityManager.TryGetEntity(clickedUid, out var attacked)) if (!EntityManager.TryGetEntity(clickedUid, out var attacked))
{
attacked = null; attacked = null;
}
//Verify player has a transform component // Verify player has a transform component
if (!player.TryGetComponent<ITransformComponent>(out var playerTransform)) if (!player.TryGetComponent<ITransformComponent>(out var playerTransform))
{ {
return; return;
} }
//Verify player is on the same map as the entity he clicked on
else if (_mapManager.GetGrid(coordinates.GridID).ParentMap.Index != playerTransform.MapID) // Verify player is on the same map as the entity he clicked on
if (_mapManager.GetGrid(coordinates.GridID).ParentMap.Index != playerTransform.MapID)
{ {
Logger.Warning(string.Format("Player named {0} clicked on a map he isn't located on", player.Name)); Logger.WarningS("system.interaction",
$"Player named {player.Name} clicked on a map he isn't located on");
return; return;
} }
//Verify player has a hand, and find what object he is currently holding in his active hand // Verify player has a hand, and find what object he is currently holding in his active hand
if (!player.TryGetComponent<IHandsComponent>(out var hands)) if (!player.TryGetComponent<IHandsComponent>(out var hands))
{ {
return; return;
@@ -224,59 +233,64 @@ namespace Content.Server.GameObjects.EntitySystems
var item = hands.GetActiveHand?.Owner; var item = hands.GetActiveHand?.Owner;
if (!ActionBlockerSystem.CanInteract(player)) if (!ActionBlockerSystem.CanInteract(player))
return;
//TODO: Check if client should be able to see that object to click on it in the first place, prevent using locaters by firing a laser or something
//Clicked on empty space behavior, try using ranged attack
if (attacked == null && item != null)
{
//AFTERATTACK: Check if we clicked on an empty location, if so the only interaction we can do is afterattack
InteractAfterattack(player, item, coordinates);
return;
}
else if (attacked == null)
{ {
return; return;
} }
//Verify attacked object is on the map if we managed to click on it somehow // TODO: Check if client should be able to see that object to click on it in the first place
if (!attacked.GetComponent<ITransformComponent>().IsMapTransform)
{
Logger.Warning(string.Format("Player named {0} clicked on object {1} that isn't currently on the map somehow", player.Name, attacked.Name));
return;
}
//Check if ClickLocation is in object bounds here, if not lets log as warning and see why // Clicked on empty space behavior, try using ranged attack
if (attacked.TryGetComponent(out BoundingBoxComponent boundingbox)) if (attacked == null)
{ {
if (!boundingbox.WorldAABB.Contains(coordinates.Position)) if (item != null)
{ {
Logger.Warning(string.Format("Player {0} clicked {1} outside of its bounding box component somehow", player.Name, attacked.Name)); // After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterAttack
InteractAfterAttack(player, item, coordinates);
}
return;
}
// Verify attacked object is on the map if we managed to click on it somehow
if (!attacked.Transform.IsMapTransform)
{
Logger.WarningS("system.interaction",
$"Player named {player.Name} clicked on object {attacked.Name} that isn't currently on the map somehow");
return;
}
// Check if ClickLocation is in object bounds here, if not lets log as warning and see why
if (attacked.TryGetComponent(out BoundingBoxComponent boundingBox))
{
if (!boundingBox.WorldAABB.Contains(coordinates.Position))
{
Logger.WarningS("system.interaction",
$"Player {player.Name} clicked {attacked.Name} outside of its bounding box component somehow");
return; return;
} }
} }
//RANGEDATTACK/AFTERATTACK: Check distance between user and clicked item, if too large parse it in the ranged function // RangedAttack/AfterAttack: Check distance between user and clicked item, if too large parse it in the ranged function
//TODO: have range based upon the item being used? or base it upon some variables of the player himself? // TODO: have range based upon the item being used? or base it upon some variables of the player himself?
var distance = (playerTransform.WorldPosition - attacked.GetComponent<ITransformComponent>().WorldPosition).LengthSquared; var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared;
if (distance > INTERACTION_RANGE_SQUARED) if (distance > InteractionRangeSquared)
{ {
if (item != null) if (item != null)
{ {
RangedInteraction(player, item, attacked, coordinates); RangedInteraction(player, item, attacked, coordinates);
return; return;
} }
return; //Add some form of ranged attackhand here if you need it someday, or perhaps just ways to modify the range of attackhand
return; // Add some form of ranged AttackHand here if you need it someday, or perhaps just ways to modify the range of AttackHand
} }
//We are close to the nearby object and the object isn't contained in our active hand // We are close to the nearby object and the object isn't contained in our active hand
//ATTACKBY/AFTERATTACK: We will either use the item on the nearby object // AttackBy/AfterAttack: We will either use the item on the nearby object
if (item != null) if (item != null)
{ {
Interaction(player, item, attacked, coordinates); Interaction(player, item, attacked, coordinates);
} }
//ATTACKHAND: Since our hand is empty we will use attackhand // AttackHand/Activate: Since our hand is empty we will use AttackHand/Activate
else else
{ {
Interaction(player, attacked); Interaction(player, attacked);
@@ -284,90 +298,101 @@ namespace Content.Server.GameObjects.EntitySystems
} }
/// <summary> /// <summary>
/// We didn't click on any entity, try doing an afterattack on the click location /// We didn't click on any entity, try doing an AfterAttack on the click location
/// </summary> /// </summary>
/// <param name="user"></param> private void InteractAfterAttack(IEntity user, IEntity weapon, GridCoordinates clickLocation)
/// <param name="weapon"></param>
/// <param name="clicklocation"></param>
public void InteractAfterattack(IEntity user, IEntity weapon, GridCoordinates clicklocation)
{ {
var message = new AfterAttackMessage(user, weapon, null, clicklocation); var message = new AfterAttackMessage(user, weapon, null, clickLocation);
RaiseEvent(message); RaiseEvent(message);
if(message.Handled) if (message.Handled)
return;
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList();
for (var i = 0; i < afterattacks.Count; i++)
{ {
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clicklocation }); return;
}
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs {User = user, ClickLocation = clickLocation};
foreach (var afterAttack in afterAttacks)
{
afterAttack.AfterAttack(afterAttackEventArgs);
} }
} }
/// <summary> /// <summary>
/// Uses a weapon/object on an entity /// Uses a weapon/object on an entity
/// Finds interactable components with the Attackby interface and calls their function /// Finds components with the AttackBy interface and calls their function
/// </summary> /// </summary>
/// <param name="user"></param> public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
/// <param name="weapon"></param>
/// <param name="attacked"></param>
public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clicklocation)
{ {
var attackMsg = new AttackByMessage(user, weapon, attacked, clicklocation); var attackMsg = new AttackByMessage(user, weapon, attacked, clickLocation);
RaiseEvent(attackMsg); RaiseEvent(attackMsg);
if(attackMsg.Handled) if (attackMsg.Handled)
return;
List<IAttackBy> interactables = attacked.GetAllComponents<IAttackBy>().ToList();
for (var i = 0; i < interactables.Count; i++)
{ {
if (interactables[i].AttackBy(new AttackByEventArgs { User = user, ClickLocation = clicklocation, AttackWith = weapon })) //If an attackby returns a status completion we finish our attack return;
}
var attackBys = attacked.GetAllComponents<IAttackBy>().ToList();
var attackByEventArgs = new AttackByEventArgs
{
User = user, ClickLocation = clickLocation, AttackWith = weapon
};
foreach (var attackBy in attackBys)
{
if (attackBy.AttackBy(attackByEventArgs))
{ {
// If an AttackBy returns a status completion we finish our attack
return; return;
} }
} }
//Else check damage component to see if we damage if not attackby, and if so can we attack object var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clicklocation);
RaiseEvent(afterAtkMsg); RaiseEvent(afterAtkMsg);
if (afterAtkMsg.Handled) if (afterAtkMsg.Handled)
return;
//If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList();
for (var i = 0; i < afterattacks.Count; i++)
{ {
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clicklocation, Attacked = attacked }); return;
}
// If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs
{
User = user, ClickLocation = clickLocation, Attacked = attacked
};
foreach (var afterAttack in afterAttacks)
{
afterAttack.AfterAttack(afterAttackEventArgs);
} }
} }
/// <summary> /// <summary>
/// Uses an empty hand on an entity /// Uses an empty hand on an entity
/// Finds interactable components with the Attackhand interface and calls their function /// Finds components with the AttackHand interface and calls their function
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="attacked"></param>
public void Interaction(IEntity user, IEntity attacked) public void Interaction(IEntity user, IEntity attacked)
{ {
var message = new AttackHandMessage(user, attacked); var message = new AttackHandMessage(user, attacked);
RaiseEvent(message); RaiseEvent(message);
if(message.Handled) if (message.Handled)
return;
List<IAttackHand> interactables = attacked.GetAllComponents<IAttackHand>().ToList();
for (var i = 0; i < interactables.Count; i++)
{ {
if (interactables[i].AttackHand(new AttackHandEventArgs { User = user})) //If an attackby returns a status completion we finish our attack return;
}
var attackHands = attacked.GetAllComponents<IAttackHand>().ToList();
var attackHandEventArgs = new AttackHandEventArgs {User = user};
foreach (var attackHand in attackHands)
{
if (attackHand.AttackHand(attackHandEventArgs))
{ {
// If an AttackHand returns a status completion we finish our attack
return; return;
} }
} }
//Else check damage component to see if we damage if not attackby, and if so can we attack object // Else we run Activate.
InteractionActivate(user, attacked);
} }
/// <summary> /// <summary>
@@ -388,22 +413,23 @@ namespace Content.Server.GameObjects.EntitySystems
/// Activates/Uses an object in control/possession of a user /// Activates/Uses an object in control/possession of a user
/// If the item has the IUse interface on one of its components we use the object in our hand /// If the item has the IUse interface on one of its components we use the object in our hand
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="attacked"></param>
public void UseInteraction(IEntity user, IEntity used) public void UseInteraction(IEntity user, IEntity used)
{ {
var useMsg = new UseInHandMessage(user, used); var useMsg = new UseInHandMessage(user, used);
RaiseEvent(useMsg); RaiseEvent(useMsg);
if(useMsg.Handled) if (useMsg.Handled)
return;
List<IUse> usables = used.GetAllComponents<IUse>().ToList();
//Try to use item on any components which have the interface
for (var i = 0; i < usables.Count; i++)
{ {
if (usables[i].UseEntity(new UseEntityEventArgs { User = user })) //If an attackby returns a status completion we finish our attack return;
}
var uses = used.GetAllComponents<IUse>().ToList();
// Try to use item on any components which have the interface
foreach (var use in uses)
{
if (use.UseEntity(new UseEntityEventArgs {User = user}))
{ {
// If a Use returns a status completion we finish our attack
return; return;
} }
} }
@@ -413,41 +439,44 @@ namespace Content.Server.GameObjects.EntitySystems
/// Will have two behaviors, either "uses" the weapon at range on the entity if it is capable of accepting that action /// Will have two behaviors, either "uses" the weapon at range on the entity if it is capable of accepting that action
/// Or it will use the weapon itself on the position clicked, regardless of what was there /// Or it will use the weapon itself on the position clicked, regardless of what was there
/// </summary> /// </summary>
/// <param name="user"></param>
/// <param name="weapon"></param>
/// <param name="attacked"></param>
public void RangedInteraction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation) public void RangedInteraction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
{ {
var rangedMsg = new RangedAttackMessage(user, weapon, attacked, clickLocation); var rangedMsg = new RangedAttackMessage(user, weapon, attacked, clickLocation);
RaiseEvent(rangedMsg); RaiseEvent(rangedMsg);
if(rangedMsg.Handled) if (rangedMsg.Handled)
return; return;
List<IRangedAttackBy> rangedusables = attacked.GetAllComponents<IRangedAttackBy>().ToList(); var rangedAttackBys = attacked.GetAllComponents<IRangedAttackBy>().ToList();
var rangedAttackByEventArgs = new RangedAttackByEventArgs
//See if we have a ranged attack interaction
for (var i = 0; i < rangedusables.Count; i++)
{ {
if (rangedusables[i].RangedAttackBy(new RangedAttackByEventArgs { User = user, Weapon = weapon, ClickLocation = clickLocation })) //If an attackby returns a status completion we finish our attack User = user, Weapon = weapon, ClickLocation = clickLocation
};
// See if we have a ranged attack interaction
foreach (var t in rangedAttackBys)
{
if (t.RangedAttackBy(rangedAttackByEventArgs))
{ {
// If an AttackBy returns a status completion we finish our attack
return; return;
} }
} }
if (weapon != null) var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
RaiseEvent(afterAtkMsg);
if (afterAtkMsg.Handled)
return;
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
var afterAttackEventArgs = new AfterAttackEventArgs
{ {
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation); User = user, ClickLocation = clickLocation, Attacked = attacked
RaiseEvent(afterAtkMsg); };
if (afterAtkMsg.Handled)
return;
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList(); //See if we have a ranged attack interaction
foreach (var afterAttack in afterAttacks)
//See if we have a ranged attack interaction {
for (var i = 0; i < afterattacks.Count; i++) afterAttack.AfterAttack(afterAttackEventArgs);
{
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clickLocation, Attacked = attacked });
}
} }
} }
} }
@@ -455,6 +484,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when being clicked on or "attacked" by a user with an object in their hand /// Raised when being clicked on or "attacked" by a user with an object in their hand
/// </summary> /// </summary>
[PublicAPI]
public class AttackByMessage : EntitySystemMessage public class AttackByMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>
@@ -494,6 +524,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when being clicked on or "attacked" by a user with an empty hand. /// Raised when being clicked on or "attacked" by a user with an empty hand.
/// </summary> /// </summary>
[PublicAPI]
public class AttackHandMessage : EntitySystemMessage public class AttackHandMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>
@@ -521,6 +552,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when being clicked by objects outside the range of direct use. /// Raised when being clicked by objects outside the range of direct use.
/// </summary> /// </summary>
[PublicAPI]
public class RangedAttackMessage : EntitySystemMessage public class RangedAttackMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>
@@ -560,6 +592,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when clicking on another object and no attack event was handled. /// Raised when clicking on another object and no attack event was handled.
/// </summary> /// </summary>
[PublicAPI]
public class AfterAttackMessage : EntitySystemMessage public class AfterAttackMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>
@@ -599,6 +632,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when using the entity in your hands. /// Raised when using the entity in your hands.
/// </summary> /// </summary>
[PublicAPI]
public class UseInHandMessage : EntitySystemMessage public class UseInHandMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>
@@ -626,6 +660,7 @@ namespace Content.Server.GameObjects.EntitySystems
/// <summary> /// <summary>
/// Raised when an entity is activated in the world. /// Raised when an entity is activated in the world.
/// </summary> /// </summary>
[PublicAPI]
public class ActivateInWorldMessage : EntitySystemMessage public class ActivateInWorldMessage : EntitySystemMessage
{ {
/// <summary> /// <summary>

View File

@@ -81,7 +81,7 @@ namespace Content.Server.GameObjects.EntitySystems
continue; continue;
var distanceSquared = (storagePos - attachedEntity.Transform.WorldPosition).LengthSquared; var distanceSquared = (storagePos - attachedEntity.Transform.WorldPosition).LengthSquared;
if (distanceSquared > InteractionSystem.INTERACTION_RANGE_SQUARED) if (distanceSquared > InteractionSystem.InteractionRangeSquared)
{ {
storageComp.UnsubscribeSession(session); storageComp.UnsubscribeSession(session);
} }