Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5188b44a81 | ||
|
|
806d86e91c | ||
|
|
937abba03d | ||
|
|
2c6be63c33 | ||
|
|
ecf9925645 | ||
|
|
7cdd8d27c0 | ||
|
|
63f5d6e8b6 |
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using Vintagestory.API.Common;
|
||||
|
||||
namespace CommandHook;
|
||||
|
||||
public delegate void CommandBeforeDelegate(ref CommandData data);
|
||||
public delegate void CommandAfterDelegate(ref CommandData data, TextCommandResult result);
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace CommandHook;
|
||||
|
||||
public delegate void CommandHookDelegate(ref CommandData data);
|
||||
@@ -1,67 +1,117 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Datastructures;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
namespace CommandHook;
|
||||
|
||||
public class CommandHookModSystem : ModSystem
|
||||
{
|
||||
private readonly Dictionary<string, CommandRegistration> wildcards = new();
|
||||
private readonly Dictionary<string, ModRegistration> registrations = new();
|
||||
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;
|
||||
}
|
||||
|
||||
public void RegisterWildcard(string modId, CommandRegistration registration)
|
||||
public override void Dispose()
|
||||
{
|
||||
wildcards[modId] = registration;
|
||||
harmony?.UnpatchAll(Mod.Info.ModID);
|
||||
Instance = null;
|
||||
}
|
||||
|
||||
public void Register(string modId, string command, CommandRegistration registration)
|
||||
{
|
||||
if (!registrations.TryGetValue(modId, out var modReg))
|
||||
{
|
||||
modReg = new ModRegistration(new Dictionary<string, CommandRegistration>());
|
||||
registrations[modId] = modReg;
|
||||
}
|
||||
|
||||
modReg.Commands[command] = registration;
|
||||
}
|
||||
|
||||
private void OnPlayerChat(
|
||||
IServerPlayer player,
|
||||
int channelId,
|
||||
ref string message,
|
||||
ref string data,
|
||||
BoolRef consumed
|
||||
public void Register(
|
||||
string modId,
|
||||
CommandRegistration registration,
|
||||
params string[] commandNames
|
||||
)
|
||||
{
|
||||
if (!message.StartsWith('/'))
|
||||
return;
|
||||
var builder = Thaw();
|
||||
|
||||
var cmdData = new CommandData(player, message);
|
||||
foreach (var commandName in commandNames)
|
||||
{
|
||||
if (!builder.TryGetValue(commandName, out var target))
|
||||
{
|
||||
target = new Dictionary<string, CommandRegistration>();
|
||||
builder[commandName] = target;
|
||||
}
|
||||
target[modId] = registration;
|
||||
}
|
||||
|
||||
foreach (var (_, reg) in wildcards)
|
||||
reg.Before?.Invoke(ref cmdData);
|
||||
registrations = Freeze(builder);
|
||||
}
|
||||
|
||||
foreach (var (_, modReg) in registrations)
|
||||
if (modReg.Commands.TryGetValue(cmdData.CommandName, out var reg))
|
||||
reg.Before?.Invoke(ref cmdData);
|
||||
public void Unregister(string modId, params string[] commandNames)
|
||||
{
|
||||
var builder = Thaw();
|
||||
|
||||
if (cmdData.Cancel)
|
||||
consumed.value = true;
|
||||
if (commandNames.Length == 0)
|
||||
{
|
||||
foreach (var (_, mods) in builder)
|
||||
mods.Remove(modId);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var commandName in commandNames)
|
||||
if (builder.TryGetValue(commandName, out var mods))
|
||||
mods.Remove(modId);
|
||||
}
|
||||
|
||||
foreach (var (_, reg) in wildcards)
|
||||
reg.After?.Invoke(ref cmdData);
|
||||
registrations = Freeze(builder);
|
||||
}
|
||||
|
||||
foreach (var (_, modReg) in registrations)
|
||||
if (modReg.Commands.TryGetValue(cmdData.CommandName, out var reg))
|
||||
reg.After?.Invoke(ref cmdData);
|
||||
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);
|
||||
}
|
||||
|
||||
private Dictionary<string, Dictionary<string, CommandRegistration>> Thaw()
|
||||
{
|
||||
var builder = new Dictionary<string, Dictionary<string, CommandRegistration>>();
|
||||
|
||||
foreach (var (cmd, mods) in registrations)
|
||||
{
|
||||
var inner = new Dictionary<string, CommandRegistration>();
|
||||
foreach (var (id, reg) in mods)
|
||||
inner[id] = reg;
|
||||
builder[cmd] = inner;
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>> Freeze(
|
||||
Dictionary<string, Dictionary<string, CommandRegistration>> builder
|
||||
)
|
||||
{
|
||||
var pruned = new Dictionary<string, FrozenDictionary<string, CommandRegistration>>();
|
||||
|
||||
foreach (var (cmd, mods) in builder)
|
||||
if (mods.Count > 0)
|
||||
pruned[cmd] = mods.ToFrozenDictionary();
|
||||
|
||||
return pruned.ToFrozenDictionary();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ namespace CommandHook;
|
||||
|
||||
public struct CommandRegistration
|
||||
{
|
||||
public readonly CommandHookDelegate? Before;
|
||||
public readonly CommandHookDelegate? After;
|
||||
public readonly CommandBeforeDelegate? Before;
|
||||
public readonly CommandAfterDelegate? After;
|
||||
|
||||
public CommandRegistration(CommandHookDelegate? before, CommandHookDelegate? after)
|
||||
public CommandRegistration(CommandBeforeDelegate? before, CommandAfterDelegate? after)
|
||||
{
|
||||
Before = before;
|
||||
After = after;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CommandHook;
|
||||
|
||||
public struct ModRegistration
|
||||
{
|
||||
public readonly Dictionary<string, CommandRegistration> Commands;
|
||||
|
||||
public ModRegistration(Dictionary<string, CommandRegistration> commands)
|
||||
{
|
||||
Commands = commands;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user