From 2e4cc25b20c064afaf62f0323eede90e85df9270 Mon Sep 17 00:00:00 2001 From: anth64 Date: Mon, 20 Jul 2026 23:28:32 +0200 Subject: [PATCH] fix: guard claim-link entries against stale indices and dead groups --- ClaimLink/ClaimLinkChatCommand.cs | 13 +++++++++---- ClaimLink/ClaimLinkModSystem.cs | 4 ++-- ClaimLink/ClaimLinkRegistry.cs | 27 +++++++++++++++++---------- ClaimLink/LandCommandListener.cs | 5 +++++ 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/ClaimLink/ClaimLinkChatCommand.cs b/ClaimLink/ClaimLinkChatCommand.cs index 76c9e44..70ea928 100644 --- a/ClaimLink/ClaimLinkChatCommand.cs +++ b/ClaimLink/ClaimLinkChatCommand.cs @@ -326,9 +326,12 @@ public static class ClaimLinkChatCommand $"{claimDesc} will be linked into '{groupName}'.", () => { - ClaimLinkModSystem.Registry.AddEntry(playerUid, groupId, claimIndex); - - return TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'."); + bool success = ClaimLinkModSystem.Registry.AddEntry(playerUid, groupId, claimIndex); + return success + ? TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.") + : TextCommandResult.Error( + $"Unable to link {claimIndex} to '{groupName}' it is currently being modified." + ); } ); } @@ -546,7 +549,9 @@ public static class ClaimLinkChatCommand public static TextCommandResult List(TextCommandCallingArgs args) { List groupIds = ClaimLinkModSystem - .Registry.All.OrderByDescending(id => ClaimLinkModSystem.Registry.MemberCountForGroup(id)) + .Registry.All.OrderByDescending(id => + ClaimLinkModSystem.Registry.MemberCountForGroup(id) + ) .ToList(); if (groupIds.Count == 0) diff --git a/ClaimLink/ClaimLinkModSystem.cs b/ClaimLink/ClaimLinkModSystem.cs index 8ea5d04..b7ae7dd 100644 --- a/ClaimLink/ClaimLinkModSystem.cs +++ b/ClaimLink/ClaimLinkModSystem.cs @@ -19,10 +19,10 @@ public class ClaimLinkModSystem : ModSystem public override void StartServerSide(ICoreServerAPI api) { LandClaimAPI = api.World.Claims; + World = api.World; + Groups = api.Groups; Logger = api.Logger; Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame); - Groups = api.Groups; - World = api.World; CmdListener = new ClaimLinkCommandListener(); CommandHookModSystem.Register(CmdListener); diff --git a/ClaimLink/ClaimLinkRegistry.cs b/ClaimLink/ClaimLinkRegistry.cs index 3752780..d13a119 100644 --- a/ClaimLink/ClaimLinkRegistry.cs +++ b/ClaimLink/ClaimLinkRegistry.cs @@ -63,14 +63,19 @@ public class ClaimLinkRegistry return null; } - public void AddEntry(string uid, int groupId, int claimIndex) + public bool AddEntry(string uid, int groupId, int claimIndex) { + if (ClaimLinkCommandListener.PendingLoads.ContainsKey(uid)) + return false; + if (!Exists(groupId)) + return false; if (!entries.TryGetValue(uid, out var groups)) entries[uid] = groups = new(); if (!groups.TryGetValue(groupId, out var claims)) groups[groupId] = claims = new(); claims.Add(claimIndex); Save(); + return true; } public void RemoveEntry(string uid, int groupId, int claimIndex) @@ -93,6 +98,7 @@ public class ClaimLinkRegistry if (claims[i] > removedIndex) claims[i]--; } + Prune(); Save(); } @@ -119,6 +125,7 @@ public class ClaimLinkRegistry if (i >= 0) claims[i] = newIndex; } + Save(); } @@ -170,15 +177,15 @@ public class ClaimLinkRegistry { var entryList = new List(); foreach (var (uid, groups) in entries) - foreach (var (groupId, claims) in groups) - entryList.Add( - new ClaimLinkEntrySaveData - { - OwnerPlayerUid = uid, - GroupId = groupId, - ClaimIndicies = new(claims), - } - ); + foreach (var (groupId, claims) in groups) + entryList.Add( + new ClaimLinkEntrySaveData + { + OwnerPlayerUid = uid, + GroupId = groupId, + ClaimIndicies = new(claims), + } + ); saveGame.StoreData( SaveKey, diff --git a/ClaimLink/LandCommandListener.cs b/ClaimLink/LandCommandListener.cs index 966e9de..642cf05 100644 --- a/ClaimLink/LandCommandListener.cs +++ b/ClaimLink/LandCommandListener.cs @@ -83,6 +83,7 @@ public class ClaimLinkCommandListener : ICommandHookListener ClaimLinkModSystem.Registry.ClaimSaved(uid, pendingIndex); PendingLoads.Remove(uid); + ClaimLinkChatCommand.PendingActions.Remove(uid); } private static void ClaimLoad(Caller caller, CmdArgs args) @@ -119,6 +120,7 @@ public class ClaimLinkCommandListener : ICommandHookListener return; ClaimLinkModSystem.Registry.ClaimRemoved(uid, (int)claimIndex); + ClaimLinkChatCommand.PendingActions.Remove(uid); } private static void AdminFree(Caller caller, CmdArgs args) @@ -132,7 +134,10 @@ public class ClaimLinkCommandListener : ICommandHookListener foreach (LandClaim c in claims) if (ClaimLinkModSystem.TryResolveClaimIndex(c.OwnedByPlayerUid, c, out int claimIndex)) + { ClaimLinkModSystem.Registry.ClaimRemoved(c.OwnedByPlayerUid, claimIndex); + ClaimLinkChatCommand.PendingActions.Remove(c.OwnedByPlayerUid); + } } internal static void OnPlayerDisconnect(IServerPlayer player)