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
|