Optimize PacketHandler performance

This commit is contained in:
Tnze
2021-12-24 15:40:39 +08:00
parent dccbf7ce46
commit 494a52320d
7 changed files with 191 additions and 69 deletions

View File

@ -32,26 +32,51 @@ func NewGlobalChat() *GlobalChat {
}
}
func (g *GlobalChat) AddPlayer(p *Player) {
g.join <- p
p.AddHandler(PacketHandler{
func (g *GlobalChat) Init(game *Game) {
game.AddHandler(&PacketHandler{
ID: packetid.ServerboundChat,
F: func(packet Packet757) error {
F: func(player *Player, packet Packet757) error {
var msg pk.String
if err := pk.Packet(packet).Scan(&msg); err != nil {
return err
}
text, _ := chat.TransCtrlSeq(string(msg), false)
g.msg <- chatItem{p: p, text: text}
g.msg <- chatItem{p: player, text: text}
return nil
},
})
}
func (g *GlobalChat) RemovePlayer(p *Player) {
g.quit <- p
func (g *GlobalChat) Run(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case item := <-g.msg:
packet := Packet757(pk.Marshal(
packetid.ClientboundChat,
item.toMessage(),
pk.Byte(0),
pk.UUID(item.p.UUID),
))
for _, p := range g.players {
err := p.WritePacket(packet)
if err != nil {
p.PutErr(err)
}
}
case p := <-g.join:
g.players[p.UUID] = p
case p := <-g.quit:
delete(g.players, p.UUID)
}
}
}
func (g *GlobalChat) AddPlayer(player *Player) { g.join <- player }
func (g *GlobalChat) RemovePlayer(p *Player) { g.quit <- p }
func (c chatItem) toMessage() chat.Message {
return chat.TranslateMsg(
"chat.type.text",
@ -86,29 +111,3 @@ func playerToSNBT(p *Player) string {
return string(s)
}
func (g *GlobalChat) Run(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case item := <-g.msg:
packet := Packet757(pk.Marshal(
packetid.ClientboundChat,
item.toMessage(),
pk.Byte(0),
pk.UUID(item.p.UUID),
))
for _, p := range g.players {
err := p.WritePacket(packet)
if err != nil {
p.PutErr(err)
}
}
case p := <-g.join:
g.players[p.UUID] = p
case p := <-g.quit:
delete(g.players, p.UUID)
}
}
}

View File

@ -25,16 +25,25 @@ type GamePlay interface {
type Game struct {
Dim Level
components []Component
handlers map[int32][]*PacketHandler
eid int32
}
type Component interface {
Init(g *Game)
Run(ctx context.Context)
AddPlayer(p *Player)
RemovePlayer(p *Player)
}
type PacketHandler struct {
ID int32
F packetHandlerFunc
}
type packetHandlerFunc func(player *Player, packet Packet757) error
//go:embed DimensionCodec.snbt
var dimensionCodecSNBT string
@ -42,10 +51,19 @@ var dimensionCodecSNBT string
var dimensionSNBT string
func NewGame(dim Level, components ...Component) *Game {
return &Game{
g := &Game{
Dim: dim,
components: components,
handlers: make(map[int32][]*PacketHandler),
}
for _, v := range components {
v.Init(g)
}
return g
}
func (g *Game) AddHandler(ph *PacketHandler) {
g.handlers[ph.ID] = append(g.handlers[ph.ID], ph)
}
func (g *Game) Run(ctx context.Context) {
@ -67,7 +85,6 @@ func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net
UUID: id,
EntityID: g.newEID(),
Gamemode: 1,
handlers: make(map[int32][]packetHandlerFunc),
errChan: make(chan error, 1),
}
dimInfo := g.Dim.Info()
@ -107,13 +124,11 @@ func (g *Game) AcceptPlayer(name string, id uuid.UUID, protocol int32, conn *net
var packet pk.Packet
for {
err := p.ReadPacket(&packet)
if err != nil {
if err := p.ReadPacket(&packet); err != nil {
return
}
for _, ph := range p.handlers[packet.ID] {
err = ph(Packet757(packet))
if err != nil {
for _, ph := range g.handlers[packet.ID] {
if err := ph.F(p, Packet757(packet)); err != nil {
return
}
}

View File

@ -49,25 +49,22 @@ func NewKeepAlive() (k *KeepAlive) {
}
}
func (k *KeepAlive) AddPlayer(p *Player) {
k.join <- p
p.AddHandler(PacketHandler{
// Init implement Component for KeepAlive
func (k *KeepAlive) Init(g *Game) {
g.AddHandler(&PacketHandler{
ID: packetid.ServerboundKeepAlive,
F: func(packet Packet757) error {
F: func(player *Player, packet Packet757) error {
var KeepAliveID pk.Long
if err := pk.Packet(packet).Scan(&KeepAliveID); err != nil {
return err
}
k.tick <- p
k.tick <- player
return nil
},
})
}
func (k *KeepAlive) RemovePlayer(p *Player) {
k.quit <- p
}
// Run implement Component for KeepAlive
func (k *KeepAlive) Run(ctx context.Context) {
for {
select {
@ -87,6 +84,12 @@ func (k *KeepAlive) Run(ctx context.Context) {
}
}
// AddPlayer implement Component for KeepAlive
func (k *KeepAlive) AddPlayer(player *Player) { k.join <- player }
// RemovePlayer implement Component for KeepAlive
func (k *KeepAlive) RemovePlayer(p *Player) { k.quit <- p }
func (k KeepAlive) pushPlayer(p *Player) {
k.listIndex[p.UUID] = k.pingList.PushBack(
keepAliveItem{player: p, t: time.Now()},

View File

@ -18,7 +18,6 @@ type Player struct {
uuid.UUID
EntityID int32
Gamemode byte
handlers map[int32][]packetHandlerFunc
errChan chan error
}
@ -51,20 +50,6 @@ func (s WritePacketError) Unwrap() error {
return s.Err
}
type PacketHandler struct {
ID int32
F packetHandlerFunc
}
type packetHandlerFunc func(packet Packet757) error
func (p *Player) AddHandler(ph PacketHandler) {
if p.handlers == nil {
p.handlers = make(map[int32][]packetHandlerFunc)
}
p.handlers[ph.ID] = append(p.handlers[ph.ID], ph.F)
}
func (p *Player) PutErr(err error) {
select {
case p.errChan <- err:

View File

@ -30,8 +30,13 @@ func NewPlayerList(maxPlayers int) *PlayerList {
}
}
// Init implement Component for PlayerList
func (p *PlayerList) Init(*Game) {}
// Run implement Component for PlayerList
func (p *PlayerList) Run(context.Context) {}
// AddPlayer implement Component for PlayerList
func (p *PlayerList) AddPlayer(player *Player) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
@ -52,12 +57,23 @@ func (p *PlayerList) AddPlayer(player *Player) {
p.players[player.UUID] = player
}
// RemovePlayer implement Component for PlayerList
func (p *PlayerList) RemovePlayer(player *Player) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
delete(p.players, player.UUID)
}
// CheckPlayer implement LoginChecker for PlayerList
func (p *PlayerList) CheckPlayer(name string, id uuid.UUID, protocol int32) (ok bool, reason chat.Message) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
if len(p.players) >= p.maxPlayer {
return false, chat.TranslateMsg("multiplayer.disconnect.server_full")
}
return true, chat.Message{}
}
func (p *PlayerList) MaxPlayer() int {
return p.maxPlayer
}
@ -72,7 +88,11 @@ func (p *PlayerList) PlayerSamples() (sample []PlayerSample) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
// Up to 10 players can be returned
sample = make([]PlayerSample, len(p.players))
length := len(p.players)
if length > 10 {
length = 10
}
sample = make([]PlayerSample, length)
var i int
for _, v := range p.players {
sample[i] = PlayerSample{
@ -80,7 +100,7 @@ func (p *PlayerList) PlayerSamples() (sample []PlayerSample) {
ID: v.UUID,
}
i++
if i >= len(p.players) {
if i >= length {
break
}
}