namespace HSchool.Protocol;
///
/// First frame from the client. is
/// or — the same language the catalog HTTP API uses.
///
public readonly record struct ClientHelloMessage(byte ProtocolVersion, byte Locale);
/// Round-trip probe; the server mirrors back untouched.
public readonly record struct ClientPingMessage(long ClientTimeMs);
/// Asks for clock updates of one school. Starts its calendar running.
public readonly record struct ClientOpenSchoolMessage(int SchoolId);
///
/// Play or pause the open school. Running and speed are separate messages on purpose: a button
/// that also resent the other field would clobber it with whatever the client last saw.
///
public readonly record struct ClientSetRunningMessage(bool Running);
/// Change the speed of the open school without touching whether it runs.
public readonly record struct ClientSetSpeedMessage(byte SpeedIndex);
/// Sent once per connection, before anything else.
public readonly record struct ServerWelcomeMessage(byte ProtocolVersion, byte TickRate, byte MaxSchools);
/// Answer to , carrying the current server tick.
public readonly record struct ServerPongMessage(long ClientTimeMs, uint ServerTick);
///
/// State of the open school's calendar, sent every tick.
/// is the in-game date as milliseconds since the Unix epoch,
/// interpreted as UTC — the game calendar has no time zone.
///
public readonly record struct ServerClockMessage(
int SchoolId,
long GameTimeUnixMs,
bool Running,
byte SpeedIndex);
/// The open school no longer exists (deleted from another tab); the client returns to the menu.
public readonly record struct ServerSchoolGoneMessage(int SchoolId);
///
/// Tree node in a map snapshot. Kind is 0 territory, 1 building, 2 floor, 3 room.
/// is empty for the yard.
/// is how many pupils can take a lesson here — summed from things
/// on the server, not by the client.
/// and are empty when the
/// room is free. are the people the timetable puts there right now.
///
public sealed record MapSnapshotNode(
byte Kind,
string Id,
string ParentId,
string Name,
ushort PupilSlots,
IReadOnlyList Items,
IReadOnlyList Positions,
string ActivitySubject = "",
string ActivityClass = "",
IReadOnlyList? Characters = null)
{
public IReadOnlyList Present => Characters ?? [];
}
/// One stacked thing in a room. is 1–255.
public sealed record MapSnapshotItem(string Name, byte Count);
///
/// One school's map, labelled in the Hello locale. Sent when that school is opened and again
/// when the current lesson slot changes. Occupancy is computed from the timetable and the clock.
///
public sealed record ServerMapSnapshotMessage(int SchoolId, IReadOnlyList Nodes);