feat: replace PlayerChat hook with Harmony patch on command dispatch

This commit is contained in:
2026-06-04 22:10:40 +02:00
parent ecf9925645
commit 2c6be63c33
2 changed files with 74 additions and 13 deletions
+48
View File
@@ -0,0 +1,48 @@
using System;
using HarmonyLib;
using Vintagestory.API.Common;
using Vintagestory.API.Server;
using Vintagestory.Common;
namespace CommandHook;
[HarmonyPatch(typeof(ChatCommandApi))]
public static class ChatCommandApiPatch
{
[HarmonyPatch(
"Execute",
new[] { typeof(string), typeof(TextCommandCallingArgs), typeof(Action<TextCommandResult>) }
)]
[HarmonyPrefix]
public static bool Prefix(
string commandName,
TextCommandCallingArgs args,
ref Action<TextCommandResult> onCommandComplete
)
{
var system = CommandHookModSystem.Instance;
if (system == null)
return true;
var sender = args.Caller.Player as IServerPlayer;
var data = new CommandData(sender, "/" + commandName);
if (system.FireBefore(commandName, ref data))
{
onCommandComplete?.Invoke(
new TextCommandResult { Status = EnumCommandStatus.Deferred }
);
return false;
}
var original = onCommandComplete;
onCommandComplete = result =>
{
original?.Invoke(result);
var afterData = data;
system.FireAfter(commandName, ref afterData, result);
};
return true;
}
}
+26 -13
View File
@@ -1,35 +1,48 @@
using System.Collections.Frozen;
using HarmonyLib;
using Vintagestory.API.Common;
using Vintagestory.API.Datastructures;
using Vintagestory.API.Server;
namespace CommandHook;
public class CommandHookModSystem : ModSystem
{
internal static CommandHookModSystem? Instance;
private FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>> registrations =
FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>>.Empty;
private Harmony? harmony;
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
public override void StartServerSide(ICoreServerAPI api)
{
Instance = this;
harmony = new Harmony(Mod.Info.ModID);
harmony.PatchAll();
Mod.Logger.Notification("Loaded");
api.Event.PlayerChat += OnPlayerChat;
}
private void OnPlayerChat(
IServerPlayer player,
int channelId,
ref string message,
ref string data,
BoolRef consumed
)
public override void Dispose()
{
if (!message.StartsWith('/'))
return;
harmony?.UnpatchAll(Mod.Info.ModID);
Instance = null;
}
var cmdData = new CommandData(player, message);
// TODO dispatch
public bool FireBefore(string commandName, ref CommandData data)
{
if (registrations.TryGetValue(commandName, out var mods))
foreach (var (_, reg) in mods)
reg.Before?.Invoke(ref data);
return data.Cancel;
}
public void FireAfter(string commandName, ref CommandData data, TextCommandResult result)
{
if (registrations.TryGetValue(commandName, out var mods))
foreach (var (_, reg) in mods)
reg.After?.Invoke(ref data, result);
}
}