Compare commits
3
Commits
5188b44a81
...
cd583a0e95
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd583a0e95 | ||
|
|
e26ad1d541 | ||
|
|
6d4f964e74 |
@@ -10,6 +10,9 @@ public class CommandHookModSystem : ModSystem
|
|||||||
{
|
{
|
||||||
internal static CommandHookModSystem? Instance;
|
internal static CommandHookModSystem? Instance;
|
||||||
|
|
||||||
|
private readonly List<ICommandHookListener> listeners = new();
|
||||||
|
private readonly List<ICommandHookListener> wildcards = new();
|
||||||
|
|
||||||
private FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>> registrations =
|
private FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>> registrations =
|
||||||
FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>>.Empty;
|
FrozenDictionary<string, FrozenDictionary<string, CommandRegistration>>.Empty;
|
||||||
|
|
||||||
@@ -17,61 +20,109 @@ public class CommandHookModSystem : ModSystem
|
|||||||
|
|
||||||
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
||||||
|
|
||||||
|
public override double ExecuteOrder() => 0.0;
|
||||||
|
|
||||||
public override void StartServerSide(ICoreServerAPI api)
|
public override void StartServerSide(ICoreServerAPI api)
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
harmony = new Harmony(Mod.Info.ModID);
|
harmony = new Harmony(Mod.Info.ModID);
|
||||||
harmony.PatchAll();
|
harmony.PatchAll();
|
||||||
|
|
||||||
|
api.Event.ServerRunPhase(EnumServerRunPhase.RunGame, Rebuild);
|
||||||
|
|
||||||
Mod.Logger.Notification("Loaded");
|
Mod.Logger.Notification("Loaded");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
harmony?.UnpatchAll(Mod.Info.ModID);
|
harmony?.UnpatchAll(Mod.Info.ModID);
|
||||||
|
listeners.Clear();
|
||||||
|
wildcards.Clear();
|
||||||
Instance = null;
|
Instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Register(
|
public void Register(ICommandHookListener listener)
|
||||||
string modId,
|
|
||||||
CommandRegistration registration,
|
|
||||||
params string[] commandNames
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
var builder = Thaw();
|
var commands = listener.Commands;
|
||||||
|
|
||||||
foreach (var commandName in commandNames)
|
if (commands == null || commands.Count == 0)
|
||||||
{
|
{
|
||||||
if (!builder.TryGetValue(commandName, out var target))
|
Unregister(listener);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < listeners.Count; i++)
|
||||||
|
{
|
||||||
|
if (listeners[i].ModId != listener.ModId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (CommandListEquals(listeners[i].Commands, commands))
|
||||||
|
return;
|
||||||
|
|
||||||
|
listeners[i] = listener;
|
||||||
|
SyncWildcard(listener, commands);
|
||||||
|
Rebuild();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.Add(listener);
|
||||||
|
SyncWildcard(listener, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister(ICommandHookListener listener)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < listeners.Count; i++)
|
||||||
|
{
|
||||||
|
if (listeners[i].ModId != listener.ModId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
listeners.RemoveAt(i);
|
||||||
|
wildcards.RemoveAll(w => w.ModId == listener.ModId);
|
||||||
|
Rebuild();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rebuild()
|
||||||
|
{
|
||||||
|
var builder = new Dictionary<string, Dictionary<string, CommandRegistration>>();
|
||||||
|
|
||||||
|
foreach (var listener in listeners)
|
||||||
|
{
|
||||||
|
var commands = listener.Commands;
|
||||||
|
if (commands == null || commands.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool isWildcard = commands.Count == 1 && commands[0] == "*";
|
||||||
|
if (isWildcard)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var cmd in commands)
|
||||||
{
|
{
|
||||||
target = new Dictionary<string, CommandRegistration>();
|
if (!builder.TryGetValue(cmd, out var mods))
|
||||||
builder[commandName] = target;
|
{
|
||||||
|
mods = new Dictionary<string, CommandRegistration>();
|
||||||
|
builder[cmd] = mods;
|
||||||
|
}
|
||||||
|
mods[listener.ModId] = listener.Registration;
|
||||||
}
|
}
|
||||||
target[modId] = registration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registrations = Freeze(builder);
|
foreach (var wildcard in wildcards)
|
||||||
|
foreach (var mods in builder.Values)
|
||||||
|
mods[wildcard.ModId] = wildcard.Registration;
|
||||||
|
|
||||||
|
var pruned = new Dictionary<string, FrozenDictionary<string, CommandRegistration>>(
|
||||||
|
builder.Count
|
||||||
|
);
|
||||||
|
foreach (var (cmd, mods) in builder)
|
||||||
|
if (mods.Count > 0)
|
||||||
|
pruned[cmd] = mods.ToFrozenDictionary();
|
||||||
|
|
||||||
|
registrations = pruned.ToFrozenDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unregister(string modId, params string[] commandNames)
|
internal bool FireBefore(string commandName, ref CommandData data)
|
||||||
{
|
|
||||||
var builder = Thaw();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
registrations = Freeze(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool FireBefore(string commandName, ref CommandData data)
|
|
||||||
{
|
{
|
||||||
if (registrations.TryGetValue(commandName, out var mods))
|
if (registrations.TryGetValue(commandName, out var mods))
|
||||||
foreach (var (_, reg) in mods)
|
foreach (var (_, reg) in mods)
|
||||||
@@ -80,38 +131,30 @@ public class CommandHookModSystem : ModSystem
|
|||||||
return data.Cancel;
|
return data.Cancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FireAfter(string commandName, ref CommandData data, TextCommandResult result)
|
internal void FireAfter(string commandName, ref CommandData data, TextCommandResult result)
|
||||||
{
|
{
|
||||||
if (registrations.TryGetValue(commandName, out var mods))
|
if (registrations.TryGetValue(commandName, out var mods))
|
||||||
foreach (var (_, reg) in mods)
|
foreach (var (_, reg) in mods)
|
||||||
reg.After?.Invoke(ref data, result);
|
reg.After?.Invoke(ref data, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, Dictionary<string, CommandRegistration>> Thaw()
|
private void SyncWildcard(ICommandHookListener listener, IReadOnlyList<string> commands)
|
||||||
{
|
{
|
||||||
var builder = new Dictionary<string, Dictionary<string, CommandRegistration>>();
|
bool isWildcard = commands.Count == 1 && commands[0] == "*";
|
||||||
|
wildcards.RemoveAll(w => w.ModId == listener.ModId);
|
||||||
foreach (var (cmd, mods) in registrations)
|
if (isWildcard)
|
||||||
{
|
wildcards.Add(listener);
|
||||||
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(
|
private static bool CommandListEquals(IReadOnlyList<string> a, IReadOnlyList<string> b)
|
||||||
Dictionary<string, Dictionary<string, CommandRegistration>> builder
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
var pruned = new Dictionary<string, FrozenDictionary<string, CommandRegistration>>();
|
if (a.Count != b.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
foreach (var (cmd, mods) in builder)
|
for (int i = 0; i < a.Count; i++)
|
||||||
if (mods.Count > 0)
|
if (a[i] != b[i])
|
||||||
pruned[cmd] = mods.ToFrozenDictionary();
|
return false;
|
||||||
|
|
||||||
return pruned.ToFrozenDictionary();
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace CommandHook;
|
||||||
|
|
||||||
|
public interface ICommandHookListener
|
||||||
|
{
|
||||||
|
string ModId { get; }
|
||||||
|
IReadOnlyList<string> Commands { get; }
|
||||||
|
CommandRegistration Registration { get; }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user