From 65e00e2f57c7f85c306e4ac6735a6618cd806b97 Mon Sep 17 00:00:00 2001 From: anth64 Date: Sun, 12 Jul 2026 19:09:40 +0200 Subject: [PATCH] feat: stage claimlink new behind confirm/cancel pending state --- ClaimLink/ClaimLinkChatCommand.cs | 73 +++++++++++++++++++++++++------ ClaimLink/LandCommandListener.cs | 1 + 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index ab67d38..3e50b29 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Vintagestory.API.Common; using Vintagestory.API.Server; @@ -113,6 +114,10 @@ public static class ClaimLinkChatCommand admin.EndSubCommand(); } + private static readonly Dictionary pendingLinks = new(); + + internal static void RemovePending(string playerUid) => pendingLinks.Remove(playerUid); + private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group) { group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName)!; @@ -125,6 +130,19 @@ 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; @@ -138,6 +156,7 @@ public static class ClaimLinkChatCommand public static TextCommandResult New(TextCommandCallingArgs args) { string groupName = (string)args[0]; + string playerUid = args.Caller.Player.PlayerUID; TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group); if (err != null) return err; @@ -145,11 +164,37 @@ 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."); - ClaimLinkModSystem.Registry.Add(new ClaimLink { GroupId = group.Uid }); - return TextCommandResult.Success($"'{groupName}' is now 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."); + } + + 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."); + + ClaimLinkModSystem.Registry.Add(pending); + pendingLinks.Remove(playerUid); + + return TextCommandResult.Success("Claim link confirmed."); + } + + 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."); + + return TextCommandResult.Success("Pending claim link discarded."); } public static TextCommandResult Link(TextCommandCallingArgs args) @@ -160,15 +205,15 @@ public static class ClaimLinkChatCommand TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group); if (err != null) return err; - err = TryResolveClaimLink(group, out ClaimLink link); + IPlayer player = args.Caller.Player; + string playerUid = player.PlayerUID; + + err = TryResolveClaimLinkForEdit(playerUid, group, out ClaimLink link, out bool isPending); 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."); @@ -183,12 +228,12 @@ public static class ClaimLinkChatCommand } member.LocalClaimIndices.Add(claimIndex); - ClaimLinkModSystem.Registry.Save(); + if (!isPending) + 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) { string groupName = (string)args[0]; @@ -197,11 +242,11 @@ public static class ClaimLinkChatCommand TextCommandResult? err = TryResolveGroup(groupName, out PlayerGroup group); if (err != null) return err; - err = TryResolveClaimLink(group, out ClaimLink link); - if (err != null) return err; - string playerUid = args.Caller.Player.PlayerUID; + err = TryResolveClaimLinkForEdit(playerUid, group, out ClaimLink link, out bool isPending); + if (err != null) return err; + ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid); if (member == null || !member.LocalClaimIndices.Remove(claimIndex)) return TextCommandResult.Error($"Claim {claimIndex} is not linked into '{groupName}' by you."); @@ -209,7 +254,9 @@ public static class ClaimLinkChatCommand if (member.LocalClaimIndices.Count == 0) link.Members.Remove(member); - ClaimLinkModSystem.Registry.Save(); + if (!isPending) + ClaimLinkModSystem.Registry.Save(); + return TextCommandResult.Success($"Unlinked claim {claimIndex} from '{groupName}'."); } public static TextCommandResult Kick(TextCommandCallingArgs args) => TextCommandResult.Success("stub: claimlink kick"); diff --git a/ClaimLink/LandCommandListener.cs b/ClaimLink/LandCommandListener.cs index 72648c4..768b938 100644 --- a/ClaimLink/LandCommandListener.cs +++ b/ClaimLink/LandCommandListener.cs @@ -131,5 +131,6 @@ public class ClaimLinkCommandListener : ICommandHookListener internal static void OnPlayerDisconnect(IServerPlayer player) { pendingLoads.Remove(player.PlayerUID); + ClaimLinkChatCommand.RemovePending(player.PlayerUID); } }