diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index ad94de9..d2beda9 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -195,6 +195,8 @@ public static class ClaimLinkChatCommand (int GroupId, Func Action) > PendingActions = new(); + internal static readonly Dictionary LastCancelReason = new(); + private static TextCommandResult Stage( string playerUid, int groupId, @@ -203,12 +205,13 @@ public static class ClaimLinkChatCommand ) { PendingActions[playerUid] = (groupId, action); + LastCancelReason.Remove(playerUid); return TextCommandResult.Success( $"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel." ); } - internal static void RemovePendingActionsForGroup(int groupId) + internal static void RemovePendingActionsForGroup(int groupId, string reason) { List? toRemove = null; foreach (var (uid, entry) in PendingActions) @@ -219,7 +222,19 @@ public static class ClaimLinkChatCommand return; foreach (string uid in toRemove) + { PendingActions.Remove(uid); + LastCancelReason[uid] = reason; + } + } + + internal static void CancelPendingAction(string uid, int groupId, string reason) + { + if (!PendingActions.TryGetValue(uid, out var pending) || pending.GroupId != groupId) + return; + + PendingActions.Remove(uid); + LastCancelReason[uid] = reason; } private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group) @@ -299,9 +314,14 @@ public static class ClaimLinkChatCommand string playerUid = args.Caller.Player.PlayerUID; if (!PendingActions.TryGetValue(playerUid, out var pending)) + { + if (LastCancelReason.Remove(playerUid, out string? reason)) + return TextCommandResult.Error($"You do not have a pending action ({reason})."); return TextCommandResult.Error("You do not have a pending action."); + } PendingActions.Remove(playerUid); + LastCancelReason.Remove(playerUid); return pending.Action(); } @@ -458,7 +478,7 @@ public static class ClaimLinkChatCommand $"'{groupName}' will be deleted as a claim link.", () => { - RemovePendingActionsForGroup(groupId); + RemovePendingActionsForGroup(groupId, "claim link was deleted"); ClaimLinkModSystem.Registry.Remove(groupId); return TextCommandResult.Success($"'{groupName}' is no longer a claim link."); } @@ -608,7 +628,7 @@ public static class ClaimLinkChatCommand ) ) { - RemovePendingActionsForGroup(groupId); + RemovePendingActionsForGroup(groupId, "group no longer exists"); ClaimLinkModSystem.Registry.Remove(groupId); continue; } diff --git a/ClaimLink/CommandListener.cs b/ClaimLink/CommandListener.cs index e2b8d02..98ecd1b 100644 --- a/ClaimLink/CommandListener.cs +++ b/ClaimLink/CommandListener.cs @@ -173,27 +173,89 @@ public class GroupCommandListener : ICommandHookListener public CommandRegistration Registration => new(Before, After); internal static Dictionary PendingDisbands = new Dictionary(); + internal static Dictionary PendingMembershipChecks = + new Dictionary(); private TextCommandResult? Before(TextCommandCallingArgs args) { if (args.Caller.Player == null) return null; + string callerUid = args.Caller.Player.PlayerUID; CmdArgs rawArgs = args.RawArgs.Clone(); - if (rawArgs.PopWord() != "confirmdisband") - return null; + string? word = rawArgs.PopWord(); + switch (word) + { + case "confirmdisband": + ConfirmDisband(args, callerUid, rawArgs); + break; + case "leave": + Leave(args, callerUid, rawArgs); + break; + case "kick": + Kick(args, callerUid, rawArgs); + break; + } + + return null; + } + + private static void ConfirmDisband( + TextCommandCallingArgs args, + string callerUid, + CmdArgs rawArgs + ) + { string? name = rawArgs.PopWord(); int? groupId = name != null ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid : args.Caller.FromChatGroupId; - if (groupId == null) - return null; + if (groupId != null) + PendingDisbands[callerUid] = (int)groupId; + } - PendingDisbands[args.Caller.Player.PlayerUID] = (int)groupId; - return null; + private static void Leave(TextCommandCallingArgs args, string callerUid, CmdArgs rawArgs) + { + string? name = rawArgs.PopWord(); + int? groupId = + name != null + ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid + : args.Caller.FromChatGroupId; + + if (groupId != null) + PendingMembershipChecks[callerUid] = (callerUid, (int)groupId); + } + + private static void Kick(TextCommandCallingArgs args, string callerUid, CmdArgs rawArgs) + { + string? word1 = rawArgs.PopWord(); + string? word2 = rawArgs.PopWord(); + + string? targetName; + int? groupId; + if (word2 != null) + { + groupId = + word1 != null ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(word1)?.Uid : null; + targetName = word2; + } + else + { + targetName = word1; + groupId = args.Caller.FromChatGroupId; + } + + if (targetName == null || groupId == null) + return; + + string? targetUid = ClaimLinkModSystem + .PlayerData.GetPlayerDataByLastKnownName(targetName) + ?.PlayerUID; + if (targetUid != null) + PendingMembershipChecks[callerUid] = (targetUid, (int)groupId); } private void After(TextCommandCallingArgs args, TextCommandResult result) @@ -201,23 +263,45 @@ public class GroupCommandListener : ICommandHookListener if (args.Caller.Player == null) return; - string uid = args.Caller.Player.PlayerUID; - if (!PendingDisbands.TryGetValue(uid, out int groupId)) - return; + string callerUid = args.Caller.Player.PlayerUID; - PendingDisbands.Remove(uid); + if (PendingDisbands.TryGetValue(callerUid, out int disbandedGroupId)) + { + PendingDisbands.Remove(callerUid); - if (ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(groupId)) - return; + if (!ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(disbandedGroupId)) + { + ClaimLinkChatCommand.RemovePendingActionsForGroup( + disbandedGroupId, + "group no longer exists" + ); - ClaimLinkChatCommand.RemovePendingActionsForGroup(groupId); + if (ClaimLinkModSystem.Registry.Exists(disbandedGroupId)) + ClaimLinkModSystem.Registry.Remove(disbandedGroupId); + } + } - if (ClaimLinkModSystem.Registry.Exists(groupId)) - ClaimLinkModSystem.Registry.Remove(groupId); + if (PendingMembershipChecks.TryGetValue(callerUid, out var check)) + { + PendingMembershipChecks.Remove(callerUid); + + bool stillMember = + ClaimLinkModSystem + .PlayerData.GetPlayerDataByUid(check.AffectedUid) + ?.PlayerGroupMemberships.ContainsKey(check.GroupId) == true; + + if (!stillMember) + ClaimLinkChatCommand.CancelPendingAction( + check.AffectedUid, + check.GroupId, + "you are no longer a member of the group" + ); + } } internal static void OnPlayerDisconnect(IServerPlayer player) { PendingDisbands.Remove(player.PlayerUID); + PendingMembershipChecks.Remove(player.PlayerUID); } }