1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-12 18:50:42 +00:00
OpenDiablo2/d2networking/d2server/connection_manager.go
dk fe47e51351
Refactor d2map (#468)
* 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
2020-06-26 16:50:24 -04:00

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()
}