Enhance support of screens

This commit is contained in:
Tnze
2021-07-04 12:38:24 +08:00
parent ebc44e7c8b
commit 7cfe5145d2
6 changed files with 148 additions and 63 deletions

7
bot/screen/events.go Normal file
View File

@ -0,0 +1,7 @@
package screen
type EventsListener struct {
Open func(id int) error
SetSlot func(id, index int) error
Close func(id int) error
}

View File

@ -1,16 +1,29 @@
package screen
import (
"fmt"
"github.com/Tnze/go-mc/data/item"
"github.com/Tnze/go-mc/nbt"
)
import "errors"
type Inventory struct {
Slots [46]Slot
}
func (inv Inventory) SetSlot(i int, id int32, count byte, NBT nbt.RawMessage) {
// TODO: accept inv data
fmt.Printf("Inventory[%d] = minecraft:%v * %d\n", i, item.ByID[item.ID(id)].Name, count)
func (inv *Inventory) onClose() error {
return nil
}
func (inv *Inventory) onSetSlot(i int, s Slot) error {
if i < 0 || i >= len(inv.Slots) {
return errors.New("slot index out of bounds")
}
inv.Slots[i] = s
return nil
}
func (inv *Inventory) CraftingOutput() *Slot { return &inv.Slots[0] }
func (inv *Inventory) CraftingInput() []Slot { return inv.Slots[1 : 1+4] }
// Armor returns to the armor section of the Inventory.
// The length is 4, which are head, chest, legs and feet.
func (inv *Inventory) Armor() []Slot { return inv.Slots[5 : 5+4] }
func (inv *Inventory) Main() []Slot { return inv.Slots[9 : 9+3*9] }
func (inv *Inventory) Hotbar() []Slot { return inv.Slots[36 : 36+9] }
func (inv *Inventory) Offhand() *Slot { return &inv.Slots[45] }

View File

@ -1,6 +1,7 @@
package screen
import (
"errors"
"io"
"github.com/Tnze/go-mc/bot"
@ -11,15 +12,23 @@ import (
)
type Manager struct {
Screens map[byte]Container
Screens map[int]Container
Inventory Inventory
Cursor Slot
events EventsListener
}
func NewManager(c *bot.Client) *Manager {
m := &Manager{Screens: make(map[byte]Container)}
m.Screens[0] = &Inventory{}
func NewManager(c *bot.Client, e EventsListener) *Manager {
m := &Manager{
Screens: make(map[int]Container),
events: e,
}
m.Screens[0] = &m.Inventory
c.Events.AddListener(
bot.PacketHandler{Priority: 64, ID: packetid.OpenWindow, F: m.onOpenScreen},
bot.PacketHandler{Priority: 64, ID: packetid.WindowItems, F: m.onSetContentPacket},
bot.PacketHandler{Priority: 0, ID: packetid.OpenWindow, F: m.onOpenScreen},
bot.PacketHandler{Priority: 0, ID: packetid.WindowItems, F: m.onSetContentPacket},
bot.PacketHandler{Priority: 0, ID: packetid.CloseWindowClientbound, F: m.onCloseScreen},
bot.PacketHandler{Priority: 0, ID: packetid.SetSlot, F: m.onSetSlot},
)
return m
}
@ -33,7 +42,14 @@ func (m *Manager) onOpenScreen(p pk.Packet) error {
if err := p.Scan(&ContainerID, &Type, &Title); err != nil {
return Error{err}
}
//if c, ok := m.Screens[byte(ContainerID)]; ok {
// TODO: Create the specified container
//}
if m.events.Open != nil {
if err := m.events.Open(int(ContainerID)); err != nil {
return Error{err}
}
}
return nil
}
@ -41,7 +57,7 @@ func (m *Manager) onSetContentPacket(p pk.Packet) error {
var (
ContainerID pk.UnsignedByte
Count pk.Short
SlotData []slot
SlotData []Slot
)
if err := p.Scan(
&ContainerID,
@ -51,32 +67,93 @@ func (m *Manager) onSetContentPacket(p pk.Packet) error {
}); err != nil {
return Error{err}
}
container := m.Screens[byte(ContainerID)]
// copy the slot data to container
container, ok := m.Screens[int(ContainerID)]
if !ok {
return Error{errors.New("setting content of non-exist container")}
}
for i, v := range SlotData {
container.SetSlot(i, int32(v.id), byte(v.count), v.nbt)
err := container.onSetSlot(i, v)
if err != nil {
return Error{err}
}
if m.events.SetSlot != nil {
if err := m.events.SetSlot(int(ContainerID), i); err != nil {
return Error{err}
}
}
}
return nil
}
type slot struct {
present pk.Boolean
id pk.VarInt
count pk.Byte
nbt nbt.RawMessage
func (m *Manager) onCloseScreen(p pk.Packet) error {
var ContainerID pk.UnsignedByte
if err := p.Scan(&ContainerID); err != nil {
return Error{err}
}
if c, ok := m.Screens[int(ContainerID)]; ok {
delete(m.Screens, int(ContainerID))
if err := c.onClose(); err != nil {
return Error{err}
}
if m.events.Close != nil {
if err := m.events.Close(int(ContainerID)); err != nil {
return Error{err}
}
}
}
return nil
}
func (s *slot) ReadFrom(r io.Reader) (n int64, err error) {
func (m *Manager) onSetSlot(p pk.Packet) (err error) {
var (
ContainerID pk.Byte
SlotID pk.Short
ItemStack Slot
)
if err := p.Scan(&ContainerID, &SlotID, &ItemStack); err != nil {
return Error{err}
}
if ContainerID == -1 && SlotID == -1 {
m.Cursor = ItemStack
} else if ContainerID == -2 {
err = m.Inventory.onSetSlot(int(SlotID), ItemStack)
} else if c, ok := m.Screens[int(ContainerID)]; ok {
err = c.onSetSlot(int(SlotID), ItemStack)
}
if m.events.Close != nil {
if err := m.events.Close(int(ContainerID)); err != nil {
return Error{err}
}
}
if err != nil {
return Error{err}
}
return nil
}
type Slot struct {
ID pk.VarInt
Count pk.Byte
NBT nbt.RawMessage
}
func (s *Slot) ReadFrom(r io.Reader) (n int64, err error) {
var present pk.Boolean
return pk.Tuple{
&s.present, pk.Opt{Has: &s.present,
&present, pk.Opt{Has: &present,
Field: pk.Tuple{
&s.id, &s.count, pk.NBT(&s.nbt),
&s.ID, &s.Count, pk.NBT(&s.NBT),
},
},
}.ReadFrom(r)
}
type Container interface {
SetSlot(i int, id int32, count byte, NBT nbt.RawMessage)
onSetSlot(i int, s Slot) error
onClose() error
}
type Error struct {

View File

@ -1,29 +0,0 @@
package screen
type Info struct {
Name string
Start, End int // Player inventory
Slots int
}
func (i Info) PlayerInvStart() int {
return i.Start
}
func (i Info) PlayerInvEnd() int {
return i.End
}
func (i Info) HotbarIdx(place int) int {
return i.End - (8 - place)
}
var ByType = map[int]Info{
-1: {Name: "inventory", Start: 9, End: 44, Slots: 46},
0: {Name: "generic_9x1", Start: 1 * 9, End: 1*9 + 35, Slots: 1*9 + 36},
1: {Name: "generic_9x2", Start: 2 * 9, End: 2*9 + 35, Slots: 2*9 + 36},
2: {Name: "generic_9x3", Start: 3 * 9, End: 3*9 + 35, Slots: 3*9 + 36},
3: {Name: "generic_9x4", Start: 4 * 9, End: 4*9 + 35, Slots: 4*9 + 36},
4: {Name: "generic_9x5", Start: 5 * 9, End: 5*9 + 35, Slots: 5*9 + 36},
5: {Name: "generic_9x6", Start: 6 * 9, End: 6*9 + 35, Slots: 6*9 + 36},
}

View File

@ -11,15 +11,15 @@ package chat
import (
"encoding/json"
"fmt"
en_us "github.com/Tnze/go-mc/data/lang/en-us"
"io"
"regexp"
"strings"
en_us "github.com/Tnze/go-mc/data/lang/en-us"
pk "github.com/Tnze/go-mc/net/packet"
)
//Message is a message sent by other
// Message is a message sent by other
type Message jsonChat
type jsonChat struct {
@ -50,7 +50,7 @@ func (m *Message) UnmarshalJSON(jsonMsg []byte) (err error) {
return
}
//Decode for a ChatMsg packet
// ReadFrom decode Message in a ChatMsg packet
func (m *Message) ReadFrom(r io.Reader) (int64, error) {
var Len pk.VarInt
if n, err := Len.ReadFrom(r); err != nil {
@ -61,7 +61,7 @@ func (m *Message) ReadFrom(r io.Reader) (int64, error) {
return int64(Len) - lr.N, err
}
//Encode for a ChatMsg packet
// WriteTo encode Message into a ChatMsg packet
func (m Message) WriteTo(w io.Writer) (int64, error) {
code, err := json.Marshal(m)
if err != nil {
@ -174,7 +174,7 @@ func (m Message) ClearString() string {
if m.Extra != nil {
for i := range m.Extra {
msg.WriteString(Message(m.Extra[i]).ClearString())
msg.WriteString(m.Extra[i].ClearString())
}
}
return msg.String()
@ -225,7 +225,7 @@ func (m Message) String() string {
if m.Extra != nil {
for i := range m.Extra {
msg.WriteString(Message(m.Extra[i]).String())
msg.WriteString(m.Extra[i].String())
}
}

View File

@ -20,6 +20,7 @@ import (
var address = flag.String("address", "127.0.0.1", "The server address")
var client *bot.Client
var player *basic.Player
var screenManager *screen.Manager
func main() {
flag.Parse()
@ -32,7 +33,11 @@ func main() {
Disconnect: onDisconnect,
Death: onDeath,
}.Attach(client)
_ = screen.NewManager(client)
screenManager = screen.NewManager(client, screen.EventsListener{
Open: nil,
SetSlot: onScreenSlotChange,
Close: nil,
})
//Login
err := client.JoinServer(*address)
@ -84,6 +89,18 @@ func onChatMsg(c chat.Message, _ byte, _ uuid.UUID) error {
return nil
}
func onScreenSlotChange(id, index int) error {
if id == -2 {
log.Printf("Slot change: inventory: %v", screenManager.Inventory.Slots[index])
} else if id == -1 && index == -1 {
log.Printf("Slot change: cursor: %v", screenManager.Cursor)
} else {
container := screenManager.Screens[id]
log.Printf("Slot change: Screen[%d].Slot[%d]: %T", id, index, container)
}
return nil
}
type DisconnectErr struct {
Reason chat.Message
}