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 System.Collections.Generic;
|
||||||
using CommandHook;
|
using Vintagestory.API.Client;
|
||||||
using Vintagestory.API.Common;
|
using Vintagestory.API.Common;
|
||||||
using Vintagestory.API.Server;
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
@@ -15,10 +15,8 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
internal static IWorldManagerAPI WorldManager = null!;
|
internal static IWorldManagerAPI WorldManager = null!;
|
||||||
internal static IPlayerDataManager PlayerData = null!;
|
internal static IPlayerDataManager PlayerData = null!;
|
||||||
internal static ClaimLinkConfig Config = null!;
|
internal static ClaimLinkConfig Config = null!;
|
||||||
internal CommandListener? CmdListener;
|
private object? cmdListenerProxy;
|
||||||
internal GroupCommandListener? GroupCmdListener;
|
private object? groupCmdListenerProxy;
|
||||||
|
|
||||||
public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server;
|
|
||||||
|
|
||||||
public override void StartServerSide(ICoreServerAPI api)
|
public override void StartServerSide(ICoreServerAPI api)
|
||||||
{
|
{
|
||||||
@@ -34,25 +32,67 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
ClaimLinkBufferIndex.Rebuild();
|
ClaimLinkBufferIndex.Rebuild();
|
||||||
api.Event.SaveGameLoaded += ClaimLinkBufferIndex.Rebuild;
|
api.Event.SaveGameLoaded += ClaimLinkBufferIndex.Rebuild;
|
||||||
|
|
||||||
CmdListener = new CommandListener();
|
if (api.ModLoader.IsModEnabled("commandhook"))
|
||||||
CommandHookModSystem.Register(CmdListener);
|
{
|
||||||
GroupCmdListener = new GroupCommandListener();
|
api.Event.SaveGameLoaded += () => RegisterCommandHooks(api);
|
||||||
CommandHookModSystem.Register(GroupCmdListener);
|
}
|
||||||
|
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);
|
ClaimLinkChatCommand.Register(api);
|
||||||
ClaimLinkVisualizerNetwork.Start(api);
|
ClaimLinkVisualizerNetwork.Start(api);
|
||||||
ClaimLinkBufferProtection.Register(api);
|
ClaimLinkBufferProtection.Register(api);
|
||||||
|
|
||||||
api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect;
|
|
||||||
api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect;
|
|
||||||
api.Event.PlayerDisconnect += ClaimLinkChatCommand.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()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
if (CmdListener != null)
|
if (cmdListenerProxy != null || groupCmdListenerProxy != null)
|
||||||
CommandHookModSystem.Unregister(CmdListener);
|
UnregisterCommandHooks();
|
||||||
if (GroupCmdListener != null)
|
}
|
||||||
CommandHookModSystem.Unregister(GroupCmdListener);
|
|
||||||
|
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(
|
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 System.Collections.Generic;
|
||||||
using CommandHook;
|
|
||||||
using Vintagestory.API.Common;
|
using Vintagestory.API.Common;
|
||||||
using Vintagestory.API.Config;
|
using Vintagestory.API.Config;
|
||||||
using Vintagestory.API.MathTools;
|
using Vintagestory.API.MathTools;
|
||||||
@@ -7,14 +6,12 @@ using Vintagestory.API.Server;
|
|||||||
|
|
||||||
namespace ClaimLink;
|
namespace ClaimLink;
|
||||||
|
|
||||||
public class CommandListener : ICommandHookListener
|
public class CommandListener
|
||||||
{
|
{
|
||||||
public string ModId => "claimlink";
|
public string ModId => "claimlink";
|
||||||
|
|
||||||
public IReadOnlyList<string> Commands => new[] { "land" };
|
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, int> PendingLoads = new Dictionary<string, int>();
|
||||||
internal static Dictionary<string, List<Cuboidi>?> PendingSaveChecks =
|
internal static Dictionary<string, List<Cuboidi>?> PendingSaveChecks =
|
||||||
new Dictionary<string, List<Cuboidi>?>();
|
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);
|
Dispatch(args);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void After(TextCommandCallingArgs args, TextCommandResult result)
|
internal void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||||
{
|
{
|
||||||
if (args.Caller.Player == null)
|
if (args.Caller.Player == null)
|
||||||
return;
|
return;
|
||||||
@@ -276,19 +273,17 @@ public class CommandListener : ICommandHookListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GroupCommandListener : ICommandHookListener
|
public class GroupCommandListener
|
||||||
{
|
{
|
||||||
public string ModId => "claimlink.group";
|
public string ModId => "claimlink.group";
|
||||||
|
|
||||||
public IReadOnlyList<string> Commands => new[] { "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, int> PendingDisbands = new Dictionary<string, int>();
|
||||||
internal static Dictionary<string, (string AffectedUid, int GroupId)> PendingMembershipChecks =
|
internal static Dictionary<string, (string AffectedUid, int GroupId)> PendingMembershipChecks =
|
||||||
new Dictionary<string, (string, int)>();
|
new Dictionary<string, (string, int)>();
|
||||||
|
|
||||||
private TextCommandResult? Before(TextCommandCallingArgs args)
|
internal TextCommandResult? Before(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
if (args.Caller.Player == null)
|
if (args.Caller.Player == null)
|
||||||
return null;
|
return null;
|
||||||
@@ -370,7 +365,7 @@ public class GroupCommandListener : ICommandHookListener
|
|||||||
PendingMembershipChecks[callerUid] = (targetUid, (int)groupId);
|
PendingMembershipChecks[callerUid] = (targetUid, (int)groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void After(TextCommandCallingArgs args, TextCommandResult result)
|
internal void After(TextCommandCallingArgs args, TextCommandResult result)
|
||||||
{
|
{
|
||||||
if (args.Caller.Player == null)
|
if (args.Caller.Player == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
"type": "Code",
|
"type": "Code",
|
||||||
"modid": "claimlink",
|
"modid": "claimlink",
|
||||||
"name": "ClaimLink",
|
"name": "ClaimLink",
|
||||||
"side": "Server",
|
"side": "Universal",
|
||||||
"authors": [
|
"authors": [
|
||||||
"anth64"
|
"anth64"
|
||||||
],
|
],
|
||||||
"description": "Link claims together with groups.",
|
"description": "Link claims together with groups.",
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"game": "1.22.5",
|
"game": "1.22.5"
|
||||||
"commandhook": "2.1.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user