Compare commits
7
Commits
841644741b
...
5188b44a81
| 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 System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
using Vintagestory.API.Common;
|
using Vintagestory.API.Common;
|
||||||
using Vintagestory.API.Datastructures;
|
|
||||||
using Vintagestory.API.Server;
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
namespace CommandHook;
|
namespace CommandHook;
|
||||||
|
|
||||||
public class CommandHookModSystem : ModSystem
|
public class CommandHookModSystem : ModSystem
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, CommandRegistration> wildcards = new();
|
internal static CommandHookModSystem? Instance;
|
||||||
private readonly Dictionary<string, ModRegistration> registrations = new();
|
|
||||||
|
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 bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
||||||
|
|
||||||
public override void StartServerSide(ICoreServerAPI api)
|
public override void StartServerSide(ICoreServerAPI api)
|
||||||
{
|
{
|
||||||
|
Instance = this;
|
||||||
|
harmony = new Harmony(Mod.Info.ModID);
|
||||||
|
harmony.PatchAll();
|
||||||
Mod.Logger.Notification("Loaded");
|
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)
|
public void Register(
|
||||||
{
|
string modId,
|
||||||
if (!registrations.TryGetValue(modId, out var modReg))
|
CommandRegistration registration,
|
||||||
{
|
params string[] commandNames
|
||||||
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
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!message.StartsWith('/'))
|
var builder = Thaw();
|
||||||
return;
|
|
||||||
|
|
||||||
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)
|
registrations = Freeze(builder);
|
||||||
reg.Before?.Invoke(ref cmdData);
|
}
|
||||||
|
|
||||||
foreach (var (_, modReg) in registrations)
|
public void Unregister(string modId, params string[] commandNames)
|
||||||
if (modReg.Commands.TryGetValue(cmdData.CommandName, out var reg))
|
{
|
||||||
reg.Before?.Invoke(ref cmdData);
|
var builder = Thaw();
|
||||||
|
|
||||||
if (cmdData.Cancel)
|
if (commandNames.Length == 0)
|
||||||
consumed.value = true;
|
{
|
||||||
|
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)
|
registrations = Freeze(builder);
|
||||||
reg.After?.Invoke(ref cmdData);
|
}
|
||||||
|
|
||||||
foreach (var (_, modReg) in registrations)
|
public bool FireBefore(string commandName, ref CommandData data)
|
||||||
if (modReg.Commands.TryGetValue(cmdData.CommandName, out var reg))
|
{
|
||||||
reg.After?.Invoke(ref cmdData);
|
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 struct CommandRegistration
|
||||||
{
|
{
|
||||||
public readonly CommandHookDelegate? Before;
|
public readonly CommandBeforeDelegate? Before;
|
||||||
public readonly CommandHookDelegate? After;
|
public readonly CommandAfterDelegate? After;
|
||||||
|
|
||||||
public CommandRegistration(CommandHookDelegate? before, CommandHookDelegate? after)
|
public CommandRegistration(CommandBeforeDelegate? before, CommandAfterDelegate? after)
|
||||||
{
|
{
|
||||||
Before = before;
|
Before = before;
|
||||||
After = after;
|
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