From c035bf1a73eece875d0c198cb4a65413f86a5790 Mon Sep 17 00:00:00 2001 From: anth64 Date: Sun, 12 Jul 2026 19:43:00 +0200 Subject: [PATCH] refactor: replace pending-link buffer with generic pending-action confirm/cancel new/link/unlink/kick now stage a validated action and require confirm to execute, instead of new alone gating a multi-edit draft. Bump to 0.0.5. --- ClaimLink/ClaimLinkChatCommand.cs | 121 +++++++++++++++--------------- ClaimLink/modinfo.json | 2 +- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index d992d92..6f78466 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -56,22 +56,22 @@ public static class ClaimLinkChatCommand CommandSpec[] playerCommands = { - new(new[] { "new", "n" }, "Promote a group you own into a claim link (enters pending state).", + new(new[] { "new", "n" }, "Promote a group you own into a claim link (requires confirm).", new ICommandArgumentParser[] { p.Word("groupname") }, true, New), - new(new[] { "link", "l" }, "Link a claim you own into a claim link.", + new(new[] { "link", "l" }, "Link a claim you own into a claim link (requires confirm).", new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) }, true, Link), - new(new[] { "confirm", "c" }, "Commit your pending claim link.", + new(new[] { "confirm", "c" }, "Confirm your pending action.", Array.Empty(), true, Confirm), - new(new[] { "cancel" }, "Discard your pending claim link.", + new(new[] { "cancel" }, "Discard your pending action.", Array.Empty(), true, Cancel), - new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link.", + new(new[] { "unlink", "ul" }, "Remove a claim you own from its claim link (requires confirm).", new ICommandArgumentParser[] { p.Word("groupname"), p.IntRange("claim", 0, 999) }, true, Unlink), - new(new[] { "kick" }, "Force-unlink all of a player's claims from the link (Owner/Op).", + new(new[] { "kick" }, "Force-unlink all of a player's claims from the link (Owner/Op, requires confirm).", new ICommandArgumentParser[] { p.Word("groupname"), p.OnlinePlayer("playername") }, true, Kick), new(new[] { "delete" }, "Delete the claim link entirely (Owner).", @@ -115,9 +115,15 @@ public static class ClaimLinkChatCommand admin.EndSubCommand(); } - private static readonly Dictionary pendingLinks = new(); + private static readonly Dictionary> pendingActions = new(); - internal static void RemovePending(string playerUid) => pendingLinks.Remove(playerUid); + internal static void RemovePending(string playerUid) => pendingActions.Remove(playerUid); + + 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."); + } private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group) { @@ -131,19 +137,6 @@ public static class ClaimLinkChatCommand return link == null ? TextCommandResult.Error($"'{group.Name}' is not a claim link.") : null; } - private static TextCommandResult? TryResolveClaimLinkForEdit(string playerUid, PlayerGroup group, out ClaimLink link, out bool isPending) - { - if (pendingLinks.TryGetValue(playerUid, out ClaimLink? pending) && pending.GroupId == group.Uid) - { - link = pending; - isPending = true; - return null; - } - - isPending = false; - return TryResolveClaimLink(group, out link); - } - private static TextCommandResult? RequireMember(IPlayer player, PlayerGroup group) { return player.GetGroup(group.Uid) == null ? TextCommandResult.Error($"You are not a member of '{group.Name}'.") : null; @@ -173,37 +166,36 @@ public static class ClaimLinkChatCommand err = RequireOwner(args.Caller.Player, group); if (err != null) return err; - if (pendingLinks.ContainsKey(playerUid)) - return TextCommandResult.Error("You already have a pending claim link. Confirm or cancel it first."); - if (ClaimLinkModSystem.Registry.Get(group.Uid) != null) return TextCommandResult.Error($"'{groupName}' is already a claim link."); - pendingLinks[playerUid] = new ClaimLink { GroupId = group.Uid }; - return TextCommandResult.Success($"'{groupName}' is now a pending claim link. Use /claimlink link to add claims, then confirm."); + int groupId = group.Uid; + return Stage(playerUid, $"'{groupName}' will be promoted into a claim link.", () => + { + ClaimLinkModSystem.Registry.Add(new ClaimLink { GroupId = groupId }); + return TextCommandResult.Success($"'{groupName}' is now a claim link."); + }); } public static TextCommandResult Confirm(TextCommandCallingArgs args) { string playerUid = args.Caller.Player.PlayerUID; - if (!pendingLinks.TryGetValue(playerUid, out ClaimLink? pending)) - return TextCommandResult.Error("You do not have a pending claim link."); + if (!pendingActions.TryGetValue(playerUid, out Func? action)) + return TextCommandResult.Error("You do not have a pending action."); - ClaimLinkModSystem.Registry.Add(pending); - pendingLinks.Remove(playerUid); - - return TextCommandResult.Success("Claim link confirmed."); + pendingActions.Remove(playerUid); + return action(); } public static TextCommandResult Cancel(TextCommandCallingArgs args) { string playerUid = args.Caller.Player.PlayerUID; - if (!pendingLinks.Remove(playerUid)) - return TextCommandResult.Error("You do not have a pending claim link."); + if (!pendingActions.Remove(playerUid)) + return TextCommandResult.Error("You do not have a pending action."); - return TextCommandResult.Success("Pending claim link discarded."); + return TextCommandResult.Success("Pending action discarded."); } public static TextCommandResult Link(TextCommandCallingArgs args) @@ -214,33 +206,35 @@ public static class ClaimLinkChatCommand TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group); if (err != null) return err; - IPlayer player = args.Caller.Player; - string playerUid = player.PlayerUID; - - err = TryResolveClaimLinkForEdit(playerUid, group, out ClaimLink link, out bool isPending); + err = TryResolveClaimLink(group, out ClaimLink link); if (err != null) return err; + IPlayer player = args.Caller.Player; err = RequireMember(player, group); if (err != null) return err; + 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) + return Stage(playerUid, $"Claim {claimIndex} will be linked into '{groupName}'.", () => { - member = new ClaimLinkMember { OwnerPlayerUid = playerUid }; - link.Members.Add(member); - } + 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); - if (!isPending) + member.LocalClaimIndices.Add(claimIndex); ClaimLinkModSystem.Registry.Save(); - return TextCommandResult.Success($"Linked claim {claimIndex} into '{groupName}'."); + return TextCommandResult.Success($"Linked claim {claimIndex} into '{groupName}'."); + }); } public static TextCommandResult Unlink(TextCommandCallingArgs args) @@ -251,23 +245,26 @@ public static class ClaimLinkChatCommand TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group); if (err != null) return err; - string playerUid = args.Caller.Player.PlayerUID; - - err = TryResolveClaimLinkForEdit(playerUid, group, out ClaimLink link, out bool isPending); + err = TryResolveClaimLink(group, out ClaimLink link); if (err != null) return err; + string playerUid = args.Caller.Player.PlayerUID; + ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid); - if (member == null || !member.LocalClaimIndices.Remove(claimIndex)) + if (member == null || !member.LocalClaimIndices.Contains(claimIndex)) return TextCommandResult.Error($"Claim {claimIndex} is not linked into '{groupName}' by you."); - if (member.LocalClaimIndices.Count == 0) - link.Members.Remove(member); + return Stage(playerUid, $"Claim {claimIndex} will be unlinked from '{groupName}'.", () => + { + member.LocalClaimIndices.Remove(claimIndex); + if (member.LocalClaimIndices.Count == 0) + link.Members.Remove(member); - if (!isPending) ClaimLinkModSystem.Registry.Save(); - - return TextCommandResult.Success($"Unlinked claim {claimIndex} from '{groupName}'."); + return TextCommandResult.Success($"Unlinked claim {claimIndex} from '{groupName}'."); + }); } + public static TextCommandResult Kick(TextCommandCallingArgs args) { string groupName = (string)args[0]; @@ -283,18 +280,24 @@ public static class ClaimLinkChatCommand if (err != null) return err; string targetUid = target.PlayerUID; + string playerUid = args.Caller.Player.PlayerUID; ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == targetUid); if (member == null) return TextCommandResult.Error($"{target.PlayerName} has no claims linked into '{groupName}'."); - link.Members.Remove(member); - ClaimLinkModSystem.Registry.Save(); + return Stage(playerUid, $"All of {target.PlayerName}'s claims will be kicked from '{groupName}'.", () => + { + link.Members.Remove(member); + ClaimLinkModSystem.Registry.Save(); - return TextCommandResult.Success($"Kicked all of {target.PlayerName}'s claims from '{groupName}'."); + return TextCommandResult.Success($"Kicked all of {target.PlayerName}'s claims from '{groupName}'."); + }); } + public static TextCommandResult Delete(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink delete"); public static TextCommandResult TransferOwnership(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink transferownership"); + public static TextCommandResult Info(TextCommandCallingArgs args) { string groupName = (string)args[0]; diff --git a/ClaimLink/modinfo.json b/ClaimLink/modinfo.json index 44871a3..12652c0 100644 --- a/ClaimLink/modinfo.json +++ b/ClaimLink/modinfo.json @@ -8,7 +8,7 @@ "anth64" ], "description": "Link claims together with groups.", - "version": "0.0.4", + "version": "0.0.5", "dependencies": { "game": "1.22.3", "commandhook": "2.1.0"