Files
Frodding/network/server.go
2026-03-03 15:05:55 +03:00

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
}