From 979f02e7f8b96e068bf978e793a59fc98bedd166 Mon Sep 17 00:00:00 2001 From: anth64 Date: Sun, 12 Jul 2026 20:50:04 +0200 Subject: [PATCH] feat: open info to any player, add claimlink list, bump to 0.0.6 Modified command messages. --- ClaimLink/ClaimLinkChatCommand.cs | 97 +++++++++++++++++++++---------- ClaimLink/ClaimLinkRegistry.cs | 2 + ClaimLink/modinfo.json | 2 +- 3 files changed, 68 insertions(+), 33 deletions(-) diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index c65ee80..07383ca 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using Vintagestory.API.Common; using Vintagestory.API.Server; @@ -51,61 +52,64 @@ public static class ClaimLinkChatCommand var root = api.ChatCommands.Create("claimlink") .WithAlias("clink", "claiml", "cl") - .WithDescription("Link vanilla land claims into shared, derived protective territory.") + .WithDescription("Link vanilla land claims together via group.") .RequiresPrivilege(Privilege.chat); CommandSpec[] playerCommands = { - new(new[] { "new", "n" }, "Promote a group you own into a claim link (requires confirm).", + new(new[] { "new", "n" }, "Promote a group you own to a claim link.", new ICommandArgumentParser[] { p.Word("groupname") }, true, New), - new(new[] { "link", "l" }, "Link a claim you own into a claim link (requires confirm).", + new(new[] { "link", "l" }, "Link a claim you own to a claim link.", new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) }, true, Link), - new(new[] { "confirm", "c" }, "Confirm your pending action.", + new(new[] { "confirm", "c" }, "Confirm pending action.", Array.Empty(), true, Confirm), - new(new[] { "cancel" }, "Discard your pending action.", + new(new[] { "cancel" }, "Cancel pending action.", Array.Empty(), true, Cancel), - new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link (requires confirm).", + new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link.", new ICommandArgumentParser[] { p.IntRange("claim", 0, 999) }, true, Unlink), - new(new[] { "kick" }, "Force-unlink all of a player's claims from the link (Owner/Op, requires confirm).", + new(new[] { "kick" }, "Force-unlink all of a player's claims from the claim link.", new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, Kick), - new(new[] { "delete" }, "Delete the claim link entirely (Owner).", + new(new[] { "delete" }, "Delete a claim link.", new ICommandArgumentParser[] { p.Word("groupname") }, true, Delete), - new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of the claim link to another player (Owner).", + new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of the claim link to another player.", new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, TransferOwnership), - new(new[] { "info", "i" }, "Show a claim link's linked claims, members, and territory (Owner/Op or admin).", + new(new[] { "info", "i" }, "Show a claim link's members and linked claims.", new ICommandArgumentParser[] { p.Word("groupname") }, true, Info), + + new(new[] { "list", "ls" }, "List all claim links.", + Array.Empty(), true, List), }; foreach (var spec in playerCommands) BuildSubCommand(root, spec); var admin = root.BeginSubCommands("admin", "a") - .WithDescription("Admin management for any claim link (op or console).") + .WithDescription("Admin commands for claim link.") .RequiresPrivilege(Privilege.controlserver); CommandSpec[] adminCommands = { - new(new[] { "delete", "del" }, "Delete any claim link entirely (claims and group untouched).", + new(new[] { "delete", "del" }, "Delete a claim link.", new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminDelete), - new(new[] { "unlink" }, "Force a single claim out of its link by player and claim (claim untouched).", + new(new[] { "unlink" }, "Unlink a claim.", new ICommandArgumentParser[] { p.OnlinePlayer("playername"), p.Word("claim") }, false, AdminUnlink), - new(new[] { "kick" }, "Force-unlink all of a player's claims from a link (claims untouched).", + new(new[] { "kick" }, "Force-unlink all of a player's claims.", new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminKick), new(new[] { "transferownership", "transfer", "to" }, "Transfer ownership of any claim link to another player.", new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, false, AdminTransferOwnership), - new(new[] { "info", "i" }, "Show any claim link's linked claims, members, and territory.", + new(new[] { "info", "i" }, "Show a claim link's members and linked claims.", new ICommandArgumentParser[] { p.Word("groupname") }, false, AdminInfo), }; @@ -122,7 +126,7 @@ public static class ClaimLinkChatCommand private static TextCommandResult Stage(string playerUid, string prompt, Func action) { pendingActions[playerUid] = action; - return TextCommandResult.Success($"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to discard."); + return TextCommandResult.Success($"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel."); } private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group) @@ -144,7 +148,7 @@ public static class ClaimLinkChatCommand private static TextCommandResult? RequireOwner(IPlayer player, PlayerGroup group) { - return group.OwnerUID != player.PlayerUID ? TextCommandResult.Error($"You do not own the group '{group.Name}'.") : null; + return group.OwnerUID != player.PlayerUID ? TextCommandResult.Error($"You do not own '{group.Name}'.") : null; } private static TextCommandResult? RequireOpOrOwner(IPlayer player, PlayerGroup group) @@ -170,7 +174,7 @@ public static class ClaimLinkChatCommand return TextCommandResult.Error($"'{groupName}' is already a claim link."); int groupId = group.Uid; - return Stage(playerUid, $"'{groupName}' will be promoted into a claim link.", () => + return Stage(playerUid, $"'{groupName}' will become a claim link.", () => { ClaimLinkModSystem.Registry.Add(new ClaimLink { GroupId = groupId }); return TextCommandResult.Success($"'{groupName}' is now a claim link."); @@ -195,7 +199,7 @@ public static class ClaimLinkChatCommand if (!pendingActions.Remove(playerUid)) return TextCommandResult.Error("You do not have a pending action."); - return TextCommandResult.Success("Pending action discarded."); + return TextCommandResult.Success("Pending action cancelled."); } public static TextCommandResult Link(TextCommandCallingArgs args) @@ -216,12 +220,13 @@ public static class ClaimLinkChatCommand string playerUid = player.PlayerUID; if (!ClaimLinkModSystem.TryResolveOwnedClaim(playerUid, claimIndex, out _, out _)) - return TextCommandResult.Error("You do not own a claim with that index."); + return TextCommandResult.Error("You do not own that claim."); if (ClaimLinkModSystem.Registry.IsClaimLinked(playerUid, claimIndex)) return TextCommandResult.Error("That claim is already part of a claim link."); - return Stage(playerUid, $"Claim {claimIndex} will be linked into '{groupName}'.", () => + string claimDesc = DescribeClaim(playerUid, claimIndex); + return Stage(playerUid, $"{claimDesc} will be linked into '{groupName}'.", () => { ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid); if (member == null) @@ -233,7 +238,7 @@ public static class ClaimLinkChatCommand member.LocalClaimIndices.Add(claimIndex); ClaimLinkModSystem.Registry.Save(); - return TextCommandResult.Success($"Linked claim {claimIndex} into '{groupName}'."); + return TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'."); }); } @@ -247,8 +252,9 @@ public static class ClaimLinkChatCommand return TextCommandResult.Error($"Claim {claimIndex} is not linked into any claim link by you."); string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name; + string claimDesc = DescribeClaim(playerUid, claimIndex); - return Stage(playerUid, $"Claim {claimIndex} will be unlinked from '{groupName}'.", () => + return Stage(playerUid, $"{claimDesc} will be unlinked from '{groupName}'.", () => { ClaimLinkMember member = link.Members.Find(m => m.OwnerPlayerUid == playerUid)!; member.LocalClaimIndices.Remove(claimIndex); @@ -256,7 +262,7 @@ public static class ClaimLinkChatCommand link.Members.Remove(member); ClaimLinkModSystem.Registry.Save(); - return TextCommandResult.Success($"Unlinked claim {claimIndex} from '{groupName}'."); + return TextCommandResult.Success($"Unlinked {claimDesc} from '{groupName}'."); }); } @@ -279,15 +285,15 @@ public static class ClaimLinkChatCommand ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == targetUid); if (member == null) - return TextCommandResult.Error($"{target.PlayerName} has no claims linked into '{groupName}'."); + return TextCommandResult.Error($"{target.PlayerName} has no claims linked in '{groupName}'."); - return Stage(playerUid, $"All of {target.PlayerName}'s claims will be kicked from '{groupName}'.", () => + return Stage(playerUid, $"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.", () => { link.Members.Remove(member); RemovePending(targetUid); ClaimLinkModSystem.Registry.Save(); - return TextCommandResult.Success($"Kicked all of {target.PlayerName}'s claims from '{groupName}'."); + return TextCommandResult.Success($"Unlinked all claims of {target.PlayerName} from '{groupName}'."); }); } @@ -327,21 +333,48 @@ public static class ClaimLinkChatCommand err = TryResolveClaimLink(group, out ClaimLink link); if (err != null) return err; - err = RequireOpOrOwner(args.Caller.Player, group); - if (err != null) return err; - return TextCommandResult.Success(FormatInfo(groupName, link)); } + public static TextCommandResult List(TextCommandCallingArgs args) + { + List links = ClaimLinkModSystem.Registry.All + .OrderByDescending(l => l.Members.Count) + .ToList(); + + if (links.Count == 0) + return TextCommandResult.Success("There are no claim links."); + + StringBuilder sb = new(); + sb.AppendLine($"Claim links ({links.Count}):"); + + foreach (ClaimLink link in links) + { + string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name; + sb.AppendLine($" {groupName}: {link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}"); + } + + return TextCommandResult.Success(sb.ToString()); + } + + private static string DescribeClaim(string ownerPlayerUid, int localIndex) + { + if (!ClaimLinkModSystem.TryResolveOwnedClaim(ownerPlayerUid, localIndex, out _, out LandClaim? claim) || claim == null) + return $"claim {localIndex}"; + + return string.IsNullOrEmpty(claim.Description) ? $"claim {localIndex}" : claim.Description; + } + private static string FormatInfo(string groupName, ClaimLink link) { StringBuilder sb = new(); - sb.AppendLine($"Claim link '{groupName}' ({link.Members.Count} member(s)):"); + sb.AppendLine($"Claim link '{groupName}' ({link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}):"); foreach (ClaimLinkMember member in link.Members) { string name = ClaimLinkModSystem.World.PlayerByUid(member.OwnerPlayerUid)?.PlayerName ?? member.OwnerPlayerUid; - sb.AppendLine($" {name}: claims [{string.Join(", ", member.LocalClaimIndices)}]"); + IEnumerable claims = member.LocalClaimIndices.Select(i => DescribeClaim(member.OwnerPlayerUid, i)); + sb.AppendLine($" {name}: claims [{string.Join(", ", claims)}]"); } return sb.ToString(); diff --git a/ClaimLink/ClaimLinkRegistry.cs b/ClaimLink/ClaimLinkRegistry.cs index 248ccfe..35b02ac 100644 --- a/ClaimLink/ClaimLinkRegistry.cs +++ b/ClaimLink/ClaimLinkRegistry.cs @@ -32,6 +32,8 @@ public class ClaimLinkRegistry public ClaimLink? Get(int groupId) => byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null; + public IReadOnlyCollection All => byGroupId.Values; + public void Add(ClaimLink link) { byGroupId[link.GroupId] = link; diff --git a/ClaimLink/modinfo.json b/ClaimLink/modinfo.json index 12652c0..c1de23a 100644 --- a/ClaimLink/modinfo.json +++ b/ClaimLink/modinfo.json @@ -8,7 +8,7 @@ "anth64" ], "description": "Link claims together with groups.", - "version": "0.0.5", + "version": "0.0.6", "dependencies": { "game": "1.22.3", "commandhook": "2.1.0"