134 lines
2.8 KiB
Go
134 lines
2.8 KiB
Go
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/cubexteam/Frodding/net/info"
|
|
"github.com/cubexteam/Frodding/raknet"
|
|
"github.com/cubexteam/Frodding/resources"
|
|
)
|
|
|
|
type Logger interface {
|
|
Infof(format string, args ...any)
|
|
Warnf(format string, args ...any)
|
|
Errorf(format string, args ...any)
|
|
Debugf(format string, args ...any)
|
|
Chat(name, message string)
|
|
}
|
|
|
|
type Server struct {
|
|
cfg *resources.Config
|
|
log Logger
|
|
rak *raknet.Server
|
|
mu sync.RWMutex
|
|
sessions map[int64]*Session
|
|
|
|
onShutdown func()
|
|
}
|
|
|
|
func NewServer(cfg *resources.Config, log Logger) *Server {
|
|
return &Server{
|
|
cfg: cfg,
|
|
log: log,
|
|
sessions: make(map[int64]*Session),
|
|
}
|
|
}
|
|
|
|
func (s *Server) SetShutdownHook(fn func()) {
|
|
s.onShutdown = fn
|
|
}
|
|
|
|
func (s *Server) Start() error {
|
|
guid := int64(0x526f6464696e6721)
|
|
|
|
motdFunc := func() string {
|
|
protocol := info.LatestProtocol
|
|
versionTag := info.LatestGameVersionNetwork
|
|
if s.cfg.MotdProtocol > 0 {
|
|
protocol = s.cfg.MotdProtocol
|
|
if vt, ok := info.SupportedProtocols[int32(protocol)]; ok {
|
|
versionTag = vt
|
|
}
|
|
}
|
|
return fmt.Sprintf("MCPE;%s;%d;%s;%d;%d;%d;%s;Survival",
|
|
s.cfg.ServerName, protocol, versionTag,
|
|
s.OnlineCount(), s.cfg.MaxPlayers,
|
|
guid, s.cfg.ServerName,
|
|
)
|
|
}
|
|
|
|
s.rak = raknet.NewServer(guid, motdFunc, s)
|
|
s.log.Infof("Starting on %s:%d (MCBE %s, protocol %d)",
|
|
s.cfg.ServerIP, s.cfg.ServerPort,
|
|
info.LatestGameVersionNetwork, info.LatestProtocol)
|
|
err := s.rak.Start(s.cfg.ServerIP, s.cfg.ServerPort)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.log.Infof("RakNet server started!")
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Shutdown() {
|
|
s.rak.Shutdown()
|
|
if s.onShutdown != nil {
|
|
s.onShutdown()
|
|
}
|
|
}
|
|
|
|
func (s *Server) OnConnect(rs *raknet.Session) {
|
|
s.log.Debugf("[NET] New connection guid=%d from %s", rs.GUID, rs.Addr)
|
|
sess := NewSession(s, rs)
|
|
s.mu.Lock()
|
|
s.sessions[rs.GUID] = sess
|
|
s.mu.Unlock()
|
|
}
|
|
|
|
func (s *Server) OnPacket(rs *raknet.Session, payload []byte) {
|
|
s.mu.RLock()
|
|
sess, ok := s.sessions[rs.GUID]
|
|
s.mu.RUnlock()
|
|
if !ok {
|
|
return
|
|
}
|
|
sess.HandlePayload(payload)
|
|
}
|
|
|
|
func (s *Server) OnDisconnect(rs *raknet.Session) {
|
|
s.mu.Lock()
|
|
sess, ok := s.sessions[rs.GUID]
|
|
delete(s.sessions, rs.GUID)
|
|
s.mu.Unlock()
|
|
if ok && sess.Spawned {
|
|
s.BroadcastMessage(fmt.Sprintf("§e%s left the game", sess.Username))
|
|
s.log.Infof("%s left the game", sess.Username)
|
|
}
|
|
}
|
|
|
|
func (s *Server) BroadcastMessage(msg string) {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
for _, sess := range s.sessions {
|
|
if sess.Spawned {
|
|
sess.SendMessage(msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Server) OnlineCount() int {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return len(s.sessions)
|
|
}
|
|
|
|
func (s *Server) GetSessions() []*Session {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
list := make([]*Session, 0, len(s.sessions))
|
|
for _, sess := range s.sessions {
|
|
list = append(list, sess)
|
|
}
|
|
return list
|
|
}
|