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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user