149 lines
3.4 KiB
Go
149 lines
3.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/Tnze/go-mc/data/packetid"
|
|
pk "github.com/Tnze/go-mc/net/packet"
|
|
)
|
|
|
|
type PlayerInfo struct {
|
|
updateDelay chan playerDelayInfo
|
|
join chan *Player
|
|
quit chan *Player
|
|
ticker *time.Ticker
|
|
}
|
|
|
|
type playerDelayInfo struct {
|
|
player *Player
|
|
delay time.Duration
|
|
}
|
|
|
|
func (p *playerDelayInfo) WriteTo(w io.Writer) (n int64, err error) {
|
|
return pk.Tuple{
|
|
pk.UUID(p.player.UUID),
|
|
pk.String(p.player.Name),
|
|
pk.Array([]pk.FieldEncoder{}),
|
|
pk.VarInt(p.player.Gamemode),
|
|
pk.VarInt(p.delay),
|
|
pk.Boolean(false),
|
|
}.WriteTo(w)
|
|
}
|
|
|
|
type playerInfoList struct {
|
|
list map[uuid.UUID]playerDelayInfo
|
|
}
|
|
|
|
func (p *playerInfoList) WriteTo(w io.Writer) (n int64, err error) {
|
|
n, err = pk.VarInt(len(p.list)).WriteTo(w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var n1 int64
|
|
for _, p := range p.list {
|
|
n1, err = p.WriteTo(w)
|
|
n += n1
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type playerDelayUpdate playerDelayInfo
|
|
|
|
func (p playerDelayUpdate) WriteTo(w io.Writer) (n int64, err error) {
|
|
return pk.Tuple{
|
|
pk.UUID(p.player.UUID),
|
|
pk.VarInt(p.delay.Milliseconds()),
|
|
}.WriteTo(w)
|
|
}
|
|
|
|
const (
|
|
actionAddPlayer = iota
|
|
actionUpdateGamemode
|
|
actionUpdateLatency
|
|
actionUpdateDisplayName
|
|
actionRemovePlayer
|
|
)
|
|
|
|
type PlayerDelaySource interface {
|
|
AddPlayerDelayUpdateHandler(f func(p *Player, delay time.Duration))
|
|
}
|
|
|
|
func NewPlayerInfo(updateFreq time.Duration, delaySource PlayerDelaySource) *PlayerInfo {
|
|
p := &PlayerInfo{
|
|
updateDelay: make(chan playerDelayInfo),
|
|
join: make(chan *Player),
|
|
quit: make(chan *Player),
|
|
ticker: time.NewTicker(updateFreq),
|
|
}
|
|
if delaySource != nil {
|
|
delaySource.AddPlayerDelayUpdateHandler(p.onPlayerDelayUpdate)
|
|
}
|
|
return p
|
|
}
|
|
|
|
func (p *PlayerInfo) Init(*Game) {}
|
|
|
|
func (p *PlayerInfo) Run(ctx context.Context) {
|
|
players := &playerInfoList{list: make(map[uuid.UUID]playerDelayInfo)}
|
|
var delayBuffer []playerDelayUpdate
|
|
for {
|
|
select {
|
|
case player := <-p.join:
|
|
info := playerDelayInfo{player: player, delay: 0}
|
|
pack := Packet758(pk.Marshal(
|
|
packetid.ClientboundPlayerInfo,
|
|
pk.VarInt(actionAddPlayer),
|
|
pk.VarInt(1),
|
|
&info,
|
|
))
|
|
players.list[player.UUID] = info
|
|
for _, p := range players.list {
|
|
p.player.WritePacket(pack)
|
|
}
|
|
player.WritePacket(Packet758(pk.Marshal(
|
|
packetid.ClientboundPlayerInfo,
|
|
pk.VarInt(actionAddPlayer),
|
|
players,
|
|
)))
|
|
case player := <-p.quit:
|
|
delete(players.list, player.UUID)
|
|
pack := Packet758(pk.Marshal(
|
|
packetid.ClientboundPlayerInfo,
|
|
pk.VarInt(actionRemovePlayer),
|
|
pk.VarInt(1),
|
|
pk.UUID(player.UUID),
|
|
))
|
|
for _, p := range players.list {
|
|
p.player.WritePacket(pack)
|
|
}
|
|
case change := <-p.updateDelay:
|
|
delayBuffer = append(delayBuffer, playerDelayUpdate(change))
|
|
case <-p.ticker.C:
|
|
pack := Packet758(pk.Marshal(
|
|
packetid.ClientboundPlayerInfo,
|
|
pk.VarInt(actionUpdateLatency),
|
|
pk.Array(&delayBuffer),
|
|
))
|
|
for _, p := range players.list {
|
|
p.player.WritePacket(pack)
|
|
}
|
|
delayBuffer = delayBuffer[:0]
|
|
case <-ctx.Done():
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (p *PlayerInfo) AddPlayer(player *Player) { p.join <- player }
|
|
func (p *PlayerInfo) RemovePlayer(player *Player) { p.quit <- player }
|
|
func (p *PlayerInfo) onPlayerDelayUpdate(player *Player, delay time.Duration) {
|
|
p.updateDelay <- playerDelayInfo{player: player, delay: delay}
|
|
}
|