feat: replace PlayerChat hook with Harmony patch on command dispatch
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user