Actions System + UI (#2710)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
This commit is contained in:
70
Content.Shared/Actions/ActionManager.cs
Normal file
70
Content.Shared/Actions/ActionManager.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to all configured actions by action type.
|
||||
/// </summary>
|
||||
public class ActionManager
|
||||
{
|
||||
[Dependency]
|
||||
private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
private Dictionary<ActionType, ActionPrototype> _typeToAction;
|
||||
private Dictionary<ItemActionType, ItemActionPrototype> _typeToItemAction;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_typeToAction = new Dictionary<ActionType, ActionPrototype>();
|
||||
foreach (var action in _prototypeManager.EnumeratePrototypes<ActionPrototype>())
|
||||
{
|
||||
if (!_typeToAction.TryAdd(action.ActionType, action))
|
||||
{
|
||||
Logger.ErrorS("action",
|
||||
"Found action with duplicate actionType {0} - all actions must have" +
|
||||
" a unique actionType, this one will be skipped", action.ActionType);
|
||||
}
|
||||
}
|
||||
|
||||
_typeToItemAction = new Dictionary<ItemActionType, ItemActionPrototype>();
|
||||
foreach (var action in _prototypeManager.EnumeratePrototypes<ItemActionPrototype>())
|
||||
{
|
||||
if (!_typeToItemAction.TryAdd(action.ActionType, action))
|
||||
{
|
||||
Logger.ErrorS("action",
|
||||
"Found itemAction with duplicate actionType {0} - all actions must have" +
|
||||
" a unique actionType, this one will be skipped", action.ActionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns>all action prototypes of all types</returns>
|
||||
public IEnumerable<BaseActionPrototype> EnumerateActions()
|
||||
{
|
||||
return _typeToAction.Values.Concat<BaseActionPrototype>(_typeToItemAction.Values);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the action of the indicated type
|
||||
/// </summary>
|
||||
/// <returns>true if found</returns>
|
||||
public bool TryGet(ActionType actionType, out ActionPrototype action)
|
||||
{
|
||||
return _typeToAction.TryGetValue(actionType, out action);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the item action of the indicated type
|
||||
/// </summary>
|
||||
/// <returns>true if found</returns>
|
||||
public bool TryGet(ItemActionType actionType, out ItemActionPrototype action)
|
||||
{
|
||||
return _typeToItemAction.TryGetValue(actionType, out action);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Content.Shared/Actions/ActionPrototype.cs
Normal file
100
Content.Shared/Actions/ActionPrototype.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// An action which is granted directly to an entity (such as an innate ability
|
||||
/// or skill).
|
||||
/// </summary>
|
||||
[Prototype("action")]
|
||||
public class ActionPrototype : BaseActionPrototype
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of action, no 2 action prototypes should have the same one.
|
||||
/// </summary>
|
||||
public ActionType ActionType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IInstantAction that should be invoked when performing this
|
||||
/// action. Null if this is not an Instant ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public IInstantAction InstantAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IToggleAction that should be invoked when performing this
|
||||
/// action. Null if this is not a Toggle ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public IToggleAction ToggleAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ITargetEntityAction that should be invoked when performing this
|
||||
/// action. Null if this is not a TargetEntity ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public ITargetEntityAction TargetEntityAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ITargetPointAction that should be invoked when performing this
|
||||
/// action. Null if this is not a TargetPoint ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public ITargetPointAction TargetPointAction { get; private set; }
|
||||
|
||||
public override void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
base.LoadFrom(mapping);
|
||||
var serializer = YamlObjectSerializer.NewReader(mapping);
|
||||
|
||||
serializer.DataField(this, x => x.ActionType, "actionType", ActionType.Error);
|
||||
if (ActionType == ActionType.Error)
|
||||
{
|
||||
Logger.ErrorS("action", "missing or invalid actionType for action with name {0}", Name);
|
||||
}
|
||||
|
||||
// TODO: Split this class into server/client after RobustToolbox#1405
|
||||
if (IoCManager.Resolve<IModuleManager>().IsClientModule) return;
|
||||
|
||||
IActionBehavior behavior = null;
|
||||
serializer.DataField(ref behavior, "behavior", null);
|
||||
switch (behavior)
|
||||
{
|
||||
case null:
|
||||
BehaviorType = BehaviorType.None;
|
||||
Logger.ErrorS("action", "missing or invalid behavior for action with name {0}", Name);
|
||||
break;
|
||||
case IInstantAction instantAction:
|
||||
ValidateBehaviorType(BehaviorType.Instant, typeof(IInstantAction));
|
||||
BehaviorType = BehaviorType.Instant;
|
||||
InstantAction = instantAction;
|
||||
break;
|
||||
case IToggleAction toggleAction:
|
||||
ValidateBehaviorType(BehaviorType.Toggle, typeof(IToggleAction));
|
||||
BehaviorType = BehaviorType.Toggle;
|
||||
ToggleAction = toggleAction;
|
||||
break;
|
||||
case ITargetEntityAction targetEntity:
|
||||
ValidateBehaviorType(BehaviorType.TargetEntity, typeof(ITargetEntityAction));
|
||||
BehaviorType = BehaviorType.TargetEntity;
|
||||
TargetEntityAction = targetEntity;
|
||||
break;
|
||||
case ITargetPointAction targetPointAction:
|
||||
ValidateBehaviorType(BehaviorType.TargetPoint, typeof(ITargetPointAction));
|
||||
BehaviorType = BehaviorType.TargetPoint;
|
||||
TargetPointAction = targetPointAction;
|
||||
break;
|
||||
default:
|
||||
BehaviorType = BehaviorType.None;
|
||||
Logger.ErrorS("action", "unrecognized behavior type for action with name {0}", Name);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Content.Shared/Actions/ActionType.cs
Normal file
33
Content.Shared/Actions/ActionType.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Every possible action. Corresponds to actionType in action prototypes.
|
||||
/// </summary>
|
||||
public enum ActionType : byte
|
||||
{
|
||||
Error,
|
||||
HumanScream,
|
||||
DebugInstant,
|
||||
DebugToggle,
|
||||
DebugTargetPoint,
|
||||
DebugTargetPointRepeat,
|
||||
DebugTargetEntity,
|
||||
DebugTargetEntityRepeat
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Every possible item action. Corresponds to actionType in itemAction prototypes.
|
||||
/// </summary>
|
||||
public enum ItemActionType : byte
|
||||
{
|
||||
Error,
|
||||
ToggleInternals,
|
||||
ToggleLight,
|
||||
DebugInstant,
|
||||
DebugToggle,
|
||||
DebugTargetPoint,
|
||||
DebugTargetPointRepeat,
|
||||
DebugTargetEntity,
|
||||
DebugTargetEntityRepeat
|
||||
}
|
||||
}
|
||||
166
Content.Shared/Actions/BaseActionPrototype.cs
Normal file
166
Content.Shared/Actions/BaseActionPrototype.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for action prototypes.
|
||||
/// </summary>
|
||||
public abstract class BaseActionPrototype : IPrototype
|
||||
{
|
||||
/// <summary>
|
||||
/// Icon representing this action in the UI.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public SpriteSpecifier Icon { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// For toggle actions only, icon to show when toggled on. If omitted,
|
||||
/// the action will simply be highlighted when turned on.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public SpriteSpecifier IconOn { get; private set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Name to show in UI. Accepts formatting.
|
||||
/// </summary>
|
||||
public FormattedMessage Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description to show in UI. Accepts formatting.
|
||||
/// </summary>
|
||||
public FormattedMessage Description { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Requirements message to show in UI. Accepts formatting, but generally should be avoided
|
||||
/// so the requirements message isn't too prominent in the tooltip.
|
||||
/// </summary>
|
||||
public string Requires { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The type of behavior this action has. This is valid clientside and serverside.
|
||||
/// </summary>
|
||||
public BehaviorType BehaviorType { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// For targetpoint or targetentity actions, if this is true the action will remain
|
||||
/// selected after it is used, so it can be continuously re-used. If this is false,
|
||||
/// the action will be deselected after one use.
|
||||
/// </summary>
|
||||
public bool Repeat { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filters that can be used to filter this item in action menu.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Filters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Keywords that can be used to search this item in action menu.
|
||||
/// </summary>
|
||||
public IEnumerable<string> Keywords { get; private set; }
|
||||
|
||||
public virtual void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
var serializer = YamlObjectSerializer.NewReader(mapping);
|
||||
|
||||
serializer.DataReadFunction("name", string.Empty,
|
||||
s => Name = FormattedMessage.FromMarkup(s));
|
||||
serializer.DataReadFunction("description", string.Empty,
|
||||
s => Description = FormattedMessage.FromMarkup(s));
|
||||
|
||||
serializer.DataField(this, x => x.Requires,"requires", null);
|
||||
serializer.DataField(this, x => x.Icon,"icon", SpriteSpecifier.Invalid);
|
||||
serializer.DataField(this, x => x.IconOn,"iconOn", SpriteSpecifier.Invalid);
|
||||
|
||||
// client needs to know what type of behavior it is even if the actual implementation is only
|
||||
// on server side. If we wanted to avoid this we'd need to always add a shared or clientside interface
|
||||
// for each action even if there was only server-side logic, which would be cumbersome
|
||||
serializer.DataField(this, x => x.BehaviorType, "behaviorType", BehaviorType.None);
|
||||
if (BehaviorType == BehaviorType.None)
|
||||
{
|
||||
Logger.ErrorS("action", "Missing behaviorType for action with name {0}", Name);
|
||||
}
|
||||
|
||||
if (BehaviorType != BehaviorType.Toggle && IconOn != SpriteSpecifier.Invalid)
|
||||
{
|
||||
Logger.ErrorS("action", "for action {0}, iconOn was specified but behavior" +
|
||||
" type was {1}. iconOn is only supported for Toggle behavior type.", Name);
|
||||
}
|
||||
|
||||
serializer.DataField(this, x => x.Repeat, "repeat", false);
|
||||
if (Repeat && BehaviorType != BehaviorType.TargetEntity && BehaviorType != BehaviorType.TargetPoint)
|
||||
{
|
||||
Logger.ErrorS("action", " action named {0} used repeat: true, but this is only supported for" +
|
||||
" TargetEntity and TargetPoint behaviorType and its behaviorType is {1}",
|
||||
Name, BehaviorType);
|
||||
}
|
||||
|
||||
serializer.DataReadFunction("filters", new List<string>(),
|
||||
rawTags =>
|
||||
{
|
||||
Filters = rawTags.Select(rawTag => rawTag.Trim()).ToList();
|
||||
});
|
||||
|
||||
serializer.DataReadFunction("keywords", new List<string>(),
|
||||
rawTags =>
|
||||
{
|
||||
Keywords = rawTags.Select(rawTag => rawTag.Trim()).ToList();
|
||||
});
|
||||
}
|
||||
|
||||
protected void ValidateBehaviorType(BehaviorType expected, Type actualInterface)
|
||||
{
|
||||
if (BehaviorType != expected)
|
||||
{
|
||||
Logger.ErrorS("action", "for action named {0}, behavior implements " +
|
||||
"{1}, so behaviorType should be {2} but was {3}", Name, actualInterface.Name, expected, BehaviorType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The behavior / logic of the action. Each of these corresponds to a particular IActionBehavior
|
||||
/// (for actions) or IItemActionBehavior (for item actions)
|
||||
/// interface. Corresponds to action.behaviorType in YAML
|
||||
/// </summary>
|
||||
public enum BehaviorType
|
||||
{
|
||||
/// <summary>
|
||||
/// Action doesn't do anything.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// IInstantAction/IInstantItemAction. Action which does something immediately when used and has
|
||||
/// no target.
|
||||
/// </summary>
|
||||
Instant,
|
||||
|
||||
/// <summary>
|
||||
/// IToggleAction/IToggleItemAction Action which can be toggled on and off
|
||||
/// </summary>
|
||||
Toggle,
|
||||
|
||||
/// <summary>
|
||||
/// ITargetEntityAction/ITargetEntityItemAction. Action which is used on a targeted entity.
|
||||
/// </summary>
|
||||
TargetEntity,
|
||||
|
||||
/// <summary>
|
||||
/// ITargetPointAction/ITargetPointItemAction. Action which requires the user to select a target point, which
|
||||
/// does not necessarily have an entity on it.
|
||||
/// </summary>
|
||||
TargetPoint
|
||||
}
|
||||
}
|
||||
44
Content.Shared/Actions/IActionBehavior.cs
Normal file
44
Content.Shared/Actions/IActionBehavior.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently just a marker interface delineating the different possible
|
||||
/// types of action behaviors.
|
||||
/// </summary>
|
||||
public interface IActionBehavior : IExposeData { }
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all action event args
|
||||
/// </summary>
|
||||
public abstract class ActionEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity performing the action.
|
||||
/// </summary>
|
||||
public readonly IEntity Performer;
|
||||
/// <summary>
|
||||
/// Action being performed
|
||||
/// </summary>
|
||||
public readonly ActionType ActionType;
|
||||
/// <summary>
|
||||
/// Actions component of the performer.
|
||||
/// </summary>
|
||||
public readonly SharedActionsComponent PerformerActions;
|
||||
|
||||
public ActionEventArgs(IEntity performer, ActionType actionType)
|
||||
{
|
||||
Performer = performer;
|
||||
ActionType = actionType;
|
||||
if (!Performer.TryGetComponent(out PerformerActions))
|
||||
{
|
||||
throw new InvalidOperationException($"performer {performer.Name} tried to perform action {actionType} " +
|
||||
$" but the performer had no actions component," +
|
||||
" which should never occur");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Content.Shared/Actions/IInstantAction.cs
Normal file
27
Content.Shared/Actions/IInstantAction.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Action which does something immediately when used and has
|
||||
/// no target.
|
||||
/// </summary>
|
||||
public interface IInstantAction : IActionBehavior
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the instant action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoInstantAction(InstantActionEventArgs args);
|
||||
}
|
||||
|
||||
public class InstantActionEventArgs : ActionEventArgs
|
||||
{
|
||||
public InstantActionEventArgs(IEntity performer, ActionType actionType) : base(performer, actionType)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Content.Shared/Actions/IInstantItemAction.cs
Normal file
28
Content.Shared/Actions/IInstantItemAction.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Item action which does something immediately when used and has
|
||||
/// no target.
|
||||
/// </summary>
|
||||
public interface IInstantItemAction : IItemActionBehavior
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the instant action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoInstantAction(InstantItemActionEventArgs args);
|
||||
}
|
||||
|
||||
public class InstantItemActionEventArgs : ItemActionEventArgs
|
||||
{
|
||||
public InstantItemActionEventArgs(IEntity performer, IEntity item, ItemActionType actionType) :
|
||||
base(performer, item, actionType)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Content.Shared/Actions/IItemActionBehavior.cs
Normal file
52
Content.Shared/Actions/IItemActionBehavior.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently just a marker interface delineating the different possible
|
||||
/// types of item action behaviors.
|
||||
/// </summary>
|
||||
public interface IItemActionBehavior : IExposeData
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all item action event args
|
||||
/// </summary>
|
||||
public abstract class ItemActionEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity performing the action.
|
||||
/// </summary>
|
||||
public readonly IEntity Performer;
|
||||
/// <summary>
|
||||
/// Item being used to perform the action
|
||||
/// </summary>
|
||||
public readonly IEntity Item;
|
||||
/// <summary>
|
||||
/// Action being performed
|
||||
/// </summary>
|
||||
public readonly ItemActionType ActionType;
|
||||
/// <summary>
|
||||
/// Item actions component of the item.
|
||||
/// </summary>
|
||||
public readonly ItemActionsComponent ItemActions;
|
||||
|
||||
public ItemActionEventArgs(IEntity performer, IEntity item, ItemActionType actionType)
|
||||
{
|
||||
Performer = performer;
|
||||
ActionType = actionType;
|
||||
Item = item;
|
||||
if (!Item.TryGetComponent(out ItemActions))
|
||||
{
|
||||
throw new InvalidOperationException($"performer {performer.Name} tried to perform item action {actionType} " +
|
||||
$" for item {Item.Name} but the item had no ItemActionsComponent," +
|
||||
" which should never occur");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Content.Shared/Actions/ITargetEntityAction.cs
Normal file
33
Content.Shared/Actions/ITargetEntityAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Action which is used on a targeted entity.
|
||||
/// </summary>
|
||||
public interface ITargetEntityAction : IActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the target entity action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoTargetEntityAction(TargetEntityActionEventArgs args);
|
||||
}
|
||||
|
||||
public class TargetEntityActionEventArgs : ActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity being targeted
|
||||
/// </summary>
|
||||
public readonly IEntity Target;
|
||||
|
||||
public TargetEntityActionEventArgs(IEntity performer, ActionType actionType, IEntity target) :
|
||||
base(performer, actionType)
|
||||
{
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
Content.Shared/Actions/ITargetEntityItemAction.cs
Normal file
34
Content.Shared/Actions/ITargetEntityItemAction.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Item action which is used on a targeted entity.
|
||||
/// </summary>
|
||||
public interface ITargetEntityItemAction : IItemActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the target entity action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoTargetEntityAction(TargetEntityItemActionEventArgs args);
|
||||
}
|
||||
|
||||
public class TargetEntityItemActionEventArgs : ItemActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity being targeted
|
||||
/// </summary>
|
||||
public readonly IEntity Target;
|
||||
|
||||
public TargetEntityItemActionEventArgs(IEntity performer, IEntity target, IEntity item,
|
||||
ItemActionType actionType) : base(performer, item, actionType)
|
||||
{
|
||||
Target = target;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Content.Shared/Actions/ITargetPointAction.cs
Normal file
33
Content.Shared/Actions/ITargetPointAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Action which requires the user to select a target point, which
|
||||
/// does not necessarily have an entity on it.
|
||||
/// </summary>
|
||||
public interface ITargetPointAction : IActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the target point action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoTargetPointAction(TargetPointActionEventArgs args);
|
||||
}
|
||||
|
||||
public class TargetPointActionEventArgs : ActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Local coordinates of the targeted position.
|
||||
/// </summary>
|
||||
public readonly EntityCoordinates Target;
|
||||
|
||||
public TargetPointActionEventArgs(IEntity performer, EntityCoordinates target, ActionType actionType)
|
||||
: base(performer, actionType)
|
||||
{
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Content.Shared/Actions/ITargetPointItemAction.cs
Normal file
33
Content.Shared/Actions/ITargetPointItemAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Item action which requires the user to select a target point, which
|
||||
/// does not necessarily have an entity on it.
|
||||
/// </summary>
|
||||
public interface ITargetPointItemAction : IItemActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the target point action should be performed.
|
||||
/// Implementation should perform the server side logic of the action.
|
||||
/// </summary>
|
||||
void DoTargetPointAction(TargetPointItemActionEventArgs args);
|
||||
}
|
||||
|
||||
public class TargetPointItemActionEventArgs : ItemActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Local coordinates of the targeted position.
|
||||
/// </summary>
|
||||
public readonly EntityCoordinates Target;
|
||||
|
||||
public TargetPointItemActionEventArgs(IEntity performer, EntityCoordinates target, IEntity item,
|
||||
ItemActionType actionType) : base(performer, item, actionType)
|
||||
{
|
||||
Target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Content.Shared/Actions/IToggleAction.cs
Normal file
41
Content.Shared/Actions/IToggleAction.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Action which can be toggled on and off
|
||||
/// </summary>
|
||||
public interface IToggleAction : IActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the action will be toggled on/off.
|
||||
/// Implementation should perform the server side logic of whatever
|
||||
/// happens when it is toggled on / off.
|
||||
/// </summary>
|
||||
/// <returns>true if the attempt to toggle was successful, meaning the state should be toggled to the desired value.
|
||||
/// False to leave toggle status unchanged. This is NOT returning the new toggle status, it is only returning
|
||||
/// whether the attempt to toggle to the indicated status was successful.
|
||||
///
|
||||
/// Note that it's still okay if the implementation directly modifies toggle status via SharedActionsComponent,
|
||||
/// this is just an additional level of safety to ensure implementations will always
|
||||
/// explicitly indicate if the toggle status should be changed.</returns>
|
||||
bool DoToggleAction(ToggleActionEventArgs args);
|
||||
}
|
||||
|
||||
public class ToggleActionEventArgs : ActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// True if the toggle is attempting to be toggled on, false if attempting to toggle off
|
||||
/// </summary>
|
||||
public readonly bool ToggledOn;
|
||||
/// <summary>
|
||||
/// Opposite of ToggledOn
|
||||
/// </summary>
|
||||
public bool ToggledOff => !ToggledOn;
|
||||
|
||||
public ToggleActionEventArgs(IEntity performer, ActionType actionType, bool toggledOn) : base(performer, actionType)
|
||||
{
|
||||
ToggledOn = toggledOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Content.Shared/Actions/IToggleItemAction.cs
Normal file
42
Content.Shared/Actions/IToggleItemAction.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// Item action which can be toggled on and off
|
||||
/// </summary>
|
||||
public interface IToggleItemAction : IItemActionBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the action will be toggled on/off.
|
||||
/// Implementation should perform the server side logic of whatever
|
||||
/// happens when it is toggled on / off.
|
||||
/// </summary>
|
||||
/// <returns>true if the attempt to toggle was successful, meaning the state should be toggled to the desired value.
|
||||
/// False to leave toggle status unchanged. This is NOT returning the new toggle status, it is only returning
|
||||
/// whether the attempt to toggle to the indicated status was successful.
|
||||
///
|
||||
/// Note that it's still okay if the implementation directly modifies toggle status via ItemActionsComponent,
|
||||
/// this is just an additional level of safety to ensure implementations will always
|
||||
/// explicitly indicate if the toggle status should be changed.</returns>
|
||||
bool DoToggleAction(ToggleItemActionEventArgs args);
|
||||
}
|
||||
|
||||
public class ToggleItemActionEventArgs : ItemActionEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// True if the toggle was toggled on, false if it was toggled off
|
||||
/// </summary>
|
||||
public readonly bool ToggledOn;
|
||||
/// <summary>
|
||||
/// Opposite of ToggledOn
|
||||
/// </summary>
|
||||
public bool ToggledOff => !ToggledOn;
|
||||
|
||||
public ToggleItemActionEventArgs(IEntity performer, bool toggledOn, IEntity item,
|
||||
ItemActionType actionType) : base(performer, item, actionType)
|
||||
{
|
||||
ToggledOn = toggledOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
Content.Shared/Actions/ItemActionPrototype.cs
Normal file
122
Content.Shared/Actions/ItemActionPrototype.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Shared.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// An action which is granted to an entity via an item (such as toggling a flashlight).
|
||||
/// </summary>
|
||||
[Prototype("itemAction")]
|
||||
public class ItemActionPrototype : BaseActionPrototype
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of item action, no 2 itemAction prototypes should have the same one.
|
||||
/// </summary>
|
||||
public ItemActionType ActionType { get; private set; }
|
||||
|
||||
/// <see cref="ItemActionIconStyle"/>
|
||||
public ItemActionIconStyle IconStyle { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IInstantItemAction that should be invoked when performing this
|
||||
/// action. Null if this is not an Instant ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public IInstantItemAction InstantAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IToggleItemAction that should be invoked when performing this
|
||||
/// action. Null if this is not a Toggle ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public IToggleItemAction ToggleAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ITargetEntityItemAction that should be invoked when performing this
|
||||
/// action. Null if this is not a TargetEntity ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public ITargetEntityItemAction TargetEntityAction { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ITargetPointItemAction that should be invoked when performing this
|
||||
/// action. Null if this is not a TargetPoint ActionBehaviorType.
|
||||
/// Will be null on client side if the behavior is not in Content.Client.
|
||||
/// </summary>
|
||||
public ITargetPointItemAction TargetPointAction { get; private set; }
|
||||
|
||||
public override void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
base.LoadFrom(mapping);
|
||||
var serializer = YamlObjectSerializer.NewReader(mapping);
|
||||
|
||||
serializer.DataField(this, x => x.ActionType, "actionType", ItemActionType.Error);
|
||||
if (ActionType == ItemActionType.Error)
|
||||
{
|
||||
Logger.ErrorS("action", "missing or invalid actionType for action with name {0}", Name);
|
||||
}
|
||||
|
||||
serializer.DataField(this, x => x.IconStyle, "iconStyle", ItemActionIconStyle.BigItem);
|
||||
|
||||
// TODO: Split this class into server/client after RobustToolbox#1405
|
||||
if (IoCManager.Resolve<IModuleManager>().IsClientModule) return;
|
||||
|
||||
IItemActionBehavior behavior = null;
|
||||
serializer.DataField(ref behavior, "behavior", null);
|
||||
switch (behavior)
|
||||
{
|
||||
case null:
|
||||
BehaviorType = BehaviorType.None;
|
||||
Logger.ErrorS("action", "missing or invalid behavior for action with name {0}", Name);
|
||||
break;
|
||||
case IInstantItemAction instantAction:
|
||||
ValidateBehaviorType(BehaviorType.Instant, typeof(IInstantItemAction));
|
||||
BehaviorType = BehaviorType.Instant;
|
||||
InstantAction = instantAction;
|
||||
break;
|
||||
case IToggleItemAction toggleAction:
|
||||
ValidateBehaviorType(BehaviorType.Toggle, typeof(IToggleItemAction));
|
||||
BehaviorType = BehaviorType.Toggle;
|
||||
ToggleAction = toggleAction;
|
||||
break;
|
||||
case ITargetEntityItemAction targetEntity:
|
||||
ValidateBehaviorType(BehaviorType.TargetEntity, typeof(ITargetEntityItemAction));
|
||||
BehaviorType = BehaviorType.TargetEntity;
|
||||
TargetEntityAction = targetEntity;
|
||||
break;
|
||||
case ITargetPointItemAction targetPointAction:
|
||||
ValidateBehaviorType(BehaviorType.TargetPoint, typeof(ITargetPointItemAction));
|
||||
BehaviorType = BehaviorType.TargetPoint;
|
||||
TargetPointAction = targetPointAction;
|
||||
break;
|
||||
default:
|
||||
BehaviorType = BehaviorType.None;
|
||||
Logger.ErrorS("action", "unrecognized behavior type for action with name {0}", Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines how the action icon appears in the hotbar for item actions.
|
||||
/// </summary>
|
||||
public enum ItemActionIconStyle : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The default - the item icon will be big with a small action icon in the corner
|
||||
/// </summary>
|
||||
BigItem,
|
||||
/// <summary>
|
||||
/// The action icon will be big with a small item icon in the corner
|
||||
/// </summary>
|
||||
BigAction,
|
||||
/// <summary>
|
||||
/// BigAction but no item icon will be shown in the corner.
|
||||
/// </summary>
|
||||
NoItem
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user