diff --git a/bot/client.go b/bot/client.go index f5b23e4..907fa0a 100644 --- a/bot/client.go +++ b/bot/client.go @@ -1,6 +1,7 @@ package bot import ( + "github.com/Tnze/go-mc/bot/world" "github.com/Tnze/go-mc/bot/world/entity" "github.com/Tnze/go-mc/bot/world/entity/player" "github.com/Tnze/go-mc/net" @@ -15,7 +16,7 @@ type Client struct { PlayInfo abilities PlayerAbilities settings Settings - // wd world //the map data + Wd world.World //the map data // Delegate allows you push a function to let HandleGame run. // Do not send at the same goroutin! @@ -40,6 +41,9 @@ func NewClient() (c *Client) { c.Name = "Steve" c.Delegate = make(chan func() error) + c.Wd.Entities = make(map[int32]entity.Entity) + c.Wd.Chunks = make(map[world.ChunkLoc]*world.Chunk) + return } diff --git a/bot/ingame.go b/bot/ingame.go index 67899b3..c4d2c2d 100644 --- a/bot/ingame.go +++ b/bot/ingame.go @@ -3,10 +3,13 @@ package bot import ( "bytes" "errors" + "io" + "io/ioutil" // "math" // "time" "fmt" + "github.com/Tnze/go-mc/bot/world" "github.com/Tnze/go-mc/bot/world/entity" "github.com/Tnze/go-mc/chat" "github.com/Tnze/go-mc/data" @@ -82,7 +85,7 @@ func (c *Client) handlePacket(p pk.Packet) (disconnect bool, err error) { case data.HeldItemChangeClientbound: err = handleHeldItemPacket(c, p) case data.ChunkData: - ////err = handleChunkDataPacket(c, p) + err = handleChunkDataPacket(c, p) case data.PlayerPositionAndLookClientbound: err = handlePlayerPositionAndLookPacket(c, p) sendPlayerPositionAndLookPacket(c) // to confirm the position @@ -345,10 +348,30 @@ func handleJoinGamePacket(c *Client, p pk.Packet) error { return nil } +// The PluginMessageData only used in recive PluginMessage packet. +// When decode it, read to end. +type pluginMessageData []byte + +//Encode a PluginMessageData +func (p *pluginMessageData) Encode(r io.Writer) error { + _, err := r.Write([]byte(*p)) + return err +} + +//Decode a PluginMessageData +func (p *pluginMessageData) Decode(r pk.DecodeReader) error { + data, err := ioutil.ReadAll(r) + if err != nil { + return err + } + *p = pluginMessageData(data) + return nil +} + func handlePluginPacket(c *Client, p pk.Packet) error { var ( Channel pk.Identifier - Data pk.PluginMessageData + Data pluginMessageData ) if err := p.Scan(&Channel, &Data); err != nil { return err @@ -405,15 +428,15 @@ func handleHeldItemPacket(c *Client, p pk.Packet) error { return nil } -// func handleChunkDataPacket(g *Client, p pk.Packet) error { -// if !g.settings.ReciveMap { -// return nil -// } +func handleChunkDataPacket(c *Client, p pk.Packet) error { + if !c.settings.ReciveMap { + return nil + } -// c, x, y, err := unpackChunkDataPacket(p, g.Info.Dimension == 0) -// g.wd.chunks[chunkLoc{x, y}] = c -// return err -// } + chunk, x, z, err := world.UnpackChunkDataPacket(p, c.Dimension == 0) + c.Wd.Chunks[world.ChunkLoc{x, z}] = chunk + return err +} // var isSpawn bool diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 9507632..0057e66 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -1,127 +1,132 @@ package world -// import ( -// "bytes" -// "fmt" -// pk "github.com/Tnze/gomcbot/network/packet" -// "io" -// ) +import ( + "github.com/Tnze/go-mc/nbt" + // "fmt" + pk "github.com/Tnze/go-mc/net/packet" + // "io" +) -// func unpackChunkDataPacket(p *pk.Packet, hasSkyLight bool) (c *Chunk, x, y int, err error) { -// reader := bytes.NewReader(p.Data) -// //区块坐标 -// X, err := pk.UnpackInt32(reader) -// if err != nil { -// return nil, 0, 0, err -// } -// Y, err := pk.UnpackInt32(reader) -// if err != nil { -// return nil, 0, 0, err -// } -// // fmt.Println("Chunk: (", X, ", ", Y, ")") //Debug: Show Chunk loc -// fc, err := reader.ReadByte() -// if err != nil { -// return nil, 0, 0, err -// } -// FullChunk := fc != 0x00 +func UnpackChunkDataPacket(p pk.Packet, hasSkyLight bool) (c *Chunk, x, z int, err error) { + var ( + X, Z pk.Int + FullChunk pk.Boolean + PrimaryBitMask pk.VarInt + Heightmaps struct{} + Data chunkData + BlockEntities blockEntities + ) -// //主掩码 -// PrimaryBitMask, err := pk.UnpackVarInt(reader) -// if err != nil { -// return nil, 0, 0, err -// } + p.Scan(&X, &Z, &FullChunk, &PrimaryBitMask, pk.NBT{V: &Heightmaps}, &Data, &BlockEntities) -// //区块数据 -// Size, err := pk.UnpackVarInt(reader) -// if err != nil { -// return nil, 0, 0, err -// } -// Data := make([]byte, Size) -// _, err = io.ReadAtLeast(reader, Data, int(Size)) -// if err != nil { -// return nil, 0, 0, err -// } + //解析区块数据 + cc, err := readChunkColumn(bool(FullChunk), int32(PrimaryBitMask), []byte(Data), hasSkyLight) + if err != nil { + panic(err) + } + return cc, int(X), int(Z), err +} -// //实体信息 -// // NumberofBlockEntities, len := pk.UnpackVarInt(p.Data[index:]) -// // index += len +type chunkData []byte +type blockEntities []blockEntitie +type blockEntitie struct { +} -// //解析区块数据 -// cc, err := readChunkColumn(FullChunk, PrimaryBitMask, bytes.NewReader(Data), hasSkyLight) -// if err != nil { -// panic(err) -// } -// return cc, int(X), int(Y), err -// } +func (c *chunkData) Decode(r pk.DecodeReader) error { + var Size pk.VarInt + if err := Size.Decode(r); err != nil { + return err + } + *c = make([]byte, Size) + if _, err := r.Read(*c); err != nil { + return err + } + return nil +} -// func readChunkColumn(isFull bool, mask int32, data *bytes.Reader, hasSkyLight bool) (*Chunk, error) { -// var c Chunk -// for sectionY := 0; sectionY < 16; sectionY++ { -// if (mask & (1 << uint(sectionY))) != 0 { // Is the given bit set in the mask? -// BitsPerBlock, err := data.ReadByte() -// if err != nil { -// return nil, fmt.Errorf("read BitsPerBlock fail: %v", err) -// } -// //读调色板 -// var palette []uint -// if BitsPerBlock < 9 { -// length, err := pk.UnpackVarInt(data) -// if err != nil { -// return nil, fmt.Errorf("read palette (id len) fail: %v", err) -// } -// palette = make([]uint, length) +func (b *blockEntities) Decode(r pk.DecodeReader) error { + var NumberofBlockEntities pk.VarInt + if err := NumberofBlockEntities.Decode(r); err != nil { + return err + } + *b = make(blockEntities, NumberofBlockEntities) + decoder := nbt.NewDecoder(r) + for i := 0; i < int(NumberofBlockEntities); i++ { + if err := decoder.Decode(&(*b)[i]); err != nil { + return err + } + } + return nil +} -// for id := uint(0); id < uint(length); id++ { -// stateID, err := pk.UnpackVarInt(data) -// if err != nil { -// return nil, fmt.Errorf("read palette (id) fail: %v", err) -// } +func readChunkColumn(isFull bool, mask int32, data []byte, hasSkyLight bool) (*Chunk, error) { + var c Chunk + // for sectionY := 0; sectionY < 16; sectionY++ { + // if (mask & (1 << uint(sectionY))) != 0 { // Is the given bit set in the mask? + // BitsPerBlock, err := data.ReadByte() + // if err != nil { + // return nil, fmt.Errorf("read BitsPerBlock fail: %v", err) + // } + // //读调色板 + // var palette []uint + // if BitsPerBlock < 9 { + // length, err := pk.UnpackVarInt(data) + // if err != nil { + // return nil, fmt.Errorf("read palette (id len) fail: %v", err) + // } + // palette = make([]uint, length) -// palette[id] = uint(stateID) -// } -// } + // for id := uint(0); id < uint(length); id++ { + // stateID, err := pk.UnpackVarInt(data) + // if err != nil { + // return nil, fmt.Errorf("read palette (id) fail: %v", err) + // } -// //Section数据 -// DataArrayLength, err := pk.UnpackVarInt(data) -// if err != nil { -// return nil, fmt.Errorf("read DataArrayLength fail: %v", err) -// } + // palette[id] = uint(stateID) + // } + // } -// DataArray := make([]int64, DataArrayLength) -// for i := 0; i < int(DataArrayLength); i++ { -// DataArray[i], err = pk.UnpackInt64(data) -// if err != nil { -// return nil, fmt.Errorf("read DataArray fail: %v", err) -// } -// } -// //用数据填充区块 -// fillSection(&c.sections[sectionY], perBits(BitsPerBlock), DataArray, palette) + // //Section数据 + // DataArrayLength, err := pk.UnpackVarInt(data) + // if err != nil { + // return nil, fmt.Errorf("read DataArrayLength fail: %v", err) + // } -// //throw BlockLight data -// _, err = pk.ReadNBytes(data, 2048) -// if err != nil { -// return nil, fmt.Errorf("read BlockLight fail: %v", err) -// } + // DataArray := make([]int64, DataArrayLength) + // for i := 0; i < int(DataArrayLength); i++ { + // DataArray[i], err = pk.UnpackInt64(data) + // if err != nil { + // return nil, fmt.Errorf("read DataArray fail: %v", err) + // } + // } + // //用数据填充区块 + // fillSection(&c.sections[sectionY], perBits(BitsPerBlock), DataArray, palette) -// if hasSkyLight { -// //throw SkyLight data -// _, err = pk.ReadNBytes(data, 2048) -// if err != nil { -// return nil, fmt.Errorf("read SkyLight fail: %v", err) -// } -// } -// } -// } -// if isFull { //need recive Biomes datas -// _, err := pk.ReadNBytes(data, 256*4) -// if err != nil { -// return nil, fmt.Errorf("read Biomes fail: %v", err) -// } -// } + // //throw BlockLight data + // _, err = pk.ReadNBytes(data, 2048) + // if err != nil { + // return nil, fmt.Errorf("read BlockLight fail: %v", err) + // } -// // fmt.Println(c) -// return &c, nil -// } + // if hasSkyLight { + // //throw SkyLight data + // _, err = pk.ReadNBytes(data, 2048) + // if err != nil { + // return nil, fmt.Errorf("read SkyLight fail: %v", err) + // } + // } + // } + // } + // if isFull { //need recive Biomes datas + // _, err := pk.ReadNBytes(data, 256*4) + // if err != nil { + // return nil, fmt.Errorf("read Biomes fail: %v", err) + // } + // } + + // fmt.Println(c) + return &c, nil +} // const defaultBitsPerBlock = 14 diff --git a/bot/world/world.go b/bot/world/world.go index 6a9a4d2..44fdc16 100644 --- a/bot/world/world.go +++ b/bot/world/world.go @@ -1,29 +1,33 @@ package world -// //World record all of the things in the world where player at -// type world struct { -// Entities map[int32]Entity -// chunks map[chunkLoc]*Chunk -// } +import ( + "github.com/Tnze/go-mc/bot/world/entity" +) -// //Chunk store a 256*16*16 clolumn blocks -// type Chunk struct { -// sections [16]Section -// } +//World record all of the things in the world where player at +type World struct { + Entities map[int32]entity.Entity + Chunks map[ChunkLoc]*Chunk +} -// //Section store a 16*16*16 cube blocks -// type Section struct { -// blocks [16][16][16]Block -// } +//Chunk store a 256*16*16 clolumn blocks +type Chunk struct { + sections [16]Section +} -// //Block is the base of world -// type Block struct { -// id uint -// } +//Section store a 16*16*16 cube blocks +type Section struct { + blocks [16][16][16]Block +} -// type chunkLoc struct { -// X, Y int -// } +//Block is the base of world +type Block struct { + id uint +} + +type ChunkLoc struct { + X, Z int +} // //Entity 表示一个实体 // type Entity interface { diff --git a/cmd/autofish/autofish.go b/cmd/autofish/autofish.go index cc88c61..c3ebab3 100644 --- a/cmd/autofish/autofish.go +++ b/cmd/autofish/autofish.go @@ -16,6 +16,7 @@ var ( func main() { c = bot.NewClient() + //Login err := c.JoinServer("localhost", 25565) if err != nil { diff --git a/go.sum b/go.sum deleted file mode 100644 index e69de29..0000000 diff --git a/net/packet/types.go b/net/packet/types.go index 86cb201..61cbaae 100644 --- a/net/packet/types.go +++ b/net/packet/types.go @@ -2,8 +2,9 @@ package packet import ( "io" - "io/ioutil" "math" + + "github.com/Tnze/go-mc/nbt" ) // A Field is both FieldEncoder and FieldDecoder @@ -70,6 +71,11 @@ type ( //UUID encoded as an unsigned 128-bit integer UUID [16]byte + + //NBT encode a value as Named Binary Tag + NBT struct { + V interface{} + } ) //ReadNBytes read N bytes from bytes.Reader @@ -344,22 +350,7 @@ func (d *Double) Decode(r DecodeReader) error { return nil } -// The PluginMessageData only used in recive PluginMessage packet. -// When decode it, read to end. -type PluginMessageData []byte - -//Encode a PluginMessageData -func (p *PluginMessageData) Encode(r io.Writer) error { - _, err := r.Write([]byte(*p)) - return err -} - -//Decode a PluginMessageData -func (p *PluginMessageData) Decode(r DecodeReader) error { - data, err := ioutil.ReadAll(r) - if err != nil { - return err - } - *p = PluginMessageData(data) - return nil +// Decode a NBT +func (n NBT) Decode(r DecodeReader) error { + return nbt.NewDecoder(r).Decode(&n.V) }