From ba5256476ccfbfd6f0266d9ca7e5986a13d08407 Mon Sep 17 00:00:00 2001 From: anth64 Date: Thu, 25 Jun 2026 20:21:31 +0200 Subject: [PATCH] docs: rewrite README for the TextCommandCallingArgs API --- README.md | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a25524b..2abdf1b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Add it as a dependency in your `modinfo.json`: ```json "dependencies": { "game": "1.22.3", - "commandhook": "1.0.0" + "commandhook": "2.0.0" } ``` @@ -31,16 +31,24 @@ A listener provides: - `Commands`, the command names you want to watch, without the leading slash - `Registration`, a `Before` delegate, an `After` delegate, or both -`Before` runs before the command executes. Set `data.Cancel = true` inside it -to stop the command from running. If you cancel, any remaining `Before` -listeners for that command are skipped, and `After` never fires for that -invocation. +`Before` receives the engine's own `TextCommandCallingArgs` for the +invocation, live and unmodified. Return a non-null `TextCommandResult` to +cancel the command and report that result to the caller, use the engine's +own factories, e.g. `TextCommandResult.Error(...)` for a visible reason, or +`TextCommandResult.Deferred` to cancel silently (per its own doc comment, +this prints no output). Return `null` to let the command run normally. If +you cancel, any remaining `Before` listeners for that command are skipped, +and `After` never fires for that invocation. -`After` runs once the command has produced a result. It only fires on the -path where the command actually ran. +`After` receives the same `TextCommandCallingArgs` object plus the +`TextCommandResult` the command actually produced. It only fires on the +path where the command ran. -`CommandData` is passed by `ref` the whole way through, no allocation per -command. +### A note on `TextCommandCallingArgs` at Before vs After + +This is the engine's own live object, not a copy, what's safe to read +depends on timing and on how the specific command you're watching is +implemented internally. ### Example @@ -56,23 +64,26 @@ public class MyListener : ICommandHookListener // Wire up Before, After, or both. public CommandRegistration Registration => new(Before, After); - private void Before(ref CommandData data) + private TextCommandResult? Before(TextCommandCallingArgs args) { - // data.Sender is null for console invocations. - if (data.Sender != null && !IsAllowed(data.Sender)) + // args.Caller.Player is null for console invocations. + if (args.Caller.Player is IServerPlayer player && !IsAllowed(player)) { - // Stops the command from running and skips any remaining - // Before listeners. After never fires for this invocation. - data.Cancel = true; + // Cancels the command, skips any remaining Before listeners, + // and After never fires for this invocation. The caller sees + // this exact result. + return TextCommandResult.Error("You're not allowed to do that", "notallowed"); } + + return null; } - private void After(ref CommandData data, TextCommandResult result) + private void After(TextCommandCallingArgs args, TextCommandResult result) { // Only runs if nothing cancelled. result is whatever the command // actually produced, check result.Status for success/error/deferred. if (result.Status != EnumCommandStatus.Success) - Logger.Warn($"/{data.CommandName} failed: {result.StatusMessage}"); + Logger.Warn($"A watched command failed: {result.StatusMessage}"); } } ```