Add playerinfo recorder for chat message

This commit is contained in:
Tnze
2022-12-30 01:09:08 +08:00
parent 6fba193255
commit 77857a1a85
6 changed files with 206 additions and 39 deletions

View File

@ -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")

View 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
}

View File

@ -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"
@ -18,9 +17,8 @@ import (
const timeout = 45 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

View File

@ -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{

View File

@ -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
View 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"`
}