refactor: rebuild claim link registry around live index tracking, drop ClaimLink type
This commit is contained in:
+117
-100
@@ -1,171 +1,188 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ProtoBuf;
|
||||
using Vintagestory.API.Server;
|
||||
|
||||
namespace ClaimLink;
|
||||
|
||||
[ProtoContract]
|
||||
public class ClaimLinkData
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public List<ClaimLink> Links = new();
|
||||
|
||||
[ProtoMember(2)]
|
||||
public List<ClaimLinkEntry> Entries = new();
|
||||
}
|
||||
|
||||
public class ClaimLinkRegistry
|
||||
{
|
||||
private const string SaveKey = "claimlink:links";
|
||||
private const string SaveKey = "claimlink:claimlinkdata";
|
||||
|
||||
private readonly ISaveGame saveGame;
|
||||
private readonly Dictionary<int, ClaimLink> byGroupId = new();
|
||||
|
||||
private readonly Dictionary<string, Dictionary<int, List<int>>> byPlayer = new();
|
||||
private readonly List<int> claimLinks = new();
|
||||
private readonly Dictionary<string, Dictionary<int, List<int>>> entries = new();
|
||||
|
||||
public ClaimLinkRegistry(ISaveGame saveGame)
|
||||
{
|
||||
this.saveGame = saveGame;
|
||||
|
||||
ClaimLinkData? data = saveGame.GetData<ClaimLinkData?>(SaveKey, null);
|
||||
ClaimLinkSaveData? data = saveGame.GetData<ClaimLinkSaveData?>(SaveKey, null);
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
foreach (ClaimLink link in data.Links)
|
||||
byGroupId[link.GroupId] = link;
|
||||
claimLinks.AddRange(data.Links);
|
||||
|
||||
foreach (ClaimLinkEntry entry in data.Entries)
|
||||
GetOrCreateIndices(entry.OwnerPlayerUid, entry.GroupId).Add(entry.ClaimIndex);
|
||||
foreach (var entry in data.Entries)
|
||||
{
|
||||
if (!entries.ContainsKey(entry.OwnerPlayerUid))
|
||||
entries[entry.OwnerPlayerUid] = new Dictionary<int, List<int>>();
|
||||
|
||||
entries[entry.OwnerPlayerUid][entry.GroupId] = new(entry.ClaimIndicies);
|
||||
}
|
||||
}
|
||||
|
||||
public ClaimLink? Get(int groupId) =>
|
||||
byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null;
|
||||
public IReadOnlyList<int> All => claimLinks;
|
||||
|
||||
public IReadOnlyCollection<ClaimLink> All => byGroupId.Values;
|
||||
public bool Exists(int groupId) => claimLinks.Contains(groupId);
|
||||
|
||||
public void Add(ClaimLink link)
|
||||
public void Add(int groupId)
|
||||
{
|
||||
byGroupId[link.GroupId] = link;
|
||||
claimLinks.Add(groupId);
|
||||
Save();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
claimLinks.Remove(groupId);
|
||||
foreach (var groups in entries.Values)
|
||||
groups.Remove(groupId);
|
||||
Prune();
|
||||
Save();
|
||||
}
|
||||
|
||||
public bool IsClaimLinked(string ownerPlayerUid, int claimIndex) =>
|
||||
FindLinkContaining(ownerPlayerUid, claimIndex) != null;
|
||||
public bool IsClaimLinked(string uid, int claimIndex) =>
|
||||
FindGroupContaining(uid, claimIndex) != null;
|
||||
|
||||
public ClaimLink? FindLinkContaining(string ownerPlayerUid, int claimIndex)
|
||||
public int? FindGroupContaining(string uid, int claimIndex)
|
||||
{
|
||||
if (!byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup))
|
||||
if (!entries.TryGetValue(uid, out var groups))
|
||||
return null;
|
||||
|
||||
foreach (KeyValuePair<int, List<int>> entry in perGroup)
|
||||
if (entry.Value.Contains(claimIndex))
|
||||
return Get(entry.Key);
|
||||
|
||||
foreach (var (groupId, claims) in groups)
|
||||
if (claims.Contains(claimIndex))
|
||||
return groupId;
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AddEntry(string ownerPlayerUid, int groupId, int claimIndex)
|
||||
public void AddEntry(string uid, int groupId, int claimIndex)
|
||||
{
|
||||
GetOrCreateIndices(ownerPlayerUid, groupId).Add(claimIndex);
|
||||
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();
|
||||
}
|
||||
|
||||
public void RemoveEntry(string ownerPlayerUid, int groupId, int claimIndex)
|
||||
public void RemoveEntry(string uid, int groupId, int claimIndex)
|
||||
{
|
||||
if (
|
||||
byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup)
|
||||
&& perGroup.TryGetValue(groupId, out List<int>? indices)
|
||||
)
|
||||
if (entries.TryGetValue(uid, out var groups) && groups.TryGetValue(groupId, out var claims))
|
||||
claims.Remove(claimIndex);
|
||||
Prune();
|
||||
Save();
|
||||
}
|
||||
|
||||
public void ClaimRemoved(string uid, int removedIndex)
|
||||
{
|
||||
if (!entries.TryGetValue(uid, out var groups))
|
||||
return;
|
||||
|
||||
foreach (var claims in groups.Values)
|
||||
{
|
||||
indices.Remove(claimIndex);
|
||||
if (indices.Count == 0)
|
||||
perGroup.Remove(groupId);
|
||||
|
||||
if (perGroup.Count == 0)
|
||||
byPlayer.Remove(ownerPlayerUid);
|
||||
claims.Remove(removedIndex);
|
||||
for (int i = 0; i < claims.Count; i++)
|
||||
if (claims[i] > removedIndex)
|
||||
claims[i]--;
|
||||
}
|
||||
|
||||
Prune();
|
||||
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)
|
||||
public void ClaimSaved(string uid, int claimIndex)
|
||||
{
|
||||
if (byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup))
|
||||
{
|
||||
perGroup.Remove(groupId);
|
||||
if (perGroup.Count == 0)
|
||||
byPlayer.Remove(ownerPlayerUid);
|
||||
}
|
||||
if (!entries.TryGetValue(uid, out var groups))
|
||||
return;
|
||||
|
||||
int count = 0;
|
||||
foreach (Vintagestory.API.Common.LandClaim c in ClaimLinkModSystem.LandClaimAPI.All)
|
||||
if (c.OwnedByPlayerUid == uid)
|
||||
count++;
|
||||
int newIndex = count - 1;
|
||||
|
||||
foreach (var claims in groups.Values)
|
||||
{
|
||||
int i = claims.IndexOf(claimIndex);
|
||||
|
||||
for (int j = 0; j < claims.Count; j++)
|
||||
if (j != i && claims[j] > claimIndex)
|
||||
claims[j]--;
|
||||
|
||||
if (i >= 0)
|
||||
claims[i] = newIndex;
|
||||
}
|
||||
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 bool HasAnyEntry(string uid, int groupId) =>
|
||||
entries.TryGetValue(uid, out var groups)
|
||||
&& groups.TryGetValue(groupId, out var claims)
|
||||
&& claims.Count > 0;
|
||||
|
||||
public int MemberCountForGroup(int groupId) => MemberUidsForGroup(groupId).Count();
|
||||
public void RemoveAllForPlayerInGroup(string uid, int groupId)
|
||||
{
|
||||
if (entries.TryGetValue(uid, out var groups))
|
||||
groups.Remove(groupId);
|
||||
Prune();
|
||||
Save();
|
||||
}
|
||||
|
||||
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
|
||||
public IEnumerable<string> MemberUidsForGroup(int groupId)
|
||||
{
|
||||
foreach (var (uid, groups) in entries)
|
||||
if (groups.TryGetValue(groupId, out var claims) && claims.Count > 0)
|
||||
yield return uid;
|
||||
}
|
||||
|
||||
public int MemberCountForGroup(int groupId)
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var uid in MemberUidsForGroup(groupId))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
public IReadOnlyList<int> ClaimsForPlayerInGroup(string uid, int groupId) =>
|
||||
entries.TryGetValue(uid, out var groups) && groups.TryGetValue(groupId, out var claims)
|
||||
? claims
|
||||
: System.Array.Empty<int>();
|
||||
|
||||
private List<int> GetOrCreateIndices(string playerUid, int groupId)
|
||||
private void Prune()
|
||||
{
|
||||
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;
|
||||
List<string>? empty = null;
|
||||
foreach (var (uid, groups) in entries)
|
||||
if (groups.Count == 0)
|
||||
(empty ??= new()).Add(uid);
|
||||
if (empty != null)
|
||||
foreach (var uid in empty)
|
||||
entries.Remove(uid);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
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
|
||||
var entryList = new List<ClaimLinkEntrySaveData>();
|
||||
foreach (var (uid, groups) in entries)
|
||||
foreach (var (groupId, claims) in groups)
|
||||
entryList.Add(
|
||||
new ClaimLinkEntrySaveData
|
||||
{
|
||||
OwnerPlayerUid = playerEntry.Key,
|
||||
GroupId = groupEntry.Key,
|
||||
ClaimIndex = index,
|
||||
OwnerPlayerUid = uid,
|
||||
GroupId = groupId,
|
||||
ClaimIndicies = new(claims),
|
||||
}
|
||||
);
|
||||
|
||||
saveGame.StoreData(
|
||||
SaveKey,
|
||||
new ClaimLinkData { Links = new List<ClaimLink>(byGroupId.Values), Entries = entries }
|
||||
new ClaimLinkSaveData { Links = claimLinks, Entries = entryList }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user