support Inventory and Delegate

This commit is contained in:
JunDao
2019-05-19 17:44:49 +08:00
parent 2c41d9b901
commit 438285676d
6 changed files with 1163 additions and 857 deletions

View File

@ -13,6 +13,8 @@ There's some library in Go support you to create your Minecraft client or server
- [x] Simple MC robot lib
- [x] Parse NBT
> 由于仍在开发中部分API在未来版本中可能会变动
Some examples are at `/cmd` folder.
有一些例子在cmd目录下

View File

@ -1,6 +1,7 @@
package bot
import (
"github.com/Tnze/go-mc/bot/world/entity"
"github.com/Tnze/go-mc/bot/world/entity/player"
"github.com/Tnze/go-mc/net"
)
@ -16,7 +17,12 @@ type Client struct {
settings Settings
// wd world //the map data
Events eventBroker
// Delegate allows you push a function to let HandleGame run.
// Do not send at the same goroutin!
Delegate chan func() error
Events eventBroker
Inventory [46]entity.Slot
}
// NewClient init and return a new Client.
@ -32,6 +38,7 @@ func NewClient() (c *Client) {
//init Client
c.settings = DefaultSettings
c.Name = "Steve"
c.Delegate = make(chan func() error)
return
}
@ -59,3 +66,13 @@ type PlayerAbilities struct {
type Position struct {
X, Y, Z int
}
//HotBar return the hotbar of inventory
func (c *Client) HotBar() []entity.Slot {
return c.Inventory[36:45]
}
// MainInventory return the main inventory slots
func (c *Client) MainInventory() []entity.Slot {
return c.Inventory[9:36]
}

View File

@ -1,13 +1,16 @@
package bot
import (
// "bytes"
"bytes"
"errors"
// "math"
// "time"
"fmt"
"github.com/Tnze/go-mc/bot/world/entity"
"github.com/Tnze/go-mc/chat"
"github.com/Tnze/go-mc/data"
"github.com/Tnze/go-mc/nbt"
pk "github.com/Tnze/go-mc/net/packet"
)
@ -25,18 +28,25 @@ import (
// Note that HandleGame will block if you don't recive from Events.
func (c *Client) HandleGame() error {
for {
//Read packets
p, err := c.conn.ReadPacket()
if err != nil {
return fmt.Errorf("bot: read packet fail: %v", err)
}
//handle packets
disconnect, err := c.handlePacket(p)
if err != nil {
return fmt.Errorf("handle packet 0x%X error: %v", p.ID, err)
}
if disconnect {
return nil
select {
case task := <-c.Delegate:
if err := task(); err != nil {
return err
}
default:
//Read packets
p, err := c.conn.ReadPacket()
if err != nil {
return fmt.Errorf("bot: read packet fail: %v", err)
}
//handle packets
disconnect, err := c.handlePacket(p)
if err != nil {
return fmt.Errorf("handle packet 0x%X error: %v", p.ID, err)
}
if disconnect {
return nil
}
}
}
}
@ -103,8 +113,8 @@ func (c *Client) handlePacket(p pk.Packet) (disconnect bool, err error) {
case 0x1A:
err = handleDisconnectPacket(c, p)
disconnect = true
case 0x16:
// err = handleSetSlotPacket(g, reader)
case data.SetSlot:
err = handleSetSlotPacket(c, p)
case data.SoundEffect:
err = handleSoundEffect(c, p)
case data.NamedSoundEffect:
@ -170,33 +180,30 @@ func handleDisconnectPacket(c *Client, p pk.Packet) error {
return c.Events.Disconnect(reason)
}
// func handleSetSlotPacket(g *Client, r *bytes.Reader) error {
// windowID, err := r.ReadByte()
// if err != nil {
// return err
// }
// slot, err := pk.UnpackInt16(r)
// if err != nil {
// return err
// }
// slotData, err := unpackSolt(r)
// if err != nil {
// return err
// }
func handleSetSlotPacket(c *Client, p pk.Packet) error {
var (
windowID pk.Byte
slotI pk.Short
slot entity.Slot
)
if err := p.Scan(&windowID, &slotI, &slot); err != nil && err != nbt.ErrEND {
return err
}
// switch int8(windowID) {
// case 0:
// if slot < 32 || slot > 44 {
// // return fmt.Errorf("slot out of range")
// break
// }
// fallthrough
// case -2:
// g.player.Inventory[slot] = slotData
// g.events <- InventoryChangeEvent(slot)
// }
// return nil
// }
switch int8(windowID) {
case 0: //if window ID is 0, it will only change the hotbar
if slotI < 32 || slotI > 44 {
return errors.New("server set slot error")
}
fallthrough
case -2: //or if it's -2, server can change any slot without animation
if slotI < 0 || slotI > 45 {
return errors.New("server set slot out of range")
}
c.Inventory[slotI] = slot
}
return nil
}
// func handleMultiBlockChangePacket(c *Client, p pk.Packet) error {
// if !c.settings.ReciveMap {
@ -621,20 +628,36 @@ func handleKeepAlivePacket(c *Client, p pk.Packet) error {
// return nil
// }
func handleWindowItemsPacket(g *Client, p pk.Packet) (err error) {
// var (
// WindowID pk.Byte
// solts entity.Solt
// )
// err = p.Scan(&WindowID, &solts)
// if err != nil {
// return
// }
func handleWindowItemsPacket(c *Client, p pk.Packet) (err error) {
r := bytes.NewReader(p.Data)
var (
windowID pk.Byte
count pk.Short
slots []entity.Slot
)
if err := windowID.Decode(r); err != nil {
return err
}
if err := count.Decode(r); err != nil {
return err
}
for i := 0; i < int(count); i++ {
var slot entity.Slot
if err := slot.Decode(r); err != nil && err != nbt.ErrEND {
return err
}
slots = append(slots, slot)
}
// switch WindowID {
// case 0: //is player inventory
// g.Inventory = solts
// }
switch windowID {
case 0: //is player's inventory
if len(slots) != len(c.Inventory) {
return errors.New("inventory len not match")
}
for i, v := range slots { //copy this Inventory to player's Inventory
c.Inventory[i] = v
}
}
return nil
}

View File

@ -1,6 +1,7 @@
package entity
import (
"github.com/Tnze/go-mc/data"
"github.com/Tnze/go-mc/nbt"
pk "github.com/Tnze/go-mc/net/packet"
)
@ -37,3 +38,7 @@ func (s *Slot) Decode(r pk.DecodeReader) error {
}
return nil
}
func (s Slot) String() string {
return data.ItemNameByID[s.ItemID]
}

View File

@ -12,7 +12,6 @@ type Player struct {
OnGround bool
HeldItem int //拿着的物品栏位
Inventory []entity.Slot
Health float32 //血量
Food int32 //饱食度

File diff suppressed because it is too large Load Diff