feat(CS): AdminPanel-friendly config (day checkboxes, minute/second durations)
Some checks failed
.NET Core / build (push) Has been cancelled
Some checks failed
.NET Core / build (push) Has been cancelled
The generic plugin-config editor couldn't edit IList<DayOfWeek> and showed durations in milliseconds + the runtime Persisted* state. Add [JsonIgnore] proxy properties that the AutoFields editor CAN render: OpenDays ([Flags] enum -> checkboxes), Registration/ Preparation/Siege minutes + CrownHold seconds (int inputs). Hide the underlying TimeSpan/ list/Persisted* fields with [Browsable(false)]. Runtime JSON shape is unchanged (proxies are JsonIgnore) so no persisted-config break.
This commit is contained in:
@@ -4,42 +4,82 @@
|
||||
|
||||
namespace MUnique.OpenMU.GameLogic.CastleSiege;
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration for the Castle Siege cycle timings.
|
||||
/// Rides on the plugin custom-configuration system (no dedicated database table in P1).
|
||||
/// Configuration for the Castle Siege cycle. Rides on the plugin custom-configuration system (no dedicated
|
||||
/// database table). A cycle runs: Ownership -> Registration -> Preparation -> Siege(war) -> Settlement, and
|
||||
/// auto-starts when the current day/time matches <see cref="OpenDays"/> + <see cref="RegistrationOpenTimes"/>.
|
||||
/// The AdminPanel-friendly properties (OpenDays checkboxes, minute/second durations) are proxies over the
|
||||
/// runtime fields, which are hidden from the editor to keep the form clean.
|
||||
/// </summary>
|
||||
public class CastleSiegeConfiguration
|
||||
{
|
||||
// --- Schedule & period lengths (editable in the AdminPanel) ---
|
||||
// A cycle runs: Ownership -> Registration -> Preparation -> Siege(war) -> Settlement -> Ownership.
|
||||
// It auto-starts when the current day/time matches RegistrationOpenDays + RegistrationOpenTimes.
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the days of week on which registration auto-opens (UTC). Empty = every day
|
||||
/// (still requires a time in <see cref="RegistrationOpenTimes"/>); with no times set, auto-start is off.
|
||||
/// Gets or sets the days of week on which registration auto-opens (UTC). None = every day (still needs a
|
||||
/// time). Editable in the AdminPanel as check boxes; proxies the runtime <see cref="RegistrationOpenDays"/>.
|
||||
/// </summary>
|
||||
public IList<DayOfWeek> RegistrationOpenDays { get; set; } = new List<DayOfWeek>();
|
||||
[JsonIgnore]
|
||||
public CastleSiegeScheduleDays OpenDays
|
||||
{
|
||||
get
|
||||
{
|
||||
var days = CastleSiegeScheduleDays.None;
|
||||
foreach (var day in this.RegistrationOpenDays)
|
||||
{
|
||||
days |= (CastleSiegeScheduleDays)(1 << (int)day);
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
|
||||
set => this.RegistrationOpenDays = Enum.GetValues<DayOfWeek>()
|
||||
.Where(day => value.HasFlag((CastleSiegeScheduleDays)(1 << (int)day)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the times of day (UTC) at which a new cycle opens registration.
|
||||
/// Empty = no auto-start (admins start cycles manually via chat command).
|
||||
/// Empty = no auto-start (admins start cycles manually via the chat command).
|
||||
/// </summary>
|
||||
public IList<TimeOnly> RegistrationOpenTimes { get; set; } = new List<TimeOnly>();
|
||||
|
||||
/// <summary>Gets or sets how long the registration period lasts (guilds may register).</summary>
|
||||
public TimeSpan RegistrationDuration { get; set; } = TimeSpan.FromMinutes(5);
|
||||
/// <summary>Gets or sets how long the registration period lasts, in minutes (guilds may register).</summary>
|
||||
[JsonIgnore]
|
||||
public int RegistrationMinutes
|
||||
{
|
||||
get => (int)this.RegistrationDuration.TotalMinutes;
|
||||
set => this.RegistrationDuration = TimeSpan.FromMinutes(Math.Max(1, value));
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets how long the preparation period lasts (between registration close and the war).</summary>
|
||||
public TimeSpan PreparationDuration { get; set; } = TimeSpan.FromMinutes(2);
|
||||
/// <summary>Gets or sets how long the preparation period lasts, in minutes (between registration and war).</summary>
|
||||
[JsonIgnore]
|
||||
public int PreparationMinutes
|
||||
{
|
||||
get => (int)this.PreparationDuration.TotalMinutes;
|
||||
set => this.PreparationDuration = TimeSpan.FromMinutes(Math.Max(0, value));
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets how long the war (siege) period lasts.</summary>
|
||||
public TimeSpan SiegeDuration { get; set; } = TimeSpan.FromMinutes(10);
|
||||
/// <summary>Gets or sets how long the war (siege) period lasts, in minutes.</summary>
|
||||
[JsonIgnore]
|
||||
public int SiegeMinutes
|
||||
{
|
||||
get => (int)this.SiegeDuration.TotalMinutes;
|
||||
set => this.SiegeDuration = TimeSpan.FromMinutes(Math.Max(1, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how long the guild master must hold the Crown (with both switches held and all gates down)
|
||||
/// to capture the throne. The client shows a 60-second countdown, so 60s matches the on-screen timer.
|
||||
/// Gets or sets how long the guild master must hold the Crown to capture the throne, in seconds.
|
||||
/// The client shows a 60-second countdown, so 60 matches the on-screen timer.
|
||||
/// </summary>
|
||||
public TimeSpan CrownHoldDuration { get; set; } = TimeSpan.FromSeconds(60);
|
||||
[JsonIgnore]
|
||||
public int CrownHoldSeconds
|
||||
{
|
||||
get => (int)this.CrownHoldDuration.TotalSeconds;
|
||||
set => this.CrownHoldDuration = TimeSpan.FromSeconds(Math.Max(1, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the registration fee (in zen) a guild master must pay to register the guild
|
||||
@@ -47,21 +87,46 @@ public class CastleSiegeConfiguration
|
||||
/// </summary>
|
||||
public int RegistrationFee { get; set; } = 100000;
|
||||
|
||||
// --- Persisted runtime state (P4 persistence) ---
|
||||
// These ride on the plugin's custom-configuration JSON (already stored in PostgreSQL), so the castle
|
||||
// owner and the current cycle survive server restarts without a dedicated database table/migration.
|
||||
// Written by CastleSiegeEventPlugIn whenever the state changes; read back on startup to restore it.
|
||||
// --- Runtime fields (hidden from the AdminPanel; proxied by the friendly properties above) ---
|
||||
|
||||
/// <summary>Gets or sets the days of week registration auto-opens (UTC). Empty = every day.</summary>
|
||||
[Browsable(false)]
|
||||
public IList<DayOfWeek> RegistrationOpenDays { get; set; } = new List<DayOfWeek>();
|
||||
|
||||
/// <summary>Gets or sets how long the registration period lasts.</summary>
|
||||
[Browsable(false)]
|
||||
public TimeSpan RegistrationDuration { get; set; } = TimeSpan.FromMinutes(5);
|
||||
|
||||
/// <summary>Gets or sets how long the preparation period lasts.</summary>
|
||||
[Browsable(false)]
|
||||
public TimeSpan PreparationDuration { get; set; } = TimeSpan.FromMinutes(2);
|
||||
|
||||
/// <summary>Gets or sets how long the war (siege) period lasts.</summary>
|
||||
[Browsable(false)]
|
||||
public TimeSpan SiegeDuration { get; set; } = TimeSpan.FromMinutes(10);
|
||||
|
||||
/// <summary>Gets or sets how long the guild master must hold the Crown to capture the throne.</summary>
|
||||
[Browsable(false)]
|
||||
public TimeSpan CrownHoldDuration { get; set; } = TimeSpan.FromSeconds(60);
|
||||
|
||||
// --- Persisted runtime state (hidden from the AdminPanel) ---
|
||||
// These ride on the plugin's custom-configuration JSON (stored in PostgreSQL), so the castle owner and the
|
||||
// current cycle survive server restarts. Written by CastleSiegeEventPlugIn; restored on startup.
|
||||
|
||||
/// <summary>Gets or sets the persisted castle owner guild name (null = unowned).</summary>
|
||||
[Browsable(false)]
|
||||
public string? PersistedOwnerGuildName { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the persisted current phase, so the cycle resumes after a restart.</summary>
|
||||
[Browsable(false)]
|
||||
public CastleSiegePhase PersistedPhase { get; set; } = CastleSiegePhase.Ownership;
|
||||
|
||||
/// <summary>Gets or sets when the persisted phase started (UTC), or null if never persisted.</summary>
|
||||
[Browsable(false)]
|
||||
public DateTime? PersistedPhaseStartedUtc { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the persisted registered guild names for the current cycle.</summary>
|
||||
[Browsable(false)]
|
||||
public IList<string> PersistedRegisteredGuilds { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
@@ -87,3 +152,35 @@ public class CastleSiegeConfiguration
|
||||
return this.RegistrationOpenTimes.Any(p => p.IsBetween(earlier, nowTime));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The days of week on which the Castle Siege registration auto-opens. A [Flags] enum so the AdminPanel
|
||||
/// renders it as a set of check boxes.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CastleSiegeScheduleDays
|
||||
{
|
||||
/// <summary>No day (auto-start day-unrestricted; still needs a time).</summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>Sunday.</summary>
|
||||
Sunday = 1 << 0,
|
||||
|
||||
/// <summary>Monday.</summary>
|
||||
Monday = 1 << 1,
|
||||
|
||||
/// <summary>Tuesday.</summary>
|
||||
Tuesday = 1 << 2,
|
||||
|
||||
/// <summary>Wednesday.</summary>
|
||||
Wednesday = 1 << 3,
|
||||
|
||||
/// <summary>Thursday.</summary>
|
||||
Thursday = 1 << 4,
|
||||
|
||||
/// <summary>Friday.</summary>
|
||||
Friday = 1 << 5,
|
||||
|
||||
/// <summary>Saturday.</summary>
|
||||
Saturday = 1 << 6,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user