Files
h-school/src/HSchool.Protocol/PacketWriter.cs
T
Leonid PershinandCursor 8e7ab46e79 Sample outdoor weather from the climate preset so people can freeze and the clock can show it.
Protocol v8 adds tenths of a °C and precipitation to the clock frame; warmth drains from insulation versus place temperature.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 03:49:40 +03:00

85 lines
2.5 KiB
C#

using System.Buffers.Binary;
using System.Text;
namespace HSchool.Protocol;
/// <summary>
/// Little-endian cursor over a caller-owned buffer. Little-endian matches the
/// browser's <c>DataView</c> calls in <c>src/HSchool.Client/src/net/protocol.ts</c>.
/// </summary>
public ref struct PacketWriter(Span<byte> buffer)
{
private readonly Span<byte> _buffer = buffer;
private int _position = 0;
public readonly int Position => _position;
public void WriteByte(byte value)
{
EnsureRoom(sizeof(byte));
_buffer[_position] = value;
_position += sizeof(byte);
}
public void WriteMessageType(MessageType value) => WriteByte((byte)value);
public void WriteUInt16(ushort value)
{
EnsureRoom(sizeof(ushort));
BinaryPrimitives.WriteUInt16LittleEndian(_buffer[_position..], value);
_position += sizeof(ushort);
}
public void WriteUInt32(uint value)
{
EnsureRoom(sizeof(uint));
BinaryPrimitives.WriteUInt32LittleEndian(_buffer[_position..], value);
_position += sizeof(uint);
}
/// <summary><c>u16</c> byte length, then UTF-8. Empty string is a zero length.</summary>
public void WriteString(string value)
{
var byteCount = Encoding.UTF8.GetByteCount(value);
if (byteCount > ushort.MaxValue)
{
throw new ProtocolException($"String is {byteCount} bytes; u16 length cannot hold it.");
}
WriteUInt16((ushort)byteCount);
EnsureRoom(byteCount);
Encoding.UTF8.GetBytes(value, _buffer[_position..]);
_position += byteCount;
}
public void WriteInt16(short value)
{
EnsureRoom(sizeof(short));
BinaryPrimitives.WriteInt16LittleEndian(_buffer[_position..], value);
_position += sizeof(short);
}
public void WriteInt32(int value)
{
EnsureRoom(sizeof(int));
BinaryPrimitives.WriteInt32LittleEndian(_buffer[_position..], value);
_position += sizeof(int);
}
public void WriteInt64(long value)
{
EnsureRoom(sizeof(long));
BinaryPrimitives.WriteInt64LittleEndian(_buffer[_position..], value);
_position += sizeof(long);
}
private readonly void EnsureRoom(int bytes)
{
if (_position + bytes > _buffer.Length)
{
throw new ProtocolException(
$"Buffer overflow: need {bytes} more bytes at offset {_position}, capacity is {_buffer.Length}.");
}
}
}