refactor: normalize claim link membership into flat entry storage

This commit is contained in:
2026-07-15 18:46:52 +02:00
parent eaa79f8f52
commit fffc046126
4 changed files with 145 additions and 65 deletions
+113 -7
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using ProtoBuf;
using Vintagestory.API.Server;
@@ -9,6 +10,9 @@ public class ClaimLinkData
{
[ProtoMember(1)]
public List<ClaimLink> Links = new();
[ProtoMember(2)]
public List<ClaimLinkEntry> Entries = new();
}
public class ClaimLinkRegistry
@@ -18,6 +22,8 @@ public class ClaimLinkRegistry
private readonly ISaveGame saveGame;
private readonly Dictionary<int, ClaimLink> byGroupId = new();
private readonly Dictionary<string, Dictionary<int, List<int>>> byPlayer = new();
public ClaimLinkRegistry(ISaveGame saveGame)
{
this.saveGame = saveGame;
@@ -28,9 +34,13 @@ public class ClaimLinkRegistry
foreach (ClaimLink link in data.Links)
byGroupId[link.GroupId] = link;
foreach (ClaimLinkEntry entry in data.Entries)
GetOrCreateIndices(entry.OwnerPlayerUid, entry.GroupId).Add(entry.ClaimIndex);
}
public ClaimLink? Get(int groupId) => byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null;
public ClaimLink? Get(int groupId) =>
byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null;
public IReadOnlyCollection<ClaimLink> All => byGroupId.Values;
@@ -43,23 +53,119 @@ public class ClaimLinkRegistry
public void Remove(int groupId)
{
byGroupId.Remove(groupId);
List<string> emptyPlayerUids = new();
foreach (KeyValuePair<string, Dictionary<int, List<int>>> playerEntry in byPlayer)
{
playerEntry.Value.Remove(groupId);
if (playerEntry.Value.Count == 0)
emptyPlayerUids.Add(playerEntry.Key);
}
foreach (string uid in emptyPlayerUids)
byPlayer.Remove(uid);
Save();
}
public bool IsClaimLinked(string ownerPlayerUid, int localIndex) => FindLinkContaining(ownerPlayerUid, localIndex) != null;
public bool IsClaimLinked(string ownerPlayerUid, int localIndex) =>
FindLinkContaining(ownerPlayerUid, localIndex) != null;
public ClaimLink? FindLinkContaining(string ownerPlayerUid, int localIndex)
{
foreach (ClaimLink link in byGroupId.Values)
foreach (ClaimLinkMember member in link.Members)
if (member.OwnerPlayerUid == ownerPlayerUid && member.LocalClaimIndices.Contains(localIndex))
return link;
if (!byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup))
return null;
foreach (KeyValuePair<int, List<int>> entry in perGroup)
if (entry.Value.Contains(localIndex))
return Get(entry.Key);
return null;
}
public void AddEntry(string ownerPlayerUid, int groupId, int localClaimIndex)
{
GetOrCreateIndices(ownerPlayerUid, groupId).Add(localClaimIndex);
Save();
}
public void RemoveEntry(string ownerPlayerUid, int groupId, int localClaimIndex)
{
if (
byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup)
&& perGroup.TryGetValue(groupId, out List<int>? indices)
)
{
indices.Remove(localClaimIndex);
if (indices.Count == 0)
perGroup.Remove(groupId);
if (perGroup.Count == 0)
byPlayer.Remove(ownerPlayerUid);
}
Save();
}
public bool HasAnyEntry(string ownerPlayerUid, int groupId) =>
byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup)
&& perGroup.TryGetValue(groupId, out List<int>? indices)
&& indices.Count > 0;
public void RemoveAllForPlayerInGroup(string ownerPlayerUid, int groupId)
{
if (byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup))
{
perGroup.Remove(groupId);
if (perGroup.Count == 0)
byPlayer.Remove(ownerPlayerUid);
}
Save();
}
public IEnumerable<string> MemberUidsForGroup(int groupId) =>
byPlayer
.Where(kv => kv.Value.TryGetValue(groupId, out List<int>? indices) && indices.Count > 0)
.Select(kv => kv.Key);
public int MemberCountForGroup(int groupId) => MemberUidsForGroup(groupId).Count();
public IReadOnlyList<int> ClaimsForPlayerInGroup(string ownerPlayerUid, int groupId) =>
byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup)
&& perGroup.TryGetValue(groupId, out List<int>? indices)
? indices
: System.Array.Empty<int>();
private List<int> GetOrCreateIndices(string playerUid, int groupId)
{
if (!byPlayer.TryGetValue(playerUid, out Dictionary<int, List<int>>? perGroup))
byPlayer[playerUid] = perGroup = new Dictionary<int, List<int>>();
if (!perGroup.TryGetValue(groupId, out List<int>? indices))
perGroup[groupId] = indices = new List<int>();
return indices;
}
public void Save()
{
saveGame.StoreData(SaveKey, new ClaimLinkData { Links = new List<ClaimLink>(byGroupId.Values) });
List<ClaimLinkEntry> entries = new();
foreach (KeyValuePair<string, Dictionary<int, List<int>>> playerEntry in byPlayer)
foreach (KeyValuePair<int, List<int>> groupEntry in playerEntry.Value)
foreach (int index in groupEntry.Value)
entries.Add(
new ClaimLinkEntry
{
OwnerPlayerUid = playerEntry.Key,
GroupId = groupEntry.Key,
ClaimIndex = index,
}
);
saveGame.StoreData(
SaveKey,
new ClaimLinkData { Links = new List<ClaimLink>(byGroupId.Values), Entries = entries }
);
}
}