add support for EnableFeature and CustomReportDetails
This commit is contained in:
@ -26,12 +26,17 @@ type Client struct {
|
|||||||
Events Events
|
Events Events
|
||||||
|
|
||||||
// Login plugins
|
// Login plugins
|
||||||
LoginPlugin map[string]func(data []byte) ([]byte, error)
|
LoginPlugin map[string]CustomPayloadHandler
|
||||||
|
|
||||||
// Configuration handler
|
// Configuration handler
|
||||||
ConfigHandler
|
ConfigHandler
|
||||||
|
|
||||||
|
CustomReportDetails map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CustomPayloadHandler is a function handling custom payload
|
||||||
|
type CustomPayloadHandler func(data []byte) ([]byte, error)
|
||||||
|
|
||||||
func (c *Client) Close() error {
|
func (c *Client) Close() error {
|
||||||
return c.Conn.Close()
|
return c.Conn.Close()
|
||||||
}
|
}
|
||||||
@ -47,7 +52,9 @@ func NewClient() *Client {
|
|||||||
return &Client{
|
return &Client{
|
||||||
Auth: Auth{Name: "Steve"},
|
Auth: Auth{Name: "Steve"},
|
||||||
Events: Events{handlers: make([][]PacketHandler, packetid.ClientboundPacketIDGuard)},
|
Events: Events{handlers: make([][]PacketHandler, packetid.ClientboundPacketIDGuard)},
|
||||||
|
LoginPlugin: make(map[string]CustomPayloadHandler),
|
||||||
ConfigHandler: NewDefaultConfigHandler(),
|
ConfigHandler: NewDefaultConfigHandler(),
|
||||||
|
CustomReportDetails: make(map[string]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package bot
|
package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/Tnze/go-mc/chat"
|
"github.com/Tnze/go-mc/chat"
|
||||||
"github.com/Tnze/go-mc/data/packetid"
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
@ -16,6 +15,8 @@ type ConfigHandler interface {
|
|||||||
GetCookie(key pk.Identifier) []byte
|
GetCookie(key pk.Identifier) []byte
|
||||||
SetCookie(key pk.Identifier, payload []byte)
|
SetCookie(key pk.Identifier, payload []byte)
|
||||||
|
|
||||||
|
EnableFeature(features []pk.Identifier)
|
||||||
|
|
||||||
PushResourcePack(res ResourcePack)
|
PushResourcePack(res ResourcePack)
|
||||||
PopResourcePack(id pk.UUID)
|
PopResourcePack(id pk.UUID)
|
||||||
PopAllResourcePack()
|
PopAllResourcePack()
|
||||||
@ -33,7 +34,6 @@ type ResourcePack struct {
|
|||||||
|
|
||||||
type ConfigData struct {
|
type ConfigData struct {
|
||||||
Registries registry.NetworkCodec
|
Registries registry.NetworkCodec
|
||||||
FeatureFlags []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigErr struct {
|
type ConfigErr struct {
|
||||||
@ -50,11 +50,10 @@ func (l ConfigErr) Unwrap() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) joinConfiguration(conn *net.Conn) error {
|
func (c *Client) joinConfiguration(conn *net.Conn) error {
|
||||||
receiving := "config custom payload"
|
|
||||||
for {
|
for {
|
||||||
var p pk.Packet
|
var p pk.Packet
|
||||||
if err := conn.ReadPacket(&p); err != nil {
|
if err := conn.ReadPacket(&p); err != nil {
|
||||||
return ConfigErr{receiving, err}
|
return ConfigErr{"config custom payload", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch packetid.ClientboundPacketID(p.ID) {
|
switch packetid.ClientboundPacketID(p.ID) {
|
||||||
@ -81,14 +80,24 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
return ConfigErr{"custom payload", err}
|
return ConfigErr{"custom payload", err}
|
||||||
}
|
}
|
||||||
// TODO: Provide configuration custom data handling interface
|
// TODO: Provide configuration custom data handling interface
|
||||||
|
//
|
||||||
|
// There are two types of Custom packet.
|
||||||
|
// One for Login stage, the other for config and play stage.
|
||||||
|
// The first one called "Custom Query", and the second one called "Custom Payload".
|
||||||
|
// We can know the different by their name, the "query" is one request to one response, paired.
|
||||||
|
// But the second one can be sent in any order.
|
||||||
|
//
|
||||||
|
// And the custome payload packet seems to be same in config stage and play stage.
|
||||||
|
// How do we provide API for that?
|
||||||
|
|
||||||
case packetid.ClientboundConfigDisconnect:
|
case packetid.ClientboundConfigDisconnect:
|
||||||
|
const ErrStage = "disconnect"
|
||||||
var reason chat.Message
|
var reason chat.Message
|
||||||
err := p.Scan(&reason)
|
err := p.Scan(&reason)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"disconnect", err}
|
return ConfigErr{ErrStage, err}
|
||||||
}
|
}
|
||||||
return ConfigErr{"disconnect", DisconnectErr(reason)}
|
return ConfigErr{ErrStage, DisconnectErr(reason)}
|
||||||
|
|
||||||
case packetid.ClientboundConfigFinishConfiguration:
|
case packetid.ClientboundConfigFinishConfiguration:
|
||||||
err := conn.WritePacket(pk.Marshal(
|
err := conn.WritePacket(pk.Marshal(
|
||||||
@ -100,10 +109,11 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
case packetid.ClientboundConfigKeepAlive:
|
case packetid.ClientboundConfigKeepAlive:
|
||||||
|
const ErrStage = "keep alive"
|
||||||
var keepAliveID pk.Long
|
var keepAliveID pk.Long
|
||||||
err := p.Scan(&keepAliveID)
|
err := p.Scan(&keepAliveID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"keep alive", err}
|
return ConfigErr{ErrStage, err}
|
||||||
}
|
}
|
||||||
// send it back
|
// send it back
|
||||||
err = conn.WritePacket(pk.Marshal(
|
err = conn.WritePacket(pk.Marshal(
|
||||||
@ -111,7 +121,7 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
keepAliveID,
|
keepAliveID,
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"keep alive", err}
|
return ConfigErr{ErrStage, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
case packetid.ClientboundConfigPing:
|
case packetid.ClientboundConfigPing:
|
||||||
@ -138,7 +148,7 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
// return ConfigErr{"registry data", err}
|
// return ConfigErr{"registry data", err}
|
||||||
// }
|
// }
|
||||||
|
|
||||||
case packetid.ClientboundConfigResourcePackPop: // TODO
|
case packetid.ClientboundConfigResourcePackPop:
|
||||||
var id pk.Option[pk.UUID, *pk.UUID]
|
var id pk.Option[pk.UUID, *pk.UUID]
|
||||||
err := p.Scan(&id)
|
err := p.Scan(&id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -187,21 +197,25 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"store cookie", err}
|
return ConfigErr{"store cookie", err}
|
||||||
}
|
}
|
||||||
// TODO: trnasfer to the server
|
// TODO: trnasfer to the specific server
|
||||||
|
// How does it work? Just connect the new server, and re-start at handshake?
|
||||||
|
|
||||||
case packetid.ClientboundConfigUpdateEnabledFeatures:
|
case packetid.ClientboundConfigUpdateEnabledFeatures:
|
||||||
err := p.Scan(pk.Array((*[]pk.Identifier)(unsafe.Pointer(&c.ConfigData.FeatureFlags))))
|
features := []pk.Identifier{}
|
||||||
|
err := p.Scan(pk.Array(&features))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"update enabled features", err}
|
return ConfigErr{"update enabled features", err}
|
||||||
}
|
}
|
||||||
|
c.ConfigHandler.EnableFeature(features)
|
||||||
|
|
||||||
case packetid.ClientboundConfigUpdateTags:
|
case packetid.ClientboundConfigUpdateTags:
|
||||||
// TODO: Handle Tags
|
// TODO: Handle Tags
|
||||||
case packetid.ClientboundConfigSelectKnownPacks:
|
case packetid.ClientboundConfigSelectKnownPacks:
|
||||||
|
const ErrStage = "select known packs"
|
||||||
packs := []DataPack{}
|
packs := []DataPack{}
|
||||||
err := p.Scan(pk.Array(&packs))
|
err := p.Scan(pk.Array(&packs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"select known packs", err}
|
return ConfigErr{ErrStage, err}
|
||||||
}
|
}
|
||||||
knwonPacks := c.ConfigHandler.SelectDataPacks(packs)
|
knwonPacks := c.ConfigHandler.SelectDataPacks(packs)
|
||||||
err = conn.WritePacket(pk.Marshal(
|
err = conn.WritePacket(pk.Marshal(
|
||||||
@ -209,11 +223,32 @@ func (c *Client) joinConfiguration(conn *net.Conn) error {
|
|||||||
pk.Array(knwonPacks),
|
pk.Array(knwonPacks),
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ConfigErr{"select known packs", err}
|
return ConfigErr{ErrStage, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
case packetid.ClientboundConfigCustomReportDetails:
|
case packetid.ClientboundConfigCustomReportDetails:
|
||||||
|
const ErrStage = "custom report details"
|
||||||
|
var length pk.VarInt
|
||||||
|
var title, description pk.String
|
||||||
|
r := bytes.NewReader(p.Data)
|
||||||
|
_, err := length.ReadFrom(r)
|
||||||
|
if err != nil {
|
||||||
|
return ConfigErr{ErrStage, err}
|
||||||
|
}
|
||||||
|
for i := 0; i < int(length); i++ {
|
||||||
|
_, err = title.ReadFrom(r)
|
||||||
|
if err != nil {
|
||||||
|
return ConfigErr{ErrStage, err}
|
||||||
|
}
|
||||||
|
_, err = description.ReadFrom(r)
|
||||||
|
if err != nil {
|
||||||
|
return ConfigErr{ErrStage, err}
|
||||||
|
}
|
||||||
|
c.CustomReportDetails[string(title)] = string(description)
|
||||||
|
}
|
||||||
|
|
||||||
case packetid.ClientboundConfigServerLinks:
|
case packetid.ClientboundConfigServerLinks:
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,6 +305,8 @@ func (d *DefaultConfigHandler) SetCookie(key pk.Identifier, payload []byte) {
|
|||||||
d.cookies[key] = payload
|
d.cookies[key] = payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DefaultConfigHandler) EnableFeature(features []pk.Identifier) {}
|
||||||
|
|
||||||
func (d *DefaultConfigHandler) PushResourcePack(res ResourcePack) {
|
func (d *DefaultConfigHandler) PushResourcePack(res ResourcePack) {
|
||||||
d.resourcesPack = append(d.resourcesPack, res)
|
d.resourcesPack = append(d.resourcesPack, res)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,9 @@ func (a Ary[LEN]) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
} else {
|
} else {
|
||||||
n += nn
|
n += nn
|
||||||
}
|
}
|
||||||
|
if Len < 0 {
|
||||||
|
return n, errors.New("array length less than zero")
|
||||||
|
}
|
||||||
|
|
||||||
array := reflect.ValueOf(a.Ary)
|
array := reflect.ValueOf(a.Ary)
|
||||||
for array.Kind() == reflect.Ptr {
|
for array.Kind() == reflect.Ptr {
|
||||||
|
Reference in New Issue
Block a user