From f8b3501b60450a93209772455a75e1d1364480b5 Mon Sep 17 00:00:00 2001 From: Tnze Date: Thu, 25 Feb 2021 20:22:06 +0800 Subject: [PATCH] Fix other code for compatible with new go-mc/net packet --- bot/ingame.go | 62 +++---- bot/login.go | 49 ++--- bot/world/chunk.go | 15 +- bot/world/entity/entity.go | 78 ++++---- chat/chatMsg.go | 15 +- chat/chatMsg_test.go | 5 +- cmd/daze/daze.go | 2 +- net/conn.go | 3 +- net/packet/builder.go | 5 +- net/packet/packet.go | 73 +++++--- net/packet/packet_test.go | 16 +- net/packet/types.go | 366 ++++++++++++++++++++----------------- net/packet/util.go | 95 ++++++---- net/ptypes/chunk.go | 116 ++++-------- net/ptypes/inventory.go | 28 +-- net/ptypes/misc.go | 11 +- 16 files changed, 461 insertions(+), 478 deletions(-) diff --git a/bot/ingame.go b/bot/ingame.go index a128782..c89620a 100644 --- a/bot/ingame.go +++ b/bot/ingame.go @@ -294,22 +294,16 @@ func handleEntityStatusPacket(c *Client, p pk.Packet) error { } func handleDestroyEntitiesPacket(c *Client, p pk.Packet) error { - var ( - count pk.VarInt - r = bytes.NewReader(p.Data) - ) - if err := count.Decode(r); err != nil { + var count pk.VarInt + var data = pk.Ary{ + Len: &count, + Ary: []pk.VarInt{}, + } + if err := p.Scan(&count, &data); err != nil { return err } - entities := make([]pk.VarInt, int(count)) - for i := 0; i < int(count); i++ { - if err := entities[i].Decode(r); err != nil { - return err - } - } - - return c.Wd.OnEntityDestroy(entities) + return c.Wd.OnEntityDestroy(data.Ary.([]pk.VarInt)) } func handleSoundEffect(c *Client, p pk.Packet) error { @@ -378,34 +372,24 @@ func handleMultiBlockChangePacket(c *Client, p pk.Packet) error { if !c.settings.ReceiveMap { return nil } - r := bytes.NewReader(p.Data) var ( loc pk.Long dontTrustEdges pk.Boolean sz pk.VarInt - ) - - if err := loc.Decode(r); err != nil { - return fmt.Errorf("packed location: %v", err) - } - if err := dontTrustEdges.Decode(r); err != nil { - return fmt.Errorf("unknown 1: %v", err) - } - if err := sz.Decode(r); err != nil { - return fmt.Errorf("array size: %v", err) - } - - packedBlocks := make([]pk.VarLong, int(sz)) - for i := 0; i < int(sz); i++ { - if err := packedBlocks[i].Decode(r); err != nil { - return fmt.Errorf("block[%d]: %v", i, err) + packedBlocks = pk.Ary{ + Len: &sz, + Ary: []pk.VarLong{}, } + ) + err := p.Scan(&loc, &dontTrustEdges, &sz, &packedBlocks) + if err != nil { + return err } - x, z, y := int((loc>>42)&((1<<22)-1)), - int((loc>>20)&((1<<22)-1)), - int(loc&((1<<20)-1)) + x := int((loc >> 42) & ((1 << 22) - 1)) + y := int((loc >> 20) & ((1 << 22) - 1)) + z := int(loc & ((1 << 20) - 1)) // Apply transform into negative (these numbers are signed) if x >= 1<<21 { @@ -415,7 +399,7 @@ func handleMultiBlockChangePacket(c *Client, p pk.Packet) error { z -= 1 << 22 } - c.Wd.MultiBlockUpdate(world.ChunkLoc{X: x, Z: z}, y, packedBlocks) + c.Wd.MultiBlockUpdate(world.ChunkLoc{X: x, Z: z}, y, packedBlocks.Ary.([]pk.VarLong)) return nil } @@ -520,14 +504,14 @@ func handlePluginPacket(c *Client, p pk.Packet) error { switch msg.Channel { case "minecraft:brand": var brandRaw pk.String - if err := brandRaw.Decode(bytes.NewReader(msg.Data)); err != nil { + if _, err := brandRaw.ReadFrom(bytes.NewReader(msg.Data)); err != nil { return err } c.ServInfo.Brand = string(brandRaw) } if c.Events.PluginMessage != nil { - return c.Events.PluginMessage(string(msg.Channel), []byte(msg.Data)) + return c.Events.PluginMessage(string(msg.Channel), msg.Data) } return nil } @@ -622,7 +606,7 @@ func handleChunkDataPacket(c *Client, p pk.Packet) error { } var pkt ptypes.ChunkData - if err := pkt.Decode(p); err != nil { + if _, err := pkt.ReadFrom(bytes.NewReader(p.Data)); err != nil { return err } @@ -641,7 +625,7 @@ func handleChunkDataPacket(c *Client, p pk.Packet) error { func handleTileEntityDataPacket(c *Client, p pk.Packet) error { var pkt ptypes.TileEntityData - if err := pkt.Decode(p); err != nil { + if _, err := pkt.ReadFrom(bytes.NewReader(p.Data)); err != nil { return err } return c.Wd.TileEntityUpdate(pkt) @@ -712,7 +696,7 @@ func handleKeepAlivePacket(c *Client, p pk.Packet) error { func handleWindowItemsPacket(c *Client, p pk.Packet) error { var pkt ptypes.WindowItems - if err := pkt.Decode(p); err != nil { + if _, err := pkt.ReadFrom(bytes.NewReader(p.Data)); err != nil { return err } diff --git a/bot/login.go b/bot/login.go index a2564f8..c6d6a18 100644 --- a/bot/login.go +++ b/bot/login.go @@ -62,34 +62,12 @@ type encryptionRequest struct { VerifyToken []byte } -func (e *encryptionRequest) Decode(r pk.DecodeReader) error { - var serverID pk.String - if err := serverID.Decode(r); err != nil { - return err - } - - var publicKeyLength, verifyTokenLength pk.VarInt - - if err := publicKeyLength.Decode(r); err != nil { - return err - } - publicKey, err := pk.ReadNBytes(r, int(publicKeyLength)) - if err != nil { - return err - } - - if err := verifyTokenLength.Decode(r); err != nil { - return err - } - verifyToken, err := pk.ReadNBytes(r, int(verifyTokenLength)) - if err != nil { - return err - } - - e.ServerID = string(serverID) - e.PublicKey = publicKey - e.VerifyToken = verifyToken - return nil +func (e *encryptionRequest) ReadFrom(r io.Reader) (int64, error) { + return pk.Tuple{ + (*pk.String)(&e.ServerID), + (*pk.ByteArray)(&e.PublicKey), + (*pk.ByteArray)(&e.VerifyToken), + }.ReadFrom(r) } // authDigest computes a special SHA-1 digest required for Minecraft web @@ -216,14 +194,9 @@ func genEncryptionKeyResponse(shareSecret, publicKey, verifyToken []byte) (erp p err = fmt.Errorf("encryption verfy tokenfail: %v", err) return } - var data []byte - data = append(data, pk.VarInt(int32(len(cryptPK))).Encode()...) - data = append(data, cryptPK...) - data = append(data, pk.VarInt(int32(len(verifyT))).Encode()...) - data = append(data, verifyT...) - erp = pk.Packet{ - ID: 0x01, - Data: data, - } - return + return pk.Marshal( + 0x01, + pk.ByteArray(cryptPK), + pk.ByteArray(verifyT), + ), nil } diff --git a/bot/world/chunk.go b/bot/world/chunk.go index fc9dfe6..c20d31a 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -3,6 +3,7 @@ package world import ( "bytes" "fmt" + "io" "math" "github.com/Tnze/go-mc/data/block" @@ -41,13 +42,13 @@ func perBits(bpb byte) uint { } } -func readSection(data pk.DecodeReader) (s Section, err error) { +func readSection(data io.Reader) (s Section, err error) { var nonAirBlockCount pk.Short - if err := nonAirBlockCount.Decode(data); err != nil { + if _, err := nonAirBlockCount.ReadFrom(data); err != nil { return nil, fmt.Errorf("block count: %w", err) } var bpb pk.UnsignedByte - if err := bpb.Decode(data); err != nil { + if _, err := bpb.ReadFrom(data); err != nil { return nil, fmt.Errorf("bits per block: %w", err) } // If bpb values greater than or equal to 9, use directSection. @@ -57,14 +58,14 @@ func readSection(data pk.DecodeReader) (s Section, err error) { if bpb <= maxPaletteBits { // read palettes var length pk.VarInt - if err := length.Decode(data); err != nil { + if _, err := length.ReadFrom(data); err != nil { return nil, fmt.Errorf("palette length: %w", err) } palettes = make([]BlockStatus, length) palettesIndex = make(map[BlockStatus]int, length) for i := 0; i < int(length); i++ { var v pk.VarInt - if err := v.Decode(data); err != nil { + if _, err := v.ReadFrom(data); err != nil { return nil, fmt.Errorf("read palettes[%d] error: %w", i, err) } palettes[i] = BlockStatus(v) @@ -74,7 +75,7 @@ func readSection(data pk.DecodeReader) (s Section, err error) { // read data array var dataLen pk.VarInt - if err := dataLen.Decode(data); err != nil { + if _, err := dataLen.ReadFrom(data); err != nil { return nil, fmt.Errorf("read data array length error: %w", err) } if int(dataLen) < 16*16*16*int(bpb)/64 { @@ -83,7 +84,7 @@ func readSection(data pk.DecodeReader) (s Section, err error) { dataArray := make([]uint64, dataLen) for i := 0; i < int(dataLen); i++ { var v pk.Long - if err := v.Decode(data); err != nil { + if _, err := v.ReadFrom(data); err != nil { return nil, fmt.Errorf("read dataArray[%d] error: %w", i, err) } dataArray[i] = uint64(v) diff --git a/bot/world/entity/entity.go b/bot/world/entity/entity.go index 302ab17..64c7c5d 100644 --- a/bot/world/entity/entity.go +++ b/bot/world/entity/entity.go @@ -1,11 +1,10 @@ package entity import ( - "bytes" + "io" "github.com/Tnze/go-mc/data/entity" item "github.com/Tnze/go-mc/data/item" - "github.com/Tnze/go-mc/nbt" pk "github.com/Tnze/go-mc/net/packet" "github.com/google/uuid" ) @@ -49,53 +48,48 @@ type Slot struct { Present bool ItemID item.ID Count int8 - NBT interface{} + NBT pk.NBT +} + +type SlotNBT struct { + data interface{} } //Decode implement packet.FieldDecoder interface -func (s *Slot) Decode(r pk.DecodeReader) error { - if err := (*pk.Boolean)(&s.Present).Decode(r); err != nil { - return err +func (s *Slot) ReadFrom(r io.Reader) (int64, error) { + var itemID pk.VarInt + n, err := pk.Tuple{ + (*pk.Boolean)(&s.Present), + pk.Opt{ + Has: (*pk.Boolean)(&s.Present), + Field: pk.Tuple{ + &itemID, + (*pk.Byte)(&s.Count), + &s.NBT, + }, + }, + }.ReadFrom(r) + if err != nil { + return n, err } - if s.Present { - var itemID pk.VarInt - if err := itemID.Decode(r); err != nil { - return err - } - s.ItemID = item.ID(itemID) - if err := (*pk.Byte)(&s.Count).Decode(r); err != nil { - return err - } - if err := nbt.NewDecoder(r).Decode(&s.NBT); err != nil { - return err - } - } - return nil + s.ItemID = item.ID(itemID) + return n, nil } -func (s Slot) Encode() []byte { - if !s.Present { - return pk.Boolean(false).Encode() - } - - var b bytes.Buffer - b.Write(pk.Boolean(true).Encode()) - b.Write(pk.VarInt(s.ItemID).Encode()) - b.Write(pk.Byte(s.Count).Encode()) - - if s.NBT != nil { - if err := nbt.NewEncoder(&b).Encode(s.NBT); err != nil { - panic(err) - } - } else { - if _, err := b.Write([]byte{nbt.TagEnd}); err != nil { - panic(err) - } - } - - return b.Bytes() +func (s Slot) WriteTo(w io.Writer) (int64, error) { + return pk.Tuple{ + pk.Boolean(s.Present), + pk.Opt{ + Has: (*pk.Boolean)(&s.Present), + Field: pk.Tuple{ + pk.VarInt(s.ItemID), + pk.Byte(s.Count), + s.NBT, + }, + }, + }.WriteTo(w) } func (s Slot) String() string { - return item.ByID[item.ID(s.ItemID)].DisplayName + return item.ByID[s.ItemID].DisplayName } diff --git a/chat/chatMsg.go b/chat/chatMsg.go index 9d3ff94..08d653c 100644 --- a/chat/chatMsg.go +++ b/chat/chatMsg.go @@ -51,22 +51,23 @@ func (m *Message) UnmarshalJSON(jsonMsg []byte) (err error) { } //Decode for a ChatMsg packet -func (m *Message) Decode(r pk.DecodeReader) error { +func (m *Message) ReadFrom(r io.Reader) (int64, error) { var Len pk.VarInt - if err := Len.Decode(r); err != nil { - return err + if n, err := Len.ReadFrom(r); err != nil { + return n, err } - - return json.NewDecoder(io.LimitReader(r, int64(Len))).Decode(m) + lr := &io.LimitedReader{R: r, N: int64(Len)} + err := json.NewDecoder(lr).Decode(m) + return int64(Len) - lr.N, err } //Encode for a ChatMsg packet -func (m Message) Encode() []byte { +func (m Message) WriteTo(w io.Writer) (int64, error) { code, err := json.Marshal(m) if err != nil { panic(err) } - return pk.String(code).Encode() + return pk.String(code).WriteTo(w) } func (m *Message) Append(extraMsg ...Message) { diff --git a/chat/chatMsg_test.go b/chat/chatMsg_test.go index 291a0d8..b419a57 100644 --- a/chat/chatMsg_test.go +++ b/chat/chatMsg_test.go @@ -101,10 +101,11 @@ func TestChatMsgClearString(t *testing.T) { } func TestMessage_Encode(t *testing.T) { - codeMsg := chat.Message{Translate: "multiplayer.disconnect.server_full"}.Encode() + var codeMsg bytes.Buffer + _, _ = chat.Message{Translate: "multiplayer.disconnect.server_full"}.WriteTo(&codeMsg) var msg pk.Chat - if err := msg.Decode(bytes.NewReader(codeMsg)); err != nil { + if _, err := msg.ReadFrom(&codeMsg); err != nil { t.Errorf("decode message fail: %v", err) } diff --git a/cmd/daze/daze.go b/cmd/daze/daze.go index 36c81d2..970747c 100644 --- a/cmd/daze/daze.go +++ b/cmd/daze/daze.go @@ -65,7 +65,7 @@ func onPluginMessage(channel string, data []byte) error { switch channel { case "minecraft:brand": var brand pk.String - if err := brand.Decode(bytes.NewReader(data)); err != nil { + if _, err := brand.ReadFrom(bytes.NewReader(data)); err != nil { return err } log.Println("Server brand is:", brand) diff --git a/net/conn.go b/net/conn.go index 137fec4..88e3143 100644 --- a/net/conn.go +++ b/net/conn.go @@ -85,8 +85,7 @@ func (c *Conn) ReadPacket(p *pk.Packet) error { //WritePacket write a Packet to Conn. func (c *Conn) WritePacket(p pk.Packet) error { - _, err := c.Write(p.Pack(c.threshold)) - return err + return p.Pack(c, c.threshold) } // SetCipher load the decode/encode stream to this Conn diff --git a/net/packet/builder.go b/net/packet/builder.go index 57d767c..61b9aa7 100644 --- a/net/packet/builder.go +++ b/net/packet/builder.go @@ -8,7 +8,10 @@ type Builder struct { func (p *Builder) WriteField(fields ...FieldEncoder) { for _, f := range fields { - p.buf.Write(f.Encode()) + _, err := f.WriteTo(&p.buf) + if err != nil { + panic(err) + } } } diff --git a/net/packet/packet.go b/net/packet/packet.go index 9253110..c33f3ac 100644 --- a/net/packet/packet.go +++ b/net/packet/packet.go @@ -15,20 +15,18 @@ type Packet struct { //Marshal generate Packet with the ID and Fields func Marshal(id int32, fields ...FieldEncoder) (pk Packet) { - pk.ID = id - + var pb Builder for _, v := range fields { - pk.Data = append(pk.Data, v.Encode()...) + pb.WriteField(v) } - - return + return pb.Packet(id) } //Scan decode the packet and fill data into fields func (p Packet) Scan(fields ...FieldDecoder) error { r := bytes.NewReader(p.Data) for _, v := range fields { - err := v.Decode(r) + _, err := v.ReadFrom(r) if err != nil { return err } @@ -37,34 +35,48 @@ func (p Packet) Scan(fields ...FieldDecoder) error { } // Pack 打包一个数据包 -func (p *Packet) Pack(threshold int) (pack []byte) { - d := append(VarInt(p.ID).Encode(), p.Data...) +func (p *Packet) Pack(w io.Writer, threshold int) error { + var content bytes.Buffer + if _, err := VarInt(p.ID).WriteTo(&content); err != nil { + panic(err) + } + if _, err := content.Write(p.Data); err != nil { + panic(err) + } if threshold > 0 { //是否启用了压缩 - if len(d) > threshold { //是否需要压缩 - Len := len(d) - VarLen := VarInt(Len).Encode() - d = compress(d) - - pack = append(pack, VarInt(len(VarLen)+len(d)).Encode()...) - pack = append(pack, VarLen...) - pack = append(pack, d...) - } else { - pack = append(pack, VarInt(int32(len(d)+1)).Encode()...) - pack = append(pack, 0x00) - pack = append(pack, d...) + Len := content.Len() + var VarLen bytes.Buffer + if _, err := VarInt(Len).WriteTo(&VarLen); err != nil { + panic(err) + } + if _, err := VarInt(VarLen.Len() + Len).WriteTo(w); err != nil { + return err + } + if Len > threshold { //是否需要压缩 + compress(&content) + } + if _, err := VarLen.WriteTo(w); err != nil { + return err + } + if _, err := content.WriteTo(w); err != nil { + return err } } else { - pack = append(pack, VarInt(int32(len(d))).Encode()...) //len - pack = append(pack, d...) + if _, err := VarInt(content.Len()).WriteTo(w); err != nil { + return err + } + if _, err := content.WriteTo(w); err != nil { + return err + } } - return + return nil } // UnPack in-place decompression a packet -func (p *Packet) UnPack(r DecodeReader, threshold int) error { +func (p *Packet) UnPack(r io.Reader, threshold int) error { var length VarInt - if err := length.Decode(r); err != nil { + if _, err := length.ReadFrom(r); err != nil { return err } if length < 1 { @@ -84,7 +96,7 @@ func (p *Packet) UnPack(r DecodeReader, threshold int) error { } var packetID VarInt - if err := packetID.Decode(buf); err != nil { + if _, err := packetID.ReadFrom(buf); err != nil { return fmt.Errorf("read packet id fail: %v", err) } p.ID = int32(packetID) @@ -97,7 +109,7 @@ func unCompress(data *bytes.Buffer) error { reader := bytes.NewReader(data.Bytes()) var sizeUncompressed VarInt - if err := sizeUncompressed.Decode(reader); err != nil { + if _, err := sizeUncompressed.ReadFrom(reader); err != nil { return err } @@ -121,14 +133,15 @@ func unCompress(data *bytes.Buffer) error { } // compress 压缩数据 -func compress(data []byte) []byte { +func compress(data *bytes.Buffer) { var b bytes.Buffer w := zlib.NewWriter(&b) - if _, err := w.Write(data); err != nil { + if _, err := data.WriteTo(w); err != nil { panic(err) } if err := w.Close(); err != nil { panic(err) } - return b.Bytes() + *data = b + return } diff --git a/net/packet/packet_test.go b/net/packet/packet_test.go index c278ece..6c277ed 100644 --- a/net/packet/packet_test.go +++ b/net/packet/packet_test.go @@ -20,9 +20,15 @@ var PackedVarInts = [][]byte{ } func TestPackVarInt(t *testing.T) { + var buf bytes.Buffer for i, v := range VarInts { - p := v.Encode() - if !bytes.Equal(p, PackedVarInts[i]) { + buf.Reset() + if n, err := v.WriteTo(&buf); err != nil { + t.Fatalf("Write to bytes.Buffer should never fail: %v", err) + } else if n != int64(buf.Len()) { + t.Errorf("Number of byte returned by WriteTo should equal to buffer.Len()") + } + if p := buf.Bytes(); !bytes.Equal(p, PackedVarInts[i]) { t.Errorf("pack int %d should be \"% x\", get \"% x\"", v, PackedVarInts[i], p) } } @@ -30,7 +36,7 @@ func TestPackVarInt(t *testing.T) { func TestUnpackVarInt(t *testing.T) { for i, v := range PackedVarInts { var vi VarInt - if err := vi.Decode(bytes.NewReader(v)); err != nil { + if _, err := vi.ReadFrom(bytes.NewReader(v)); err != nil { t.Errorf("unpack \"% x\" error: %v", v, err) } if vi != VarInts[i] { @@ -42,7 +48,7 @@ func TestUnpackVarInt(t *testing.T) { func TestUnpackVarInt_TooLongData(t *testing.T) { var vi VarInt var data = []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01} - if err := vi.Decode(bytes.NewReader(data)); err != nil { + if _, err := vi.ReadFrom(bytes.NewReader(data)); err != nil { t.Logf("unpack \"% x\" error: %v", data, err) } else { t.Errorf("unpack \"% x\" should be error, get %d", data, vi) @@ -76,7 +82,7 @@ func TestPackVarLong(t *testing.T) { func TestUnpackVarLong(t *testing.T) { for i, v := range PackedVarLongs { var vi VarLong - if err := vi.Decode(bytes.NewReader(v)); err != nil { + if _, err := vi.ReadFrom(bytes.NewReader(v)); err != nil { t.Errorf("unpack \"% x\" error: %v", v, err) } if vi != VarLongs[i] { diff --git a/net/packet/types.go b/net/packet/types.go index 6c3a61d..883b727 100644 --- a/net/packet/types.go +++ b/net/packet/types.go @@ -18,20 +18,10 @@ type Field interface { } // A FieldEncoder can be encode as minecraft protocol used. -type FieldEncoder interface { - Encode() []byte -} +type FieldEncoder io.WriterTo // A FieldDecoder can Decode from minecraft protocol -type FieldDecoder interface { - Decode(r DecodeReader) error -} - -//DecodeReader is both io.Reader and io.ByteReader -type DecodeReader interface { - io.ByteReader - io.Reader -} +type FieldDecoder io.ReaderFrom type ( //Boolean of True is encoded as 0x01, false as 0x00. @@ -71,7 +61,7 @@ type ( } //Angle is rotation angle in steps of 1/256 of a full turn - Angle int8 + Angle Byte //UUID encoded as an unsigned 128-bit integer UUID uuid.UUID @@ -86,174 +76,190 @@ type ( ByteArray []byte ) -//ReadNBytes read N bytes from bytes.Reader -func ReadNBytes(r DecodeReader, n int) (bs []byte, err error) { - bs = make([]byte, n) - for i := 0; i < n; i++ { - bs[i], err = r.ReadByte() - if err != nil { - return - } - } - return -} +const MaxVarIntLen = 5 +const MaxVarLongLen = 10 //Encode a Boolean -func (b Boolean) Encode() []byte { +func (b Boolean) WriteTo(w io.Writer) (n int64, err error) { + var nn int if b { - return []byte{0x01} + nn, err = w.Write([]byte{0x01}) } - return []byte{0x00} + nn, err = w.Write([]byte{0x00}) + return int64(nn), err } //Decode a Boolean -func (b *Boolean) Decode(r DecodeReader) error { - v, err := r.ReadByte() +func (b *Boolean) ReadFrom(r io.Reader) (n int64, err error) { + v, err := readByte(r) if err != nil { - return err + return 1, err } - *b = Boolean(v != 0) - return nil + *b = v != 0 + return 1, nil } // Encode a String -func (s String) Encode() (p []byte) { - byteString := []byte(s) - p = append(p, VarInt(len(byteString)).Encode()...) //len - p = append(p, byteString...) //data - return +func (s String) WriteTo(w io.Writer) (int64, error) { + byteStr := []byte(s) + n1, err := VarInt(len(byteStr)).WriteTo(w) + if err != nil { + return n1, err + } + n2, err := w.Write(byteStr) + return n1 + int64(n2), err } //Decode a String -func (s *String) Decode(r DecodeReader) error { +func (s *String) ReadFrom(r io.Reader) (n int64, err error) { var l VarInt //String length - if err := l.Decode(r); err != nil { - return err - } - bs, err := ReadNBytes(r, int(l)) + nn, err := l.ReadFrom(r) if err != nil { - return err + return nn, err } + n += nn + + bs := make([]byte, l) + if _, err := io.ReadFull(r, bs); err != nil { + return n, err + } + n += int64(l) *s = String(bs) - return nil + return n, nil +} + +// readByte read one byte from io.Reader +func readByte(r io.Reader) (byte, error) { + if r, ok := r.(io.ByteReader); ok { + return r.ReadByte() + } + var v [1]byte + _, err := io.ReadFull(r, v[:]) + return v[0], err } //Encode a Byte -func (b Byte) Encode() []byte { - return []byte{byte(b)} +func (b Byte) WriteTo(w io.Writer) (n int64, err error) { + nn, err := w.Write([]byte{byte(b)}) + return int64(nn), err } //Decode a Byte -func (b *Byte) Decode(r DecodeReader) error { - v, err := r.ReadByte() +func (b *Byte) ReadFrom(r io.Reader) (n int64, err error) { + v, err := readByte(r) if err != nil { - return err + return 0, err } *b = Byte(v) - return nil + return 1, nil } //Encode a UnsignedByte -func (ub UnsignedByte) Encode() []byte { - return []byte{byte(ub)} +func (u UnsignedByte) WriteTo(w io.Writer) (n int64, err error) { + nn, err := w.Write([]byte{byte(u)}) + return int64(nn), err } //Decode a UnsignedByte -func (ub *UnsignedByte) Decode(r DecodeReader) error { - v, err := r.ReadByte() +func (u *UnsignedByte) ReadFrom(r io.Reader) (n int64, err error) { + v, err := readByte(r) if err != nil { - return err + return 0, err } - *ub = UnsignedByte(v) - return nil + *u = UnsignedByte(v) + return 1, nil } // Encode a Signed Short -func (s Short) Encode() []byte { +func (s Short) WriteTo(w io.Writer) (int64, error) { n := uint16(s) - return []byte{ - byte(n >> 8), - byte(n), - } + nn, err := w.Write([]byte{byte(n >> 8), byte(n)}) + return int64(nn), err } //Decode a Short -func (s *Short) Decode(r DecodeReader) error { - bs, err := ReadNBytes(r, 2) - if err != nil { - return err +func (s *Short) ReadFrom(r io.Reader) (n int64, err error) { + var bs [2]byte + if nn, err := io.ReadFull(r, bs[:]); err != nil { + return int64(nn), err + } else { + n += int64(nn) } *s = Short(int16(bs[0])<<8 | int16(bs[1])) - return nil + return } // Encode a Unsigned Short -func (us UnsignedShort) Encode() []byte { +func (us UnsignedShort) WriteTo(w io.Writer) (int64, error) { n := uint16(us) - return []byte{ - byte(n >> 8), - byte(n), - } + nn, err := w.Write([]byte{byte(n >> 8), byte(n)}) + return int64(nn), err } //Decode a UnsignedShort -func (us *UnsignedShort) Decode(r DecodeReader) error { - bs, err := ReadNBytes(r, 2) - if err != nil { - return err +func (us *UnsignedShort) ReadFrom(r io.Reader) (n int64, err error) { + var bs [2]byte + if nn, err := io.ReadFull(r, bs[:]); err != nil { + return int64(nn), err + } else { + n += int64(nn) } *us = UnsignedShort(int16(bs[0])<<8 | int16(bs[1])) - return nil + return } // Encode a Int -func (i Int) Encode() []byte { +func (i Int) WriteTo(w io.Writer) (int64, error) { n := uint32(i) - return []byte{ - byte(n >> 24), byte(n >> 16), - byte(n >> 8), byte(n), - } + nn, err := w.Write([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}) + return int64(nn), err } //Decode a Int -func (i *Int) Decode(r DecodeReader) error { - bs, err := ReadNBytes(r, 4) - if err != nil { - return err +func (i *Int) ReadFrom(r io.Reader) (n int64, err error) { + var bs [4]byte + if nn, err := io.ReadFull(r, bs[:]); err != nil { + return int64(nn), err + } else { + n += int64(nn) } *i = Int(int32(bs[0])<<24 | int32(bs[1])<<16 | int32(bs[2])<<8 | int32(bs[3])) - return nil + return } // Encode a Long -func (l Long) Encode() []byte { +func (l Long) WriteTo(w io.Writer) (int64, error) { n := uint64(l) - return []byte{ + nn, err := w.Write([]byte{ byte(n >> 56), byte(n >> 48), byte(n >> 40), byte(n >> 32), byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n), - } + }) + return int64(nn), err } //Decode a Long -func (l *Long) Decode(r DecodeReader) error { - bs, err := ReadNBytes(r, 8) - if err != nil { - return err +func (l *Long) ReadFrom(r io.Reader) (n int64, err error) { + var bs [8]byte + if nn, err := io.ReadFull(r, bs[:]); err != nil { + return int64(nn), err + } else { + n += int64(nn) } *l = Long(int64(bs[0])<<56 | int64(bs[1])<<48 | int64(bs[2])<<40 | int64(bs[3])<<32 | int64(bs[4])<<24 | int64(bs[5])<<16 | int64(bs[6])<<8 | int64(bs[7])) - return nil + return } //Encode a VarInt -func (v VarInt) Encode() (vi []byte) { +func (v VarInt) WriteTo(w io.Writer) (n int64, err error) { + var vi = make([]byte, 0, MaxVarIntLen) num := uint32(v) for { b := num & 0x7F @@ -266,29 +272,28 @@ func (v VarInt) Encode() (vi []byte) { break } } - return + nn, err := w.Write(vi) + return int64(nn), err } //Decode a VarInt -func (v *VarInt) Decode(r DecodeReader) error { - var n uint32 - for i := 0; ; i++ { //读数据前的长度标记 - sec, err := r.ReadByte() +func (v *VarInt) ReadFrom(r io.Reader) (n int64, err error) { + var V uint32 + for sec := byte(0x80); sec&0x80 != 0; n++ { + if n > MaxVarIntLen { + return n, errors.New("VarInt is too big") + } + + sec, err = readByte(r) if err != nil { - return err + return n, err } - n |= uint32(sec&0x7F) << uint32(7*i) - - if i >= 5 { - return errors.New("VarInt is too big") - } else if sec&0x80 == 0 { - break - } + V |= uint32(sec&0x7F) << uint32(7*n) } - *v = VarInt(n) - return nil + *v = VarInt(V) + return } //Encode a VarLong @@ -309,44 +314,44 @@ func (v VarLong) Encode() (vi []byte) { } //Decode a VarLong -func (v *VarLong) Decode(r DecodeReader) error { - var n uint64 - for i := 0; ; i++ { //读数据前的长度标记 - sec, err := r.ReadByte() +func (v *VarLong) ReadFrom(r io.Reader) (n int64, err error) { + var V uint64 + for sec := byte(0x80); sec&0x80 != 0; n++ { + if n >= MaxVarLongLen { + return n, errors.New("VarLong is too big") + } + sec, err = readByte(r) if err != nil { - return err + return } - n |= uint64(sec&0x7F) << uint64(7*i) - - if i >= 10 { - return errors.New("VarLong is too big") - } else if sec&0x80 == 0 { - break - } + V |= uint64(sec&0x7F) << uint64(7*n) } - *v = VarLong(n) - return nil + *v = VarLong(V) + return } //Encode a Position -func (p Position) Encode() []byte { - b := make([]byte, 8) +func (p Position) WriteTo(w io.Writer) (n int64, err error) { + var b [8]byte position := uint64(p.X&0x3FFFFFF)<<38 | uint64((p.Z&0x3FFFFFF)<<12) | uint64(p.Y&0xFFF) for i := 7; i >= 0; i-- { b[i] = byte(position) position >>= 8 } - return b + nn, err := w.Write(b[:]) + return int64(nn), err } // Decode a Position -func (p *Position) Decode(r DecodeReader) error { +func (p *Position) ReadFrom(r io.Reader) (n int64, err error) { var v Long - if err := v.Decode(r); err != nil { - return err + nn, err := v.ReadFrom(r) + if err != nil { + return nn, err } + n += nn x := int(v >> 38) y := int(v & 0xFFF) @@ -364,88 +369,111 @@ func (p *Position) Decode(r DecodeReader) error { } p.X, p.Y, p.Z = x, y, z - return nil + return } -//Decodes an Angle -func (b *Angle) Decode(r DecodeReader) error { - v, err := r.ReadByte() - if err != nil { - return err - } - *b = Angle(v) - return nil +// ToDeg convert Angle to Degree +func (a Angle) ToDeg() float64 { + return 360 * float64(a) / 256 +} + +// ToRad convert Angle to Radian +func (a Angle) ToRad() float64 { + return 2 * math.Pi * float64(a) / 256 +} + +func (a Angle) WriteTo(w io.Writer) (int64, error) { + return Byte(a).WriteTo(w) +} + +func (a *Angle) ReadFrom(r io.Reader) (int64, error) { + return (*Byte)(a).ReadFrom(r) } //Encode a Float -func (f Float) Encode() []byte { - return Int(math.Float32bits(float32(f))).Encode() +func (f Float) WriteTo(w io.Writer) (n int64, err error) { + return Int(math.Float32bits(float32(f))).WriteTo(w) } // Decode a Float -func (f *Float) Decode(r DecodeReader) error { +func (f *Float) ReadFrom(r io.Reader) (n int64, err error) { var v Int - if err := v.Decode(r); err != nil { - return err + + n, err = v.ReadFrom(r) + if err != nil { + return } *f = Float(math.Float32frombits(uint32(v))) - return nil + return } //Encode a Double -func (d Double) Encode() []byte { - return Long(math.Float64bits(float64(d))).Encode() +func (d Double) WriteTo(w io.Writer) (n int64, err error) { + return Long(math.Float64bits(float64(d))).WriteTo(w) } // Decode a Double -func (d *Double) Decode(r DecodeReader) error { +func (d *Double) ReadFrom(r io.Reader) (n int64, err error) { var v Long - if err := v.Decode(r); err != nil { - return err + n, err = v.ReadFrom(r) + if err != nil { + return } *d = Double(math.Float64frombits(uint64(v))) - return nil + return } // Encode a NBT -func (n NBT) Encode() []byte { +func (n *NBT) WriteTo(w io.Writer) (int64, error) { var buf bytes.Buffer if err := nbt.NewEncoder(&buf).Encode(n.V); err != nil { panic(err) } - return buf.Bytes() + return buf.WriteTo(w) } // Decode a NBT -func (n NBT) Decode(r DecodeReader) error { - return nbt.NewDecoder(r).Decode(n.V) +func (n *NBT) ReadFrom(r io.Reader) (int64, error) { + // LimitReader is used to count reader length + lr := &io.LimitedReader{R: r, N: math.MaxInt64} + err := nbt.NewDecoder(lr).Decode(n.V) + return math.MaxInt64 - lr.N, err } // Encode a ByteArray -func (b ByteArray) Encode() []byte { - return append(VarInt(len(b)).Encode(), b...) +func (b ByteArray) WriteTo(w io.Writer) (n int64, err error) { + n1, err := VarInt(len(b)).WriteTo(w) + if err != nil { + return n1, err + } + n2, err := w.Write(b) + return n1 + int64(n2), err } // Decode a ByteArray -func (b *ByteArray) Decode(r DecodeReader) error { +func (b *ByteArray) ReadFrom(r io.Reader) (n int64, err error) { var Len VarInt - if err := Len.Decode(r); err != nil { - return err + n1, err := Len.ReadFrom(r) + if err != nil { + return n1, err } - *b = make([]byte, Len) - _, err := r.Read(*b) - return err + buf := bytes.NewBuffer(*b) + buf.Reset() + n2, err := io.CopyN(buf, r, int64(Len)) + *b = buf.Bytes() + return n1 + n2, err } // Encode a UUID -func (u UUID) Encode() []byte { - return u[:] +func (u UUID) WriteTo(w io.Writer) (n int64, err error) { + nn, err := w.Write(u[:]) + return int64(nn), err } // Decode a UUID -func (u *UUID) Decode(r DecodeReader) error { - _, err := io.ReadFull(r, (*u)[:]) - return err +func (u *UUID) ReadFrom(r io.Reader) (n int64, err error) { + nn, err := io.ReadFull(r, (*u)[:]) + return int64(nn), err } diff --git a/net/packet/util.go b/net/packet/util.go index 2f1fa6c..216744a 100644 --- a/net/packet/util.go +++ b/net/packet/util.go @@ -1,51 +1,84 @@ package packet import ( + "io" "reflect" ) type Ary struct { - Len Field - Ary interface{} + Len Field // One of VarInt, VarLong, Int or Long + Ary interface{} // FieldEncoder, FieldDecoder or both (Field) } -func (a Ary) Encode() (data []byte) { +func (a Ary) WriteTo(r io.Writer) (n int64, err error) { length := int(reflect.ValueOf(a.Len).Int()) array := reflect.ValueOf(a.Ary).Elem() for i := 0; i < length; i++ { elem := array.Index(i) - data = append(data, elem.Interface().(FieldEncoder).Encode()...) + nn, err := elem.Interface().(FieldEncoder).WriteTo(r) + n += nn + if err != nil { + return n, err + } + } + return n, nil +} + +func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { + length := int(reflect.ValueOf(a.Len).Int()) + array := reflect.ValueOf(a.Ary).Elem() + for i := 0; i < length; i++ { + elem := array.Index(i) + nn, err := elem.Interface().(FieldDecoder).ReadFrom(r) + n += nn + if err != nil { + return n, err + } + } + return n, err +} + +type Opt struct { + Has *Boolean + Field interface{} // FieldEncoder, FieldDecoder or both (Field) +} + +func (o Opt) WriteTo(w io.Writer) (int64, error) { + if *o.Has { + return o.Field.(FieldEncoder).WriteTo(w) + } + return 0, nil +} + +func (o Opt) ReadFrom(r io.Reader) (int64, error) { + if *o.Has { + return o.Field.(FieldDecoder).ReadFrom(r) + } + return 0, nil +} + +type Tuple []interface{} // FieldEncoder, FieldDecoder or both (Field) + +// WriteTo write Tuple to io.Writer, panic when any of filed don't implement FieldEncoder +func (t Tuple) WriteTo(w io.Writer) (n int64, err error) { + for _, v := range t { + nn, err := v.(FieldEncoder).WriteTo(w) + if err != nil { + return n, err + } + n += nn } return } -func (a Ary) Decode(r DecodeReader) error { - length := int(reflect.ValueOf(a.Len).Int()) - array := reflect.ValueOf(a.Ary).Elem() - for i := 0; i < length; i++ { - elem := array.Index(i) - if err := elem.Interface().(FieldDecoder).Decode(r); err != nil { - return err +// ReadFrom read Tuple from io.Reader, panic when any of field don't implement FieldDecoder +func (t Tuple) ReadFrom(r io.Reader) (n int64, err error) { + for _, v := range t { + nn, err := v.(FieldDecoder).ReadFrom(r) + if err != nil { + return n, err } + n += nn } - return nil -} - -type Opt struct { - Has func() bool - Field interface{} -} - -func (o Opt) Encode() []byte { - if o.Has() { - return nil - } - return o.Field.(FieldEncoder).Encode() -} - -func (o Opt) Decode(r DecodeReader) error { - if o.Has() { - return nil - } - return o.Field.(FieldDecoder).Decode(r) + return } diff --git a/net/ptypes/chunk.go b/net/ptypes/chunk.go index 7dbec71..ae77f57 100644 --- a/net/ptypes/chunk.go +++ b/net/ptypes/chunk.go @@ -2,8 +2,8 @@ package ptypes import ( - "bytes" - "fmt" + "io" + "math" "github.com/Tnze/go-mc/bot/world/entity" "github.com/Tnze/go-mc/nbt" @@ -17,96 +17,53 @@ type ChunkData struct { PrimaryBitMask pk.VarInt Heightmaps struct{} Biomes biomesData - Data chunkData + Data pk.ByteArray BlockEntities blockEntities } -func (p *ChunkData) Decode(pkt pk.Packet) error { - r := bytes.NewReader(pkt.Data) - if err := p.X.Decode(r); err != nil { - return fmt.Errorf("decode X: %v", err) - } - if err := p.Z.Decode(r); err != nil { - return fmt.Errorf("decode Z: %v", err) - } - if err := p.FullChunk.Decode(r); err != nil { - return fmt.Errorf("full chunk: %v", err) - } - if err := p.PrimaryBitMask.Decode(r); err != nil { - return fmt.Errorf("bit mask: %v", err) - } - if err := (pk.NBT{V: &p.Heightmaps}).Decode(r); err != nil { - return fmt.Errorf("heightmaps: %v", err) - } - - // Biomes data is only present for full chunks. - if p.FullChunk { - if err := p.Biomes.Decode(r); err != nil { - return fmt.Errorf("heightmaps: %v", err) - } - } - - if err := p.Data.Decode(r); err != nil { - return fmt.Errorf("data: %v", err) - } - if err := p.BlockEntities.Decode(r); err != nil { - return fmt.Errorf("block entities: %v", err) - } - return nil +func (p *ChunkData) ReadFrom(r io.Reader) (int64, error) { + return pk.Tuple{ + &p.X, + &p.Z, + &p.FullChunk, + &p.PrimaryBitMask, + &pk.NBT{V: &p.Heightmaps}, + pk.Opt{Has: &p.FullChunk, Field: &p.Biomes}, + &p.Data, + &p.BlockEntities, + }.ReadFrom(r) } type biomesData struct { data []pk.VarInt } -func (b *biomesData) Decode(r pk.DecodeReader) error { - var BiomesDataNums pk.VarInt // Number of Biomes Data - if err := BiomesDataNums.Decode(r); err != nil { - return err - } - b.data = make([]pk.VarInt, BiomesDataNums) - - for i := 0; i < int(BiomesDataNums); i++ { - var d pk.VarInt - if err := d.Decode(r); err != nil { - return err - } - b.data[i] = d - } - - return nil +func (b *biomesData) ReadFrom(r io.Reader) (int64, error) { + var n pk.VarInt // Number of Biomes Data + return pk.Tuple{ + &n, pk.Ary{Len: &n, Ary: []pk.VarInt{}}, + }.ReadFrom(r) } -type chunkData []byte type blockEntities []entity.BlockEntity // Decode implement net.packet.FieldDecoder -func (c *chunkData) Decode(r pk.DecodeReader) error { - var sz pk.VarInt - if err := sz.Decode(r); err != nil { - return err - } - *c = make([]byte, sz) - if _, err := r.Read(*c); err != nil { - return err - } - return nil -} - -// Decode implement net.packet.FieldDecoder -func (b *blockEntities) Decode(r pk.DecodeReader) error { +func (b *blockEntities) ReadFrom(r io.Reader) (n int64, err error) { var sz pk.VarInt // Number of BlockEntities - if err := sz.Decode(r); err != nil { - return err + if nn, err := sz.ReadFrom(r); err != nil { + return nn, err + } else { + n += nn } *b = make(blockEntities, sz) - decoder := nbt.NewDecoder(r) + lr := &io.LimitedReader{R: r, N: math.MaxInt64} + d := nbt.NewDecoder(lr) for i := 0; i < int(sz); i++ { - if err := decoder.Decode(&(*b)[i]); err != nil { - return err + if err := d.Decode(&(*b)[i]); err != nil { + return math.MaxInt64 - lr.N, err } } - return nil + return math.MaxInt64 - lr.N, nil } // TileEntityData describes a change to a tile entity. @@ -116,13 +73,10 @@ type TileEntityData struct { Data entity.BlockEntity } -func (p *TileEntityData) Decode(pkt pk.Packet) error { - r := bytes.NewReader(pkt.Data) - if err := p.Pos.Decode(r); err != nil { - return fmt.Errorf("position: %v", err) - } - if err := p.Action.Decode(r); err != nil { - return fmt.Errorf("action: %v", err) - } - return nbt.NewDecoder(r).Decode(&p.Data) +func (p *TileEntityData) ReadFrom(r io.Reader) (int64, error) { + return pk.Tuple{ + &p.Pos, + &p.Action, + &pk.NBT{V: &p.Data}, + }.ReadFrom(r) } diff --git a/net/ptypes/inventory.go b/net/ptypes/inventory.go index c0fe944..3cb44cb 100644 --- a/net/ptypes/inventory.go +++ b/net/ptypes/inventory.go @@ -2,8 +2,8 @@ package ptypes import ( - "bytes" "errors" + "io" "github.com/Tnze/go-mc/bot/world/entity" "github.com/Tnze/go-mc/chat" @@ -35,24 +35,16 @@ type WindowItems struct { Slots []entity.Slot } -func (p *WindowItems) Decode(pkt pk.Packet) error { - r := bytes.NewReader(pkt.Data) - if err := p.WindowID.Decode(r); err != nil { - return err - } - +func (p *WindowItems) ReadFrom(r io.Reader) (int64, error) { var count pk.Short - if err := count.Decode(r); err != nil { - return err - } - - p.Slots = make([]entity.Slot, int(count)) - for i := 0; i < int(count); i++ { - if err := p.Slots[i].Decode(r); err != nil && !errors.Is(err, nbt.ErrEND) { - return err - } - } - return nil + return pk.Tuple{ + &p.WindowID, + &count, + &pk.Ary{ + Len: &count, + Ary: []entity.Slot{}, + }, + }.ReadFrom(r) } // OpenWindow is a clientbound packet which opens an inventory. diff --git a/net/ptypes/misc.go b/net/ptypes/misc.go index 91a7a20..591367c 100644 --- a/net/ptypes/misc.go +++ b/net/ptypes/misc.go @@ -59,17 +59,18 @@ func (p *UpdateHealth) Decode(pkt pk.Packet) error { // PluginData encodes the custom data encoded in a plugin message. type PluginData []byte -func (p PluginData) Encode() []byte { - return []byte(p) +func (p PluginData) WriteTo(w io.Writer) (int64, error) { + n, err := w.Write(p) + return int64(n), err } -func (p *PluginData) Decode(r pk.DecodeReader) error { +func (p *PluginData) ReadFrom(r io.Reader) (int64, error) { d, err := io.ReadAll(r) if err != nil { - return err + return int64(len(d)), err } *p = d - return nil + return int64(len(d)), nil } // PluginMessage represents a packet with a customized payload.