Provide official ListPingHandler implementation

This commit is contained in:
Tnze
2021-12-08 13:18:24 +08:00
parent 2274463c6c
commit 1c2332d678
4 changed files with 135 additions and 77 deletions

View File

@ -16,7 +16,7 @@ type ListPingHandler interface {
MaxPlayer() int
OnlinePlayer() int
PlayerSamples() []PlayerSample
Description() chat.Message
Description() *chat.Message
}
type PlayerSample struct {
@ -60,8 +60,8 @@ func (s *Server) listResp() ([]byte, error) {
Online int `json:"online"`
Sample []PlayerSample `json:"sample"`
} `json:"players"`
Description chat.Message `json:"description"`
FavIcon string `json:"favicon,omitempty"`
Description *chat.Message `json:"description"`
FavIcon string `json:"favicon,omitempty"`
}
list.Version.Name = s.ListPingHandler.Name()

90
server/playerlist.go Normal file
View File

@ -0,0 +1,90 @@
package server
import (
"container/list"
"sync"
"github.com/Tnze/go-mc/chat"
)
// PlayerList is an implement of ListPingHandler based on linked-list.
// This struct should not be copied after used.
type PlayerList struct {
name string
protocol int
maxPlayer int
description *chat.Message
players *list.List
// Only the linked-list is protected by this Mutex.
// Because others field never change after created.
playersLock sync.Mutex
}
// NewPlayerList create a PlayerList which implement ListPingHandler.
func NewPlayerList(name string, protocol, maxPlayers int, motd *chat.Message) *PlayerList {
return &PlayerList{
name: name,
protocol: protocol,
maxPlayer: maxPlayers,
description: motd,
players: list.New(),
}
}
// TryInsert trying to insert player into PlayerList.
// Return nil if the server is full (length of list larger than maxPlayers),
// otherwise return a function which is used to remove the player from PlayerList
func (p *PlayerList) TryInsert(player PlayerSample) (remove func()) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
if p.players.Len() >= p.maxPlayer {
return nil
}
elem := p.players.PushBack(player)
return func() {
p.playersLock.Lock()
p.players.Remove(elem)
p.playersLock.Unlock()
}
}
func (p *PlayerList) Name() string {
return p.name
}
func (p *PlayerList) Protocol() int {
return p.protocol
}
func (p *PlayerList) MaxPlayer() int {
return p.maxPlayer
}
func (p *PlayerList) OnlinePlayer() int {
p.playersLock.Lock()
defer p.playersLock.Unlock()
return p.players.Len()
}
func (p *PlayerList) PlayerSamples() (sample []PlayerSample) {
p.playersLock.Lock()
defer p.playersLock.Unlock()
// Up to 10 players can be returned
length := p.players.Len()
if length > 10 {
length = 10
}
sample = make([]PlayerSample, length)
v := p.players.Front()
for i := 0; i < length; i++ {
sample[i] = v.Value.(PlayerSample)
v = v.Next()
}
return
}
func (p *PlayerList) Description() *chat.Message {
return p.description
}

View File

@ -1,3 +1,25 @@
// Package server provide a minecraft server framework.
// You can build the server you want by combining the various functional modules provided here.
// An example can be found in examples/frameworkServer.
//
// A server is roughly divided into two parts:
//
// +----------------------------------------------+
// | Go-MC Server Framework |
// +-----------------------+----------------------+
// | Gate | GamePlay |
// +--------------+--------+--------+-------------+
// | LoginHandler | ListPingHandler | Coming Soon |
// +--------------+-----------------+-------------+
//
// Gate, which is used to respond to the client login request, provide login verification,
// respond to the List Ping Request and providing the online players' information.
//
// Gameplay, which is used to handle all things after a player successfully logs in
// (that is, after the LoginSuccess package is sent),
// and is responsible for functions including player status, chunk management, keep alive, chat, etc.
//
// The implement of Gameplay will provide later.
package server
import "github.com/Tnze/go-mc/net"