Documentation ¶
Index ¶
- Constants
- type Angle
- type Ary
- type BitSet
- type Boolean
- type Builder
- type Byte
- type ByteArray
- type Chat
- type Double
- type Field
- type FieldDecoder
- type FieldEncoder
- type FixedBitSet
- type Float
- type Identifier
- type Int
- type Long
- type NBTField
- type Opt
- type Option
- type OptionDecoder
- type OptionEncoder
- type Packet
- type PluginMessageData
- type Position
- type Short
- type String
- type Tuple
- type UUID
- type UnsignedByte
- type UnsignedShort
- type VarInt
- type VarLong
Examples ¶
Constants ¶
const ( MaxVarIntLen = 5 MaxVarLongLen = 10 )
const MaxDataLength = 0x200000
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
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 ¶
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 ¶
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 Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
func (*Builder) WriteField ¶
func (p *Builder) WriteField(fields ...FieldEncoder)
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
type Field ¶
type Field interface { FieldEncoder FieldDecoder }
A Field is both FieldEncoder and FieldDecoder
func NBT ¶
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 ¶
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) Set ¶
func (f FixedBitSet) Set(index int, value bool)
type Identifier ¶
type Identifier = String
Identifier is encoded as a String with max length of 32767.
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 ¶
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
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 ¶
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
type OptionDecoder ¶
OptionDecoder is basically same with Option, but support FieldDecoder only. This allowed wrapping a FieldDecoder type (which isn't a FieldEncoder) to an Option.
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.
type Packet ¶
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) 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>
type PluginMessageData ¶
type PluginMessageData []byte
PluginMessageData is only used in LoginPlugin,and it will read all left bytes
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)
type Tuple ¶
type Tuple []any // FieldEncoder, FieldDecoder or both (Field)
func (Tuple) ReadFrom ¶
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:
type UnsignedShort ¶
type UnsignedShort uint16
UnsignedShort is unsigned 16-bit integer
type VarInt ¶
type VarInt int32
VarInt is variable-length data encoding a two's complement signed 32-bit integer
func (VarInt) WriteToBytes ¶
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) WriteToBytes ¶
WriteToBytes encodes the VarLong into buf and returns the number of bytes written. If the buffer is too small, WriteToBytes will panic.