147 lines
3.6 KiB
Go
147 lines
3.6 KiB
Go
package mcproto
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Frame struct {
|
|
Length int
|
|
Payload []byte
|
|
}
|
|
|
|
type State int
|
|
|
|
/*
|
|
Handshaking -> Status
|
|
Handshaking -> Login -> ...
|
|
*/
|
|
const (
|
|
StateHandshaking State = 0
|
|
StateStatus State = 1
|
|
StateLogin State = 2
|
|
)
|
|
|
|
var trimLimit = 64
|
|
|
|
func trimBytes(data []byte) ([]byte, string) {
|
|
if len(data) < trimLimit {
|
|
return data, ""
|
|
} else {
|
|
return data[:trimLimit], "..."
|
|
}
|
|
}
|
|
|
|
func (f *Frame) String() string {
|
|
trimmed, cont := trimBytes(f.Payload)
|
|
return fmt.Sprintf("Frame:[len=%d, payload=%#X%s]", f.Length, trimmed, cont)
|
|
}
|
|
|
|
type Packet struct {
|
|
Length int
|
|
PacketID int
|
|
// Data is either a byte slice of raw content or a decoded message
|
|
Data interface{}
|
|
}
|
|
|
|
func (p *Packet) String() string {
|
|
if dataBytes, ok := p.Data.([]byte); ok {
|
|
trimmed, cont := trimBytes(dataBytes)
|
|
return fmt.Sprintf("Frame:[len=%d, packetId=%d, data=%#X%s]", p.Length, p.PacketID, trimmed, cont)
|
|
} else {
|
|
return fmt.Sprintf("Frame:[len=%d, packetId=%d, data=%+v]", p.Length, p.PacketID, p.Data)
|
|
}
|
|
}
|
|
|
|
type ProtocolVersion int
|
|
|
|
// Source: https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol_History
|
|
const (
|
|
// ProtocolVersion1_18_2 is the protocol version for Minecraft 1.18.2
|
|
// Docs: https://minecraft.wiki/w/Java_Edition_protocol/Packets?oldid=2772791
|
|
ProtocolVersion1_18_2 ProtocolVersion = 758
|
|
// ProtocolVersion1_19 is the protocol version for Minecraft 1.19
|
|
// Docs: https://minecraft.wiki/w/Java_Edition_protocol/Packets?oldid=2772904
|
|
ProtocolVersion1_19 ProtocolVersion = 759
|
|
// ProtocolVersion1_19_2 is the protocol version for Minecraft 1.19.2
|
|
// Docs: https://minecraft.wiki/w/Java_Edition_protocol/Packets?oldid=2772944
|
|
ProtocolVersion1_19_2 ProtocolVersion = 760
|
|
// ProtocolVersion1_19_2 is the protocol version for Minecraft 1.19.3
|
|
ProtocolVersion1_19_3 ProtocolVersion = 761
|
|
// ProtocolVersion1_20_2 is the protocol version for Minecraft 1.20.2
|
|
ProtocolVersion1_20_2 ProtocolVersion = 764
|
|
// ProtocolVersion1_21_5 is the protocol version for Minecraft 1.21.5
|
|
ProtocolVersion1_21_5 ProtocolVersion = 770
|
|
)
|
|
|
|
const (
|
|
PacketIdHandshake = 0x00
|
|
PacketIdLogin = 0x00 // during StateLogin
|
|
PacketIdLegacyServerListPing = 0xFE
|
|
PacketIdStatusRequest = 0x00
|
|
PacketIdPingRequest = 0x01
|
|
)
|
|
|
|
const (
|
|
PacketIdStatusResponse = 0x00
|
|
PackedIdPongResponse = 0x01
|
|
)
|
|
|
|
type Handshake struct {
|
|
ProtocolVersion ProtocolVersion
|
|
ServerAddress string
|
|
ServerPort uint16
|
|
NextState State
|
|
}
|
|
|
|
type LoginStart struct {
|
|
Name string
|
|
PlayerUuid uuid.UUID
|
|
}
|
|
|
|
func NewLoginStart() *LoginStart {
|
|
return &LoginStart{
|
|
// Note: This is indistinguishable between no UUID provided, and a provided UUID of all 0s
|
|
PlayerUuid: uuid.Nil,
|
|
}
|
|
}
|
|
|
|
type LegacyServerListPing struct {
|
|
ProtocolVersion int
|
|
ServerAddress string
|
|
ServerPort uint16
|
|
}
|
|
|
|
// StatusResponse is a minimal structure for the status JSON
|
|
type StatusResponse struct {
|
|
Version struct {
|
|
Name string `json:"name"`
|
|
Protocol int `json:"protocol"`
|
|
} `json:"version"`
|
|
Players struct {
|
|
Max int `json:"max"`
|
|
Online int `json:"online"`
|
|
Sample []struct {
|
|
Name string `json:"name"`
|
|
ID string `json:"id"`
|
|
} `json:"sample,omitempty"`
|
|
} `json:"players"`
|
|
Description map[string]interface{} `json:"description"`
|
|
Favicon string `json:"favicon,omitempty"`
|
|
EnforcesSecureChat *bool `json:"enforcesSecureChat,omitempty"`
|
|
}
|
|
|
|
// PingPayload represents the status ping payload (packet 0x01)
|
|
type PingPayload struct {
|
|
Timestamp int64
|
|
}
|
|
|
|
type ByteReader interface {
|
|
ReadByte() (byte, error)
|
|
}
|
|
|
|
const (
|
|
PacketLengthFieldBytes = 1
|
|
)
|