From 02c9a22bf1a45e9394904d64e0950c0b7ac3c95a Mon Sep 17 00:00:00 2001 From: anth64 Date: Sun, 12 Jul 2026 18:31:21 +0200 Subject: [PATCH] feat: add ClaimLink persistence via savegame-backed registry Adds a ClaimLink data model and ClaimLinkRegistry that loads from and writes to the savegame's keyed data store (protobuf-net, via WorldManager.SaveGame), so claim link state survives restarts without touching vanilla claim data. Also silences nullable warnings on statics that are guaranteed set by StartServerSide before any use, and on TryGetValue out-params guarded by the if. --- ClaimLink/ClaimLink.cs | 10 +++++++ ClaimLink/ClaimLink.csproj | 4 +++ ClaimLink/ClaimLinkModSystem.cs | 6 ++-- ClaimLink/ClaimLinkRegistry.cs | 51 ++++++++++++++++++++++++++++++++ ClaimLink/LandCommandListener.cs | 4 +-- 5 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 ClaimLink/ClaimLink.cs create mode 100644 ClaimLink/ClaimLinkRegistry.cs diff --git a/ClaimLink/ClaimLink.cs b/ClaimLink/ClaimLink.cs new file mode 100644 index 0000000..cbf4aeb --- /dev/null +++ b/ClaimLink/ClaimLink.cs @@ -0,0 +1,10 @@ +using ProtoBuf; + +namespace ClaimLink; + +[ProtoContract] +public class ClaimLink +{ + [ProtoMember(1)] + public int GroupId; +} diff --git a/ClaimLink/ClaimLink.csproj b/ClaimLink/ClaimLink.csproj index f22b882..ae0fee9 100644 --- a/ClaimLink/ClaimLink.csproj +++ b/ClaimLink/ClaimLink.csproj @@ -16,6 +16,10 @@ $(COMMANDHOOK)/CommandHook.dll false + + $(VINTAGE_STORY)/Lib/protobuf-net.dll + false + diff --git a/ClaimLink/ClaimLinkModSystem.cs b/ClaimLink/ClaimLinkModSystem.cs index 90850e8..5f47ea8 100644 --- a/ClaimLink/ClaimLinkModSystem.cs +++ b/ClaimLink/ClaimLinkModSystem.cs @@ -6,8 +6,9 @@ namespace ClaimLink; public class ClaimLinkModSystem : ModSystem { - internal static ILandClaimAPI LandClaimAPI; - internal static ILogger Logger; + internal static ILandClaimAPI LandClaimAPI = null!; + internal static ILogger Logger = null!; + internal static ClaimLinkRegistry Registry = null!; internal ClaimLinkCommandListener? cmdListener; public override bool ShouldLoad(EnumAppSide forSide) => forSide == EnumAppSide.Server; @@ -16,6 +17,7 @@ public class ClaimLinkModSystem : ModSystem { LandClaimAPI = api.World.Claims; Logger = api.Logger; + Registry = new ClaimLinkRegistry(api.WorldManager.SaveGame); cmdListener = new ClaimLinkCommandListener(); CommandHookModSystem.Register(cmdListener); diff --git a/ClaimLink/ClaimLinkRegistry.cs b/ClaimLink/ClaimLinkRegistry.cs new file mode 100644 index 0000000..09dec59 --- /dev/null +++ b/ClaimLink/ClaimLinkRegistry.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using ProtoBuf; +using Vintagestory.API.Server; + +namespace ClaimLink; + +[ProtoContract] +public class ClaimLinkData +{ + [ProtoMember(1)] + public List Links = new(); +} + +public class ClaimLinkRegistry +{ + private const string SaveKey = "claimlink:links"; + + private readonly ISaveGame saveGame; + private readonly Dictionary byGroupId = new(); + + public ClaimLinkRegistry(ISaveGame saveGame) + { + this.saveGame = saveGame; + + ClaimLinkData? data = saveGame.GetData(SaveKey, null); + if (data == null) + return; + + foreach (ClaimLink link in data.Links) + byGroupId[link.GroupId] = link; + } + + public ClaimLink? Get(int groupId) => byGroupId.TryGetValue(groupId, out ClaimLink? link) ? link : null; + + public void Add(ClaimLink link) + { + byGroupId[link.GroupId] = link; + Save(); + } + + public void Remove(int groupId) + { + byGroupId.Remove(groupId); + Save(); + } + + private void Save() + { + saveGame.StoreData(SaveKey, new ClaimLinkData { Links = new List(byGroupId.Values) }); + } +} diff --git a/ClaimLink/LandCommandListener.cs b/ClaimLink/LandCommandListener.cs index 3faab54..df40a9e 100644 --- a/ClaimLink/LandCommandListener.cs +++ b/ClaimLink/LandCommandListener.cs @@ -55,7 +55,7 @@ public class ClaimLinkCommandListener : ICommandHookListener { string word = rawArgs.PeekWord(); - if (topLevel.TryGetValue(word, out SubHandler handler)) + if (topLevel.TryGetValue(word, out SubHandler? handler)) { rawArgs.PopWord(); handler(args.Caller, rawArgs); @@ -77,7 +77,7 @@ public class ClaimLinkCommandListener : ICommandHookListener { string word = args.PeekWord(); - if (claimSub.TryGetValue(word, out SubHandler handler)) + if (claimSub.TryGetValue(word, out SubHandler? handler)) { args.PopWord(); handler(caller, args);