refactor: normalize claim link membership into flat entry storage
This commit is contained in:
+11
-12
@@ -1,24 +1,23 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using ProtoBuf;
|
using ProtoBuf;
|
||||||
|
|
||||||
namespace ClaimLink;
|
namespace ClaimLink;
|
||||||
|
|
||||||
[ProtoContract]
|
|
||||||
public class ClaimLinkMember
|
|
||||||
{
|
|
||||||
[ProtoMember(1)]
|
|
||||||
public string OwnerPlayerUid = "";
|
|
||||||
|
|
||||||
[ProtoMember(2)]
|
|
||||||
public List<int> LocalClaimIndices = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
[ProtoContract]
|
[ProtoContract]
|
||||||
public class ClaimLink
|
public class ClaimLink
|
||||||
{
|
{
|
||||||
[ProtoMember(1)]
|
[ProtoMember(1)]
|
||||||
public int GroupId;
|
public int GroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public class ClaimLinkEntry
|
||||||
|
{
|
||||||
|
[ProtoMember(1)]
|
||||||
|
public string OwnerPlayerUid = "";
|
||||||
|
|
||||||
[ProtoMember(2)]
|
[ProtoMember(2)]
|
||||||
public List<ClaimLinkMember> Members = new();
|
public int ClaimIndex;
|
||||||
|
|
||||||
|
[ProtoMember(3)]
|
||||||
|
public int GroupId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,15 +328,7 @@ public static class ClaimLinkChatCommand
|
|||||||
$"{claimDesc} will be linked into '{groupName}'.",
|
$"{claimDesc} will be linked into '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == playerUid);
|
ClaimLinkModSystem.Registry.AddEntry(playerUid, link.GroupId, claimIndex);
|
||||||
if (member == null)
|
|
||||||
{
|
|
||||||
member = new ClaimLinkMember { OwnerPlayerUid = playerUid };
|
|
||||||
link.Members.Add(member);
|
|
||||||
}
|
|
||||||
|
|
||||||
member.LocalClaimIndices.Add(claimIndex);
|
|
||||||
ClaimLinkModSystem.Registry.Save();
|
|
||||||
|
|
||||||
return TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.");
|
return TextCommandResult.Success($"Linked {claimDesc} to '{groupName}'.");
|
||||||
}
|
}
|
||||||
@@ -362,12 +354,7 @@ public static class ClaimLinkChatCommand
|
|||||||
$"{claimDesc} will be unlinked from '{groupName}'.",
|
$"{claimDesc} will be unlinked from '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
ClaimLinkMember member = link.Members.Find(m => m.OwnerPlayerUid == playerUid)!;
|
ClaimLinkModSystem.Registry.RemoveEntry(playerUid, link.GroupId, claimIndex);
|
||||||
member.LocalClaimIndices.Remove(claimIndex);
|
|
||||||
if (member.LocalClaimIndices.Count == 0)
|
|
||||||
link.Members.Remove(member);
|
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.Save();
|
|
||||||
return TextCommandResult.Success($"Unlinked {claimDesc} from '{groupName}'.");
|
return TextCommandResult.Success($"Unlinked {claimDesc} from '{groupName}'.");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -382,7 +369,7 @@ public static class ClaimLinkChatCommand
|
|||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = TryResolveClaimLink(group, out ClaimLink link);
|
err = TryResolveClaimLink(group, out _);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -393,8 +380,7 @@ public static class ClaimLinkChatCommand
|
|||||||
string targetUid = target.PlayerUID;
|
string targetUid = target.PlayerUID;
|
||||||
string playerUid = args.Caller.Player.PlayerUID;
|
string playerUid = args.Caller.Player.PlayerUID;
|
||||||
|
|
||||||
ClaimLinkMember? member = link.Members.Find(m => m.OwnerPlayerUid == targetUid);
|
if (!ClaimLinkModSystem.Registry.HasAnyEntry(targetUid, group.Uid))
|
||||||
if (member == null)
|
|
||||||
return TextCommandResult.Error(
|
return TextCommandResult.Error(
|
||||||
$"{target.PlayerName} has no claims linked in '{groupName}'."
|
$"{target.PlayerName} has no claims linked in '{groupName}'."
|
||||||
);
|
);
|
||||||
@@ -404,9 +390,8 @@ public static class ClaimLinkChatCommand
|
|||||||
$"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.",
|
$"All of {target.PlayerName}'s claims will be unlinked from '{groupName}'.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
link.Members.Remove(member);
|
ClaimLinkModSystem.Registry.RemoveAllForPlayerInGroup(targetUid, group.Uid);
|
||||||
RemovePending(targetUid);
|
RemovePending(targetUid);
|
||||||
ClaimLinkModSystem.Registry.Save();
|
|
||||||
|
|
||||||
return TextCommandResult.Success(
|
return TextCommandResult.Success(
|
||||||
$"Unlinked all claims of {target.PlayerName} from '{groupName}'."
|
$"Unlinked all claims of {target.PlayerName} from '{groupName}'."
|
||||||
@@ -424,7 +409,7 @@ public static class ClaimLinkChatCommand
|
|||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = TryResolveClaimLink(group, out ClaimLink link);
|
err = TryResolveClaimLink(group, out _);
|
||||||
if (err != null)
|
if (err != null)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@@ -438,8 +423,8 @@ public static class ClaimLinkChatCommand
|
|||||||
$"'{groupName}' will be deleted as a claim link.",
|
$"'{groupName}' will be deleted as a claim link.",
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
foreach (ClaimLinkMember member in link.Members)
|
foreach (string uid in ClaimLinkModSystem.Registry.MemberUidsForGroup(groupId))
|
||||||
RemovePending(member.OwnerPlayerUid);
|
RemovePending(uid);
|
||||||
|
|
||||||
ClaimLinkModSystem.Registry.Remove(groupId);
|
ClaimLinkModSystem.Registry.Remove(groupId);
|
||||||
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
return TextCommandResult.Success($"'{groupName}' is no longer a claim link.");
|
||||||
@@ -531,7 +516,7 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
string notice = $"'{group.Name}' is now owned by {target.PlayerName}.";
|
string notice = $"'{group.Name}' is now owned by {target.PlayerName}.";
|
||||||
|
|
||||||
HashSet<string> notifyUids = link.Members.Select(m => m.OwnerPlayerUid).ToHashSet();
|
HashSet<string> notifyUids = ClaimLinkModSystem.Registry.MemberUidsForGroup(link.GroupId).ToHashSet();
|
||||||
notifyUids.Add(oldOwnerUid);
|
notifyUids.Add(oldOwnerUid);
|
||||||
notifyUids.Add(target.PlayerUID);
|
notifyUids.Add(target.PlayerUID);
|
||||||
|
|
||||||
@@ -565,7 +550,7 @@ public static class ClaimLinkChatCommand
|
|||||||
public static TextCommandResult List(TextCommandCallingArgs args)
|
public static TextCommandResult List(TextCommandCallingArgs args)
|
||||||
{
|
{
|
||||||
List<ClaimLink> links = ClaimLinkModSystem
|
List<ClaimLink> links = ClaimLinkModSystem
|
||||||
.Registry.All.OrderByDescending(l => l.Members.Count)
|
.Registry.All.OrderByDescending(l => ClaimLinkModSystem.Registry.MemberCountForGroup(l.GroupId))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (links.Count == 0)
|
if (links.Count == 0)
|
||||||
@@ -577,9 +562,8 @@ public static class ClaimLinkChatCommand
|
|||||||
foreach (ClaimLink link in links)
|
foreach (ClaimLink link in links)
|
||||||
{
|
{
|
||||||
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name;
|
string groupName = ClaimLinkModSystem.Groups.PlayerGroupsById[link.GroupId].Name;
|
||||||
sb.AppendLine(
|
int memberCount = ClaimLinkModSystem.Registry.MemberCountForGroup(link.GroupId);
|
||||||
$" {groupName}: {link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}"
|
sb.AppendLine($" {groupName}: {memberCount} member{(memberCount == 1 ? "" : "s")}");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextCommandResult.Success(sb.ToString());
|
return TextCommandResult.Success(sb.ToString());
|
||||||
@@ -603,19 +587,17 @@ public static class ClaimLinkChatCommand
|
|||||||
|
|
||||||
private static string FormatInfo(string groupName, ClaimLink link)
|
private static string FormatInfo(string groupName, ClaimLink link)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new();
|
int memberCount = ClaimLinkModSystem.Registry.MemberCountForGroup(link.GroupId);
|
||||||
sb.AppendLine(
|
|
||||||
$"Claim link '{groupName}' ({link.Members.Count} member{(link.Members.Count == 1 ? "" : "s")}):"
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (ClaimLinkMember member in link.Members)
|
StringBuilder sb = new();
|
||||||
|
sb.AppendLine($"Claim link '{groupName}' ({memberCount} member{(memberCount == 1 ? "" : "s")}):");
|
||||||
|
|
||||||
|
foreach (string uid in ClaimLinkModSystem.Registry.MemberUidsForGroup(link.GroupId))
|
||||||
{
|
{
|
||||||
string name =
|
string name = ClaimLinkModSystem.World.PlayerByUid(uid)?.PlayerName ?? uid;
|
||||||
ClaimLinkModSystem.World.PlayerByUid(member.OwnerPlayerUid)?.PlayerName
|
IEnumerable<string> claims = ClaimLinkModSystem
|
||||||
?? member.OwnerPlayerUid;
|
.Registry.ClaimsForPlayerInGroup(uid, link.GroupId)
|
||||||
IEnumerable<string> claims = member.LocalClaimIndices.Select(i =>
|
.Select(i => DescribeClaim(uid, i));
|
||||||
DescribeClaim(member.OwnerPlayerUid, i)
|
|
||||||
);
|
|
||||||
sb.AppendLine($" {name}: [{string.Join(", ", claims)}]");
|
sb.AppendLine($" {name}: [{string.Join(", ", claims)}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,13 +29,6 @@ public class ClaimLinkModSystem : ModSystem
|
|||||||
ClaimLinkChatCommand.Register(api);
|
ClaimLinkChatCommand.Register(api);
|
||||||
|
|
||||||
api.Event.PlayerDisconnect += ClaimLinkCommandListener.OnPlayerDisconnect;
|
api.Event.PlayerDisconnect += ClaimLinkCommandListener.OnPlayerDisconnect;
|
||||||
|
|
||||||
// TODO remove debug logging once transfer ownership persistence is confirmed tested
|
|
||||||
foreach (ClaimLink link in Registry.All)
|
|
||||||
{
|
|
||||||
PlayerGroup group = Groups.PlayerGroupsById[link.GroupId];
|
|
||||||
Logger.Notification($"claimlink: startup state '{group.Name}' (uid {group.Uid}) OwnerUID={group.OwnerUID}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using ProtoBuf;
|
using ProtoBuf;
|
||||||
using Vintagestory.API.Server;
|
using Vintagestory.API.Server;
|
||||||
|
|
||||||
@@ -9,6 +10,9 @@ public class ClaimLinkData
|
|||||||
{
|
{
|
||||||
[ProtoMember(1)]
|
[ProtoMember(1)]
|
||||||
public List<ClaimLink> Links = new();
|
public List<ClaimLink> Links = new();
|
||||||
|
|
||||||
|
[ProtoMember(2)]
|
||||||
|
public List<ClaimLinkEntry> Entries = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ClaimLinkRegistry
|
public class ClaimLinkRegistry
|
||||||
@@ -18,6 +22,8 @@ public class ClaimLinkRegistry
|
|||||||
private readonly ISaveGame saveGame;
|
private readonly ISaveGame saveGame;
|
||||||
private readonly Dictionary<int, ClaimLink> byGroupId = new();
|
private readonly Dictionary<int, ClaimLink> byGroupId = new();
|
||||||
|
|
||||||
|
private readonly Dictionary<string, Dictionary<int, List<int>>> byPlayer = new();
|
||||||
|
|
||||||
public ClaimLinkRegistry(ISaveGame saveGame)
|
public ClaimLinkRegistry(ISaveGame saveGame)
|
||||||
{
|
{
|
||||||
this.saveGame = saveGame;
|
this.saveGame = saveGame;
|
||||||
@@ -28,9 +34,13 @@ public class ClaimLinkRegistry
|
|||||||
|
|
||||||
foreach (ClaimLink link in data.Links)
|
foreach (ClaimLink link in data.Links)
|
||||||
byGroupId[link.GroupId] = link;
|
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;
|
public IReadOnlyCollection<ClaimLink> All => byGroupId.Values;
|
||||||
|
|
||||||
@@ -43,23 +53,119 @@ public class ClaimLinkRegistry
|
|||||||
public void Remove(int groupId)
|
public void Remove(int groupId)
|
||||||
{
|
{
|
||||||
byGroupId.Remove(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();
|
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)
|
public ClaimLink? FindLinkContaining(string ownerPlayerUid, int localIndex)
|
||||||
{
|
{
|
||||||
foreach (ClaimLink link in byGroupId.Values)
|
if (!byPlayer.TryGetValue(ownerPlayerUid, out Dictionary<int, List<int>>? perGroup))
|
||||||
foreach (ClaimLinkMember member in link.Members)
|
return null;
|
||||||
if (member.OwnerPlayerUid == ownerPlayerUid && member.LocalClaimIndices.Contains(localIndex))
|
|
||||||
return link;
|
foreach (KeyValuePair<int, List<int>> entry in perGroup)
|
||||||
|
if (entry.Value.Contains(localIndex))
|
||||||
|
return Get(entry.Key);
|
||||||
|
|
||||||
return null;
|
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()
|
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 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user