Add playerinfo recorder for chat message
This commit is contained in:
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Tnze/go-mc/bot"
|
"github.com/Tnze/go-mc/bot"
|
||||||
"github.com/Tnze/go-mc/bot/basic"
|
"github.com/Tnze/go-mc/bot/basic"
|
||||||
|
"github.com/Tnze/go-mc/bot/playerlist"
|
||||||
"github.com/Tnze/go-mc/chat"
|
"github.com/Tnze/go-mc/chat"
|
||||||
"github.com/Tnze/go-mc/chat/sign"
|
"github.com/Tnze/go-mc/chat/sign"
|
||||||
"github.com/Tnze/go-mc/data/packetid"
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
@ -20,12 +21,12 @@ type Manager struct {
|
|||||||
p *basic.Player
|
p *basic.Player
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(c *bot.Client, p *basic.Player, events EventsHandler) *Manager {
|
func New(c *bot.Client, p *basic.Player, pl *playerlist.PlayerList, events EventsHandler) *Manager {
|
||||||
attachPlayerMsg(c, p, events.PlayerChatMessage)
|
attachPlayerMsg(c, p, pl, events.PlayerChatMessage)
|
||||||
return &Manager{c, p}
|
return &Manager{c, p}
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachPlayerMsg(c *bot.Client, p *basic.Player, handler func(msg chat.Message) error) {
|
func attachPlayerMsg(c *bot.Client, p *basic.Player, _ *playerlist.PlayerList, handler func(msg chat.Message) error) {
|
||||||
c.Events.AddListener(
|
c.Events.AddListener(
|
||||||
bot.PacketHandler{
|
bot.PacketHandler{
|
||||||
Priority: 64, ID: packetid.ClientboundPlayerChat,
|
Priority: 64, ID: packetid.ClientboundPlayerChat,
|
||||||
@ -85,3 +86,5 @@ func (m *Manager) SendMessage(msg string) error {
|
|||||||
))
|
))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var InvalidChatPacket = errors.New("invalid chat packet")
|
||||||
|
137
bot/playerlist/playerlist.go
Normal file
137
bot/playerlist/playerlist.go
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package playerlist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/Tnze/go-mc/bot"
|
||||||
|
"github.com/Tnze/go-mc/chat"
|
||||||
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
"github.com/Tnze/go-mc/yggdrasil/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PlayerList struct {
|
||||||
|
PlayerInfos map[uuid.UUID]*PlayerInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(c *bot.Client) *PlayerList {
|
||||||
|
pl := PlayerList{
|
||||||
|
PlayerInfos: make(map[uuid.UUID]*PlayerInfo),
|
||||||
|
}
|
||||||
|
c.Events.AddListener(
|
||||||
|
bot.PacketHandler{
|
||||||
|
Priority: 64, ID: packetid.ClientboundPlayerInfoUpdate,
|
||||||
|
F: pl.handlePlayerInfoUpdatePacket,
|
||||||
|
},
|
||||||
|
bot.PacketHandler{
|
||||||
|
Priority: 64, ID: packetid.ClientboundPlayerInfoRemove,
|
||||||
|
F: pl.handlePlayerInfoRemovePacket,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return &pl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pl *PlayerList) handlePlayerInfoUpdatePacket(p pk.Packet) error {
|
||||||
|
r := bytes.NewReader(p.Data)
|
||||||
|
|
||||||
|
action := pk.NewFixedBitSet(6)
|
||||||
|
if _, err := action.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var length pk.VarInt
|
||||||
|
if _, err := length.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(length); i++ {
|
||||||
|
var id pk.UUID
|
||||||
|
if _, err := id.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
player, ok := pl.PlayerInfos[uuid.UUID(id)]
|
||||||
|
if !ok { // create new player info if not exist
|
||||||
|
player = new(PlayerInfo)
|
||||||
|
pl.PlayerInfos[uuid.UUID(id)] = player
|
||||||
|
}
|
||||||
|
|
||||||
|
// add player
|
||||||
|
if action.Get(0) {
|
||||||
|
var name pk.String
|
||||||
|
var properties []user.Property
|
||||||
|
if _, err := (pk.Tuple{&name, pk.Array(&properties)}).ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
player.GameProfile = GameProfile{
|
||||||
|
ID: uuid.UUID(id),
|
||||||
|
Name: string(name),
|
||||||
|
Properties: properties,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// initialize chat
|
||||||
|
if action.Get(1) {
|
||||||
|
return errors.New("unsupported initialize chat yet")
|
||||||
|
}
|
||||||
|
// update gamemode
|
||||||
|
if action.Get(2) {
|
||||||
|
var gamemode pk.VarInt
|
||||||
|
if _, err := gamemode.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
player.Gamemode = int32(gamemode)
|
||||||
|
}
|
||||||
|
// update listed
|
||||||
|
if action.Get(3) {
|
||||||
|
var listed pk.Boolean
|
||||||
|
if _, err := listed.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
player.Listed = bool(listed)
|
||||||
|
}
|
||||||
|
// update latency
|
||||||
|
if action.Get(4) {
|
||||||
|
var latency pk.VarInt
|
||||||
|
if _, err := latency.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
player.Latency = int32(latency)
|
||||||
|
}
|
||||||
|
// display name
|
||||||
|
if action.Get(5) {
|
||||||
|
var displayName pk.Option[chat.Message, *chat.Message]
|
||||||
|
if _, err := displayName.ReadFrom(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if displayName.Has {
|
||||||
|
player.DisplayName = &displayName.Val
|
||||||
|
} else {
|
||||||
|
player.DisplayName = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pl *PlayerList) handlePlayerInfoRemovePacket(p pk.Packet) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlayerInfo struct {
|
||||||
|
GameProfile
|
||||||
|
// chatSession
|
||||||
|
Gamemode int32
|
||||||
|
Latency int32
|
||||||
|
Listed bool
|
||||||
|
DisplayName *chat.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
type GameProfile struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
Name string
|
||||||
|
Properties []user.Property
|
||||||
|
}
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Tnze/go-mc/bot"
|
"github.com/Tnze/go-mc/bot"
|
||||||
"github.com/Tnze/go-mc/bot/basic"
|
"github.com/Tnze/go-mc/bot/basic"
|
||||||
"github.com/Tnze/go-mc/bot/msg"
|
|
||||||
"github.com/Tnze/go-mc/chat"
|
"github.com/Tnze/go-mc/chat"
|
||||||
_ "github.com/Tnze/go-mc/data/lang/en-us"
|
_ "github.com/Tnze/go-mc/data/lang/en-us"
|
||||||
"github.com/Tnze/go-mc/data/packetid"
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
@ -20,7 +19,6 @@ const timeout = 45
|
|||||||
var (
|
var (
|
||||||
c *bot.Client
|
c *bot.Client
|
||||||
p *basic.Player
|
p *basic.Player
|
||||||
bc *msg.Manager
|
|
||||||
|
|
||||||
watch chan time.Time
|
watch chan time.Time
|
||||||
)
|
)
|
||||||
@ -34,7 +32,6 @@ func main() {
|
|||||||
Disconnect: onDisconnect,
|
Disconnect: onDisconnect,
|
||||||
Death: onDeath,
|
Death: onDeath,
|
||||||
})
|
})
|
||||||
bc = msg.New(c, p, msg.EventsHandler{PlayerChatMessage: onChatMsg})
|
|
||||||
|
|
||||||
// Register event handlers
|
// Register event handlers
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/Tnze/go-mc/bot"
|
"github.com/Tnze/go-mc/bot"
|
||||||
"github.com/Tnze/go-mc/bot/basic"
|
"github.com/Tnze/go-mc/bot/basic"
|
||||||
"github.com/Tnze/go-mc/bot/msg"
|
"github.com/Tnze/go-mc/bot/msg"
|
||||||
|
"github.com/Tnze/go-mc/bot/playerlist"
|
||||||
"github.com/Tnze/go-mc/bot/screen"
|
"github.com/Tnze/go-mc/bot/screen"
|
||||||
"github.com/Tnze/go-mc/bot/world"
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
"github.com/Tnze/go-mc/chat"
|
"github.com/Tnze/go-mc/chat"
|
||||||
@ -31,6 +32,7 @@ var (
|
|||||||
var (
|
var (
|
||||||
client *bot.Client
|
client *bot.Client
|
||||||
player *basic.Player
|
player *basic.Player
|
||||||
|
playerList *playerlist.PlayerList
|
||||||
chatHandler *msg.Manager
|
chatHandler *msg.Manager
|
||||||
worldManager *world.World
|
worldManager *world.World
|
||||||
screenManager *screen.Manager
|
screenManager *screen.Manager
|
||||||
@ -52,7 +54,8 @@ func main() {
|
|||||||
HealthChange: onHealthChange,
|
HealthChange: onHealthChange,
|
||||||
Death: onDeath,
|
Death: onDeath,
|
||||||
})
|
})
|
||||||
chatHandler = msg.New(client, player, msg.EventsHandler{
|
playerList = playerlist.New(client)
|
||||||
|
chatHandler = msg.New(client, player, playerList, msg.EventsHandler{
|
||||||
PlayerChatMessage: onPlayerMsg,
|
PlayerChatMessage: onPlayerMsg,
|
||||||
})
|
})
|
||||||
worldManager = world.NewWorld(client, player, world.EventsListener{
|
worldManager = world.NewWorld(client, player, world.EventsListener{
|
||||||
|
@ -15,11 +15,13 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/Tnze/go-mc/data/packetid"
|
"github.com/Tnze/go-mc/data/packetid"
|
||||||
"github.com/Tnze/go-mc/net"
|
"github.com/Tnze/go-mc/net"
|
||||||
"github.com/Tnze/go-mc/net/CFB8"
|
"github.com/Tnze/go-mc/net/CFB8"
|
||||||
pk "github.com/Tnze/go-mc/net/packet"
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
"github.com/google/uuid"
|
"github.com/Tnze/go-mc/yggdrasil/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
const verifyTokenLen = 16
|
const verifyTokenLen = 16
|
||||||
@ -171,42 +173,20 @@ func twosComplement(p []byte) []byte {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
Texture = user.Texture
|
||||||
|
Property = user.Property
|
||||||
|
)
|
||||||
|
|
||||||
// Resp is the response of authentication
|
// Resp is the response of authentication
|
||||||
type Resp struct {
|
type Resp struct {
|
||||||
Name string
|
Name string
|
||||||
ID uuid.UUID
|
ID uuid.UUID
|
||||||
Properties []Property
|
Properties []user.Property
|
||||||
}
|
|
||||||
|
|
||||||
type Property struct {
|
|
||||||
Name, Value, Signature string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Property) WriteTo(w io.Writer) (n int64, err error) {
|
|
||||||
return pk.Tuple{
|
|
||||||
pk.String(p.Name),
|
|
||||||
pk.String(p.Value),
|
|
||||||
pk.Option[pk.String, *pk.String]{
|
|
||||||
Has: p.Signature != "",
|
|
||||||
Val: pk.String(p.Signature),
|
|
||||||
},
|
|
||||||
}.WriteTo(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Texture includes player's skin and cape
|
|
||||||
type Texture struct {
|
|
||||||
TimeStamp int64 `json:"timestamp"`
|
|
||||||
ID uuid.UUID `json:"profileId"`
|
|
||||||
Name string `json:"profileName"`
|
|
||||||
Textures struct {
|
|
||||||
SKIN, CAPE struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
}
|
|
||||||
} `json:"textures"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture unmarshal the base64 encoded texture of Resp
|
// Texture unmarshal the base64 encoded texture of Resp
|
||||||
func (r *Resp) Texture() (t Texture, err error) {
|
func (r *Resp) Texture() (t user.Texture, err error) {
|
||||||
var texture []byte
|
var texture []byte
|
||||||
texture, err = base64.StdEncoding.DecodeString(r.Properties[0].Value)
|
texture, err = base64.StdEncoding.DecodeString(r.Properties[0].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
47
yggdrasil/user/auth.go
Normal file
47
yggdrasil/user/auth.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Property struct {
|
||||||
|
Name, Value, Signature string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Property) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.String(p.Name),
|
||||||
|
pk.String(p.Value),
|
||||||
|
pk.Option[pk.String, *pk.String]{
|
||||||
|
Has: p.Signature != "",
|
||||||
|
Val: pk.String(p.Signature),
|
||||||
|
},
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Property) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
var signature pk.Option[pk.String, *pk.String]
|
||||||
|
n, err = pk.Tuple{
|
||||||
|
(*pk.String)(&p.Name),
|
||||||
|
(*pk.String)(&p.Value),
|
||||||
|
&signature,
|
||||||
|
}.ReadFrom(r)
|
||||||
|
p.Signature = string(signature.Val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Texture includes player's skin and cape
|
||||||
|
type Texture struct {
|
||||||
|
TimeStamp int64 `json:"timestamp"`
|
||||||
|
ID uuid.UUID `json:"profileId"`
|
||||||
|
Name string `json:"profileName"`
|
||||||
|
Textures struct {
|
||||||
|
SKIN, CAPE struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
} `json:"textures"`
|
||||||
|
}
|
Reference in New Issue
Block a user