From 64132168763d57f7e458b4d403da9ef28305650e Mon Sep 17 00:00:00 2001 From: Master290 Date: Tue, 21 Jul 2026 10:22:31 +0300 Subject: [PATCH] Fix default spawn packet layout --- internal/network/play.go | 6 ++++- internal/network/play_spawn_test.go | 40 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 internal/network/play_spawn_test.go diff --git a/internal/network/play.go b/internal/network/play.go index 5a87065..f841240 100644 --- a/internal/network/play.go +++ b/internal/network/play.go @@ -72,9 +72,13 @@ func (h *handler) sendChunkCacheCenter(cx, cz int32) error { } func (h *handler) sendDefaultSpawnPosition() error { - w := protocol.NewWriter(12) + // 26.1.2 wraps the spawn in LevelData.RespawnData: GlobalPos followed by + // yaw and pitch. GlobalPos starts with the dimension resource key. + w := protocol.NewWriter(40) + w.String("minecraft:overworld") w.Position(8, 100, 8) w.Float32(0.0) + w.Float32(0.0) return h.conn.SendWriter(protocol.PlayDefaultSpawnPos, w) } diff --git a/internal/network/play_spawn_test.go b/internal/network/play_spawn_test.go new file mode 100644 index 0000000..5079ed9 --- /dev/null +++ b/internal/network/play_spawn_test.go @@ -0,0 +1,40 @@ +package network + +import ( + "testing" + + "regionio/internal/protocol" +) + +func TestSendDefaultSpawnPositionLayout(t *testing.T) { + recorder := &recordingConn{} + h := &handler{conn: NewConn(recorder)} + + if err := h.sendDefaultSpawnPosition(); err != nil { + t.Fatal(err) + } + packets := recorder.take(t) + if len(packets) != 1 { + t.Fatalf("packet count = %d, want 1", len(packets)) + } + if packets[0].ID != protocol.PlayDefaultSpawnPos { + t.Fatalf("packet ID = %#x, want %#x", packets[0].ID, protocol.PlayDefaultSpawnPos) + } + + r := protocol.NewReader(packets[0].Data) + if dimension, err := r.String(); err != nil || dimension != "minecraft:overworld" { + t.Fatalf("dimension = %q, %v; want minecraft:overworld", dimension, err) + } + if x, y, z, err := r.Position(); err != nil || x != 8 || y != 100 || z != 8 { + t.Fatalf("position = (%d, %d, %d), %v; want (8, 100, 8)", x, y, z, err) + } + if yaw, err := r.Float32(); err != nil || yaw != 0 { + t.Fatalf("yaw = %v, %v; want 0", yaw, err) + } + if pitch, err := r.Float32(); err != nil || pitch != 0 { + t.Fatalf("pitch = %v, %v; want 0", pitch, err) + } + if remaining := r.Remaining(); remaining != 0 { + t.Fatalf("remaining bytes = %d, want 0", remaining) + } +}