feat(CS-P3): warp registered members to Valley of Loren on siege start + Crown Switch throne capture (NPC 217/218)
Some checks failed
.NET Core / build (push) Has been cancelled

This commit is contained in:
Acentech Dev
2026-07-15 00:57:28 +03:00
parent 9f2078d724
commit c7147f7a63
2 changed files with 146 additions and 5 deletions

View File

@@ -5,19 +5,24 @@
namespace MUnique.OpenMU.GameLogic.PlugIns.PeriodicTasks;
using System.Collections.Concurrent;
using System.Linq;
using System.Runtime.InteropServices;
using MUnique.OpenMU.GameLogic.CastleSiege;
using MUnique.OpenMU.Interfaces;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// Drives the Castle Siege phase state machine: ticks it every second and carries its configuration.
/// State is per-<see cref="IGameContext"/> and kept in memory (P1: no persistence).
/// When the siege phase starts (P3), warps registered guild members to the Valley of Loren battle map.
/// </summary>
[PlugIn]
[Display(Name = nameof(CastleSiegeEventPlugIn), Description = "Castle Siege event (P1 skeleton: phase state machine + scheduling).")]
[Display(Name = nameof(CastleSiegeEventPlugIn), Description = "Castle Siege event (phase state machine, scheduling, siege warp).")]
[Guid("6E2C8B41-9A4D-4C2E-9E7B-1F2A3B4C5D60")]
public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustomConfiguration<CastleSiegeConfiguration>, ISupportDefaultCustomConfiguration
{
private const ushort ValleyOfLorenMapNumber = 30;
private static readonly ConcurrentDictionary<IGameContext, CastleSiegeContext> Contexts = new();
/// <inheritdoc />
@@ -28,9 +33,6 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
/// </summary>
/// <param name="gameContext">The game context.</param>
/// <returns>The context, or <c>null</c> if not yet initialized.</returns>
/// <remarks>Static so GM chat commands can reach the state machine without a plugin instance
/// (<c>GetKnownPlugInsOf</c> returns Types, not instances). The tick runs every second, so the
/// context exists within ~1s of server start.</remarks>
public static CastleSiegeContext? TryGetContext(IGameContext gameContext)
=> Contexts.TryGetValue(gameContext, out var context) ? context : null;
@@ -40,7 +42,22 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
/// <inheritdoc />
public async ValueTask ExecuteTaskAsync(GameContext gameContext)
{
var context = Contexts.GetOrAdd(gameContext, _ => new CastleSiegeContext(this.Configuration ?? new CastleSiegeConfiguration()));
var context = Contexts.GetOrAdd(gameContext, gc =>
{
var created = new CastleSiegeContext(this.Configuration ?? new CastleSiegeConfiguration());
// When the siege phase begins, pull all registered guild members onto the battle map.
created.PhaseChanged += phase =>
{
if (phase == CastleSiegePhase.Siege)
{
_ = WarpRegisteredMembersToSiegeAsync(gc, created);
}
};
return created;
});
await context.TickAsync(DateTime.UtcNow).ConfigureAwait(false);
}
@@ -53,4 +70,49 @@ public sealed class CastleSiegeEventPlugIn : IPeriodicTaskPlugIn, ISupportCustom
_ = context.ForceStartRegistrationAsync(DateTime.UtcNow);
}
}
private static async Task WarpRegisteredMembersToSiegeAsync(IGameContext gameContext, CastleSiegeContext context)
{
try
{
var map = await gameContext.GetMapAsync(ValleyOfLorenMapNumber).ConfigureAwait(false);
if (map?.SafeZoneSpawnGate is not { } gate)
{
return;
}
await gameContext.ForEachPlayerAsync(async player =>
{
var guildName = await GetGuildNameAsync(player).ConfigureAwait(false);
if (guildName is not null && context.RegisteredGuilds.Contains(guildName))
{
await player.WarpToAsync(gate).ConfigureAwait(false);
}
}).ConfigureAwait(false);
}
catch (Exception ex)
{
gameContext.LoggerFactory.CreateLogger<CastleSiegeEventPlugIn>()
.LogError(ex, "Castle Siege: error while warping registered members to the battle map.");
}
}
private static async ValueTask<string?> GetGuildNameAsync(Player player)
{
if (player.GuildStatus is not { } guildStatus)
{
return null;
}
if (player.GameContext is IGameServerContext serverContext)
{
var guild = await serverContext.GuildServer.GetGuildAsync(guildStatus.GuildId).ConfigureAwait(false);
if (guild?.Name is { Length: > 0 } name)
{
return name;
}
}
return guildStatus.GuildId.ToString();
}
}