feat(CS): persist owner/phase/registrations across restarts via plugin config JSON
Some checks failed
.NET Core / build (push) Has been cancelled
Some checks failed
.NET Core / build (push) Has been cancelled
Castle Siege state was in-memory, so the castle owner (and thus the P4 hunting-map reward) reset on every server restart/redeploy. Now the context marks itself dirty on any persistable change (phase transition, registration, owner set); the plugin's periodic tick writes a snapshot into its own PlugInConfiguration CustomConfiguration (a JSON blob already stored in PostgreSQL - no schema migration) and restores it on startup. Battle state (defenses/switches/occupier) stays transient. +2 unit tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,12 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
|
||||
{
|
||||
var context = Contexts.GetOrAdd(gameContext, gc =>
|
||||
{
|
||||
var created = new CastleSiegeContext(this.Configuration ?? new CastleSiegeConfiguration());
|
||||
var config = this.Configuration ?? new CastleSiegeConfiguration();
|
||||
var created = new CastleSiegeContext(config);
|
||||
|
||||
// Restore state persisted before the last restart (owner/phase/registrations) BEFORE subscribing,
|
||||
// so restoring doesn't announce phases or re-spawn defenses.
|
||||
created.RestoreState(config.PersistedOwnerGuildName, config.PersistedPhase, config.PersistedPhaseStartedUtc, config.PersistedRegisteredGuilds);
|
||||
|
||||
// Announce phase changes to the whole server and, when the siege begins, warp registered members.
|
||||
created.PhaseChanged += phase => _ = OnPhaseChangedAsync(gc, created, phase);
|
||||
@@ -84,6 +89,12 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
|
||||
{
|
||||
await ProcessSiegeTickAsync(gameContext, context).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Persist owner/phase/registrations to the database whenever they changed, so they survive a restart.
|
||||
if (context.ConsumeDirty())
|
||||
{
|
||||
await this.PersistStateAsync(gameContext, context).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -124,6 +135,41 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
|
||||
}
|
||||
}
|
||||
|
||||
private async ValueTask PersistStateAsync(GameContext gameContext, CastleSiegeContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.Configuration is not { } config)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Snapshot the live context into the persisted config fields.
|
||||
config.PersistedOwnerGuildName = context.OwnerGuildName;
|
||||
config.PersistedPhase = context.Phase;
|
||||
config.PersistedPhaseStartedUtc = context.PhaseStartedUtc;
|
||||
config.PersistedRegisteredGuilds = context.RegisteredGuilds.ToList();
|
||||
|
||||
// Write the plugin's custom-configuration JSON row back to the database (durable across restarts).
|
||||
var pluginTypeId = typeof(CastleSiegeEventPlugIn).GUID;
|
||||
using var ctx = gameContext.PersistenceContextProvider.CreateNewContext(gameContext.Configuration);
|
||||
var configurations = await ctx.GetAsync<PlugInConfiguration>().ConfigureAwait(false);
|
||||
var row = configurations.FirstOrDefault(c => c.TypeId == pluginTypeId);
|
||||
if (row is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
row.SetConfiguration(config, gameContext.PlugInManager.CustomConfigReferenceHandler);
|
||||
await ctx.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gameContext.LoggerFactory.CreateLogger<CastleSiegeEventPlugIn>()
|
||||
.LogError(ex, "Castle Siege: error while persisting state to the database.");
|
||||
}
|
||||
}
|
||||
|
||||
private static ValueTask AnnounceAsync(IGameContext gameContext, string message)
|
||||
=> gameContext.ForEachPlayerAsync(player =>
|
||||
player.InvokeViewPlugInAsync<IShowMessagePlugIn>(p => p.ShowMessageAsync(message, MessageType.GoldenCenter)).AsTask());
|
||||
|
||||
Reference in New Issue
Block a user