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. /// is the server's verdict; the client must not recompute it. /// is 0 when skip is refused. /// is outdoor °C × 10. is /// . /// public readonly record struct ServerClockMessage( int SchoolId, long GameTimeUnixMs, bool Running, byte SpeedIndex, bool SkipAllowed = false, long SkipTargetUnixMs = 0, short TemperatureTenths = 0, byte Precipitation = 0); /// Outdoor precipitation on the clock frame. Below 0 °C the same weather roll is snow. public static class PrecipitationKind { public const byte None = 0; public const byte Rain = 1; public const byte Snow = 2; } /// 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. Live occupancy lives on . /// public sealed record MapSnapshotNode( byte Kind, string Id, string ParentId, string Name, ushort PupilSlots, IReadOnlyList Items, IReadOnlyList Positions); /// 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 once when that school is opened. /// Structure only — people and the current lesson ride the presence stream. /// public sealed record ServerMapSnapshotMessage(int SchoolId, IReadOnlyList Nodes); /// Jump empty nights, weekends and holidays. The server re-checks the conditions. public readonly record struct ClientSkipEmptyMessage; /// Closes one notice by id. Info is not stored; pausing dismiss is phase 65. public readonly record struct ClientDismissNoticeMessage(uint Id); /// Wire values for . public static class NoticeSeverity { public const byte Info = 0; public const byte Warning = 1; public const byte Error = 2; } /// /// One school event for open clients. is 0 when nobody is in frame. /// Info toasts are not replayed on OpenSchool. /// public readonly record struct ServerNoticeMessage( uint Id, string DefName, byte Severity, bool Pause, uint TtlMs, uint PersonId = 0); /// Where people are: 1 in a node, 2 walking through it. Off campus is omitted. public static class PresenceState { public const byte Here = 1; public const byte Walking = 2; } /// One occupied (or currently taught) map node in a presence frame. public sealed record PresenceNode( string Id, ushort Count, string ActivitySubject = "", string ActivityClass = ""); /// /// One on-campus person. Names are resolved over HTTP, not on this frame. Talk members and /// topic are ids; an empty list means the person is not in a circle. /// public sealed record PresencePerson( string Id, string NodeId, byte State, IReadOnlyList TalkMemberIds, string TalkTopicId) { public PresencePerson(string id, string nodeId, byte state) : this(id, nodeId, state, [], "") { } } /// /// Live occupancy of an open school, about twice a second. Counts and people cover the whole /// map; the client filters to the selected tree node. /// public sealed record ServerPresenceMessage( int SchoolId, IReadOnlyList Nodes, IReadOnlyList People);