HomeServer/Server/AllServer/GameServer/ServerManage.lua

365 lines
14 KiB
Lua
Raw Permalink Normal View History

2024-11-20 15:41:09 +08:00
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