2023-03-27 22:02:13 +00:00
package shard
2023-03-17 21:27:47 +00:00
import (
"fmt"
"log"
"net"
"sync"
2023-06-22 06:53:38 +00:00
"github.com/CPunch/gopenfusion/config"
2023-03-22 05:30:58 +00:00
"github.com/CPunch/gopenfusion/core"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
2023-06-22 06:53:38 +00:00
"github.com/CPunch/gopenfusion/core/redis"
2023-03-17 21:27:47 +00:00
)
2023-03-27 22:02:13 +00:00
type PacketHandler func ( peer * protocol . CNPeer , pkt protocol . Packet ) error
func stubbedPacket ( _ * protocol . CNPeer , _ protocol . Packet ) error { /* stubbed */ return nil }
2023-03-17 21:27:47 +00:00
type ShardServer struct {
2023-06-25 03:36:04 +00:00
listener net . Listener
port int
dbHndlr * db . DBHandler
redisHndlr * redis . RedisHandler
packetHandlers map [ uint32 ] PacketHandler
peersLock sync . Mutex
peers map [ * protocol . CNPeer ] * core . Player
2023-03-17 21:27:47 +00:00
}
2023-06-22 06:53:38 +00:00
func NewShardServer ( dbHndlr * db . DBHandler , redisHndlr * redis . RedisHandler , port int ) ( * ShardServer , error ) {
2023-03-17 21:27:47 +00:00
listener , err := net . Listen ( "tcp" , fmt . Sprintf ( ":%d" , port ) )
if err != nil {
return nil , err
}
server := & ShardServer {
listener : listener ,
port : port ,
dbHndlr : dbHndlr ,
2023-06-22 06:53:38 +00:00
redisHndlr : redisHndlr ,
2023-03-17 21:27:47 +00:00
packetHandlers : make ( map [ uint32 ] PacketHandler ) ,
}
2023-03-18 21:40:20 +00:00
server . packetHandlers = map [ uint32 ] PacketHandler {
2023-03-22 22:07:16 +00:00
protocol . P_CL2FE_REQ_PC_ENTER : server . RequestEnter ,
protocol . P_CL2FE_REQ_PC_LOADING_COMPLETE : server . LoadingComplete ,
2023-03-18 21:40:20 +00:00
}
2023-03-17 21:27:47 +00:00
2023-06-22 06:53:38 +00:00
redisHndlr . RegisterShard ( redis . ShardMetadata {
IP : config . GetAnnounceIP ( ) ,
Port : port ,
} )
2023-03-17 21:27:47 +00:00
return server , nil
}
func ( server * ShardServer ) RegisterPacketHandler ( typeID uint32 , hndlr PacketHandler ) {
server . packetHandlers [ typeID ] = hndlr
}
func ( server * ShardServer ) Start ( ) {
2023-06-22 06:53:38 +00:00
log . Printf ( "Shard service hosted on %s:%d\n" , config . GetAnnounceIP ( ) , server . port )
2023-03-17 21:27:47 +00:00
for {
conn , err := server . listener . Accept ( )
if err != nil {
log . Println ( "Connection error: " , err )
return
}
2023-03-18 21:40:20 +00:00
client := protocol . NewCNPeer ( server , conn )
2023-03-17 21:27:47 +00:00
server . Connect ( client )
go client . Handler ( )
}
}
2023-03-27 22:02:13 +00:00
func ( server * ShardServer ) GetPort ( ) int {
return server . port
}
2023-03-18 21:40:20 +00:00
func ( server * ShardServer ) HandlePacket ( peer * protocol . CNPeer , typeID uint32 , pkt protocol . Packet ) error {
2023-03-17 21:27:47 +00:00
if hndlr , ok := server . packetHandlers [ typeID ] ; ok {
if err := hndlr ( peer , pkt ) ; err != nil {
return err
}
} else {
log . Printf ( "[WARN] invalid packet ID: %x\n" , typeID )
}
return nil
}
2023-03-18 21:40:20 +00:00
func ( server * ShardServer ) Disconnect ( peer * protocol . CNPeer ) {
2023-03-17 21:27:47 +00:00
log . Printf ( "Peer %p disconnected from SHARD\n" , peer )
2023-06-25 03:36:04 +00:00
delete ( server . peers , peer )
2023-03-17 21:27:47 +00:00
}
2023-03-18 21:40:20 +00:00
func ( server * ShardServer ) Connect ( peer * protocol . CNPeer ) {
2023-03-17 21:27:47 +00:00
log . Printf ( "New peer %p connected to SHARD\n" , peer )
2023-06-25 03:36:04 +00:00
server . peers [ peer ] = nil
2023-03-17 21:27:47 +00:00
}
2023-06-25 03:36:04 +00:00
// Returns a copy of the player
func ( server * ShardServer ) LoadPlayer ( peer * protocol . CNPeer ) ( core . Player , error ) {
plr , ok := server . peers [ peer ]
2023-03-22 22:07:16 +00:00
if ! ok {
2023-06-25 03:36:04 +00:00
return core . Player { } , fmt . Errorf ( "Player not found" )
2023-03-22 22:07:16 +00:00
}
2023-06-25 03:36:04 +00:00
return * plr , nil
2023-03-22 22:07:16 +00:00
}
2023-03-27 02:08:13 +00:00
// UpdatePlayer locks the peers map, and calls the provided callback. The returned new pointer will be stored, however if an error returns it will be passed back.
// Since it is UNSAFE to write to the returned pointer from LoadPlayer, this wrapper is for the cases that state in the player struct needs to be updated.
2023-06-25 03:36:04 +00:00
// The pointers new and old may be the same if you are just updating struct fields. This function should NOT be called recursively.
2023-03-27 02:08:13 +00:00
func ( server * ShardServer ) UpdatePlayer ( peer * protocol . CNPeer , f func ( old * core . Player ) ( new * core . Player , err error ) ) error {
server . peersLock . Lock ( )
defer server . peersLock . Unlock ( )
// on fail, the player should not be stored
2023-06-25 03:36:04 +00:00
new , err := f ( server . peers [ peer ] )
2023-03-27 02:08:13 +00:00
if err != nil {
return err
}
2023-06-25 03:36:04 +00:00
server . peers [ peer ] = new
2023-03-27 02:08:13 +00:00
return nil
}
2023-06-25 03:36:04 +00:00
// If f returns false the iteration is stopped.
func ( server * ShardServer ) RangePeers ( f func ( peer * protocol . CNPeer ) bool ) {
for peer := range server . peers {
if f ( peer ) {
return
2023-03-17 21:27:47 +00:00
}
2023-06-25 03:36:04 +00:00
}
2023-03-17 21:27:47 +00:00
}