Files
OldThink/Content.Shared/Verbs/SharedVerbSystem.cs
Jabak 9f00d4b9aa Upstream (#148)
* Content changes for engine delta-state PR (#28134)

* Update GasTileOverlayState

* Update DecalGridState

* Update NavMapState

* poke

* poke2

* poke3

* Poke dem tests

* Update engine to v223.0.0 (#28239)

* Update RobustToolbox

* Improve InteractionSystem range & BUI checks (#27999)

* Improve InteractionSystem range & BUI checks

* Ghost fixes

* AAA

* Fix test

* fix nullable

* revert to broadcast event

* Fixes for eengine PR

* Ah buckle code

* )

* Update engine to v223.0.0

* Update engine to v223.1.0

* Update engine to v223.1.1

* Hotfix for crashes from bad item names (#28256)

* Fix weapon error logs (#28264)

* Update engine to v223.1.2 (#28273)

* Update RobustToolbox

* Update RobustToolbox

* Fix dud modular grenade visuals (#28265)

* Fix not networking whitelist and blacklist in storage component (#28238)

* fix id card console not updating records (#28237)

* fix id card console not updating records

* test

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>

* Remove the network tab (#28231)

It is useless and bloat, if a user needs to change these settings they are free to modify their cvars manually via the clientconfig.toml file or via the cvar command.

* antag objective issuing refactor (#28216)

* add AntagObjectives from GenericAntag

* add AntagRandomObjectives that traitor and thief can use

* make ObjectivesSystem use initial character name which AntagSelection passes

* make thief and traitor use AntagRandomObjectives

* remove now unused locale

* make sleeper agents rule use baseTraitorRule

* restore dragon rule oop

* bandaid for genericantag

* real

* typo

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>

* move nukie profile loading into its own rule (#28208)

* move profile loading out of nukeops rule

* make BaseNukeopsRule and use AntagLoadProfileRule

* untroll

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>

* fix antagSelect

* Objects ordered through cargo system shouldn't start anchored (#28115)

* Order normal space heater instead of anchored variant

* Make sure ordered objects don't spawn anchored

* Order space heater flatpack instead of a regular space heater

* Remove obsolete TODO

* Remove unnecessary name

---------

Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>

* Move PendingZombieComponent to Shared (#28143)

* Move PendingZombieComponent to Shared

* network me boy

---------

Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>

* Make it possible to hide full health bars below a total damage threshold (#28127)

* Make it possible to hide full health bars below a total damage threshold

* Fix not setting state

* Fix storage UI interactions (#28291)

* Fix storage UI interactions

* Add VV support

* Fix stripping not marking interactions as handled (#28292)

* Make NetworkConfigurator use BoundUserInterfaceCheckRangeEvent (#28293)

* Fix hypodarts not injecting with people that have ANY outerclothing (#28301)

Update darts.yml

* fix borg ui mispredict opening (#28305)

move borg ui junk to shared

* Add loadout group check (#28311)

Forgot to add it back in one of the rewrites.

* fix mirror server crashes (#28318)

* Remove bogus C# finalizers (#28315)

Begging people to learn how this programming language works before throwing random syntax into a file.

None of these finalizers ever worked. I also checked whether they were memory leaks and needed *proper* shutdown logic, but they're all instantiated-once UI controls that last for the entire lifetime of the program so it's probably fine.

* Cleans up some entity-related spawnmenu stuff (#28234)

* cleans up a lot of stuff in the spawnmenu

* skibidi dode

* spawners update

* Revert "spawners update"

This reverts commit bc27d9f556b29f6fb1f89cebbe0ac37e28319fd0.

* fix antag selection being evil (#28197)

* fix antag selection being evil

* fix test

* untroll the other tests

* remove role timer troll

* Allow tests to modify antag preferences

* Fix antag selection

* Misc test fixes

* Add AntagPreferenceTest

* Fix lazy mistakes

* Test cleanup

* Try stop players in lobbies from being assigned mid-round antags

* ranting

* I am going insane

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>

* Revert "fix mirror server crashes (#28318)"

This reverts commit bcb0e555b058a4049d0cdb32d64eaf86c35a67be.

* fix

* Update engine to 223.2.0 (#28329)

* Update RobustToolbox

* Update RobustToolbox

---------

Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: Vasilis <vasilis@pikachu.systems>
Co-authored-by: eoineoineoin <github@eoinrul.es>
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>
Co-authored-by: Ady4ik <141335742+Ady4ik@users.noreply.github.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
Co-authored-by: Kara <lunarautomaton6@gmail.com>
2024-10-22 20:47:03 +03:00

197 lines
8.6 KiB
C#

using Content.Shared.ActionBlocker;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Inventory.VirtualItem;
using Robust.Shared.Containers;
namespace Content.Shared.Verbs
{
public abstract class SharedVerbSystem : EntitySystem
{
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<ExecuteVerbEvent>(HandleExecuteVerb);
}
private void HandleExecuteVerb(ExecuteVerbEvent args, EntitySessionEventArgs eventArgs)
{
var user = eventArgs.SenderSession.AttachedEntity;
if (user == null)
return;
if (!TryGetEntity(args.Target, out var target))
return;
// It is possible that client-side prediction can cause this event to be raised after the target entity has
// been deleted. So we need to check that the entity still exists.
if (Deleted(user))
return;
// Get the list of verbs. This effectively also checks that the requested verb is in fact a valid verb that
// the user can perform.
var verbs = GetLocalVerbs(target.Value, user.Value, args.RequestedVerb.GetType());
// Note that GetLocalVerbs might waste time checking & preparing unrelated verbs even though we know
// precisely which one we want to run. However, MOST entities will only have 1 or 2 verbs of a given type.
// The one exception here is the "other" verb type, which has 3-4 verbs + all the debug verbs.
// Find the requested verb.
if (verbs.TryGetValue(args.RequestedVerb, out var verb))
ExecuteVerb(verb, user.Value, target.Value);
}
/// <summary>
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server.
/// </summary>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, Type type, bool force = false)
{
return GetLocalVerbs(target, user, new List<Type>() { type }, force);
}
/// <inheritdoc cref="GetLocalVerbs(Robust.Shared.GameObjects.EntityUid,Robust.Shared.GameObjects.EntityUid,System.Type,bool)"/>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types, bool force = false)
{
return GetLocalVerbs(target, user, types, out _, force);
}
/// <summary>
/// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This
/// does not request verbs from the server.
/// </summary>
public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type> types,
out List<VerbCategory> extraCategories, bool force = false)
{
SortedSet<Verb> verbs = new();
extraCategories = new();
// accessibility checks
var canAccess = force || _interactionSystem.InRangeAndAccessible(user, target);
// A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
// call ActionBlocker checks, just cache it for the verb request.
var canInteract = force || _actionBlockerSystem.CanInteract(user, target);
EntityUid? @using = null;
if (TryComp(user, out HandsComponent? hands) && (force || _actionBlockerSystem.CanUseHeldEntity(user)))
{
// if we don't actually have any hands, pass in a null value for the events.
if (hands.Count == 0)
{
hands = null;
}
else
{
@using = hands.ActiveHandEntity;
// Check whether the "Held" entity is a virtual pull entity. If yes, set that as the entity being "Used".
// This allows you to do things like buckle a dragged person onto a surgery table, without click-dragging
// their sprite.
if (TryComp(@using, out VirtualItemComponent? pull))
{
@using = pull.BlockingEntity;
}
}
}
// TODO: fix this garbage and use proper generics or reflection or something else, not this.
if (types.Contains(typeof(InteractionVerb)))
{
var verbEvent = new GetVerbsEvent<InteractionVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(UtilityVerb))
&& @using != null
&& @using != target)
{
var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(@using.Value, verbEvent, true); // directed at used, not at target
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(InnateVerb)))
{
var verbEvent = new GetVerbsEvent<InnateVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(user, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(AlternativeVerb)))
{
var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(ActivationVerb)))
{
var verbEvent = new GetVerbsEvent<ActivationVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(ExamineVerb)))
{
var verbEvent = new GetVerbsEvent<ExamineVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
// generic verbs
if (types.Contains(typeof(Verb)))
{
var verbEvent = new GetVerbsEvent<Verb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
RaiseLocalEvent(target, verbEvent, true);
verbs.UnionWith(verbEvent.Verbs);
}
if (types.Contains(typeof(EquipmentVerb)))
{
var access = canAccess || _interactionSystem.CanAccessEquipment(user, target);
var verbEvent = new GetVerbsEvent<EquipmentVerb>(user, target, @using, hands, canInteract, access, extraCategories);
RaiseLocalEvent(target, verbEvent);
verbs.UnionWith(verbEvent.Verbs);
}
return verbs;
}
/// <summary>
/// Execute the provided verb.
/// </summary>
/// <remarks>
/// This will try to call the action delegates and raise the local events for the given verb.
/// </remarks>
public virtual void ExecuteVerb(Verb verb, EntityUid user, EntityUid target, bool forced = false)
{
// invoke any relevant actions
verb.Act?.Invoke();
// Maybe raise a local event
if (verb.ExecutionEventArgs != null)
{
if (verb.EventTarget.IsValid())
RaiseLocalEvent(verb.EventTarget, verb.ExecutionEventArgs);
else
RaiseLocalEvent(verb.ExecutionEventArgs);
}
if (Deleted(user) || Deleted(target))
return;
// Perform any contact interactions
if (verb.DoContactInteraction ?? (verb.DefaultDoContactInteraction && _interactionSystem.InRangeUnobstructed(user, target)))
_interactionSystem.DoContactInteraction(user, target);
}
}
}