diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index 80b8196..3f27637 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -190,20 +190,38 @@ public static class ClaimLinkChatCommand admin.EndSubCommand(); } - internal static readonly Dictionary> PendingActions = new(); + internal static readonly Dictionary< + string, + (int GroupId, Func Action) + > PendingActions = new(); private static TextCommandResult Stage( string playerUid, + int groupId, string prompt, Func action ) { - PendingActions[playerUid] = action; + PendingActions[playerUid] = (groupId, action); return TextCommandResult.Success( $"{prompt} Use /claimlink confirm to proceed, or /claimlink cancel to cancel." ); } + internal static void RemovePendingActionsForGroup(int groupId) + { + List? toRemove = null; + foreach (var (uid, entry) in PendingActions) + if (entry.GroupId == groupId) + (toRemove ??= new()).Add(uid); + + if (toRemove == null) + return; + + foreach (string uid in toRemove) + PendingActions.Remove(uid); + } + private static TextCommandResult? TryResolveGroup(string groupName, out PlayerGroup group) { group = ClaimLinkModSystem.Groups.GetPlayerGroupByName(groupName)!; @@ -263,6 +281,7 @@ public static class ClaimLinkChatCommand int groupId = group.Uid; return Stage( playerUid, + groupId, $"'{groupName}' will become a claim link.", () => { @@ -276,11 +295,11 @@ public static class ClaimLinkChatCommand { string playerUid = args.Caller.Player.PlayerUID; - if (!PendingActions.TryGetValue(playerUid, out Func? action)) + if (!PendingActions.TryGetValue(playerUid, out var pending)) return TextCommandResult.Error("You do not have a pending action."); PendingActions.Remove(playerUid); - return action(); + return pending.Action(); } public static TextCommandResult Cancel(TextCommandCallingArgs args) @@ -323,6 +342,7 @@ public static class ClaimLinkChatCommand string claimDesc = DescribeClaim(playerUid, claimIndex); return Stage( playerUid, + groupId, $"{claimDesc} will be linked into '{groupName}'.", () => { @@ -359,6 +379,7 @@ public static class ClaimLinkChatCommand return Stage( playerUid, + (int)groupId, $"{claimDesc} will be unlinked from '{groupName}'.", () => { @@ -395,11 +416,12 @@ public static class ClaimLinkChatCommand return Stage( playerUid, + group.Uid, $"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.", () => { ClaimLinkModSystem.Registry.RemoveAllForPlayerInGroup(targetUid, group.Uid); - ClaimLinkCommandListener.PendingLoads.Remove(targetUid); + CommandListener.PendingLoads.Remove(targetUid); PendingActions.Remove(targetUid); return TextCommandResult.Success( @@ -429,12 +451,11 @@ public static class ClaimLinkChatCommand int groupId = group.Uid; return Stage( playerUid, + groupId, $"'{groupName}' will be deleted as a claim link.", () => { - foreach (string uid in ClaimLinkModSystem.Registry.MemberUidsForGroup(groupId)) - PendingActions.Remove(uid); - + RemovePendingActionsForGroup(groupId); ClaimLinkModSystem.Registry.Remove(groupId); return TextCommandResult.Success($"'{groupName}' is no longer a claim link."); } @@ -476,6 +497,7 @@ public static class ClaimLinkChatCommand return Stage( playerUid, + group.Uid, $"Ownership of '{groupName}' will be transferred to {target.PlayerName}.", () => ExecuteTransferOwnership(group, target) ); @@ -572,16 +594,31 @@ public static class ClaimLinkChatCommand return TextCommandResult.Success("There are no claim links."); StringBuilder sb = new(); - sb.AppendLine($"Claim links ({groupIds.Count}):"); + int shown = 0; foreach (int groupId in groupIds) { - string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[groupId].Name; + if ( + !ClaimLinkModSystem.Groups.PlayerGroupsById.TryGetValue( + groupId, + out PlayerGroup? group + ) + ) + { + RemovePendingActionsForGroup(groupId); + ClaimLinkModSystem.Registry.Remove(groupId); + continue; + } + int memberCount = ClaimLinkModSystem.Registry.MemberCountForGroup(groupId); - sb.AppendLine($" {groupName}: {memberCount} member{(memberCount == 1 ? "" : "s")}"); + sb.AppendLine($" {group.Name}: {memberCount} member{(memberCount == 1 ? "" : "s")}"); + shown++; } - return TextCommandResult.Success(sb.ToString()); + if (shown == 0) + return TextCommandResult.Success("There are no claim links."); + + return TextCommandResult.Success($"Claim links ({shown}):\n{sb}"); } private static string DescribeClaim(string ownerPlayerUid, int claimIndex) diff --git a/ClaimLink/ClaimLinkModSystem.cs b/ClaimLink/ClaimLinkModSystem.cs index 3f1f086..f71a46b 100644 --- a/ClaimLink/ClaimLinkModSystem.cs +++ b/ClaimLink/ClaimLinkModSystem.cs @@ -13,7 +13,8 @@ public class ClaimLinkModSystem : ModSystem internal static IGroupManager Groups = null!; internal static IWorldAccessor World = null!; internal static IPlayerDataManager PlayerData = null!; - internal ClaimLinkCommandListener? CmdListener; + internal CommandListener? CmdListener; + internal GroupCommandListener? GroupCmdListener; public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server; @@ -26,11 +27,14 @@ public class ClaimLinkModSystem : ModSystem PlayerData = api.PlayerData; Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame); - CmdListener = new ClaimLinkCommandListener(); + CmdListener = new CommandListener(); CommandHookModSystem.Register(CmdListener); + GroupCmdListener = new GroupCommandListener(); + CommandHookModSystem.Register(GroupCmdListener); ClaimLinkChatCommand.Register(api); - api.Event.PlayerDisconnect += ClaimLinkCommandListener.OnPlayerDisconnect; + api.Event.PlayerDisconnect += CommandListener.OnPlayerDisconnect; + api.Event.PlayerDisconnect += GroupCommandListener.OnPlayerDisconnect; api.Event.PlayerDisconnect += ClaimLinkChatCommand.OnPlayerDisconnect; } @@ -38,6 +42,8 @@ public class ClaimLinkModSystem : ModSystem { if (CmdListener != null) CommandHookModSystem.Unregister(CmdListener); + if (GroupCmdListener != null) + CommandHookModSystem.Unregister(GroupCmdListener); } private static IEnumerable<(int claimIndex, LandClaim claim)> EnumerateOwnedClaims( diff --git a/ClaimLink/ClaimLinkRegistry.cs b/ClaimLink/ClaimLinkRegistry.cs index 6323a1c..03bfc33 100644 --- a/ClaimLink/ClaimLinkRegistry.cs +++ b/ClaimLink/ClaimLinkRegistry.cs @@ -65,7 +65,7 @@ public class ClaimLinkRegistry public bool AddEntry(string uid, int groupId, int claimIndex) { - if (ClaimLinkCommandListener.PendingLoads.ContainsKey(uid)) + if (CommandListener.PendingLoads.ContainsKey(uid)) return false; if (!Exists(groupId)) return false; diff --git a/ClaimLink/CommandListener.cs b/ClaimLink/CommandListener.cs index ba3fed1..60fd6eb 100644 --- a/ClaimLink/CommandListener.cs +++ b/ClaimLink/CommandListener.cs @@ -5,16 +5,15 @@ using Vintagestory.API.Server; namespace ClaimLink; -public class ClaimLinkCommandListener : ICommandHookListener +public class CommandListener : ICommandHookListener { public string ModId => "claimlink"; - public IReadOnlyList Commands => new[] { "land", "group" }; + public IReadOnlyList Commands => new[] { "land" }; public CommandRegistration Registration => new(Before, After); internal static Dictionary PendingLoads = new Dictionary(); - internal static Dictionary PendingDisbands = new Dictionary(); private delegate void SubHandler(Caller caller, CmdArgs args); @@ -33,23 +32,15 @@ public class ClaimLinkCommandListener : ICommandHookListener ["cancel"] = ClaimCancel, }; - private static readonly Dictionary groupTopLevel = new() - { - ["confirmdisband"] = GroupConfirmDisband, - }; - private static void Dispatch(TextCommandCallingArgs args) { - Dictionary table = - args.Command?.Name == "group" ? groupTopLevel : topLevel; - CmdArgs rawArgs = args.RawArgs.Clone(); while (rawArgs.Length > 0) { string word = rawArgs.PeekWord(); - if (table.TryGetValue(word, out SubHandler? handler)) + if (topLevel.TryGetValue(word, out SubHandler? handler)) { rawArgs.PopWord(); handler(args.Caller, rawArgs); @@ -67,45 +58,7 @@ public class ClaimLinkCommandListener : ICommandHookListener return null; } - private void After(TextCommandCallingArgs args, TextCommandResult result) - { - if (args.Caller.Player == null) - return; - - string uid = args.Caller.Player.PlayerUID; - if (!PendingDisbands.TryGetValue(uid, out int groupId)) - return; - - PendingDisbands.Remove(uid); - - if (ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(groupId)) - return; - - if (!ClaimLinkModSystem.Registry.Exists(groupId)) - return; - - foreach (string memberUid in ClaimLinkModSystem.Registry.MemberUidsForGroup(groupId)) - ClaimLinkChatCommand.PendingActions.Remove(memberUid); - - ClaimLinkModSystem.Registry.Remove(groupId); - } - - private static void GroupConfirmDisband(Caller caller, CmdArgs args) - { - if (caller.Player == null) - return; - - string? name = args.PopWord(); - int? groupId = - name != null - ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid - : caller.FromChatGroupId; - - if (groupId == null) - return; - - PendingDisbands[caller.Player.PlayerUID] = (int)groupId; - } + private void After(TextCommandCallingArgs args, TextCommandResult result) { } private static void Claim(Caller caller, CmdArgs args) { @@ -210,3 +163,62 @@ public class ClaimLinkCommandListener : ICommandHookListener PendingLoads.Remove(player.PlayerUID); } } + +public class GroupCommandListener : ICommandHookListener +{ + public string ModId => "claimlink.group"; + + public IReadOnlyList Commands => new[] { "group" }; + + public CommandRegistration Registration => new(Before, After); + + internal static Dictionary PendingDisbands = new Dictionary(); + + private TextCommandResult? Before(TextCommandCallingArgs args) + { + if (args.Caller.Player == null) + return null; + + CmdArgs rawArgs = args.RawArgs.Clone(); + if (rawArgs.PopWord() != "confirmdisband") + return null; + + string? name = rawArgs.PopWord(); + int? groupId = + name != null + ? ClaimLinkModSystem.Groups.GetPlayerGroupByName(name)?.Uid + : args.Caller.FromChatGroupId; + + if (groupId == null) + return null; + + PendingDisbands[args.Caller.Player.PlayerUID] = (int)groupId; + return null; + } + + private void After(TextCommandCallingArgs args, TextCommandResult result) + { + if (args.Caller.Player == null) + return; + + string uid = args.Caller.Player.PlayerUID; + if (!PendingDisbands.TryGetValue(uid, out int groupId)) + return; + + PendingDisbands.Remove(uid); + + if (ClaimLinkModSystem.Groups.PlayerGroupsById.ContainsKey(groupId)) + return; + + if (!ClaimLinkModSystem.Registry.Exists(groupId)) + return; + + ClaimLinkChatCommand.RemovePendingActionsForGroup(groupId); + ClaimLinkModSystem.Registry.Remove(groupId); + } + + internal static void OnPlayerDisconnect(IServerPlayer player) + { + PendingDisbands.Remove(player.PlayerUID); + } +} diff --git a/ClaimLink/modinfo.json b/ClaimLink/modinfo.json index c1de23a..ae3ae38 100644 --- a/ClaimLink/modinfo.json +++ b/ClaimLink/modinfo.json @@ -10,7 +10,7 @@ "description": "Link claims together with groups.", "version": "0.0.6", "dependencies": { - "game": "1.22.3", + "game": "1.22.5", "commandhook": "2.1.0" } }