feat: convert to Universal mod, merge ClaimLinkVisualizer in, keep CommandHook as a true soft dependency via runtime proxy
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using CommandHook;
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
@@ -15,10 +15,8 @@ public class ClaimLinkModSystem : ModSystem
|
||||
internal static IWorldManagerAPI WorldManager = null!;
|
||||
internal static IPlayerDataManager PlayerData = null!;
|
||||
internal static ClaimLinkConfig Config = null!;
|
||||
internal CommandListener? CmdListener;
|
||||
internal GroupCommandListener? GroupCmdListener;
|
||||
|
||||
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
||||
private object? cmdListenerProxy;
|
||||
private object? groupCmdListenerProxy;
|
||||
|
||||
public override void StartServerSide(ICoreServerAPI api)
|
||||
{
|
||||
@@ -34,25 +32,67 @@ public class ClaimLinkModSystem : ModSystem
|
||||
ClaimLinkBufferIndex.Rebuild();
|
||||
api.Event.SaveGameLoaded += ClaimLinkBufferIndex.Rebuild;
|
||||
|
||||
CmdListener = new CommandListener();
|
||||
CommandHookModSystem.Register(CmdListener);
|
||||
GroupCmdListener = new GroupCommandListener();
|
||||
CommandHookModSystem.Register(GroupCmdListener);
|
||||
if (api.ModLoader.IsModEnabled("commandhook"))
|
||||
{
|
||||
api.Event.SaveGameLoaded += () => RegisterCommandHooks(api);
|
||||
}
|
||||
else
|
||||
{
|
||||
api.Logger.Fatal(
|
||||
"ClaimLink requires the CommandHook mod on the server for /land and /group integration. That integration is disabled; /claimlink commands and buffer protection still work."
|
||||
);
|
||||
}
|
||||
|
||||
ClaimLinkChatCommand.Register(api);
|
||||
ClaimLinkVisualizerNetwork.Start(api);
|
||||
ClaimLinkBufferProtection.Register(api);
|
||||
|
||||
api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect;
|
||||
api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect;
|
||||
api.Event.PlayerDisconnect += ClaimLinkChatCommand.OnPlayerDisconnect;
|
||||
}
|
||||
|
||||
private void RegisterCommandHooks(ICoreServerAPI api)
|
||||
{
|
||||
CommandListener cmdListener = new();
|
||||
CommandHook.ICommandHookListener cmdProxy = CommandHookListenerProxy.Create(
|
||||
cmdListener.ModId,
|
||||
cmdListener.Commands,
|
||||
cmdListener.Before,
|
||||
cmdListener.After
|
||||
);
|
||||
CommandHook.CommandHookModSystem.Register(cmdProxy);
|
||||
cmdListenerProxy = cmdProxy;
|
||||
|
||||
GroupCommandListener groupListener = new();
|
||||
CommandHook.ICommandHookListener groupProxy = CommandHookListenerProxy.Create(
|
||||
groupListener.ModId,
|
||||
groupListener.Commands,
|
||||
groupListener.Before,
|
||||
groupListener.After
|
||||
);
|
||||
CommandHook.CommandHookModSystem.Register(groupProxy);
|
||||
groupCmdListenerProxy = groupProxy;
|
||||
|
||||
api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect;
|
||||
api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect;
|
||||
}
|
||||
|
||||
public override void StartClientSide(ICoreClientAPI api) => ClaimLinkVisualizerClient.Start(api);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (CmdListener != null)
|
||||
CommandHookModSystem.Unregister(CmdListener);
|
||||
if (GroupCmdListener != null)
|
||||
CommandHookModSystem.Unregister(GroupCmdListener);
|
||||
if (cmdListenerProxy != null || groupCmdListenerProxy != null)
|
||||
UnregisterCommandHooks();
|
||||
}
|
||||
|
||||
private void UnregisterCommandHooks()
|
||||
{
|
||||
if (cmdListenerProxy != null)
|
||||
CommandHook.CommandHookModSystem.Unregister(
|
||||
(CommandHook.ICommandHookListener)cmdListenerProxy
|
||||
);
|
||||
if (groupCmdListenerProxy != null)
|
||||
CommandHook.CommandHookModSystem.Unregister(
|
||||
(CommandHook.ICommandHookListener)groupCmdListenerProxy
|
||||
);
|
||||
}
|
||||
|
||||
private static IEnumerable<(int claimIndex, LandClaim claim)> EnumerateOwnedClaims(
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Collections.Generic;
|
||||
using Vintagestory.API.Client;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.MathTools;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
internal static class ClaimLinkVisualizerClient
|
||||
{
|
||||
private const int HighlightSlotId = 8341;
|
||||
private static ICoreClientAPI capi = null!;
|
||||
private static bool visible;
|
||||
private static ClaimLinkVisualizerConfig config = null!;
|
||||
private static IClientNetworkChannel channel = null!;
|
||||
|
||||
internal static void Start(ICoreClientAPI api)
|
||||
{
|
||||
capi = api;
|
||||
config = api.LoadModConfig<ClaimLinkVisualizerConfig>("claimlinkvisualizer.json") ?? new ClaimLinkVisualizerConfig();
|
||||
api.StoreModConfig(config, "claimlinkvisualizer.json");
|
||||
|
||||
channel = api.Network.RegisterChannel(ClaimLinkVisualizerNetwork.ChannelName)
|
||||
.RegisterMessageType<ClaimLinkBufferRequest>()
|
||||
.RegisterMessageType<ClaimLinkBufferResponse>()
|
||||
.SetMessageHandler<ClaimLinkBufferResponse>(OnBufferResponse);
|
||||
|
||||
api.Input.RegisterHotKey(
|
||||
"claimlinkvisualizertoggle",
|
||||
"Toggle ClaimLink buffer visualization",
|
||||
GlKeys.R,
|
||||
HotkeyType.CharacterControls,
|
||||
ctrlPressed: true
|
||||
);
|
||||
api.Input.SetHotKeyHandler("claimlinkvisualizertoggle", OnToggle);
|
||||
}
|
||||
|
||||
private static bool OnToggle(KeyCombination comb)
|
||||
{
|
||||
visible = !visible;
|
||||
if (visible)
|
||||
{
|
||||
if (channel.Connected)
|
||||
channel.SendPacket(new ClaimLinkBufferRequest());
|
||||
}
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void OnBufferResponse(ClaimLinkBufferResponse response)
|
||||
{
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
List<BlockPos> positions = new();
|
||||
List<int> colors = new();
|
||||
|
||||
foreach (ClaimLinkBufferEntryDto entry in response.Entries)
|
||||
{
|
||||
int color = HashToColor(entry.GroupId);
|
||||
foreach (ClaimLinkBufferCuboidDto cuboid in entry.Cuboids)
|
||||
{
|
||||
positions.Add(new BlockPos(cuboid.MinX, cuboid.MinY, cuboid.MinZ));
|
||||
positions.Add(new BlockPos(cuboid.MaxX, cuboid.MaxY, cuboid.MaxZ));
|
||||
colors.Add(color);
|
||||
}
|
||||
}
|
||||
|
||||
capi.World.HighlightBlocks(
|
||||
capi.World.Player,
|
||||
HighlightSlotId,
|
||||
positions,
|
||||
colors,
|
||||
EnumHighlightBlocksMode.Absolute,
|
||||
EnumHighlightShape.Cubes
|
||||
);
|
||||
}
|
||||
|
||||
private static void Clear() =>
|
||||
capi.World.HighlightBlocks(
|
||||
capi.World.Player,
|
||||
HighlightSlotId,
|
||||
new List<BlockPos>(),
|
||||
new List<int>()
|
||||
);
|
||||
|
||||
private static int HashToColor(int groupId)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint h = (uint)groupId * config.ColorHashSeed;
|
||||
int r = (byte)(h >> 16);
|
||||
int g = (byte)(h >> 8);
|
||||
int b = (byte)h;
|
||||
return ColorUtil.ColorFromRgba(r, g, b, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace ClaimLink;
|
||||
|
||||
internal class ClaimLinkVisualizerConfig
|
||||
{
|
||||
public uint ColorHashSeed = 2654435761u;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Vintagestory.API.Common;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
internal delegate TextCommandResult? HookBeforeDelegate(TextCommandCallingArgs args);
|
||||
|
||||
internal delegate void HookAfterDelegate(TextCommandCallingArgs args, TextCommandResult result);
|
||||
|
||||
internal class CommandHookListenerProxy : DispatchProxy
|
||||
{
|
||||
private string modId = null!;
|
||||
private IReadOnlyList<string> commands = null!;
|
||||
private HookBeforeDelegate? before;
|
||||
private HookAfterDelegate? after;
|
||||
|
||||
internal static CommandHook.ICommandHookListener Create(
|
||||
string modId,
|
||||
IReadOnlyList<string> commands,
|
||||
HookBeforeDelegate? before,
|
||||
HookAfterDelegate? after
|
||||
)
|
||||
{
|
||||
object proxy = Create<CommandHook.ICommandHookListener, CommandHookListenerProxy>()!;
|
||||
CommandHookListenerProxy p = (CommandHookListenerProxy)proxy;
|
||||
p.modId = modId;
|
||||
p.commands = commands;
|
||||
p.before = before;
|
||||
p.after = after;
|
||||
return (CommandHook.ICommandHookListener)proxy;
|
||||
}
|
||||
|
||||
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args) =>
|
||||
targetMethod!.Name switch
|
||||
{
|
||||
"get_ModId" => modId,
|
||||
"get_Commands" => commands,
|
||||
"get_Registration" => new CommandHook.CommandRegistration(
|
||||
before == null ? null : new CommandHook.CommandBeforeDelegate(before),
|
||||
after == null ? null : new CommandHook.CommandAfterDelegate(after)
|
||||
),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using CommandHook;
|
||||
using Vintagestory.API.Common;
|
||||
using Vintagestory.API.Config;
|
||||
using Vintagestory.API.MathTools;
|
||||
@@ -7,14 +6,12 @@ using Vintagestory.API.Server;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
public class CommandListener : ICommandHookListener
|
||||
public class CommandListener
|
||||
{
|
||||
public string ModId => "claimlink";
|
||||
|
||||
public IReadOnlyList<string> Commands => new[] { "land" };
|
||||
|
||||
public CommandRegistration Registration => new(Before, After);
|
||||
|
||||
internal static Dictionary<string, int> PendingLoads = new Dictionary<string, int>();
|
||||
internal static Dictionary<string, List<Cuboidi>?> PendingSaveChecks =
|
||||
new Dictionary<string, List<Cuboidi>?>();
|
||||
@@ -57,13 +54,13 @@ public class CommandListener : ICommandHookListener
|
||||
}
|
||||
}
|
||||
|
||||
private TextCommandResult? Before(TextCommandCallingArgs args)
|
||||
internal TextCommandResult? Before(TextCommandCallingArgs args)
|
||||
{
|
||||
Dispatch(args);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||
internal void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||
{
|
||||
if (args.Caller.Player == null)
|
||||
return;
|
||||
@@ -276,19 +273,17 @@ public class CommandListener : ICommandHookListener
|
||||
}
|
||||
}
|
||||
|
||||
public class GroupCommandListener : ICommandHookListener
|
||||
public class GroupCommandListener
|
||||
{
|
||||
public string ModId => "claimlink.group";
|
||||
|
||||
public IReadOnlyList<string> Commands => new[] { "group" };
|
||||
|
||||
public CommandRegistration Registration => new(Before, After);
|
||||
|
||||
internal static Dictionary<string, int> PendingDisbands = new Dictionary<string, int>();
|
||||
internal static Dictionary<string, (string AffectedUid, int GroupId)> PendingMembershipChecks =
|
||||
new Dictionary<string, (string, int)>();
|
||||
|
||||
private TextCommandResult? Before(TextCommandCallingArgs args)
|
||||
internal TextCommandResult? Before(TextCommandCallingArgs args)
|
||||
{
|
||||
if (args.Caller.Player == null)
|
||||
return null;
|
||||
@@ -370,7 +365,7 @@ public class GroupCommandListener : ICommandHookListener
|
||||
PendingMembershipChecks[callerUid] = (targetUid, (int)groupId);
|
||||
}
|
||||
|
||||
private void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||
internal void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||
{
|
||||
if (args.Caller.Player == null)
|
||||
return;
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
"type": "Code",
|
||||
"modid": "claimlink",
|
||||
"name": "ClaimLink",
|
||||
"side": "Server",
|
||||
"side": "Universal",
|
||||
"authors": [
|
||||
"anth64"
|
||||
],
|
||||
"description": "Link claims together with groups.",
|
||||
"version": "0.5.1",
|
||||
"dependencies": {
|
||||
"game": "1.22.5",
|
||||
"commandhook": "2.1.0"
|
||||
"game": "1.22.5"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user