packet

package
v1.20.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2023 License: MIT Imports: 10 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const (
	MaxVarIntLen  = 5
	MaxVarLongLen = 10
)
View Source
const MaxDataLength = 0x200000

Variables

This section is empty.

Functions

This section is empty.

Types

type Angle

type Angle Byte

Angle is rotation angle in steps of 1/256 of a full turn

func (*Angle) ReadFrom

func (a *Angle) ReadFrom(r io.Reader) (int64, error)

func (Angle) ToDeg

func (a Angle) ToDeg() float64

ToDeg convert Angle to Degree

func (Angle) ToRad

func (a Angle) ToRad() float64

ToRad convert Angle to Radian

func (Angle) WriteTo

func (a Angle) WriteTo(w io.Writer) (int64, error)

type Ary

type Ary[LEN VarInt | VarLong | Byte | UnsignedByte | Short | UnsignedShort | Int | Long] struct {
	Ary any // Slice or Pointer of Slice of FieldEncoder, FieldDecoder or both (Field)
}

Ary is used to send or receive the packet field like "Array of X" which has a count must be known from the context.

Typically, you must decode an integer representing the length. Then receive the corresponding amount of data according to the length. In this case, the field Len should be a pointer of integer type so the value can be updating when Packet.Scan() method is decoding the previous field. In some special cases, you might want to read an "Array of X" with a fix length. So it's allowed to directly set an integer type Len, but not a pointer.

Note that Ary DO read or write the Len. You aren't need to do so by your self.

func (Ary[LEN]) ReadFrom

func (a Ary[LEN]) ReadFrom(r io.Reader) (n int64, err error)
Example
package main

import (
	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	var data []pk.String

	var p pk.Packet // = conn.ReadPacket()
	if err := p.Scan(
		pk.Ary[pk.VarInt]{ // then decode Ary according to length
			Ary: &data,
		},
	); err != nil {
		panic(err)
	}
}
Output:

func (Ary[LEN]) WriteTo

func (a Ary[LEN]) WriteTo(w io.Writer) (n int64, err error)
Example
package main

import (
	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	data := []pk.Int{0, 1, 2, 3, 4, 5, 6}
	// Len is completely ignored by WriteTo method.
	// The length is inferred from the length of Ary.
	pk.Marshal(
		0x00,
		pk.Ary[pk.VarInt]{
			Ary: data,
		},
	)
}
Output:

type BitSet

type BitSet []int64

BitSet represents Java's BitSet, a list of bits.

func (BitSet) Get

func (b BitSet) Get(index int) bool

func (BitSet) Len

func (b BitSet) Len() int

func (*BitSet) ReadFrom

func (b *BitSet) ReadFrom(r io.Reader) (n int64, err error)

func (BitSet) Set

func (b BitSet) Set(index int, value bool)

func (BitSet) WriteTo

func (b BitSet) WriteTo(w io.Writer) (n int64, err error)

type Boolean

type Boolean bool

Boolean of True is encoded as 0x01, false as 0x00.

func (*Boolean) ReadFrom

func (b *Boolean) ReadFrom(r io.Reader) (n int64, err error)

func (Boolean) WriteTo

func (b Boolean) WriteTo(w io.Writer) (int64, error)

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

func (*Builder) Packet

func (p *Builder) Packet(id int32) Packet

func (*Builder) WriteField

func (p *Builder) WriteField(fields ...FieldEncoder)

type Byte

type Byte int8

Byte is signed 8-bit integer, two's complement

func (*Byte) ReadFrom

func (b *Byte) ReadFrom(r io.Reader) (n int64, err error)

func (Byte) WriteTo

func (b Byte) WriteTo(w io.Writer) (n int64, err error)

type ByteArray

type ByteArray []byte

ByteArray is []byte with prefix VarInt as length

func (*ByteArray) ReadFrom

func (b *ByteArray) ReadFrom(r io.Reader) (n int64, err error)

func (ByteArray) WriteTo

func (b ByteArray) WriteTo(w io.Writer) (n int64, err error)

type Chat

type Chat = String

Chat is encoded as a String with max length of 32767. Deprecated: Use chat.Message

type Double

type Double float64

A Double is a double-precision 64-bit IEEE 754 floating point number

func (*Double) ReadFrom

func (d *Double) ReadFrom(r io.Reader) (n int64, err error)

func (Double) WriteTo

func (d Double) WriteTo(w io.Writer) (n int64, err error)

type Field

