update 1.19.2 bot, chat support

This commit is contained in:
Tnze
2022-11-26 15:58:31 +08:00
parent 6a3589ad61
commit 7814e7b1ab
20 changed files with 532 additions and 136 deletions

View File

@ -20,7 +20,7 @@
// - HealthChange
// - Death
//
// You must manully attach the [EventsListener] to the [Client] as needed.
// You must manually attach the [EventsListener] to the [Client] as needed.
package basic
import (
@ -38,22 +38,23 @@ type Player struct {
isSpawn bool
}
func NewPlayer(c *bot.Client, settings Settings) *Player {
b := &Player{c: c, Settings: settings}
func NewPlayer(c *bot.Client, settings Settings, events EventsListener) *Player {
p := &Player{c: c, Settings: settings}
c.Events.AddListener(
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundLogin, F: b.handleLoginPacket},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundKeepAlive, F: b.handleKeepAlivePacket},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundPlayerPosition, F: b.handlePlayerPosition},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundRespawn, F: b.handleRespawnPacket},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundLogin, F: p.handleLoginPacket},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundKeepAlive, F: p.handleKeepAlivePacket},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundPlayerPosition, F: p.handlePlayerPosition},
bot.PacketHandler{Priority: 0, ID: packetid.ClientboundRespawn, F: p.handleRespawnPacket},
)
return b
events.attach(p)
return p
}
func (p *Player) Respawn() error {
const PerformRespawn = 0
err := p.c.Conn.WritePacket(pk.Marshal(
packetid.ServerboundClientCommand,
int32(packetid.ServerboundClientCommand),
pk.VarInt(PerformRespawn),
))
if err != nil {

View File

@ -5,35 +5,30 @@ import (
"github.com/Tnze/go-mc/chat"
"github.com/Tnze/go-mc/data/packetid"
pk "github.com/Tnze/go-mc/net/packet"
"io"
)
type EventsListener struct {
GameStart func() error
ChatMsg func(c *PlayerMessage) error
SystemMsg func(c chat.Message, overlay bool) error
Disconnect func(reason chat.Message) error
HealthChange func(health float32) error
Death func() error
}
// Attach your event listener to the client.
// attach your event listener to the client.
// The functions are copied when attaching, and modify on [EventListener] doesn't affect after that.
func (e EventsListener) Attach(c *bot.Client) {
func (e EventsListener) attach(p *Player) {
if e.GameStart != nil {
attachJoinGameHandler(c, e.GameStart)
}
if e.ChatMsg != nil {
attachPlayerMsg(c, e.ChatMsg)
attachJoinGameHandler(p.c, e.GameStart)
}
if e.SystemMsg != nil {
attachSystemMsg(c, e.SystemMsg)
attachSystemMsg(p.c, e.SystemMsg)
}
if e.Disconnect != nil {
attachDisconnect(c, e.Disconnect)
attachDisconnect(p.c, e.Disconnect)
}
if e.HealthChange != nil || e.Death != nil {
attachUpdateHealth(c, e.HealthChange, e.Death)
attachUpdateHealth(p.c, e.HealthChange, e.Death)
}
}
@ -46,60 +41,6 @@ func attachJoinGameHandler(c *bot.Client, handler func() error) {
})
}
type PlayerMessage struct {
}
func (p *PlayerMessage) ReadFrom(r io.Reader) (n int64, err error) {
// SignedMessageHeader
// MessageSignature
// SignedMessageBody
// Optional<Component>
// FilterMask
panic("implement me")
}
type ChatType struct {
ID int32
Name chat.Message
TargetName *chat.Message
}
func (c *ChatType) ReadFrom(r io.Reader) (n int64, err error) {
var hasTargetName pk.Boolean
n1, err := (*pk.VarInt)(&c.ID).ReadFrom(r)
if err != nil {
return n1, err
}
n2, err := c.Name.ReadFrom(r)
if err != nil {
return n1 + n2, err
}
n3, err := hasTargetName.ReadFrom(r)
if err != nil {
return n1 + n2 + n3, err
}
if hasTargetName {
c.TargetName = new(chat.Message)
n4, err := c.TargetName.ReadFrom(r)
return n1 + n2 + n3 + n4, err
}
return n1 + n2 + n3, nil
}
func attachPlayerMsg(c *bot.Client, handler func(c *PlayerMessage) error) {
c.Events.AddListener(bot.PacketHandler{
Priority: 64, ID: packetid.ClientboundPlayerChat,
F: func(p pk.Packet) error {
var message PlayerMessage
var chatType ChatType
if err := p.Scan(&message, &chatType); err != nil {
return Error{err}
}
return handler(&message)
},
})
}
func attachSystemMsg(c *bot.Client, handler func(c chat.Message, overlay bool) error) {
c.Events.AddListener(bot.PacketHandler{
Priority: 64, ID: packetid.ClientboundSystemChat,

View File

@ -1,6 +1,7 @@
package basic
import (
"github.com/Tnze/go-mc/chat"
"unsafe"
"github.com/Tnze/go-mc/data/packetid"
@ -46,9 +47,14 @@ type Dimension struct {
MonsterSpawnBlockLightLimit int32 `nbt:"monster_spawn_block_light_limit"`
}
type ChatType struct {
Chat chat.Decoration `nbt:"chat"`
Narration chat.Decoration `nbt:"narration"`
}
type RegistryCodec struct {
// What is Below? (wiki.vg)
ChatType Registry[nbt.RawMessage] `nbt:"minecraft:chat_type"`
ChatType Registry[ChatType] `nbt:"minecraft:chat_type"`
DimensionType Registry[Dimension] `nbt:"minecraft:dimension_type"`
WorldGenBiome Registry[nbt.RawMessage] `nbt:"minecraft:worldgen/biome"`
}
@ -71,6 +77,18 @@ func (r *Registry[E]) Find(name string) *E {
return nil
}
func (r *Registry[E]) FindByID(id int32) *E {
if id >= 0 && id < int32(len(r.Value)) && r.Value[id].ID == id {
return &r.Value[id].Element
}
for i := range r.Value {
if r.Value[i].ID == id {
return &r.Value[i].Element
}
}
return nil
}
type PlayerInfo struct {
EID int32 // The player's Entity ID (EID).
Hardcore bool // Is hardcore
@ -106,7 +124,7 @@ func (p *Player) handleLoginPacket(packet pk.Packet) error {
return Error{err}
}
err = p.c.Conn.WritePacket(pk.Marshal( //PluginMessage packet
packetid.ServerboundCustomPayload,
int32(packetid.ServerboundCustomPayload),
pk.Identifier("minecraft:brand"),
pk.String(p.Settings.Brand),
))
@ -115,7 +133,7 @@ func (p *Player) handleLoginPacket(packet pk.Packet) error {
}
err = p.c.Conn.WritePacket(pk.Marshal(
packetid.ServerboundClientInformation, // Client settings
int32(packetid.ServerboundClientInformation), // Client settings
pk.String(p.Settings.Locale),
pk.Byte(p.Settings.ViewDistance),
pk.VarInt(p.Settings.ChatMode),

View File

@ -12,7 +12,7 @@ func (p Player) handleKeepAlivePacket(packet pk.Packet) error {
}
// Response
err := p.c.Conn.WritePacket(pk.Packet{
ID: packetid.ServerboundKeepAlive,
ID: int32(packetid.ServerboundKeepAlive),
Data: packet.Data,
})
if err != nil {

168
bot/chat/chat.go Normal file
View File

@ -0,0 +1,168 @@
package chat
import (
"fmt"
"io"
"time"
"github.com/Tnze/go-mc/bot"
"github.com/Tnze/go-mc/bot/basic"
"github.com/Tnze/go-mc/chat"
"github.com/Tnze/go-mc/data/packetid"
pk "github.com/Tnze/go-mc/net/packet"
"github.com/google/uuid"
)
type Chat struct {
c *bot.Client
p *basic.Player
}
func NewChat(c *bot.Client, p *basic.Player, events EventsHandler) *Chat {
attachPlayerMsg(c, p, events.PlayerChatMessage)
return &Chat{c, p}
}
func attachPlayerMsg(c *bot.Client, p *basic.Player, handler func(msg chat.Message) error) {
c.Events.AddListener(bot.PacketHandler{
Priority: 64, ID: packetid.ClientboundPlayerChat,
F: func(packet pk.Packet) error {
var message PlayerMessage
if err := packet.Scan(&message); err != nil {
return err
}
var content chat.Message
if message.content.formatted != nil {
content = *message.content.formatted
} else {
content = chat.Text(message.content.plainMsg)
}
ct := p.WorldInfo.RegistryCodec.ChatType.FindByID(message.chatType.ID)
if ct == nil {
return fmt.Errorf("chat type %d not found", message.chatType.ID)
}
msg := (*chat.Type)(&message.chatType).Decorate(content, &ct.Chat)
return handler(msg)
},
})
}
type PlayerMessage struct {
// SignedMessageHeader
signature []byte
sender uuid.UUID
// MessageSignature
msgSignature []byte
// SignedMessageBody
content msgContent
timestamp time.Time
salt int64
prevMessages []prevMsg
// Optional<Component>
unsignedContent *chat.Message
// FilterMask
filterType int32
filterSet pk.BitSet
// ChatType
chatType chatType
}
func (p *PlayerMessage) String() string {
return p.content.plainMsg
}
func (p *PlayerMessage) ReadFrom(r io.Reader) (n int64, err error) {
var hasMsgSign, hasUnsignedContent pk.Boolean
var timestamp pk.Long
var unsignedContent chat.Message
n, err = pk.Tuple{
&hasMsgSign, pk.Opt{Has: &hasMsgSign,
Field: (*pk.ByteArray)(&p.signature),
},
(*pk.UUID)(&p.sender),
(*pk.ByteArray)(&p.msgSignature),
&p.content,
&timestamp,
(*pk.Long)(&p.salt),
pk.Array(&p.prevMessages),
&hasUnsignedContent, pk.Opt{Has: &hasUnsignedContent,
Field: &unsignedContent,
},
(*pk.VarInt)(&p.filterType),
pk.Opt{
Has: func() bool { return p.filterType == 2 },
Field: &p.filterSet,
},
&p.chatType,
}.ReadFrom(r)
if err != nil {
return
}
p.timestamp = time.UnixMilli(int64(timestamp))
if hasUnsignedContent {
p.unsignedContent = &unsignedContent
}
return n, err
}
type msgContent struct {
plainMsg string
formatted *chat.Message
}
func (m *msgContent) ReadFrom(r io.Reader) (n int64, err error) {
var hasFormatted pk.Boolean
n1, err := (*pk.String)(&m.plainMsg).ReadFrom(r)
if err != nil {
return n1, err
}
n2, err := hasFormatted.ReadFrom(r)
if err != nil {
return n1 + n2, err
}
if hasFormatted {
m.formatted = new(chat.Message)
n3, err := m.formatted.ReadFrom(r)
return n1 + n2 + n3, err
}
return n1 + n2, err
}
type prevMsg struct {
sender uuid.UUID
signature []byte
}
func (p *prevMsg) ReadFrom(r io.Reader) (n int64, err error) {
return pk.Tuple{
(*pk.UUID)(&p.sender),
(*pk.ByteArray)(&p.signature),
}.ReadFrom(r)
}
type chatType chat.Type
func (c *chatType) ReadFrom(r io.Reader) (n int64, err error) {
var hasTargetName pk.Boolean
n1, err := (*pk.VarInt)(&c.ID).ReadFrom(r)
if err != nil {
return n1, err
}
n2, err := c.SenderName.ReadFrom(r)
if err != nil {
return n1 + n2, err
}
n3, err := hasTargetName.ReadFrom(r)
if err != nil {
return n1 + n2 + n3, err
}
if hasTargetName {
c.TargetName = new(chat.Message)
n4, err := c.TargetName.ReadFrom(r)
return n1 + n2 + n3 + n4, err
}
return n1 + n2 + n3, nil
}

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

@ -0,0 +1,7 @@
package chat
import "github.com/Tnze/go-mc/chat"
type EventsHandler struct {
PlayerChatMessage func(msg chat.Message) error
}

View File

@ -1,6 +1,7 @@
package bot
import (
"github.com/Tnze/go-mc/data/packetid"
"github.com/Tnze/go-mc/net"
"github.com/Tnze/go-mc/yggdrasil/user"
"github.com/google/uuid"
@ -33,7 +34,7 @@ func (c *Client) Close() error {
func NewClient() *Client {
return &Client{
Auth: Auth{Name: "Steve"},
Events: Events{handlers: make(map[int32]*handlerHeap)},
Events: Events{handlers: make(map[packetid.ClientboundPacketID]*handlerHeap)},
}
}

View File

@ -1,12 +1,13 @@
package bot
import (
"github.com/Tnze/go-mc/data/packetid"
pk "github.com/Tnze/go-mc/net/packet"
)
type Events struct {
generic *handlerHeap // for every packet
handlers map[int32]*handlerHeap // for specific packet id only
handlers map[packetid.ClientboundPacketID]*handlerHeap // for specific packet id only
}
func (e *Events) AddListener(listeners ...PacketHandler) {
@ -36,7 +37,7 @@ func (e *Events) AddGeneric(listeners ...PacketHandler) {
type PacketHandlerFunc func(p pk.Packet) error
type PacketHandler struct {
ID int32
ID packetid.ClientboundPacketID
Priority int
F func(p pk.Packet) error
}

View File

@ -2,6 +2,8 @@ package bot
import (
"fmt"
"github.com/Tnze/go-mc/data/packetid"
pk "github.com/Tnze/go-mc/net/packet"
)
@ -24,12 +26,12 @@ func (c *Client) HandleGame() error {
}
type PacketHandlerError struct {
ID int32
ID packetid.ClientboundPacketID
Err error
}
func (d PacketHandlerError) Error() string {
return fmt.Sprintf("handle packet 0x%X error: %v", d.ID, d.Err)
return fmt.Sprintf("handle packet %v error: %v", d.ID, d.Err)
}
func (d PacketHandlerError) Unwrap() error {
@ -37,18 +39,19 @@ func (d PacketHandlerError) Unwrap() error {
}
func (c *Client) handlePacket(p pk.Packet) (err error) {
packetID := packetid.ClientboundPacketID(p.ID)
if c.Events.generic != nil {
for _, handler := range *c.Events.generic {
if err = handler.F(p); err != nil {
return PacketHandlerError{ID: p.ID, Err: err}
return PacketHandlerError{ID: packetID, Err: err}
}
}
}
if listeners := c.Events.handlers[p.ID]; listeners != nil {
if listeners := c.Events.handlers[packetID]; listeners != nil {
for _, handler := range *listeners {
err = handler.F(p)
if err != nil {
return PacketHandlerError{ID: p.ID, Err: err}
return PacketHandlerError{ID: packetID, Err: err}
}
}
}

51
chat/decoration.go Normal file
View File

@ -0,0 +1,51 @@
package chat
type Decoration struct {
TranslationKey string `nbt:"translation_key"`
Parameters []string `nbt:"parameters"`
Style struct {
Bold bool `nbt:"bold"`
Italic bool `nbt:"italic"`
UnderLined bool `nbt:"underlined"`
StrikeThrough bool `nbt:"strikethrough"`
Obfuscated bool `nbt:"obfuscated"`
Color string `nbt:"color"`
Insertion string `nbt:"insertion"`
Font string `nbt:"font"`
} `nbt:"style"`
}
type Type struct {
ID int32
SenderName Message
TargetName *Message
}
func (t *Type) Decorate(content Message, d *Decoration) (msg Message) {
with := make([]Message, len(d.Parameters))
for i, para := range d.Parameters {
switch para {
case "sender":
with[i] = t.SenderName
case "target":
with[i] = *t.TargetName
case "content":
with[i] = content
default:
with[i] = Text("<nil>")
}
}
return Message{
Translate: d.TranslationKey,
With: with,
Bold: d.Style.Bold,
Italic: d.Style.Italic,
UnderLined: d.Style.UnderLined,
StrikeThrough: d.Style.StrikeThrough,
Obfuscated: d.Style.Obfuscated,
Font: d.Style.Font,
Color: d.Style.Color,
Insertion: d.Style.Insertion,
}
}

View File

@ -22,10 +22,8 @@ import (
pk "github.com/Tnze/go-mc/net/packet"
)
type Type int32
const (
Chat Type = iota
Chat = iota
System
GameInfo
SayCommand
@ -77,7 +75,7 @@ type Message struct {
HoverEvent *HoverEvent `json:"hoverEvent,omitempty"`
Translate string `json:"translate,omitempty"`
With []json.RawMessage `json:"with,omitempty"`
With []Message `json:"with,omitempty"`
Extra []Message `json:"extra,omitempty"`
}
@ -99,7 +97,7 @@ type translateMsg struct {
HoverEvent *HoverEvent `json:"hoverEvent,omitempty"`
Translate string `json:"translate"`
With []json.RawMessage `json:"with,omitempty"`
With []Message `json:"with,omitempty"`
Extra []Message `json:"extra,omitempty"`
}
@ -180,10 +178,7 @@ func Text(str string) Message {
func TranslateMsg(key string, with ...Message) (m Message) {
m.Translate = key
m.With = make([]json.RawMessage, len(with))
for i, v := range with {
m.With[i], _ = json.Marshal(v)
}
m.With = with
return
}
@ -250,9 +245,7 @@ func (m Message) ClearString() string {
if m.Translate != "" {
args := make([]interface{}, len(m.With))
for i, v := range m.With {
var arg Message
_ = arg.UnmarshalJSON(v) //ignore error
args[i] = arg.ClearString()
args[i] = v.ClearString()
}
_, _ = fmt.Fprintf(&msg, translateMap[m.Translate], args...)
@ -297,9 +290,7 @@ func (m Message) String() string {
if m.Translate != "" {
args := make([]interface{}, len(m.With))
for i, v := range m.With {
var arg Message
_ = arg.UnmarshalJSON(v) //ignore error
args[i] = arg
args[i] = v
}
_, _ = fmt.Fprintf(&msg, translateMap[m.Translate], args...)

View File

@ -0,0 +1,130 @@
// Code generated by "stringer -type ClientboundPacketID"; DO NOT EDIT.
package packetid
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ClientboundAddEntity-0]
_ = x[ClientboundAddExperienceOrb-1]
_ = x[ClientboundAddPlayer-2]
_ = x[ClientboundAnimate-3]
_ = x[ClientboundAwardStats-4]
_ = x[ClientboundBlockChangedAck-5]
_ = x[ClientboundBlockDestruction-6]
_ = x[ClientboundBlockEntityData-7]
_ = x[ClientboundBlockEvent-8]
_ = x[ClientboundBlockUpdate-9]
_ = x[ClientboundBossEvent-10]
_ = x[ClientboundChangeDifficulty-11]
_ = x[ClientboundChatPreview-12]
_ = x[ClientboundClearTitles-13]
_ = x[ClientboundCommandSuggestions-14]
_ = x[ClientboundCommands-15]
_ = x[ClientboundContainerClose-16]
_ = x[ClientboundContainerSetContent-17]
_ = x[ClientboundContainerSetData-18]
_ = x[ClientboundContainerSetSlot-19]
_ = x[ClientboundCooldown-20]
_ = x[ClientboundCustomChatCompletions-21]
_ = x[ClientboundCustomPayload-22]
_ = x[ClientboundCustomSound-23]
_ = x[ClientboundDeleteChat-24]
_ = x[ClientboundDisconnect-25]
_ = x[ClientboundEntityEvent-26]
_ = x[ClientboundExplode-27]
_ = x[ClientboundForgetLevelChunk-28]
_ = x[ClientboundGameEvent-29]
_ = x[ClientboundHorseScreenOpen-30]
_ = x[ClientboundInitializeBorder-31]
_ = x[ClientboundKeepAlive-32]
_ = x[ClientboundLevelChunkWithLight-33]
_ = x[ClientboundLevelEvent-34]
_ = x[ClientboundLevelParticles-35]
_ = x[ClientboundLightUpdate-36]
_ = x[ClientboundLogin-37]
_ = x[ClientboundMapItemData-38]
_ = x[ClientboundMerchantOffers-39]
_ = x[ClientboundMoveEntityPos-40]
_ = x[ClientboundMoveEntityPosRot-41]
_ = x[ClientboundMoveEntityRot-42]
_ = x[ClientboundMoveVehicle-43]
_ = x[ClientboundOpenBook-44]
_ = x[ClientboundOpenScreen-45]
_ = x[ClientboundOpenSignEditor-46]
_ = x[ClientboundPing-47]
_ = x[ClientboundPlaceGhostRecipe-48]
_ = x[ClientboundPlayerAbilities-49]
_ = x[ClientboundPlayerChatHeader-50]
_ = x[ClientboundPlayerChat-51]
_ = x[ClientboundPlayerCombatEnd-52]
_ = x[ClientboundPlayerCombatEnter-53]
_ = x[ClientboundPlayerCombatKill-54]
_ = x[ClientboundPlayerInfo-55]
_ = x[ClientboundPlayerLookAt-56]
_ = x[ClientboundPlayerPosition-57]
_ = x[ClientboundRecipe-58]
_ = x[ClientboundRemoveEntities-59]
_ = x[ClientboundRemoveMobEffect-60]
_ = x[ClientboundResourcePack-61]
_ = x[ClientboundRespawn-62]
_ = x[ClientboundRotateHead-63]
_ = x[ClientboundSectionBlocksUpdate-64]
_ = x[ClientboundSelectAdvancementsTab-65]
_ = x[ClientboundServerData-66]
_ = x[ClientboundSetActionBarText-67]
_ = x[ClientboundSetBorderCenter-68]
_ = x[ClientboundSetBorderLerpSize-69]
_ = x[ClientboundSetBorderSize-70]
_ = x[ClientboundSetBorderWarningDelay-71]
_ = x[ClientboundSetBorderWarningDistance-72]
_ = x[ClientboundSetCamera-73]
_ = x[ClientboundSetCarriedItem-74]
_ = x[ClientboundSetChunkCacheCenter-75]
_ = x[ClientboundSetChunkCacheRadius-76]
_ = x[ClientboundSetDefaultSpawnPosition-77]
_ = x[ClientboundSetDisplayChatPreview-78]
_ = x[ClientboundSetDisplayObjective-79]
_ = x[ClientboundSetEntityData-80]
_ = x[ClientboundSetEntityLink-81]
_ = x[ClientboundSetEntityMotion-82]
_ = x[ClientboundSetEquipment-83]
_ = x[ClientboundSetExperience-84]
_ = x[ClientboundSetHealth-85]
_ = x[ClientboundSetObjective-86]
_ = x[ClientboundSetPassengers-87]
_ = x[ClientboundSetPlayerTeam-88]
_ = x[ClientboundSetScore-89]
_ = x[ClientboundSetSimulationDistance-90]
_ = x[ClientboundSetSubtitleText-91]
_ = x[ClientboundSetTime-92]
_ = x[ClientboundSetTitleText-93]
_ = x[ClientboundSetTitlesAnimation-94]
_ = x[ClientboundSoundEntity-95]
_ = x[ClientboundSound-96]
_ = x[ClientboundStopSound-97]
_ = x[ClientboundSystemChat-98]
_ = x[ClientboundTabList-99]
_ = x[ClientboundTagQuery-100]
_ = x[ClientboundTakeItemEntity-101]
_ = x[ClientboundTeleportEntity-102]
_ = x[ClientboundUpdateAdvancements-103]
_ = x[ClientboundUpdateAttributes-104]
_ = x[ClientboundUpdateMobEffect-105]
_ = x[ClientboundUpdateRecipes-106]
_ = x[ClientboundUpdateTags-107]
}
const _ClientboundPacketID_name = "ClientboundAddEntityClientboundAddExperienceOrbClientboundAddPlayerClientboundAnimateClientboundAwardStatsClientboundBlockChangedAckClientboundBlockDestructionClientboundBlockEntityDataClientboundBlockEventClientboundBlockUpdateClientboundBossEventClientboundChangeDifficultyClientboundChatPreviewClientboundClearTitlesClientboundCommandSuggestionsClientboundCommandsClientboundContainerCloseClientboundContainerSetContentClientboundContainerSetDataClientboundContainerSetSlotClientboundCooldownClientboundCustomChatCompletionsClientboundCustomPayloadClientboundCustomSoundClientboundDeleteChatClientboundDisconnectClientboundEntityEventClientboundExplodeClientboundForgetLevelChunkClientboundGameEventClientboundHorseScreenOpenClientboundInitializeBorderClientboundKeepAliveClientboundLevelChunkWithLightClientboundLevelEventClientboundLevelParticlesClientboundLightUpdateClientboundLoginClientboundMapItemDataClientboundMerchantOffersClientboundMoveEntityPosClientboundMoveEntityPosRotClientboundMoveEntityRotClientboundMoveVehicleClientboundOpenBookClientboundOpenScreenClientboundOpenSignEditorClientboundPingClientboundPlaceGhostRecipeClientboundPlayerAbilitiesClientboundPlayerChatHeaderClientboundPlayerChatClientboundPlayerCombatEndClientboundPlayerCombatEnterClientboundPlayerCombatKillClientboundPlayerInfoClientboundPlayerLookAtClientboundPlayerPositionClientboundRecipeClientboundRemoveEntitiesClientboundRemoveMobEffectClientboundResourcePackClientboundRespawnClientboundRotateHeadClientboundSectionBlocksUpdateClientboundSelectAdvancementsTabClientboundServerDataClientboundSetActionBarTextClientboundSetBorderCenterClientboundSetBorderLerpSizeClientboundSetBorderSizeClientboundSetBorderWarningDelayClientboundSetBorderWarningDistanceClientboundSetCameraClientboundSetCarriedItemClientboundSetChunkCacheCenterClientboundSetChunkCacheRadiusClientboundSetDefaultSpawnPositionClientboundSetDisplayChatPreviewClientboundSetDisplayObjectiveClientboundSetEntityDataClientboundSetEntityLinkClientboundSetEntityMotionClientboundSetEquipmentClientboundSetExperienceClientboundSetHealthClientboundSetObjectiveClientboundSetPassengersClientboundSetPlayerTeamClientboundSetScoreClientboundSetSimulationDistanceClientboundSetSubtitleTextClientboundSetTimeClientboundSetTitleTextClientboundSetTitlesAnimationClientboundSoundEntityClientboundSoundClientboundStopSoundClientboundSystemChatClientboundTabListClientboundTagQueryClientboundTakeItemEntityClientboundTeleportEntityClientboundUpdateAdvancementsClientboundUpdateAttributesClientboundUpdateMobEffectClientboundUpdateRecipesClientboundUpdateTags"
var _ClientboundPacketID_index = [...]uint16{0, 20, 47, 67, 85, 106, 132, 159, 185, 206, 228, 248, 275, 297, 319, 348, 367, 392, 422, 449, 476, 495, 527, 551, 573, 594, 615, 637, 655, 682, 702, 728, 755, 775, 805, 826, 851, 873, 889, 911, 936, 960, 987, 1011, 1033, 1052, 1073, 1098, 1113, 1140, 1166, 1193, 1214, 1240, 1268, 1295, 1316, 1339, 1364, 1381, 1406, 1432, 1455, 1473, 1494, 1524, 1556, 1577, 1604, 1630, 1658, 1682, 1714, 1749, 1769, 1794, 1824, 1854, 1888, 1920, 1950, 1974, 1998, 2024, 2047, 2071, 2091, 2114, 2138, 2162, 2181, 2213, 2239, 2257, 2280, 2309, 2331, 2347, 2367, 2388, 2406, 2425, 2450, 2475, 2504, 2531, 2557, 2581, 2602}
func (i ClientboundPacketID) String() string {
if i < 0 || i >= ClientboundPacketID(len(_ClientboundPacketID_index)-1) {
return "ClientboundPacketID(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ClientboundPacketID_name[_ClientboundPacketID_index[i]:_ClientboundPacketID_index[i+1]]
}

View File

@ -1,5 +1,11 @@
package packetid
//go:generate stringer -type ClientboundPacketID
//go:generate stringer -type ServerboundPacketID
type ClientboundPacketID int32
type ServerboundPacketID int32
// Login Clientbound
const (
LoginDisconnect = iota
@ -30,7 +36,7 @@ const (
// Game Clientbound
const (
ClientboundAddEntity = iota
ClientboundAddEntity ClientboundPacketID = iota
ClientboundAddExperienceOrb
ClientboundAddPlayer
ClientboundAnimate
@ -142,7 +148,7 @@ const (
// Game Serverbound
const (
ServerboundAcceptTeleportation = iota
ServerboundAcceptTeleportation ServerboundPacketID = iota
ServerboundBlockEntityTagQuery
ServerboundChangeDifficulty
ServerboundChatAck

View File

@ -0,0 +1,73 @@
// Code generated by "stringer -type ServerboundPacketID"; DO NOT EDIT.
package packetid
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ServerboundAcceptTeleportation-0]
_ = x[ServerboundBlockEntityTagQuery-1]
_ = x[ServerboundChangeDifficulty-2]
_ = x[ServerboundChatAck-3]
_ = x[ServerboundChatCommand-4]
_ = x[ServerboundChat-5]
_ = x[ServerboundChatPreview-6]
_ = x[ServerboundClientCommand-7]
_ = x[ServerboundClientInformation-8]
_ = x[ServerboundCommandSuggestion-9]
_ = x[ServerboundContainerButtonClick-10]
_ = x[ServerboundContainerClick-11]
_ = x[ServerboundContainerClose-12]
_ = x[ServerboundCustomPayload-13]
_ = x[ServerboundEditBook-14]
_ = x[ServerboundEntityTagQuery-15]
_ = x[ServerboundInteract-16]
_ = x[ServerboundJigsawGenerate-17]
_ = x[ServerboundKeepAlive-18]
_ = x[ServerboundLockDifficulty-19]
_ = x[ServerboundMovePlayerPos-20]
_ = x[ServerboundMovePlayerPosRot-21]
_ = x[ServerboundMovePlayerRot-22]
_ = x[ServerboundMovePlayerStatusOnly-23]
_ = x[ServerboundMoveVehicle-24]
_ = x[ServerboundPaddleBoat-25]
_ = x[ServerboundPickItem-26]
_ = x[ServerboundPlaceRecipe-27]
_ = x[ServerboundPlayerAbilities-28]
_ = x[ServerboundPlayerAction-29]
_ = x[ServerboundPlayerCommand-30]
_ = x[ServerboundPlayerInput-31]
_ = x[ServerboundPong-32]
_ = x[ServerboundRecipeBookChangeSettings-33]
_ = x[ServerboundRecipeBookSeenRecipe-34]
_ = x[ServerboundRenameItem-35]
_ = x[ServerboundResourcePack-36]
_ = x[ServerboundSeenAdvancements-37]
_ = x[ServerboundSelectTrade-38]
_ = x[ServerboundSetBeacon-39]
_ = x[ServerboundSetCarriedItem-40]
_ = x[ServerboundSetCommandBlock-41]
_ = x[ServerboundSetCommandMinecart-42]
_ = x[ServerboundSetCreativeModeSlot-43]
_ = x[ServerboundSetJigsawBlock-44]
_ = x[ServerboundSetStructureBlock-45]
_ = x[ServerboundSignUpdate-46]
_ = x[ServerboundSwing-47]
_ = x[ServerboundTeleportToEntity-48]
_ = x[ServerboundUseItemOn-49]
_ = x[ServerboundUseItem-50]
}
const _ServerboundPacketID_name = "ServerboundAcceptTeleportationServerboundBlockEntityTagQueryServerboundChangeDifficultyServerboundChatAckServerboundChatCommandServerboundChatServerboundChatPreviewServerboundClientCommandServerboundClientInformationServerboundCommandSuggestionServerboundContainerButtonClickServerboundContainerClickServerboundContainerCloseServerboundCustomPayloadServerboundEditBookServerboundEntityTagQueryServerboundInteractServerboundJigsawGenerateServerboundKeepAliveServerboundLockDifficultyServerboundMovePlayerPosServerboundMovePlayerPosRotServerboundMovePlayerRotServerboundMovePlayerStatusOnlyServerboundMoveVehicleServerboundPaddleBoatServerboundPickItemServerboundPlaceRecipeServerboundPlayerAbilitiesServerboundPlayerActionServerboundPlayerCommandServerboundPlayerInputServerboundPongServerboundRecipeBookChangeSettingsServerboundRecipeBookSeenRecipeServerboundRenameItemServerboundResourcePackServerboundSeenAdvancementsServerboundSelectTradeServerboundSetBeaconServerboundSetCarriedItemServerboundSetCommandBlockServerboundSetCommandMinecartServerboundSetCreativeModeSlotServerboundSetJigsawBlockServerboundSetStructureBlockServerboundSignUpdateServerboundSwingServerboundTeleportToEntityServerboundUseItemOnServerboundUseItem"
var _ServerboundPacketID_index = [...]uint16{0, 30, 60, 87, 105, 127, 142, 164, 188, 216, 244, 275, 300, 325, 349, 368, 393, 412, 437, 457, 482, 506, 533, 557, 588, 610, 631, 650, 672, 698, 721, 745, 767, 782, 817, 848, 869, 892, 919, 941, 961, 986, 1012, 1041, 1071, 1096, 1124, 1145, 1161, 1188, 1208, 1226}
func (i ServerboundPacketID) String() string {
if i < 0 || i >= ServerboundPacketID(len(_ServerboundPacketID_index)-1) {
return "ServerboundPacketID(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ServerboundPacketID_name[_ServerboundPacketID_index[i]:_ServerboundPacketID_index[i+1]]
}

View File

@ -1,6 +1,7 @@
package main
import (
botchat "github.com/Tnze/go-mc/bot/chat"
"log"
"time"
@ -19,6 +20,7 @@ const timeout = 45
var (
c *bot.Client
p *basic.Player
bc *botchat.Chat
watch chan time.Time
)
@ -26,16 +28,16 @@ var (
func main() {
//log.SetOutput(colorable.NewColorableStdout()) // optional for colorable output
c = bot.NewClient()
p = basic.NewPlayer(c, basic.DefaultSettings)
//Register event handlers
basic.EventsListener{
p = basic.NewPlayer(c, basic.DefaultSettings, basic.EventsListener{
GameStart: onGameStart,
ChatMsg: onChatMsg,
SystemMsg: onSystemMsg,
Disconnect: onDisconnect,
Death: onDeath,
}.Attach(c)
})
bc = botchat.NewChat(c, p, botchat.EventsHandler{PlayerChatMessage: onChatMsg})
//Register event handlers
c.Events.AddListener(soundListener)
//Login
@ -107,13 +109,13 @@ func onSound(id int, category int, x, y, z float64, volume, pitch float32) error
return nil
}
func onChatMsg(c *basic.PlayerMessage) error {
log.Println("Chat:", c.SignedMessage)
func onChatMsg(c chat.Message) error {
log.Println("Chat:", c)
return nil
}
func onSystemMsg(c chat.Message, pos byte) error {
log.Printf("System: %v, Location: %v", c, pos)
func onSystemMsg(c chat.Message, overlay bool) error {
log.Printf("System: %v, Overlay: %v", c, overlay)
return nil
}

View File

@ -12,6 +12,7 @@ import (
"github.com/Tnze/go-mc/bot"
"github.com/Tnze/go-mc/bot/basic"
botchat "github.com/Tnze/go-mc/bot/chat"
"github.com/Tnze/go-mc/bot/screen"
"github.com/Tnze/go-mc/bot/world"
"github.com/Tnze/go-mc/chat"
@ -27,6 +28,7 @@ var accessToken = flag.String("token", "", "AccessToken")
var client *bot.Client
var player *basic.Player
var chatHandler *botchat.Chat
var worldManager *world.World
var screenManager *screen.Manager
@ -39,15 +41,16 @@ func main() {
UUID: *playerID,
AsTk: *accessToken,
}
player = basic.NewPlayer(client, basic.DefaultSettings)
basic.EventsListener{
player = basic.NewPlayer(client, basic.DefaultSettings, basic.EventsListener{
GameStart: onGameStart,
ChatMsg: onChatMsg,
SystemMsg: onSystemMsg,
Disconnect: onDisconnect,
HealthChange: onHealthChange,
Death: onDeath,
}.Attach(client)
})
chatHandler = botchat.NewChat(client, player, botchat.EventsHandler{
PlayerChatMessage: onPlayerMsg,
})
worldManager = world.NewWorld(client, player, world.EventsListener{
LoadChunk: onChunkLoad,
UnloadChunk: onChunkUnload,
@ -103,13 +106,13 @@ func onGameStart() error {
return nil //if err isn't nil, HandleGame() will return it.
}
func onChatMsg(c *basic.PlayerMessage) error {
log.Println("Chat:", c.SignedMessage.String())
func onPlayerMsg(msg chat.Message) error {
log.Printf("Player: %v", msg)
return nil
}
func onSystemMsg(c chat.Message, pos byte) error {
log.Printf("System: %v, Location: %v", c, pos)
func onSystemMsg(c chat.Message, overlay bool) error {
log.Printf("System: %v, Overlay: %v", c, overlay)
return nil
}

View File

@ -28,7 +28,7 @@ func main() {
//log.SetOutput(colorable.NewColorableStdout())
client = bot.NewClient()
client.Auth.Name = "Daze"
player = basic.NewPlayer(client, basic.DefaultSettings)
player = basic.NewPlayer(client, basic.DefaultSettings, basic.EventsListener{})
client.Events.AddListener(bot.PacketHandler{
ID: packetid.ClientboundCommands,
Priority: 50,

View File

@ -44,11 +44,10 @@ func newIndividual(id int, name string) (i *individual) {
i.id = id
i.client = bot.NewClient()
i.client.Auth.Name = name
i.player = basic.NewPlayer(i.client, basic.DefaultSettings)
basic.EventsListener{
i.player = basic.NewPlayer(i.client, basic.DefaultSettings, basic.EventsListener{
GameStart: i.onGameStart,
Disconnect: onDisconnect,
}.Attach(i.client)
})
return
}

View File

@ -17,12 +17,12 @@ type Packet struct {
}
// Marshal generate Packet with the ID and Fields
func Marshal(id int32, fields ...FieldEncoder) (pk Packet) {
func Marshal[ID ~int32 | int](id ID, fields ...FieldEncoder) (pk Packet) {
var pb Builder
for _, v := range fields {
pb.WriteField(v)
}
return pb.Packet(id)
return pb.Packet(int32(id))
}
// Scan decode the packet and fill data into fields

View File

@ -2,6 +2,7 @@ package packet
import (
"errors"
"fmt"
"io"
"reflect"
)
@ -130,10 +131,10 @@ func (t Tuple) WriteTo(w io.Writer) (n int64, err error) {
// 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 {
for i, v := range t {
nn, err := v.(FieldDecoder).ReadFrom(r)
if err != nil {
return n, err
return n, fmt.Errorf("decode tuple[%d] error: %w", i, err)
}
n += nn
}