Add EventDef notices, morning and lesson bells, and info toasts.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -42,6 +42,8 @@ internal abstract record GameCommand
|
||||
|
||||
internal sealed record SkipEmpty(uint PlayerId, string NormalizedUserName) : GameCommand;
|
||||
|
||||
internal sealed record DismissNotice(uint PlayerId, uint NoticeId) : GameCommand;
|
||||
|
||||
/// <summary>Stops every worker, re-reads the save directory, starts workers from those files.</summary>
|
||||
internal sealed record ReloadSaves(TaskCompletionSource Result) : GameCommand;
|
||||
|
||||
|
||||
@@ -225,6 +225,10 @@ internal sealed class GameLoopService(
|
||||
HandleClockCommand(skipEmpty.PlayerId, skipEmpty.NormalizedUserName, new WorkerCommand.SkipEmpty());
|
||||
break;
|
||||
|
||||
case GameCommand.DismissNotice dismiss:
|
||||
RouteOpenSchool(dismiss.PlayerId, new WorkerCommand.DismissNotice(dismiss.NoticeId));
|
||||
break;
|
||||
|
||||
case GameCommand.ReloadSaves reload:
|
||||
await HandleReloadAsync(reload).ConfigureAwait(false);
|
||||
break;
|
||||
|
||||
@@ -61,6 +61,10 @@ internal sealed partial class SchoolWorker
|
||||
ApplySkip(school);
|
||||
break;
|
||||
|
||||
case WorkerCommand.DismissNotice:
|
||||
// Info is not stored; pausing dismiss is phase 65.
|
||||
break;
|
||||
|
||||
case WorkerCommand.Dump dump:
|
||||
dump.Result.TrySetResult(SchoolDumpReader.Read(school, _options.SchoolWeekDays));
|
||||
break;
|
||||
|
||||
@@ -165,6 +165,7 @@ internal sealed partial class SchoolWorker
|
||||
{
|
||||
PublishSnapshot();
|
||||
BroadcastClock();
|
||||
EmitWorldEvents(school);
|
||||
MaybeBroadcastPresence(school);
|
||||
}
|
||||
|
||||
@@ -244,6 +245,7 @@ internal sealed partial class SchoolWorker
|
||||
PublishSnapshot();
|
||||
Persist();
|
||||
BroadcastClock();
|
||||
EmitWorldEvents(school);
|
||||
BroadcastPresence();
|
||||
_presenceAge = 0;
|
||||
}
|
||||
@@ -489,4 +491,48 @@ internal sealed partial class SchoolWorker
|
||||
var length = ProtocolCodec.WritePresence(frame, message);
|
||||
client.TrySendReliable(frame.AsMemory(0, length));
|
||||
}
|
||||
|
||||
private void EmitWorldEvents(School school)
|
||||
{
|
||||
var catalog = school.Catalog;
|
||||
if (catalog is null)
|
||||
{
|
||||
school.DrainWorldEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var fact in school.DrainWorldEvents())
|
||||
{
|
||||
foreach (var def in catalog.Events.Values)
|
||||
{
|
||||
if (def.Abstract
|
||||
|| !def.Trigger.Equals(fact.Trigger, StringComparison.Ordinal)
|
||||
|| !def.Severity.Equals(EventSeverities.Info, StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BroadcastNotice(new ServerNoticeMessage(
|
||||
++_nextNoticeId,
|
||||
def.DefName,
|
||||
NoticeSeverity.Info,
|
||||
def.Pause,
|
||||
(uint)Math.Max(0, def.TtlMs)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BroadcastNotice(in ServerNoticeMessage message)
|
||||
{
|
||||
var frame = new byte[ProtocolCodec.NoticeSize(message)];
|
||||
var length = ProtocolCodec.WriteNotice(frame, message);
|
||||
var payload = frame.AsMemory(0, length);
|
||||
foreach (var client in _clients.All)
|
||||
{
|
||||
if (client.IsReady && client.OpenSchoolId == _id)
|
||||
{
|
||||
client.TrySendReliable(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ internal sealed partial class SchoolWorker
|
||||
private Timetable? _timetableSnapshot;
|
||||
private MapLayout? _mapSnapshot;
|
||||
private int _presenceAge;
|
||||
private uint _nextNoticeId;
|
||||
private School? _school;
|
||||
private Task? _run;
|
||||
private bool _persistOnStop = true;
|
||||
|
||||
@@ -22,6 +22,8 @@ internal abstract record WorkerCommand
|
||||
|
||||
internal sealed record SkipEmpty : WorkerCommand;
|
||||
|
||||
internal sealed record DismissNotice(uint Id) : WorkerCommand;
|
||||
|
||||
internal sealed record Dump(TaskCompletionSource<SchoolLiveDump?> Result) : WorkerCommand;
|
||||
|
||||
internal sealed record GetPerson(
|
||||
|
||||
Reference in New Issue
Block a user