RegionIO/internal/protocol/types.go
Master290 a7bb9496ae Initial commit: RegionIO Minecraft server core (26.1.2/protocol 775)
Vanilla-faithful overworld generator (final_density + multi-noise biomes),
full connection lifecycle (status/login/configuration/play), chunk streaming,
creative block editing, and the protocol/nbt/registry infrastructure.
2026-06-24 00:32:51 +03:00

137 lines
3.4 KiB
Go

// Package protocol implements the wire-level primitives of the Minecraft
// Java Edition protocol (version 26.1.2, protocol 775).
//
// All multi-byte numeric fields are big-endian. Length-prefixed and
// frequently-used integers use the LEB128-style VarInt/VarLong encoding.
package protocol
import (
"errors"
"io"
)
// Protocol constants for the targeted Minecraft version.
const (
// ProtocolVersion is the handshake protocol number for 26.1.2.
ProtocolVersion = 775
// GameVersion is the human-readable version string.
GameVersion = "26.1.2"
)
// State is a connection state as negotiated during the handshake. The numeric
// values of Status/Login match the "next state" field of the handshake packet.
type State int
const (
StateHandshaking State = iota
StateStatus
StateLogin
StateConfiguration
StatePlay
)
func (s State) String() string {
switch s {
case StateHandshaking:
return "handshaking"
case StateStatus:
return "status"
case StateLogin:
return "login"
case StateConfiguration:
return "configuration"
case StatePlay:
return "play"
default:
return "unknown"
}
}
// Protocol limits guarding against malicious or malformed input.
const (
// MaxVarIntLen is the maximum number of bytes a 32-bit VarInt may occupy.
MaxVarIntLen = 5
// MaxVarLongLen is the maximum number of bytes a 64-bit VarLong may occupy.
MaxVarLongLen = 10
// MaxStringLen bounds decoded strings to the protocol's 32767-char limit.
MaxStringLen = 32767
// MaxPacketSize bounds a single uncompressed packet body.
MaxPacketSize = 2 * 1024 * 1024
)
var (
// ErrVarIntTooBig is returned when a VarInt/VarLong exceeds its byte limit.
ErrVarIntTooBig = errors.New("protocol: varint is too big")
// ErrStringTooLong is returned when a string exceeds MaxStringLen.
ErrStringTooLong = errors.New("protocol: string too long")
// ErrPacketTooLarge is returned when a packet length exceeds MaxPacketSize.
ErrPacketTooLarge = errors.New("protocol: packet too large")
)
// ReadVarInt reads a 32-bit VarInt from r, returning the value and the number
// of bytes consumed.
func ReadVarInt(r io.ByteReader) (value int32, n int, err error) {
var result uint32
for i := 0; i < MaxVarIntLen; i++ {
b, e := r.ReadByte()
if e != nil {
return 0, i, e
}
result |= uint32(b&0x7F) << (7 * i)
if b&0x80 == 0 {
return int32(result), i + 1, nil
}
}
return 0, MaxVarIntLen, ErrVarIntTooBig
}
// ReadVarLong reads a 64-bit VarLong from r.
func ReadVarLong(r io.ByteReader) (value int64, n int, err error) {
var result uint64
for i := 0; i < MaxVarLongLen; i++ {
b, e := r.ReadByte()
if e != nil {
return 0, i, e
}
result |= uint64(b&0x7F) << (7 * i)
if b&0x80 == 0 {
return int64(result), i + 1, nil
}
}
return 0, MaxVarLongLen, ErrVarIntTooBig
}
// AppendVarInt encodes v as a VarInt and appends it to dst.
func AppendVarInt(dst []byte, v int32) []byte {
u := uint32(v)
for {
if u&^0x7F == 0 {
return append(dst, byte(u))
}
dst = append(dst, byte(u&0x7F)|0x80)
u >>= 7
}
}
// AppendVarLong encodes v as a VarLong and appends it to dst.
func AppendVarLong(dst []byte, v int64) []byte {
u := uint64(v)
for {
if u&^uint64(0x7F) == 0 {
return append(dst, byte(u))
}
dst = append(dst, byte(u&0x7F)|0x80)
u >>= 7
}
}
// VarIntLen returns the number of bytes the VarInt encoding of v occupies.
func VarIntLen(v int32) int {
u := uint32(v)
n := 1
for u&^0x7F != 0 {
u >>= 7
n++
}
return n
}