Refactor project structure and update documentation. Replace PixiJS with plain DOM for UI rendering, enhance README with game features, and revise protocol documentation for HTTP API. Remove unused files and streamline client code for better maintainability.
This commit is contained in:
@@ -7,21 +7,14 @@ namespace HSchool.Protocol;
|
||||
/// </summary>
|
||||
public static class ProtocolCodec
|
||||
{
|
||||
/// <summary>Largest frame this codec produces; handlers can size their buffers from it.</summary>
|
||||
public const int MaxFrameSize = 16;
|
||||
|
||||
public static int WriteHello(Span<byte> destination, in ClientHelloMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientHello);
|
||||
writer.WriteByte(message.ProtocolVersion);
|
||||
writer.WriteShortString(message.PlayerName);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteInput(Span<byte> destination, in ClientInputMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientInput);
|
||||
writer.WriteUInt32(message.Sequence);
|
||||
writer.WriteByte((byte)message.Buttons);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
@@ -33,15 +26,44 @@ public static class ProtocolCodec
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteOpenSchool(Span<byte> destination, in ClientOpenSchoolMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientOpenSchool);
|
||||
writer.WriteInt32(message.SchoolId);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteCloseSchool(Span<byte> destination)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientCloseSchool);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteSetRunning(Span<byte> destination, in ClientSetRunningMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientSetRunning);
|
||||
writer.WriteByte(message.Running ? (byte)1 : (byte)0);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteSetSpeed(Span<byte> destination, in ClientSetSpeedMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ClientSetSpeed);
|
||||
writer.WriteByte(message.SpeedIndex);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static int WriteWelcome(Span<byte> destination, in ServerWelcomeMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ServerWelcome);
|
||||
writer.WriteByte(message.ProtocolVersion);
|
||||
writer.WriteUInt32(message.PlayerEntityId);
|
||||
writer.WriteByte(message.TickRate);
|
||||
writer.WriteSingle(message.WorldWidth);
|
||||
writer.WriteSingle(message.WorldHeight);
|
||||
writer.WriteByte(message.MaxSchools);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
@@ -54,35 +76,24 @@ public static class ProtocolCodec
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
/// <summary>Writes a full-state snapshot; entities missing from it are despawned by the client.</summary>
|
||||
public static int WriteSnapshot(Span<byte> destination, uint tick, ReadOnlySpan<EntitySnapshot> entities)
|
||||
public static int WriteClock(Span<byte> destination, in ServerClockMessage message)
|
||||
{
|
||||
if (entities.Length > ushort.MaxValue)
|
||||
{
|
||||
throw new ProtocolException($"Snapshot holds {entities.Length} entities, limit is {ushort.MaxValue}.");
|
||||
}
|
||||
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ServerSnapshot);
|
||||
writer.WriteUInt32(tick);
|
||||
writer.WriteUInt16((ushort)entities.Length);
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
writer.WriteUInt32(entity.Id);
|
||||
writer.WriteByte((byte)entity.Kind);
|
||||
writer.WriteSingle(entity.X);
|
||||
writer.WriteSingle(entity.Y);
|
||||
writer.WriteSingle(entity.Radius);
|
||||
writer.WriteUInt32(entity.Color);
|
||||
}
|
||||
|
||||
writer.WriteMessageType(MessageType.ServerClock);
|
||||
writer.WriteInt32(message.SchoolId);
|
||||
writer.WriteInt64(message.GameTimeUnixMs);
|
||||
writer.WriteByte(message.Running ? (byte)1 : (byte)0);
|
||||
writer.WriteByte(message.SpeedIndex);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
/// <summary>Exact byte size of a snapshot frame for <paramref name="entityCount"/> entities.</summary>
|
||||
public static int SnapshotSize(int entityCount) =>
|
||||
ProtocolConstants.SnapshotHeaderSize + (entityCount * ProtocolConstants.EntitySnapshotSize);
|
||||
public static int WriteSchoolGone(Span<byte> destination, in ServerSchoolGoneMessage message)
|
||||
{
|
||||
var writer = new PacketWriter(destination);
|
||||
writer.WriteMessageType(MessageType.ServerSchoolGone);
|
||||
writer.WriteInt32(message.SchoolId);
|
||||
return writer.Position;
|
||||
}
|
||||
|
||||
public static MessageType PeekMessageType(ReadOnlySpan<byte> source) =>
|
||||
source.IsEmpty ? MessageType.None : (MessageType)source[0];
|
||||
@@ -91,18 +102,7 @@ public static class ProtocolCodec
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ClientHello);
|
||||
var version = reader.ReadByte();
|
||||
var name = reader.ReadShortString();
|
||||
return new ClientHelloMessage(version, name);
|
||||
}
|
||||
|
||||
public static ClientInputMessage ReadInput(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ClientInput);
|
||||
var sequence = reader.ReadUInt32();
|
||||
var buttons = (InputButtons)reader.ReadByte();
|
||||
return new ClientInputMessage(sequence, buttons);
|
||||
return new ClientHelloMessage(reader.ReadByte());
|
||||
}
|
||||
|
||||
public static ClientPingMessage ReadPing(ReadOnlySpan<byte> source)
|
||||
@@ -112,16 +112,35 @@ public static class ProtocolCodec
|
||||
return new ClientPingMessage(reader.ReadInt64());
|
||||
}
|
||||
|
||||
public static ClientOpenSchoolMessage ReadOpenSchool(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ClientOpenSchool);
|
||||
return new ClientOpenSchoolMessage(reader.ReadInt32());
|
||||
}
|
||||
|
||||
public static ClientSetRunningMessage ReadSetRunning(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ClientSetRunning);
|
||||
return new ClientSetRunningMessage(reader.ReadByte() != 0);
|
||||
}
|
||||
|
||||
public static ClientSetSpeedMessage ReadSetSpeed(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ClientSetSpeed);
|
||||
return new ClientSetSpeedMessage(reader.ReadByte());
|
||||
}
|
||||
|
||||
public static ServerWelcomeMessage ReadWelcome(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ServerWelcome);
|
||||
var version = reader.ReadByte();
|
||||
var playerEntityId = reader.ReadUInt32();
|
||||
var tickRate = reader.ReadByte();
|
||||
var width = reader.ReadSingle();
|
||||
var height = reader.ReadSingle();
|
||||
return new ServerWelcomeMessage(version, playerEntityId, tickRate, width, height);
|
||||
var maxSchools = reader.ReadByte();
|
||||
return new ServerWelcomeMessage(version, tickRate, maxSchools);
|
||||
}
|
||||
|
||||
public static ServerPongMessage ReadPong(ReadOnlySpan<byte> source)
|
||||
@@ -133,31 +152,22 @@ public static class ProtocolCodec
|
||||
return new ServerPongMessage(clientTime, serverTick);
|
||||
}
|
||||
|
||||
/// <summary>Reads a snapshot into <paramref name="destination"/> and returns the entity count.</summary>
|
||||
public static int ReadSnapshot(ReadOnlySpan<byte> source, Span<EntitySnapshot> destination, out uint tick)
|
||||
public static ServerClockMessage ReadClock(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ServerSnapshot);
|
||||
tick = reader.ReadUInt32();
|
||||
var count = reader.ReadUInt16();
|
||||
Expect(ref reader, MessageType.ServerClock);
|
||||
var schoolId = reader.ReadInt32();
|
||||
var gameTime = reader.ReadInt64();
|
||||
var running = reader.ReadByte() != 0;
|
||||
var speedIndex = reader.ReadByte();
|
||||
return new ServerClockMessage(schoolId, gameTime, running, speedIndex);
|
||||
}
|
||||
|
||||
if (count > destination.Length)
|
||||
{
|
||||
throw new ProtocolException($"Snapshot holds {count} entities, destination fits {destination.Length}.");
|
||||
}
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
destination[i] = new EntitySnapshot(
|
||||
reader.ReadUInt32(),
|
||||
(EntityKind)reader.ReadByte(),
|
||||
reader.ReadSingle(),
|
||||
reader.ReadSingle(),
|
||||
reader.ReadSingle(),
|
||||
reader.ReadUInt32());
|
||||
}
|
||||
|
||||
return count;
|
||||
public static ServerSchoolGoneMessage ReadSchoolGone(ReadOnlySpan<byte> source)
|
||||
{
|
||||
var reader = new PacketReader(source);
|
||||
Expect(ref reader, MessageType.ServerSchoolGone);
|
||||
return new ServerSchoolGoneMessage(reader.ReadInt32());
|
||||
}
|
||||
|
||||
private static void Expect(ref PacketReader reader, MessageType expected)
|
||||
|
||||
Reference in New Issue
Block a user