Skip to content

Targeting

Axwabo edited this page Apr 27, 2025 · 4 revisions

Targeting Commands

Targeting commands are executed on select players based on arguments.

The player list is obtained using RAUtils.ProcessPlayerIdOrNamesList (overwritten by Axwabo.CommandSystem.Patches.ProcessPlayersListPatch::ProcessPlayerIdOrNamesList)

See also: custom player selectors

Tip

If you'd like to use the LabAPI Player wrappers, invoke:

  • Player.Get if you only have one ReferenceHub
  • the ToPlayers extension methods to select each player per ReferenceHub from an IEnumerable (including List)
  • the ToPlayerList extension methods to collect ReferenceHub instances to a list

The extension methods can be found in Axwabo.CommandSystem.Extensions.ReferenceHubEnumerableExtensions

UnifiedTargetingCommand

Supplies the player list as an argument to execute the command.

A subclass of this type must override the method ExecuteOnTargets(List<ReferenceHub>, ArraySegment<string>, CommandSender)

Specifying the following members (which are used by SeparatedTargetingCommand) is possible by using attributes or resolvers: IAffectedMultiplePlayersMessageGenerator IAffectedAllPlayersMessageGenerator IAffectedOnePlayerMessageGenerator ITargetSelectionManager

Example:

using System;
using System.Collections.Generic;
using Axwabo.CommandSystem.Attributes;
using Axwabo.CommandSystem.Commands;
using Axwabo.CommandSystem.Extensions;
using CustomPlayerEffects;

[CommandProperties(CommandHandlerType.RemoteAdmin, "speed", "Grants an infinite speed boost of 20% to the specified players.")]
public sealed class SpeedCommand : UnifiedTargetingCommand
{

    protected override CommandResult ExecuteOnTargets(List<ReferenceHub> targets, ArraySegment<string> arguments, CommandSender sender)
    {
        foreach (var player in targets.ToPlayers())
            player.EnableEffect<MovementBoost>(20);
        return "Speed granted!";
    }

}

Override the OnNoTargetsFound(ArraySegment<string> originalArguments, ArraySegment<string> postParsingArguments, CommandSender sender) method to handle the case where no targets were found.

The default no targets found message can be overwritten by adding a Axwabo.CommandSystem.Attributes.Targeting.NoTargetsMessageAttribute

Execution Sequence

  1. CommandBase execution sequence
  2. A targeting pre-execution filter may intercept the execution here
  3. Check for at least one target
  4. MinArgumentsWithoutTargets new argument count is checked
  5. The targeting command's ExecuteOnTargets method is called

Pre execution filter

Implement the ITargetingPreExecutionFilter interface in the command class to add certain custom conditions before the command is executed. If the OnBeforeExecuted method returns CommandResult.Null, the execution sequence continues at step 3.

Caution

Returning null will be implicitly converted as a null string, leading to an exception. Use CommandResult.Null to allow execution to continue.

TargetSelectionManager

The ITargetSelectionManager can be implemented by the command class, an attribute or resolved

  • Method bool IsEveryoneAffected(int) should return whether all targets have been successfully processed

  • Inherits the interface IShouldAffectSpectators: property AffectSpectators determines whether spectators should be considered command targets

  • Inherits the interface ITargetFilteringPolicy: method bool FilterTarget(ReferenceHub) should return whether the player should be affected based on an extra condition

If the command implements the IShouldAffectSpectators interface, its AffectSpectators property is stored upon initialization. The default behavior is true but you can also change this using the Axwabo.CommandSystem.Attributes.Targeting.ShouldAffectSpectatorsAttribute

SeparatedTargetingCommand

Calls the same method per target. The results are combined into one.

A subclass of this type must override the ExecuteOn(ReferenceHub, ArraySegment<string>, CommandSender) method.

Example:

using System;
using Axwabo.CommandSystem.Attributes;
using Axwabo.CommandSystem.Attributes.Targeting;
using Axwabo.CommandSystem.Commands;
using InventorySystem;
using InventorySystem.Items;

[CommandProperties(CommandHandlerType.RemoteAdmin, "giveFlashlight")]
[ShouldAffectSpectators(false)] // don't target spectators
public sealed class GiveFlashlight : SeparatedTargetingCommand
{

    protected override CommandResult ExecuteOn(ReferenceHub target, ArraySegment<string> arguments, CommandSender sender)
    {
        // if the flashlight was not added, ServerAddItem returns null
        // ItemBase (UnityEngine.Object) is cast to a bool (false if null)
        // then, the bool is implicitly converted to a CommandResult
        return (bool) target.inventory.ServerAddItem(ItemType.Flashlight, ItemAddReason.AdminCommand);
    }

}

Combining Results

Default output examples:

  • None affected: No players were affected.
  • On 1 success: Done! The request affected Nickname.
  • On more than 1 success: Done! The request affected 4 players.

Use the following attributes to set static messages:

  • AffectedMultiplePlayersMessageAttribute (amount is passed as a format argument)
  • AffectedOnePlayerMessageAttribute (player's nickname is passed as a format argument)
  • NoPlayersAffectedMessageAttribute
  • StaticTargetingMessagesAttribute

Failed executions are not displayed by default.

ICustomResultCompiler

An ICustomResultCompiler may be specified by implementing the interface or by specifying it through the use of attributes or resolvers

The custom compiler has to implement the method CommandResult? CompileResultCustom(List<CommandResultOnTarget> success, List<CommandResultOnTarget> failures)

If CommandResult.Null is returned, a message will be generated using the default method.

Recommended extension methods from Axwabo.CommandSystem.Extensions

  • string JoinResults(this IEnumerable<CommandResultOnTarget> results, string separator, bool includeNicknames)
  • string CombineNicknames(this IEnumerable<CommandResultOnTarget> results, string separator)
Clone this wiki locally