type Field interface {
	FieldEncoder
	FieldDecoder
}

A Field is both FieldEncoder and FieldDecoder

func Array

func Array(ary any) Field

func NBT

func NBT(v any, optionalTagName ...string) Field

NBT is used to write or read Named Binary Tag data from/to packets.

When using as FieldDecoder, unknown fields are not allowed by default. For allow unknown fields, using NBTField instead.

Example
package main

import (
	"encoding/hex"
	"fmt"

	"github.com/Tnze/go-mc/data/packetid"
	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	type T struct {
		Name string `nbt:"name"`
	}
	var send, recv T
	send.Name = "Tnze"

	// Example of how pk.NBT() is used in pk.Marshal()
	p := pk.Marshal(
		packetid.ServerboundPacketID(0),
		//...
		pk.NBT(send),           // without tag name
		pk.NBT(send, "player"), // with tag name
		//...
	)
	fmt.Println("Marshal:")
	fmt.Println(hex.Dump(p.Data))

	// Example of how pk.NBT() is used in pk.Packet.Scan()
	_ = p.Scan(
		//...
		pk.NBT(&recv),
		// pk.NBT(&recv) // The tag name are going to be ignored. To receive the tag name, pk.NBTField has to be used.
		//...
	)
	fmt.Println("Scan:", recv.Name)

}
Output:

Marshal:
00000000  0a 00 00 08 00 04 6e 61  6d 65 00 04 54 6e 7a 65  |......name..Tnze|
00000010  00 0a 00 06 70 6c 61 79  65 72 08 00 04 6e 61 6d  |....player...nam|
00000020  65 00 04 54 6e 7a 65 00                           |e..Tnze.|

Scan: Tnze

type FieldDecoder

type FieldDecoder io.ReaderFrom

A FieldDecoder can Decode from minecraft protocol

type FieldEncoder

type FieldEncoder io.WriterTo

A FieldEncoder can be encoded as minecraft protocol used.

type FixedBitSet

type FixedBitSet []byte

FixedBitSet is a fixed size BitSet

func NewFixedBitSet

func NewFixedBitSet(n int64) FixedBitSet

NewFixedBitSet make a FixedBitSet which can store n bits at least. If n <= 0, return nil

func (FixedBitSet) Get

func (f FixedBitSet) Get(index int) bool

func (FixedBitSet) Len

func (f FixedBitSet) Len() int

func (FixedBitSet) ReadFrom

func (f FixedBitSet) ReadFrom(r io.Reader) (n int64, err error)

func (FixedBitSet) Set

func (f FixedBitSet) Set(index int, value bool)

func (FixedBitSet) WriteTo

func (f FixedBitSet) WriteTo(w io.Writer) (n int64, err error)

type Float

type Float float32

A Float is a single-precision 32-bit IEEE 754 floating point number

func (*Float) ReadFrom

func (f *Float) ReadFrom(r io.Reader) (n int64, err error)

func (Float) WriteTo

func (f Float) WriteTo(w io.Writer) (n int64, err error)

type Identifier

type Identifier = String

Identifier is encoded as a String with max length of 32767.

type Int

type Int int32

Int is signed 32-bit integer, two's complement

func (*Int) ReadFrom

func (i *Int) ReadFrom(r io.Reader) (n int64, err error)

func (Int) WriteTo

func (i Int) WriteTo(w io.Writer) (int64, error)

type Long

type Long int64

Long is signed 64-bit integer, two's complement

func (*Long) ReadFrom

func (l *Long) ReadFrom(r io.Reader) (n int64, err error)

func (Long) WriteTo

func (l Long) WriteTo(w io.Writer) (int64, error)

type NBTField

type NBTField struct {
	TagName string
	V       any

	AllowUnknownFields bool
}

func (NBTField) ReadFrom

func (n NBTField) ReadFrom(r io.Reader) (int64, error)

func (NBTField) WriteTo

func (n NBTField) WriteTo(w io.Writer) (int64, error)

type Opt

type Opt struct {
	Has   any // Pointer of bool, or `func() bool`
	Field any // FieldEncoder, FieldDecoder, `func() FieldEncoder`, `func() FieldDecoder` or `func() Field`
}

Opt is an optional Field which sending/receiving or not is depending on its Has field. When calling `WriteTo()` or `ReadFrom()`, if Has is true, the Field's `WriteTo` or `ReadFrom()` is called. Otherwise, it does nothing and return 0 and nil.

The different between Opt and Option is that Opt does NOT read or write the Has field for you. Which should be cared.

