- Bumped the wire protocol version to 6, reflecting changes in the communication structure.
- Expanded the timetable API with new endpoints for fetching and managing lesson schedules, including `GET /api/schools/{id}/timetable` and `POST /api/schools/{id}/timetable/pin`.
- Updated the protocol documentation to include detailed descriptions of the new timetable features and message structures.
- Enhanced the client-side implementation to support the new timetable functionalities, including lesson pinning and unpinning.
- Revised server-side logic to handle timetable operations and ensure proper integration with existing school management features.
- Added tests to validate the new timetable functionalities and ensure robustness in handling lesson data.
75 lines
3.4 KiB
C#
75 lines
3.4 KiB
C#
namespace HSchool.Protocol;
|
||
|
||
/// <summary>
|
||
/// First frame from the client. <paramref name="Locale"/> is <see cref="ProtocolConstants.LocaleRussian"/>
|
||
/// or <see cref="ProtocolConstants.LocaleEnglish"/> — the same language the catalog HTTP API uses.
|
||
/// </summary>
|
||
public readonly record struct ClientHelloMessage(byte ProtocolVersion, byte Locale);
|
||
|
||
/// <summary>Round-trip probe; the server mirrors <paramref name="ClientTimeMs"/> back untouched.</summary>
|
||
public readonly record struct ClientPingMessage(long ClientTimeMs);
|
||
|
||
/// <summary>Asks for clock updates of one school. Starts its calendar running.</summary>
|
||
public readonly record struct ClientOpenSchoolMessage(int SchoolId);
|
||
|
||
/// <summary>
|
||
/// 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.
|
||
/// </summary>
|
||
public readonly record struct ClientSetRunningMessage(bool Running);
|
||
|
||
/// <summary>Change the speed of the open school without touching whether it runs.</summary>
|
||
public readonly record struct ClientSetSpeedMessage(byte SpeedIndex);
|
||
|
||
/// <summary>Sent once per connection, before anything else.</summary>
|
||
public readonly record struct ServerWelcomeMessage(byte ProtocolVersion, byte TickRate, byte MaxSchools);
|
||
|
||
/// <summary>Answer to <see cref="ClientPingMessage"/>, carrying the current server tick.</summary>
|
||
public readonly record struct ServerPongMessage(long ClientTimeMs, uint ServerTick);
|
||
|
||
/// <summary>
|
||
/// State of the open school's calendar, sent every tick.
|
||
/// <paramref name="GameTimeUnixMs"/> is the in-game date as milliseconds since the Unix epoch,
|
||
/// interpreted as UTC — the game calendar has no time zone.
|
||
/// </summary>
|
||
public readonly record struct ServerClockMessage(
|
||
int SchoolId,
|
||
long GameTimeUnixMs,
|
||
bool Running,
|
||
byte SpeedIndex);
|
||
|
||
/// <summary>The open school no longer exists (deleted from another tab); the client returns to the menu.</summary>
|
||
public readonly record struct ServerSchoolGoneMessage(int SchoolId);
|
||
|
||
/// <summary>
|
||
/// Tree node in a map snapshot. Kind is <c>0</c> territory, <c>1</c> building, <c>2</c> floor, <c>3</c> room.
|
||
/// <paramref name="ParentId"/> is empty for the yard.
|
||
/// <paramref name="PupilSlots"/> is how many pupils can take a lesson here — summed from things
|
||
/// on the server, not by the client.
|
||
/// <paramref name="ActivitySubject"/> and <paramref name="ActivityClass"/> are empty when the
|
||
/// room is free. <paramref name="Characters"/> are the people the timetable puts there right now.
|
||
/// </summary>
|
||
public sealed record MapSnapshotNode(
|
||
byte Kind,
|
||
string Id,
|
||
string ParentId,
|
||
string Name,
|
||
ushort PupilSlots,
|
||
IReadOnlyList<MapSnapshotItem> Items,
|
||
IReadOnlyList<string> Positions,
|
||
string ActivitySubject = "",
|
||
string ActivityClass = "",
|
||
IReadOnlyList<string>? Characters = null)
|
||
{
|
||
public IReadOnlyList<string> Present => Characters ?? [];
|
||
}
|
||
|
||
/// <summary>One stacked thing in a room. <paramref name="Count"/> is 1–255.</summary>
|
||
public sealed record MapSnapshotItem(string Name, byte Count);
|
||
|
||
/// <summary>
|
||
/// 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.
|
||
/// </summary>
|
||
public sealed record ServerMapSnapshotMessage(int SchoolId, IReadOnlyList<MapSnapshotNode> Nodes);
|