From ac79d2ac94307d30017c5baf0df14bacd9d28a66 Mon Sep 17 00:00:00 2001 From: anth64 Date: Sun, 12 Jul 2026 19:00:10 +0200 Subject: [PATCH] feat: implement claimlink link --- ClaimLink/ClaimLinkChatCommand.cs | 42 ++++++++++++++++++++++++++++--- ClaimLink/ClaimLinkModSystem.cs | 28 ++++++++++++++++++++- ClaimLink/ClaimLinkRegistry.cs | 12 ++++++++- ClaimLink/LandCommandListener.cs | 15 ++--------- 4 files changed, 79 insertions(+), 18 deletions(-) diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index ffe634d..ccda32e 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -57,8 +57,8 @@ public static class ClaimLinkChatCommand new(new[] { "new", "n" }, "Promote a group you own into a claim link (enters pending state).", new ICommandArgumentParser[] { p.Word("groupname") }, true, New), - new(new[] { "link", "l" }, "Link a claim you own into the pending or committed claim link.", - new ICommandArgumentParser[] { p.Word("claim") }, true, Link), + new(new[] { "link", "l" }, "Link a claim you own into a claim link.", + new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) }, true, Link), new(new[] { "confirm", "c" }, "Commit your pending claim link.", Array.Empty(), true, Confirm), @@ -130,7 +130,43 @@ public static class ClaimLinkChatCommand ClaimLinkModSystem.Registry.Add(new ClaimLink { GroupId = group.Uid }); return TextCommandResult.Success($"'{groupName}' is now a claim link."); } - public static TextCommandResult Link(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink link"); + public static TextCommandResult Link(TextCommandCallingArgs args) + { + string groupName = (string)args[0]; + int claimIndex = (int)args[1]; + + PlayerGroup? group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName); + if (group == null) + return TextCommandResult.Error($"No group named '{groupName}' exists."); + + ClaimLink? link = ClaimLinkModSystem.Registry.Get(group.Uid); + if (link == null) + return TextCommandResult.Error($"'{groupName}' is not a claim link."); + + IPlayer player = args.Caller.Player; + if (player.GetGroup(group.Uid) == null) + return TextCommandResult.Error($"You are not a member of '{groupName}'."); + + string playerUid = player.PlayerUID; + + if (!ClaimLinkModSystem.TryResolveOwnedClaim(playerUid, claimIndex, out _, out _)) + return TextCommandResult.Error("You do not own a claim with that index."); + + if (ClaimLinkModSystem.Registry.IsClaimLinked(playerUid, claimIndex)) + return TextCommandResult.Error("That claim is already part of a claim link."); + + ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid); + if (member == null) + { + member = new ClaimLinkMember { OwnerPlayerUid = playerUid }; + link.Members.Add(member); + } + + member.LocalClaimIndices.Add(claimIndex); + ClaimLinkModSystem.Registry.Save(); + + return TextCommandResult.Success($"Linked claim {claimIndex} into '{groupName}'."); + } public static TextCommandResult Confirm(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink confirm"); public static TextCommandResult Cancel(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink cancel"); public static TextCommandResult Unlink(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink unlink"); diff --git a/ClaimLink/ClaimLinkModSystem.cs b/ClaimLink/ClaimLinkModSystem.cs index 522f302..e8537b5 100644 --- a/ClaimLink/ClaimLinkModSystem.cs +++ b/ClaimLink/ClaimLinkModSystem.cs @@ -1,4 +1,5 @@ -using CommandHook; +using System.Collections.Generic; +using CommandHook; using Vintagestory.API.Common; using Vintagestory.API.Server; @@ -33,4 +34,29 @@ public class ClaimLinkModSystem : ModSystem if (cmdListener != null) CommandHookModSystem.Unregister(cmdListener); } + + internal static bool TryResolveOwnedClaim(string ownerPlayerUid, int localIndex, out int globalIndex, out LandClaim? claim) + { + globalIndex = -1; + claim = null; + + List claims = LandClaimAPI.All; + int count = 0; + for (int i = 0; i < claims.Count; ++i) + { + if (claims[i].OwnedByPlayerUid != ownerPlayerUid) + continue; + + if (count == localIndex) + { + globalIndex = i; + claim = claims[i]; + return true; + } + + count++; + } + + return false; + } } diff --git a/ClaimLink/ClaimLinkRegistry.cs b/ClaimLink/ClaimLinkRegistry.cs index 09dec59..ae1ae78 100644 --- a/ClaimLink/ClaimLinkRegistry.cs +++ b/ClaimLink/ClaimLinkRegistry.cs @@ -44,7 +44,17 @@ public class ClaimLinkRegistry Save(); } - private void Save() + public bool IsClaimLinked(string ownerPlayerUid, int localIndex) + { + foreach (ClaimLink link in byGroupId.Values) + foreach (ClaimLinkMember member in link.Members) + if (member.OwnerPlayerUid == ownerPlayerUid && member.LocalClaimIndices.Contains(localIndex)) + return true; + + return false; + } + + public void Save() { saveGame.StoreData(SaveKey, new ClaimLinkData { Links = new List(byGroupId.Values) }); } diff --git a/ClaimLink/LandCommandListener.cs b/ClaimLink/LandCommandListener.cs index df40a9e..72648c4 100644 --- a/ClaimLink/LandCommandListener.cs +++ b/ClaimLink/LandCommandListener.cs @@ -93,21 +93,10 @@ public class ClaimLinkCommandListener : ICommandHookListener if (claimIndex == null || claimIndex < 0 || claimIndex > 999) return; - List claims = ClaimLinkModSystem.LandClaimAPI.All, ownedClaims = new List(); - List globalIndex = new List(); - for (int i = 0; i < claims.Count; ++i) - { - if (claims[i].OwnedByPlayerUid != caller.Player.PlayerUID) - continue; - - globalIndex.Add(i); - ownedClaims.Add(claims[i]); - } - - if (claimIndex >= ownedClaims.Count) + if (!ClaimLinkModSystem.TryResolveOwnedClaim(caller.Player.PlayerUID, (int)claimIndex, out int globalIndex, out _)) return; - pendingLoads[caller.Player.PlayerUID] = globalIndex[(int)claimIndex]; + pendingLoads[caller.Player.PlayerUID] = globalIndex; } private static void ClaimCancel(Caller caller, CmdArgs args)