func (Opt) ReadFrom

func (o Opt) ReadFrom(r io.Reader) (int64, error)
Example
package main

import (
	"fmt"

	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	var has pk.Boolean

	var data pk.String
	p1 := pk.Packet{Data: []byte{
		0x01,                  // pk.Boolean(true)
		4, 'T', 'n', 'z', 'e', // pk.String
	}}
	if err := p1.Scan(
		&has,
		pk.Opt{
			Has: &has, Field: &data,
		},
	); err != nil {
		panic(err)
	}
	fmt.Println(data)

	var data2 pk.String = "WILL NOT BE READ, WILL NOT BE COVERED"
	p2 := pk.Packet{Data: []byte{
		0x00, // pk.Boolean(false)
		// empty
	}}
	if err := p2.Scan(
		&has,
		pk.Opt{Has: &has, Field: &data2},
	); err != nil {
		panic(err)
	}
	fmt.Println(data2)

}
Output:

Tnze
WILL NOT BE READ, WILL NOT BE COVERED
Example (Func)

As an example, we define this packet as this: +------+-----------------+----------------------------------+ | Name | Type | Notes | +------+-----------------+----------------------------------+ | Flag | Unsigned Byte | Odd if the following is present. | +------+-----------------+----------------------------------+ | User | Optional String | The player's name. | +------+-----------------+----------------------------------+ So we need a function to decide if the User field is present.

package main

import (
	"fmt"

	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	var flag pk.Byte
	var data pk.String
	p := pk.Packet{Data: []byte{
		0b_0010_0011,          // pk.Byte(flag)
		4, 'T', 'n', 'z', 'e', // pk.String
	}}
	if err := p.Scan(
		&flag,
		pk.Opt{
			Has: func() bool {
				return flag&1 != 0
			},
			Field: &data,
		},
	); err != nil {
		panic(err)
	}
	fmt.Println(data)

}
Output:

Tnze

func (Opt) WriteTo

func (o Opt) WriteTo(w io.Writer) (int64, error)

type Option

type Option[T FieldEncoder, P fieldPointer[T]] struct {
	Has Boolean
	Val T
}

Option is a helper type for encoding/decoding these kind of packet:

+-----------+------------+----------------------------------- +
| Name      | Type       | Notes                              |
+-----------+------------+------------------------------------+
| Has Value | Boolean    | Whether the Value should be sent.  |
+-----------+------------+------------------------------------+
| Value     | Optional T | Only exist when Has Value is true. |
+-----------+------------+------------------------------------+

Usage

`Option[T]` implements FieldEncoder and `*Option[T]` implements FieldDecoder. That is, you can call `WriteTo()` and `ReadFrom()` methods on it.

var optStr Option[String]
n, err := optStr.ReadFrom(r)
if err != nil {
	// ...
}
if optStr.Has {
	fmt.Println(optStr.Val)
}

Notes

Currently we have to repeat T in the type arguments.

var opt Option[String, *String]

Constraint type will inference makes it less awkward in the future. See: https://github.com/golang/go/issues/54469

func (*Option[T, P]) Pointer

func (o *Option[T, P]) Pointer() (p *T)

Pointer returns the pointer of Val if Has is true, otherwise return nil.

func (*Option[T, P]) ReadFrom

func (o *Option[T, P]) ReadFrom(r io.Reader) (n int64, err error)
Example (Func)

As an example, we define this packet as this: +------+-----------------+-----------------------------------+ | Name | Type | Notes | +------+-----------------+-----------------------------------+ | Has | Boolean | True if the following is present. | +------+-----------------+-----------------------------------+ | User | Optional String | The player's name. | +------+-----------------+-----------------------------------+ So we need a function to decide if the User field is present.

package main

import (
	"fmt"

	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	p1 := pk.Packet{Data: []byte{
		0x01,                  // pk.Boolean(true)
		4, 'T', 'n', 'z', 'e', // pk.String("Tnze")
	}}
	p2 := pk.Packet{Data: []byte{
		0x00, // pk.Boolean(false)
		// empty
	}}

	var User1, User2 pk.Option[pk.String, *pk.String]
	if err := p1.Scan(&User1); err != nil {
		panic(err)
	}
	if err := p2.Scan(&User2); err != nil {
		panic(err)
	}

	fmt.Println(User1.Has, User1.Val)
	fmt.Println(User2.Has, User2.Val)

}
Output:

true Tnze
false

func (Option[T, P]) WriteTo

