forked from Tnze/go-mc
-
Notifications
You must be signed in to change notification settings - Fork 1
/
playerlist.go
167 lines (151 loc) · 3.87 KB
/
playerlist.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Package playerlist contains a PlayerList struct that used to manage player information.
//
// The [PlayerList] contains a list of [PlayerInfo] which is received from server when client join.
// The playerlist contains every players' information of name, display name, uuid, gamemode, latency, public key, etc.
// And can be used to render the "TAB List". Other packages may also require playerlist to work,
// for example, the bot/msg package.
package playerlist
import (
"bytes"
"github.com/google/uuid"
"github.com/maxsupermanhd/go-vmc/v762/bot"
"github.com/maxsupermanhd/go-vmc/v762/chat"
"github.com/maxsupermanhd/go-vmc/v762/chat/sign"
"github.com/maxsupermanhd/go-vmc/v762/data/packetid"
pk "github.com/maxsupermanhd/go-vmc/v762/net/packet"
"github.com/maxsupermanhd/go-vmc/v762/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) {
var chatSession pk.Option[sign.Session, *sign.Session]
if _, err := chatSession.ReadFrom(r); err != nil {
return err
}
if chatSession.Has {
player.ChatSession = chatSession.Pointer()
player.ChatSession.InitValidate()
} else {
player.ChatSession = nil
}
}
// 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 {
r := bytes.NewReader(p.Data)
var (
length pk.VarInt
id pk.UUID
)
if _, err := length.ReadFrom(r); err != nil {
return err
}
for i := 0; i < int(length); i++ {
if _, err := id.ReadFrom(r); err != nil {
return err
}
delete(pl.PlayerInfos, uuid.UUID(id))
}
return nil
}
type PlayerInfo struct {
GameProfile
ChatSession *sign.Session
Gamemode int32
Latency int32
Listed bool
DisplayName *chat.Message
}
type GameProfile struct {
ID uuid.UUID
Name string
Properties []user.Property
}