mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-06-12 18:50:42 +00:00
fe47e51351
* WIP refactor of d2map stuff * more d2map refactor adding realm init to game client passing map engine from client and server into realm at init change `generate map packet` to have act and level index as data * client explodes, but getting there * realm now initializes, networking works, but map generators dont currently do anything * changed the way that level type records are loaded * fixed funcs for level data lookups * started implementing level generator, currently crashing * client no longer exploding * d2networking refactor put exports into d2client.go and d2server.go kept GameClient and GameServer methods into their respective files made methods for packet handlers instead of the giant switch statements * bugfix: getting first level id by act * minor refactor of gamescreen for readability * towns now generate on server start, create player takes act and level id as args, levels have their own map engine
99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
package d2server
|
|
|
|
import (
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ConnectionManager is responsible for cleanup up connections accepted by the
|
|
// game server. As the server communicates over
|
|
// UDP and is stateless we need to implement some loose state management via a
|
|
// ping/pong system. ConnectionManager also handles
|
|
// communication for graceful shutdowns.
|
|
//
|
|
// retries: # of attempts before the dropping the client
|
|
// interval: How long to wait before each ping/pong test
|
|
// gameServer: The *GameServer is argument provided for the connection manager
|
|
// to watch over
|
|
// status: map of inflight ping/pong requests
|
|
type ConnectionManager struct {
|
|
sync.RWMutex
|
|
retries int
|
|
interval time.Duration
|
|
gameServer *GameServer
|
|
status map[string]int
|
|
}
|
|
|
|
func CreateConnectionManager(gameServer *GameServer) *ConnectionManager {
|
|
manager := &ConnectionManager{
|
|
retries: 3,
|
|
interval: time.Millisecond * 1000,
|
|
gameServer: gameServer,
|
|
status: make(map[string]int),
|
|
}
|
|
|
|
go manager.Run()
|
|
|
|
return manager
|
|
}
|
|
|
|
// Run starts up any watchers for for the connection manager
|
|
func (c *ConnectionManager) Run() {
|
|
log.Print("Starting connection manager...")
|
|
for {
|
|
c.checkPeers()
|
|
time.Sleep(c.interval)
|
|
}
|
|
}
|
|
|
|
// checkPeers manages connection validation and cleanup for all peers.
|
|
func (c *ConnectionManager) checkPeers() {
|
|
for id, connection := range c.gameServer.clientConnections {
|
|
if connection.GetConnectionType() != d2clientconnectiontype.Local {
|
|
pingPacket := d2netpacket.CreatePingPacket()
|
|
if err := connection.SendPacketToClient(pingPacket); err != nil {
|
|
log.Printf("Cannot ping client id: %s", id)
|
|
}
|
|
c.RWMutex.Lock()
|
|
c.status[id] += 1
|
|
|
|
if c.status[id] >= c.retries {
|
|
delete(c.status, id)
|
|
c.Drop(id)
|
|
}
|
|
|
|
c.RWMutex.Unlock()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Recv simply resets the counter, acknowledging we have received a pong from
|
|
// the client.
|
|
func (c *ConnectionManager) Recv(id string) {
|
|
c.status[id] = 0
|
|
}
|
|
|
|
// Drop removes the client id from the connection pool of the game server.
|
|
func (c *ConnectionManager) Drop(id string) {
|
|
c.gameServer.RWMutex.Lock()
|
|
defer c.gameServer.RWMutex.Unlock()
|
|
delete(c.gameServer.clientConnections, id)
|
|
log.Printf("%s has been disconnected...", id)
|
|
}
|
|
|
|
// Shutdown will notify all of the clients that the server has been shutdown.
|
|
func (c *ConnectionManager) Shutdown() {
|
|
// TODO: Currently this will never actually get called as the go routines
|
|
// are never signaled about the application termination.
|
|
// Things can be done more cleanly once we have graceful exits however we
|
|
// still need to account for other OS Signals
|
|
log.Print("Notifying clients server is shutting down...")
|
|
for _, connection := range c.gameServer.clientConnections {
|
|
connection.SendPacketToClient(d2netpacket.CreateServerClosedPacket())
|
|
}
|
|
Stop()
|
|
}
|