func (o Option[T, P]) WriteTo(w io.Writer) (n int64, err error)

type OptionDecoder

type OptionDecoder[T any, P fieldPointer[T]] struct {
	Has Boolean
	Val T
}

OptionDecoder is basically same with Option, but support FieldDecoder only. This allowed wrapping a FieldDecoder type (which isn't a FieldEncoder) to an Option.

func (*OptionDecoder[T, P]) ReadFrom

func (o *OptionDecoder[T, P]) ReadFrom(r io.Reader) (n int64, err error)

type OptionEncoder

type OptionEncoder[T FieldEncoder] struct {
	Has Boolean
	Val T
}

OptionEncoder is basically same with Option, but support FieldEncoder only. This allowed wrapping a FieldEncoder type (which isn't a FieldDecoder) to an Option.

func (OptionEncoder[T]) WriteTo

func (o OptionEncoder[T]) WriteTo(w io.Writer) (n int64, err error)

type Packet

type Packet struct {
	ID   int32
	Data []byte
}

Packet define a net data package

func Marshal

func Marshal[ID ~int32 | int](id ID, fields ...FieldEncoder) (pk Packet)

Marshal generate Packet with the ID and Fields

Example (SetSlot)
package main

import (
	"fmt"

	_ "embed"
	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	for _, pf := range []struct {
		WindowID  byte
		Slot      int16
		Present   bool
		ItemID    int
		ItemCount byte
		NBT       any
	}{
		{WindowID: 0, Slot: 5, Present: false},
		{WindowID: 0, Slot: 5, Present: true, ItemID: 0x01, ItemCount: 1, NBT: pk.Byte(0)},
		{WindowID: 0, Slot: 5, Present: true, ItemID: 0x01, ItemCount: 1, NBT: pk.NBT(int32(0x12345678))},
	} {
		p := pk.Marshal(0x15,
			pk.Byte(pf.WindowID),
			pk.Short(pf.Slot),
			pk.Boolean(pf.Present),
			pk.Opt{Has: pf.Present, Field: pk.Tuple{
				pk.VarInt(pf.ItemID),
				pk.Byte(pf.ItemCount),
				pf.NBT,
			}},
		)
		fmt.Printf("%02X % 02X\n", p.ID, p.Data)
	}
}
Output:

15 00 00 05 00
15 00 00 05 01 01 01 00
15 00 00 05 01 01 01 03 00 00 12 34 56 78

func (*Packet) Pack

func (p *Packet) Pack(w io.Writer, threshold int) error

Pack 打包一个数据包

func (Packet) Scan

func (p Packet) Scan(fields ...FieldDecoder) error

Scan decode the packet and fill data into fields

Example (JoinGame)
package main

import (
	"fmt"

	_ "embed"
	pk "github.com/Tnze/go-mc/net/packet"
)

//go:embed joingame_test.bin
var testJoinGameData []byte

func main() {
	p := pk.Packet{ID: 0x24, Data: testJoinGameData}
	var (
		EID            pk.Int
		Hardcore       pk.Boolean
		Gamemode       pk.UnsignedByte
		PreGamemode    pk.Byte
		WorldNames     = []pk.Identifier{} // This cannot replace with "var DimensionNames []pk.Identifier" because "nil" has no type information
		DimensionCodec struct {
			DimensionType any `nbt:"minecraft:dimension_type"`
			WorldgenBiome any `nbt:"minecraft:worldgen/biome"`
		}
		Dimension                 any
		WorldName                 pk.Identifier
		HashedSeed                pk.Long
		MaxPlayers                pk.VarInt
		ViewDistance              pk.VarInt
		RDI, ERS, IsDebug, IsFlat pk.Boolean
	)
	err := p.Scan(
		&EID,
		&Hardcore,
		&Gamemode,
		&PreGamemode,
		pk.Array(&WorldNames),
		pk.NBT(&DimensionCodec),
		pk.NBT(&Dimension),
		&WorldName,
		&HashedSeed,
		&MaxPlayers,
		&ViewDistance,
		&RDI, &ERS, &IsDebug, &IsFlat,
	)
	fmt.Print(err)
}
Output:

<nil>

func (*Packet) UnPack

func (p *Packet) UnPack(r io.Reader, threshold int) error

UnPack in-place decompression a packet

type PluginMessageData

type PluginMessageData []byte

PluginMessageData is only used in LoginPlugin,and it will read all left bytes

func (*PluginMessageData) ReadFrom

func (p *PluginMessageData) ReadFrom(r io.Reader) (n int64, err error)

func (PluginMessageData) WriteTo

func (p PluginMessageData) WriteTo(w io.Writer) (n int64, err error)

type Position

type Position struct {
	X, Y, Z int
}

Position x as a 26-bit integer, followed by y as a 12-bit integer, followed by z as a 26-bit integer (all signed, two's complement)

func (*Position) ReadFrom

func (p *Position) ReadFrom(r io.Reader) (n int64, err error)

func (Position) WriteTo

func (p Position) WriteTo(w io.Writer) (n int64, err error)

type Short

type Short int16

Short is signed 16-bit integer, two's complement

func (*Short) ReadFrom

func (s *Short) ReadFrom(r io.Reader) (n int64, err error)

func (Short) WriteTo

func (s Short) WriteTo(w io.Writer) (int64, error)

type String

type String string

String is sequence of Unicode scalar values

func (*String) ReadFrom

func (s *String) ReadFrom(r io.Reader) (n int64, err error)

func (String) WriteTo

func (s String) WriteTo(w io.Writer) (int64, error)

type Tuple

type Tuple []any // FieldEncoder, FieldDecoder or both (Field)

func (Tuple) ReadFrom

func (t Tuple) ReadFrom(r io.Reader) (n int64, err error)

ReadFrom read Tuple from io.Reader, panic when any of field don't implement FieldDecoder

Example
package main

import (
	pk "github.com/Tnze/go-mc/net/packet"
)

func main() {
	// When you need to read an "Optional Array of X":
	var has pk.Boolean
	var ary []pk.String

	var p pk.Packet // = conn.ReadPacket()
	if err := p.Scan(
		&has,
		pk.Opt{
			Has: &has,
			Field: pk.Tuple{
				pk.Ary[pk.Int]{Ary: &ary},
			},
		},
	); err != nil {
		panic(err)
	}
}
Output:

func (Tuple) WriteTo

func (t Tuple) WriteTo(w io.Writer) (n int64, err error)

WriteTo write Tuple to io.Writer, panic when any of filed don't implement FieldEncoder

type UUID

type UUID uuid.UUID

UUID encoded as an unsigned 128-bit integer

func (*UUID) ReadFrom

func (u *UUID) ReadFrom(r io.Reader) (n int64, err error)

func (UUID) WriteTo

func (u UUID) WriteTo(w io.Writer) (n int64, err error)

type UnsignedByte

type UnsignedByte uint8

UnsignedByte is unsigned 8-bit integer

func (*UnsignedByte) ReadFrom

func (u *UnsignedByte) ReadFrom(r io.Reader) (n int64, err error)

func (UnsignedByte) WriteTo

func (u UnsignedByte) WriteTo(w io.Writer) (n int64, err error)

type UnsignedShort

type UnsignedShort uint16

UnsignedShort is unsigned 16-bit integer

func (*UnsignedShort) ReadFrom

func (us *UnsignedShort) ReadFrom(r io.Reader) (n int64, err error)

func (UnsignedShort) WriteTo

func (us UnsignedShort) WriteTo(w io.Writer) (int64, error)

type VarInt

type VarInt int32

VarInt is variable-length data encoding a two's complement signed 32-bit integer

func (VarInt) Len

func (v VarInt) Len() int

Len returns the number of bytes required to encode the VarInt.

func (*VarInt) ReadFrom

func (v *VarInt) ReadFrom(r io.Reader) (n int64, err error)

func (VarInt) WriteTo

func (v VarInt) WriteTo(w io.Writer) (n int64, err error)

func (VarInt) WriteToBytes

func (v VarInt) WriteToBytes(buf []byte) int

WriteToBytes encodes the VarInt into buf and returns the number of bytes written. If the buffer is too small, WriteToBytes will panic.

type VarLong

type VarLong int64

VarLong is variable-length data encoding a two's complement signed 64-bit integer

func (VarLong) Len

func (v VarLong) Len() int

Len returns the number of bytes required to encode the VarLong.

func (*VarLong) ReadFrom

func (v *VarLong) ReadFrom(r io.Reader) (n int64, err error)

func (VarLong) WriteTo

func (v VarLong) WriteTo(w io.Writer) (n int64, err error)

func (VarLong) WriteToBytes

func (v VarLong) WriteToBytes(buf []byte) int

WriteToBytes encodes the VarLong into buf and returns the number of bytes written. If the buffer is too small, WriteToBytes will panic.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL