Add EventDef notices, morning and lesson bells, and info toasts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 20:46:33 +03:00
co-authored by Cursor
parent ea3f5c7bf1
commit a554738084
38 changed files with 952 additions and 22 deletions
@@ -90,6 +90,37 @@ public class GameSocketTests(AppHostFixture fixture)
Assert.InRange(elapsed.TotalMinutes, 0.5, 2);
}
[Fact]
public async Task OpenSchool_AfterMorning_GetsNotice_AndReopenDoesNotReplayInfo()
{
using var client = await CreateOwnerHttpClientAsync();
await SchoolApiTests.ResetAsync(client);
var beforeMorning = new DateTime(2012, 4, 3, 5, 55, 0, DateTimeKind.Utc);
var school = await SchoolApiTests.CreateAsync(client, "Утро тост", beforeMorning);
using var socket = await OpenSchoolAsync(school.Id, client);
await SendAsync(socket, buffer =>
ProtocolCodec.WriteSetSpeed(buffer, new ClientSetSpeedMessage(SpeedIndex: 4)));
var notice = ProtocolCodec.ReadNotice(
await ReceiveUntilAsync(socket, MessageType.ServerNotice, TimeSpan.FromSeconds(20)));
Assert.Equal("DayStarted", notice.DefName);
Assert.Equal(NoticeSeverity.Info, notice.Severity);
Assert.False(notice.Pause);
Assert.Equal(8000u, notice.TtlMs);
Assert.Equal(0u, notice.PersonId);
await SendAsync(socket, buffer =>
ProtocolCodec.WriteSetRunning(buffer, new ClientSetRunningMessage(Running: false)));
await SendAsync(socket, buffer => ProtocolCodec.WriteCloseSchool(buffer));
await SendAsync(socket, buffer =>
ProtocolCodec.WriteOpenSchool(buffer, new ClientOpenSchoolMessage(school.Id)));
var replayed = await TryReceiveNoticeAsync(socket, TimeSpan.FromSeconds(2));
Assert.Null(replayed);
}
[Fact]
public async Task OpeningASchool_SendsAMapSnapshot()
{
@@ -707,6 +738,45 @@ public class GameSocketTests(AppHostFixture fixture)
}
}
private static async Task<ServerNoticeMessage?> TryReceiveNoticeAsync(WebSocket socket, TimeSpan duration)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
cts.CancelAfter(duration);
var buffer = new byte[64 * 1024];
var chunks = new List<byte>();
while (true)
{
WebSocketReceiveResult result;
try
{
result = await socket.ReceiveAsync(buffer, cts.Token);
}
catch (OperationCanceledException) when (!TestContext.Current.CancellationToken.IsCancellationRequested)
{
return null;
}
if (result.MessageType == WebSocketMessageType.Close)
{
return null;
}
chunks.AddRange(buffer.AsSpan(0, result.Count).ToArray());
if (!result.EndOfMessage)
{
continue;
}
var frame = chunks.ToArray();
chunks.Clear();
if (ProtocolCodec.PeekMessageType(frame) == MessageType.ServerNotice)
{
return ProtocolCodec.ReadNotice(frame);
}
}
}
private sealed record StaffingSnapshot(IReadOnlyList<ApplicantSnapshot> Applicants);
private sealed record ApplicantSnapshot(string Id, string FullName);