365 lines
14 KiB
Lua
365 lines
14 KiB
Lua
local skynet = require "skynet"
|
||
local oo = require "Class"
|
||
local log = require "Log"
|
||
local json =require "json"
|
||
local sqlUrl = require "SqlUrl"
|
||
local curServerId = tonumber(skynet.getenv "serverId")
|
||
local manageCmd = require "ManageCmd"
|
||
local clusterServer = require "ClusterServer"
|
||
local errorInfo = require "ErrorInfo"
|
||
local redisKeyUrl = require "RedisKeyUrl"
|
||
|
||
local ServerManage = oo.class()
|
||
|
||
function ServerManage:Init()
|
||
end
|
||
|
||
--获取服务器
|
||
function ServerManage:GetServer()
|
||
local server = nil --找出对应的服务器信息
|
||
if curServerId == clusterServer.centerServerID then
|
||
server = skynet.server.centerServer
|
||
elseif curServerId == clusterServer.multiServerID then
|
||
server = skynet.server.multiServer
|
||
elseif curServerId == clusterServer.payServerID then
|
||
server = skynet.server.payServer
|
||
elseif curServerId >= clusterServer.routeServerMinID and curServerId <= clusterServer.routeServerMaxID then
|
||
server = skynet.server.routeServer
|
||
elseif curServerId >= clusterServer.gameServerMinID and curServerId <= clusterServer.gameServerMaxID then
|
||
server = skynet.server.gameServer
|
||
end
|
||
|
||
return server
|
||
end
|
||
|
||
--执行服务器命令
|
||
function ServerManage:DoManageCmd( c2sData , s2cData)
|
||
local cmd = c2sData.cmd
|
||
local userId = c2sData.userId or nil
|
||
local value = c2sData.value or nil
|
||
|
||
s2cData.data = {}
|
||
s2cData.data.serverId = curServerId
|
||
s2cData.data.isSuc = true
|
||
log.info("执行服务器命令" ,cmd ,userId ,value)
|
||
if cmd > manageCmd.AllServerStart and cmd < manageCmd.AllServerEnd then --所有服务器
|
||
local server = self:GetServer()
|
||
|
||
if manageCmd.ReloadClusterConfig == cmd then
|
||
self:ReloadClusterConfig( server )
|
||
elseif manageCmd.Reg == cmd then
|
||
self:Reg( server )
|
||
elseif manageCmd.UnReg == cmd then
|
||
self:UnReg( server )
|
||
elseif manageCmd.ReConnectDB == cmd then
|
||
self:ReConnectDB( server )
|
||
elseif manageCmd.ShutDown == cmd then
|
||
self:ShutDown( server , c2sData , s2cData )
|
||
end
|
||
elseif curServerId == clusterServer.centerServerID then --中心服
|
||
if manageCmd.QueryPlayerDBInfo == cmd then
|
||
self:QueryPlayerDBInfo( c2sData , s2cData )
|
||
elseif manageCmd.QueryPlayerOnlineInfo == cmd then
|
||
self:QueryPlayerOnlineInfo( c2sData , s2cData )
|
||
elseif manageCmd.RestartGameServer == cmd then
|
||
self:RestartGameServer( c2sData , s2cData )
|
||
end
|
||
elseif curServerId >= clusterServer.routeServerMinID and curServerId <= clusterServer.routeServerMaxID and cmd > manageCmd.RouteServerStart and cmd < manageCmd.RouteServerEnd then --路由服务器
|
||
if manageCmd.RouteSyncWhiteList == cmd then
|
||
self:RouteSyncWhiteList( c2sData , s2cData )
|
||
elseif manageCmd.RouteSyncBlackList == cmd then
|
||
self:RouteSyncBlackList( c2sData , s2cData )
|
||
end
|
||
elseif curServerId >= clusterServer.gameServerMinID and curServerId <= clusterServer.gameServerMaxID and cmd > manageCmd.GameServerStart and cmd < manageCmd.GameServerEnd then --游戏服务器
|
||
if manageCmd.NeedPlayerCount == cmd then
|
||
self:NeedPlayerCount( c2sData , s2cData)
|
||
elseif manageCmd.SaveUserToDB == cmd then
|
||
self:SaveUserToDB( c2sData , s2cData)
|
||
elseif manageCmd.SaveUserToTxt == cmd then
|
||
self:SaveUserToTxt( c2sData , s2cData )
|
||
elseif manageCmd.ForceUserOffline == cmd then
|
||
self:ForceUserOffline( c2sData , s2cData )
|
||
elseif manageCmd.QueryPlayerInServer == cmd then
|
||
self:QueryPlayerInServer( c2sData , s2cData )
|
||
elseif manageCmd.UpdateGameVersion == cmd then
|
||
self:UpdateGameVersion( s2cData )
|
||
elseif manageCmd.UpdateUserData == cmd then
|
||
self:UpdateUserData( c2sData , s2cData )
|
||
elseif manageCmd.SaveAllUserDataToFile == cmd then
|
||
self:SaveAllUserDataToFile( c2sData , s2cData )
|
||
elseif manageCmd.ReStartTimer == cmd then
|
||
self:ReStartTimer( c2sData , s2cData )
|
||
end
|
||
else
|
||
s2cData.code = errorInfo.ErrorCode.ErrRequestParam
|
||
end
|
||
|
||
if errorInfo.Suc ~= s2cData.code then
|
||
s2cData.data.isSuc = false
|
||
end
|
||
|
||
return s2cData
|
||
end
|
||
|
||
--注册服务器
|
||
function ServerManage:Reg( server )
|
||
skynet.server.clusterServer:Reg()
|
||
log.info("成功注册服务")
|
||
end
|
||
|
||
--注销服务器
|
||
function ServerManage:UnReg( server )
|
||
skynet.server.clusterServer:UnReg()
|
||
log.info("成功注销服务")
|
||
end
|
||
|
||
--重连数据库
|
||
function ServerManage:ReConnectDB( server )
|
||
log.info("开始 重新连接数据库")
|
||
skynet.InitDB( true )
|
||
log.info("结束 重新连接数据库")
|
||
end
|
||
|
||
--关闭服务器
|
||
function ServerManage:ShutDown( server , c2sData , s2cData )
|
||
skynet.server.clusterServer:UnReg()
|
||
if server:StopServer( c2sData , s2cData ) then
|
||
log.info("强制关闭服务器成功")
|
||
else
|
||
log.info("强制关闭服务器失败")
|
||
end
|
||
end
|
||
|
||
--关闭服务器
|
||
function ServerManage:ReloadClusterConfig( server )
|
||
server:ReloadClusterNode()
|
||
log.info("成功载入集群配置")
|
||
end
|
||
|
||
--查询玩家DB信息
|
||
function ServerManage:QueryPlayerDBInfo( c2sData , s2cData)
|
||
local account = c2sData.account
|
||
local userDBInfo = skynet.server.redisCenter:GetRedisDBInfo( account )
|
||
s2cData.data.userDBInfo = userDBInfo
|
||
end
|
||
|
||
|
||
--查询玩家在线信息
|
||
function ServerManage:QueryPlayerOnlineInfo( c2sData , s2cData)
|
||
local account = c2sData.account
|
||
local redisKey = string.format( redisKeyUrl.RouteServerLoginInfoHash , account )
|
||
local queryData = skynet.server.redis:hgetall( redisKey )
|
||
queryData = redisKeyUrl:CovertTable(queryData)
|
||
s2cData.data.onlineInfo = queryData
|
||
end
|
||
|
||
--重启游戏服
|
||
function ServerManage:RestartGameServer( c2sData , s2cData)
|
||
local startServerId = c2sData.startServerId --游戏服起始ID
|
||
local endServerId = c2sData.endServerId --游戏服结束ID
|
||
local opTime = c2sData.opTime --操作时间
|
||
|
||
if nil == endServerId then
|
||
endServerId = startServerId
|
||
end
|
||
|
||
if nil == opTime or "" == opTime then
|
||
s2cData.code = errorInfo.ErrorCode.ErrRequestParam
|
||
return s2cData
|
||
end
|
||
|
||
--将时间格式 2022-02-22 22:22:22 转为时间戳
|
||
local tmpOpTime = opTime
|
||
opTime = skynet.server.common:GetTime( opTime )
|
||
|
||
--将执行计划写入redis
|
||
local planInfo = {}
|
||
planInfo.startServerId = startServerId
|
||
planInfo.endServerId = endServerId
|
||
planInfo.opTime = opTime
|
||
for k, v in pairs( skynet.server.clusterServer.clusterInfo ) do
|
||
if v.serverId >= skynet.server.clusterServer.routeServerMinID and v.serverId <= skynet.server.clusterServer.routeServerMaxID then
|
||
skynet.server.redis:hset( redisKeyUrl.RestartPlanHSet , v.serverId , json:encode( planInfo ) )
|
||
end
|
||
end
|
||
|
||
log.info(string.format("成功写入重启计划 游戏服ID 起始 %d 结束 %d 开始时间 %s", startServerId , endServerId, tmpOpTime))
|
||
end
|
||
|
||
--路由服加入白名单
|
||
function ServerManage:RouteSyncWhiteList( c2sData , s2cData )
|
||
skynet.server.routeServer:SyncWhiteList()
|
||
s2cData.data.isSuc = true
|
||
end
|
||
|
||
--路由服加入黑名单
|
||
function ServerManage:RouteSyncBlackList( c2sData , s2cData )
|
||
skynet.server.routeServer:SyncBlackList()
|
||
s2cData.data.isSuc = true
|
||
end
|
||
|
||
--需要玩家数量
|
||
function ServerManage:NeedPlayerCount( c2sData , s2cData)
|
||
local param = c2sData.param
|
||
skynet.server.gameServer.serverInfo.needPlayerCount = tonumber( param.needCount )
|
||
|
||
log.info(string.format("游戏服需要 %d 个玩家", skynet.server.gameServer.serverInfo.needPlayerCount))
|
||
end
|
||
|
||
--保存用户数据到DB
|
||
function ServerManage:SaveUserToDB( c2sData , s2cData)
|
||
local account = c2sData.account
|
||
local player = skynet.server.playerCenter:GetPlayerForAccount( account )
|
||
if not player then
|
||
s2cData.code = errorInfo.ErrorCode.NoExistUser
|
||
else
|
||
local sucSave = skynet.server.accountCenter:SavePlayerToMysql( player )
|
||
if sucSave then
|
||
log.info(string.format("玩家 %s 强制将玩家数据保存到Mysql成功", account ))
|
||
else
|
||
--强制失败,先存玩家的sql,如果无法组装数据,只能打印成文本
|
||
s2cData.code = errorInfo.ErrorCode.OpFailed
|
||
log.info(string.format("玩家 %s 强制将玩家数据保存到Mysql失败", account ))
|
||
skynet.server.accountCenter:SaveFailedPlayerDataToFile( player )
|
||
end
|
||
end
|
||
end
|
||
|
||
--保存用户数据到Txt
|
||
function ServerManage:SaveUserToTxt( c2sData , s2cData )
|
||
local account = c2sData.account
|
||
local param = c2sData.param
|
||
local player = skynet.server.playerCenter:GetPlayerForAccount( account )
|
||
if not player then
|
||
s2cData.code = errorInfo.ErrorCode.NoExistUser
|
||
else
|
||
local basicInfo = player.basicInfo
|
||
local gameData = player.gameData
|
||
|
||
local file = io.open("UserData.txt", "a+")
|
||
file:write( account )
|
||
if param.isJson then
|
||
file:write( json:encode( basicInfo ))
|
||
file:write("\r\n")
|
||
file:write( json:encode( gameData ))
|
||
file:write("\r\n")
|
||
|
||
log.info(string.format("玩家 %s 强制将玩家数据以Json格式保存到Txt ", account ))
|
||
else
|
||
file:write( skynet.server.common:TableToString( basicInfo ))
|
||
file:write("\r\n")
|
||
file:write( skynet.server.common:TableToString( gameData ))
|
||
file:write("\r\n")
|
||
|
||
log.info(string.format("玩家 %s 强制将玩家数据以文本格式保存到Txt ", account ))
|
||
end
|
||
file:close()
|
||
end
|
||
end
|
||
|
||
--强制玩家下线
|
||
function ServerManage:ForceUserOffline( c2sData , s2cData)
|
||
local account = c2sData.account
|
||
local player = skynet.server.playerCenter:GetPlayerForAccount( account )
|
||
if not player then
|
||
s2cData.code = errorInfo.ErrorCode.NoExistUser
|
||
else
|
||
local sucSave = skynet.server.accountCenter:SavePlayerToMysql( player )
|
||
if sucSave then
|
||
log.info(string.format("玩家 %s 强制玩家下线并保存到Mysql成功", account ))
|
||
else
|
||
--强制失败,先存玩家的sql,如果无法组装数据,只能打印成文本
|
||
s2cData.code = errorInfo.ErrorCode.OpFailed
|
||
log.info(string.format("玩家 %s 强制玩家下线并保存到Mysql失败", account ))
|
||
skynet.server.accountCenter:SaveFailedPlayerDataToFile( player )
|
||
end
|
||
|
||
skynet.server.accountCenter:OfflineProcess( player )
|
||
end
|
||
end
|
||
|
||
--查询玩家在哪个游戏服
|
||
function ServerManage:QueryPlayerInServer( c2sData , s2cData )
|
||
local playerList = skynet.server.playerCenter:GetPlayerList()
|
||
for curUseId, value in pairs( playerList ) do
|
||
if curUseId == userId then
|
||
s2cData.data.isSuc = true
|
||
break
|
||
end
|
||
end
|
||
end
|
||
|
||
--更新游戏版本号
|
||
function ServerManage:UpdateGameVersion( s2cData )
|
||
skynet.server.redis:incr( redisKeyUrl.GameServerVersion )
|
||
end
|
||
|
||
--更新玩家数据(玩家可能在线,某种数据,导致无法数据落地,我们将进行修复)
|
||
function ServerManage:UpdateUserData( c2sData , s2cData )
|
||
local playerList = skynet.server.playerCenter:GetPlayerList()
|
||
for curUseId, v in pairs( playerList ) do
|
||
if curUseId == userId then
|
||
local resetKey = c2sData.resetKey
|
||
local resetValue = c2sData.resetValue
|
||
local listResetKey = skynet.server.common:Split( resetKey , ".")
|
||
local gameData = v.player[ c2sData.dataType ]
|
||
--s2cData.data.isSuc = true
|
||
break
|
||
end
|
||
end
|
||
end
|
||
|
||
--保存所有玩家数据到文件
|
||
function ServerManage:SaveAllUserDataToFile( c2sData , s2cData )
|
||
--保存玩家数据的文件列表
|
||
local fileList = {}
|
||
for i = 1, 5, 1 do
|
||
local fileName = string.format("ForceSaveUserDataToFile_%d_%d.txt", curServerId , i)
|
||
fileList[ i ] = io.open( fileName , "w+")
|
||
end
|
||
|
||
local playerList = skynet.server.playerCenter:GetPlayerList()
|
||
for curUseId, v in pairs( playerList ) do
|
||
function Do()
|
||
local basicInfo = v.player.basicInfo
|
||
local gameData = v.player.gameData
|
||
local dbIndex = basicInfo.dbIndex
|
||
local userId = basicInfo.userID
|
||
local account = basicInfo.accountName
|
||
|
||
local sql = string.format(sqlUrl.saveAccountToPlayer , json:encode(basicInfo) , json:encode(gameData) , userId )
|
||
sql = string.format("%s|%d|%s \r\n" , account, userId , sql)
|
||
fileList[ dbIndex ]:write( sql )
|
||
log.info(string.format("玩家 %d 成功保存玩家数据sql到文件", userId ))
|
||
end
|
||
|
||
local isDo,callData = pcall( Do )
|
||
if not isDo then
|
||
local errorText = "保存所有玩家数据到文件 失败"
|
||
if curUseId then
|
||
log.warning(errorText , curUseId , callData )
|
||
else
|
||
log.warning( errorText , callData)
|
||
end
|
||
end
|
||
end
|
||
|
||
for i = 1, 5, 1 do
|
||
fileList[ i ]:close()
|
||
end
|
||
end
|
||
|
||
--重启Timer
|
||
function ServerManage:ReStartTimer( c2sData , s2cData )
|
||
local timerType = c2sData.timerType
|
||
if 1 == timerType then
|
||
skynet.fork(skynet.SaveMongoDBTimer,500) --500
|
||
elseif 2 == timerType then
|
||
skynet.fork(skynet.SaveMysqlDBTimer,500) --500
|
||
end
|
||
|
||
log.info("重启Timer成功 TimerType" , timerType)
|
||
end
|
||
|
||
skynet.server.serverManage = ServerManage
|
||
return ServerManage |