Add EntityWorldTargetAction (#29819)

* Add EntityWorldTargetAction initial implementation

* Update obsolete methods

* Partially working EntityWorldTargetAction

* Fix entity selection

* Move and clean up AfterInteract

* Fix building new walls

* Readd no entity or coordinates error

* Consolidate action validation code

* Add summaries to component

---------

Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
This commit is contained in:
ShadowCommander
2024-08-08 02:47:08 -07:00
committed by GitHub
parent 489efeb717
commit 1df84515c7
7 changed files with 266 additions and 19 deletions

View File

@@ -38,10 +38,12 @@ public abstract class SharedActionsSystem : EntitySystem
SubscribeLocalEvent<InstantActionComponent, MapInitEvent>(OnActionMapInit);
SubscribeLocalEvent<EntityTargetActionComponent, MapInitEvent>(OnActionMapInit);
SubscribeLocalEvent<WorldTargetActionComponent, MapInitEvent>(OnActionMapInit);
SubscribeLocalEvent<EntityWorldTargetActionComponent, MapInitEvent>(OnActionMapInit);
SubscribeLocalEvent<InstantActionComponent, ComponentShutdown>(OnActionShutdown);
SubscribeLocalEvent<EntityTargetActionComponent, ComponentShutdown>(OnActionShutdown);
SubscribeLocalEvent<WorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
SubscribeLocalEvent<EntityWorldTargetActionComponent, ComponentShutdown>(OnActionShutdown);
SubscribeLocalEvent<ActionsComponent, DidEquipEvent>(OnDidEquip);
SubscribeLocalEvent<ActionsComponent, DidEquipHandEvent>(OnHandEquipped);
@@ -56,10 +58,12 @@ public abstract class SharedActionsSystem : EntitySystem
SubscribeLocalEvent<InstantActionComponent, ComponentGetState>(OnInstantGetState);
SubscribeLocalEvent<EntityTargetActionComponent, ComponentGetState>(OnEntityTargetGetState);
SubscribeLocalEvent<WorldTargetActionComponent, ComponentGetState>(OnWorldTargetGetState);
SubscribeLocalEvent<EntityWorldTargetActionComponent, ComponentGetState>(OnEntityWorldTargetGetState);
SubscribeLocalEvent<InstantActionComponent, GetActionDataEvent>(OnGetActionData);
SubscribeLocalEvent<EntityTargetActionComponent, GetActionDataEvent>(OnGetActionData);
SubscribeLocalEvent<WorldTargetActionComponent, GetActionDataEvent>(OnGetActionData);
SubscribeLocalEvent<EntityWorldTargetActionComponent, GetActionDataEvent>(OnGetActionData);
SubscribeAllEvent<RequestPerformActionEvent>(OnActionRequest);
}
@@ -102,6 +106,11 @@ public abstract class SharedActionsSystem : EntitySystem
args.State = new WorldTargetActionComponentState(component, EntityManager);
}
private void OnEntityWorldTargetGetState(EntityUid uid, EntityWorldTargetActionComponent component, ref ComponentGetState args)
{
args.State = new EntityWorldTargetActionComponentState(component, EntityManager);
}
private void OnGetActionData<T>(EntityUid uid, T component, ref GetActionDataEvent args) where T : BaseActionComponent
{
args.Action = component;
@@ -442,6 +451,34 @@ public abstract class SharedActionsSystem : EntitySystem
}
break;
case EntityWorldTargetActionComponent entityWorldAction:
{
var actionEntity = GetEntity(ev.EntityTarget);
var actionCoords = GetCoordinates(ev.EntityCoordinatesTarget);
if (actionEntity is null && actionCoords is null)
{
Log.Error($"Attempted to perform an entity-world-targeted action without an entity or world coordinates! Action: {name}");
return;
}
var entWorldAction = new Entity<EntityWorldTargetActionComponent>(actionEnt, entityWorldAction);
if (!ValidateEntityWorldTarget(user, actionEntity, actionCoords, entWorldAction))
return;
_adminLogger.Add(LogType.Action,
$"{ToPrettyString(user):user} is performing the {name:action} action (provided by {ToPrettyString(action.Container ?? user):provider}) targeted at {ToPrettyString(actionEntity):target} {actionCoords:target}.");
if (entityWorldAction.Event != null)
{
entityWorldAction.Event.Entity = actionEntity;
entityWorldAction.Event.Coords = actionCoords;
Dirty(actionEnt, entityWorldAction);
performEvent = entityWorldAction.Event;
}
break;
}
case InstantActionComponent instantAction:
if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, null))
return;
@@ -465,7 +502,14 @@ public abstract class SharedActionsSystem : EntitySystem
public bool ValidateEntityTarget(EntityUid user, EntityUid target, Entity<EntityTargetActionComponent> actionEnt)
{
if (!ValidateEntityTargetBase(user, target, actionEnt))
var comp = actionEnt.Comp;
if (!ValidateEntityTargetBase(user,
target,
comp.Whitelist,
comp.CheckCanInteract,
comp.CanTargetSelf,
comp.CheckCanAccess,
comp.Range))
return false;
var ev = new ValidateActionEntityTargetEvent(user, target);
@@ -473,21 +517,27 @@ public abstract class SharedActionsSystem : EntitySystem
return !ev.Cancelled;
}
private bool ValidateEntityTargetBase(EntityUid user, EntityUid target, EntityTargetActionComponent action)
private bool ValidateEntityTargetBase(EntityUid user,
EntityUid? targetEntity,
EntityWhitelist? whitelist,
bool checkCanInteract,
bool canTargetSelf,
bool checkCanAccess,
float range)
{
if (!target.IsValid() || Deleted(target))
if (targetEntity is not { } target || !target.IsValid() || Deleted(target))
return false;
if (_whitelistSystem.IsWhitelistFail(action.Whitelist, target))
if (_whitelistSystem.IsWhitelistFail(whitelist, target))
return false;
if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, target))
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target))
return false;
if (user == target)
return action.CanTargetSelf;
return canTargetSelf;
if (!action.CheckCanAccess)
if (!checkCanAccess)
{
// even if we don't check for obstructions, we may still need to check the range.
var xform = Transform(user);
@@ -496,19 +546,20 @@ public abstract class SharedActionsSystem : EntitySystem
if (xform.MapID != targetXform.MapID)
return false;
if (action.Range <= 0)
if (range <= 0)
return true;
var distance = (_transformSystem.GetWorldPosition(xform) - _transformSystem.GetWorldPosition(targetXform)).Length();
return distance <= action.Range;
return distance <= range;
}
return _interactionSystem.InRangeAndAccessible(user, target, range: action.Range);
return _interactionSystem.InRangeAndAccessible(user, target, range: range);
}
public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, Entity<WorldTargetActionComponent> action)
{
if (!ValidateWorldTargetBase(user, coords, action))
var comp = action.Comp;
if (!ValidateWorldTargetBase(user, coords, comp.CheckCanInteract, comp.CheckCanAccess, comp.Range))
return false;
var ev = new ValidateActionWorldTargetEvent(user, coords);
@@ -516,12 +567,19 @@ public abstract class SharedActionsSystem : EntitySystem
return !ev.Cancelled;
}
private bool ValidateWorldTargetBase(EntityUid user, EntityCoordinates coords, WorldTargetActionComponent action)
private bool ValidateWorldTargetBase(EntityUid user,
EntityCoordinates? entityCoordinates,
bool checkCanInteract,
bool checkCanAccess,
float range)
{
if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, null))
if (entityCoordinates is not { } coords)
return false;
if (!action.CheckCanAccess)
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, null))
return false;
if (!checkCanAccess)
{
// even if we don't check for obstructions, we may still need to check the range.
var xform = Transform(user);
@@ -529,13 +587,40 @@ public abstract class SharedActionsSystem : EntitySystem
if (xform.MapID != coords.GetMapId(EntityManager))
return false;
if (action.Range <= 0)
if (range <= 0)
return true;
return _transformSystem.InRange(coords, Transform(user).Coordinates, action.Range);
return coords.InRange(EntityManager, _transformSystem, Transform(user).Coordinates, range);
}
return _interactionSystem.InRangeUnobstructed(user, coords, range: action.Range);
return _interactionSystem.InRangeUnobstructed(user, coords, range: range);
}
public bool ValidateEntityWorldTarget(EntityUid user,
EntityUid? entity,
EntityCoordinates? coords,
Entity<EntityWorldTargetActionComponent> action)
{
var comp = action.Comp;
var entityValidated = ValidateEntityTargetBase(user,
entity,
comp.Whitelist,
comp.CheckCanInteract,
comp.CanTargetSelf,
comp.CheckCanAccess,
comp.Range);
var worldValidated
= ValidateWorldTargetBase(user, coords, comp.CheckCanInteract, comp.CheckCanAccess, comp.Range);
if (!entityValidated && !worldValidated)
return false;
var ev = new ValidateActionEntityWorldTargetEvent(user,
entityValidated ? entity : null,
worldValidated ? coords : null);
RaiseLocalEvent(action, ref ev);
return !ev.Cancelled;
}
public void PerformAction(EntityUid performer, ActionsComponent? component, EntityUid actionId, BaseActionComponent action, BaseActionEvent? actionEvent, TimeSpan curTime, bool predicted = true)