Enhance school creation and map management features by updating the API to support mod packs and map layouts. Introduce a new map snapshot protocol for efficient data handling during school sessions. Revise documentation to reflect these changes, including updates to the protocol and architecture documents. Improve UI components for mod selection and map editing, ensuring a better user experience. Update tests to validate new functionalities and ensure robustness.
ci / server (push) Failing after 3m31s
ci / client (push) Successful in 14s

This commit is contained in:
Leonid Pershin
2026-08-18 15:15:49 +03:00
parent 1bc75244e8
commit 30cc937069
36 changed files with 1876 additions and 171 deletions
@@ -8,14 +8,17 @@ namespace HSchool.Protocol.Tests;
public class ProtocolCodecTests
{
[Fact]
public void Hello_RoundTripsAndIsTwoBytes()
public void Hello_RoundTripsAndIsThreeBytes()
{
var message = new ClientHelloMessage(ProtocolConstants.Version);
var message = new ClientHelloMessage(ProtocolConstants.Version, ProtocolConstants.LocaleEnglish);
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
var length = ProtocolCodec.WriteHello(buffer, message);
Assert.Equal(2, length);
Assert.Equal(3, length);
Assert.Equal((byte)MessageType.ClientHello, buffer[0]);
Assert.Equal(ProtocolConstants.Version, buffer[1]);
Assert.Equal(ProtocolConstants.LocaleEnglish, buffer[2]);
Assert.Equal(message, ProtocolCodec.ReadHello(buffer[..length]));
}
@@ -130,6 +133,31 @@ public class ProtocolCodecTests
Assert.Equal(message, ProtocolCodec.ReadSchoolGone(buffer[..length]));
}
[Fact]
public void MapSnapshot_RoundTripsAndWritesHeaderOffsets()
{
var message = new ServerMapSnapshotMessage(7, [
new MapSnapshotNode(0, "yard", "", "Двор", [], []),
new MapSnapshotNode(3, "office", "floor-1", "Кабинет директора", ["Стул"], ["Директор"]),
]);
var buffer = new byte[ProtocolConstants.MaxMessageSize];
var length = ProtocolCodec.WriteMapSnapshot(buffer, message);
Assert.Equal((byte)MessageType.ServerMapSnapshot, buffer[0]);
Assert.Equal(7, BitConverter.ToInt32(buffer.AsSpan(1, 4)));
Assert.Equal((ushort)2, BitConverter.ToUInt16(buffer.AsSpan(5, 2)));
var read = ProtocolCodec.ReadMapSnapshot(buffer.AsSpan(0, length));
Assert.Equal(message.SchoolId, read.SchoolId);
Assert.Equal(2, read.Nodes.Count);
Assert.Equal("yard", read.Nodes[0].Id);
Assert.Equal("", read.Nodes[0].ParentId);
Assert.Equal("Двор", read.Nodes[0].Name);
Assert.Equal(["Стул"], read.Nodes[1].Items);
Assert.Equal(["Директор"], read.Nodes[1].Positions);
}
[Fact]
public void Numbers_AreLittleEndian()
{
@@ -141,9 +169,9 @@ public class ProtocolCodecTests
}
[Fact]
public void MaxFrameSize_FitsEveryMessage()
public void MaxFrameSize_FitsEveryFixedSizeMessage()
{
// The handlers size their buffers from this constant; the clock frame is the largest one.
// Handlers size clock/welcome/pong buffers from this constant; map snapshots use MaxMessageSize.
Span<byte> buffer = stackalloc byte[ProtocolCodec.MaxFrameSize];
var clock = ProtocolCodec.WriteClock(buffer, new ServerClockMessage(1, long.MaxValue, true, 4));