You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

300 lines
11 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Sog;
using ProtoCSStruct;
namespace World
{
public static class GameReportSvc
{
//上报时间间隔,服务器启动的时候会变
private static int m_ReportAccountSecondInterVal = 5;
//最大上报时间间隔, 也不能太慢,realmList进程需要及时知道个game进程的online情况,用来做选择
private const int ReportAccountSecondInterValMax = 20;
private static long lastReportAccountTime = 0;
private static long lastLogOnlineTime = 0;
private static long lastForceGetAllRealmTime = 0;
public static int WorldOnlinePlayerCount { get; private set;}
//game或者gamegate的上报
public static void OnGameReportReq(uint remoteAppID, StructPacket packet)
{
ref SSGameReportReq gameReportReq = ref packet.GetMessage<SSGameReportReq>();
int onlinePlayer = gameReportReq.OnlinePlayer;
bool find = false;
var svrData = WorldServerUtils.GetWorldServerData();
foreach (var info in svrData.m_gameSvrInfo)
{
if (info.serverId == gameReportReq.GameSvrid)
{
info.onlinePlayer = onlinePlayer;
find = true;
break;
}
}
if (find == false)
{
svrData.m_gameSvrInfo.Add(new GameSvrInfoWorld {serverId = gameReportReq.GameSvrid, onlinePlayer = onlinePlayer});
}
//如果是game,要判断md5是否已经成功拉取
if (ServerIDUtils.GetServerType(gameReportReq.GameSvrid) == (int)ServerType.Game)
{
//如果有game进程没有获取成功RecvConfigRealmListMd5, 则强制全量拉取
if (gameReportReq.RecvConfigRealmListMd5.IsEmpty())
{
svrData.recvRealmListMd5 = null;
m_ReportAccountSecondInterVal = 2; //马上发起一次查询
TraceLog.Trace("SysSvc.OnGameReportReq from server {0}, RecvConfigRealmListMd5 is empty , force clear svrData.recvRealmListMd5"
, ServerIDUtils.IDToString(gameReportReq.GameSvrid));
}
}
TraceLog.Trace("SysSvc.OnGameReportReq from server {0}, online {1}"
, ServerIDUtils.IDToString(gameReportReq.GameSvrid)
, gameReportReq.OnlinePlayer);
}
public static void OnRealmOnlineReport(uint remoteAppID, StructPacket packet)
{
ref SSOnlineReport report = ref packet.GetMessage<SSOnlineReport>();
var onlineTable = WorldServerUtils.GetWorldServerData().realmOnlineGame;
// 一个realm可以分布在多个gamesvr上, 一个gamesvr可以有多个realm
// 统计每个gamesvr上的realm在线信息, 然后在tick时累加获得realm的实际在线
List<RealmOnline> gameSvrOnline;
if (! onlineTable.TryGetValue(remoteAppID, out gameSvrOnline))
{
gameSvrOnline = new List<RealmOnline>();
onlineTable.Add(remoteAppID, gameSvrOnline);
}
for (int i = 0; i < report.RealmOnline.Count; i++)
{
int realmId = report.RealmOnline[i].Id;
int onlineNum = report.RealmOnline[i].Value;
RealmOnline info = gameSvrOnline.FirstOrDefault(d => d.realmId == realmId);
if (info != null)
{
info.onlineNum = onlineNum;
}
else
{
info = new RealmOnline {realmId = realmId, onlineNum = onlineNum};
gameSvrOnline.Add(info);
}
}
}
public static void OnGameReportRealmlistRes(uint remoteAppID, StructPacket packet)
{
//备机不处理
if(AccountServerSelect.IsBackAccountServer(remoteAppID))
{
return;
}
ref SSGameReportRealmlistRes res = ref packet.GetMessage<SSGameReportRealmlistRes>();
var serverData = WorldServerUtils.GetWorldServerData();
//需要这个临时保存列表,是为了防止2个消息过程中有不完整的configRealm的情况发生
var tmpRealmsRecv = serverData.m_configRealmTempForRecv;
//0 表示realmList服务器还没有更新,是老的, 1表示是新的realmList发出的第一个消息
if (res.MsgIndexFrom1 == 0 || res.MsgIndexFrom1 == 1)
{
tmpRealmsRecv.Clear();
}
//先加入临时列表
for (int i = 0; i < res.RealmList.Count; i++)
{
var realm = new RealmBriefInfo(ref res.RealmList[i]);
tmpRealmsRecv[realm.realmId] = realm;
}
//如果是最后一个消息了
if (res.MsgIndexFrom1 == 0 || res.RealmList.Count == 0)
{
serverData.m_configRealm.Clear();
serverData.m_configRealmMap.Clear();
var recordInfo = WorldServerUtils.GetWorldMainlandRecordData();
//排个序
var list = tmpRealmsRecv.OrderBy(o => o.Key).ToList();
for (int i = 0; i < list.Count; i++)
{
var realm = list[i].Value;
serverData.m_configRealm.Add(realm);
serverData.m_configRealmMap.Add(realm.realmId, realm);
if (!recordInfo.m_logicWorldMap.ContainsKey(realm.logicWorldId))
{
}
}
serverData.recvRealmListMd5 = res.RealmListMd5.GetString();
}
TraceLog.Trace("GameReportSvc.OnGameReportRealmlistRes m_configRealm count {0}, m_configRealmTempForRecv count {1}",
serverData.m_configRealm.Count, serverData.m_configRealmTempForRecv.Count);
//广播给所有game
WorldServerUtils.GetPacketSender().Broadcast<SSGameReportRealmlistRes>((int)ServerType.Game, packet);
}
public static void OnTick(long nowSec)
{
TickNotifyAccountGateCount(nowSec);
TickLogOnlineReportWorldOnline(nowSec);
}
public static void TickNotifyAccountGateCount(long nowSec)
{
if (nowSec - lastReportAccountTime < m_ReportAccountSecondInterVal)
{
return;
}
lastReportAccountTime = nowSec;
if (m_ReportAccountSecondInterVal < ReportAccountSecondInterValMax)
{
m_ReportAccountSecondInterVal += 1;
}
var reportReq = new SSGameReportRealmlistReq();
var svrData = WorldServerUtils.GetWorldServerData();
int iAllServerOnlinePlayer = 0;
foreach (var info in svrData.m_gameSvrInfo)
{
if (ServerIDUtils.GetServerType(info.serverId) == (int)ServerType.Game)
{
iAllServerOnlinePlayer += info.onlinePlayer;
}
if(ServerIDUtils.GetServerType(info.serverId) == (int)ServerType.GameGate ||
ServerIDUtils.GetServerType(info.serverId) == (int)ServerType.ChatGate)
{
GameGateSvrInfo gateInfo;
gateInfo.GateSvrid = info.serverId;
gateInfo.OnlinePlayer = info.onlinePlayer;
reportReq.Gates.Add(ref gateInfo);
}
}
//上报world的在线(包括gate的连接数量)给account->realmlist,
reportReq.OnlinePlayer = iAllServerOnlinePlayer;
reportReq.WorldSvrid = WorldServerUtils.GetAppID();
//为了以防万一,每10分钟强制拉一次全量
if (nowSec - lastForceGetAllRealmTime >= 600)
{
lastForceGetAllRealmTime = nowSec;
}
else
{
reportReq.RealmListMd5.SetString(svrData.recvRealmListMd5);
}
// 广播给主机和备机上的RealmsList
WorldServerUtils.GetPacketSender().Broadcast((int)ServerType.RealmsList, (int)SSMsgID.GameReportRealmlistReq, ref reportReq, 0 , 0);
WorldOnlinePlayerCount = iAllServerOnlinePlayer;
}
public static void TickLogOnlineReportWorldOnline(long nowSec)
{
//1分钟1次就行了,其实也没啥用
if (nowSec - lastLogOnlineTime < 60)
{
return;
}
lastLogOnlineTime = nowSec;
var svrData = WorldServerUtils.GetWorldServerData();
int iAllServerOnlinePlayer = 0;
foreach (var info in svrData.m_gameSvrInfo)
{
if (ServerIDUtils.GetServerType(info.serverId) == (int)ServerType.Game)
{
iAllServerOnlinePlayer += info.onlinePlayer;
}
}
//上报全服人数
// 写 bill 日记
WorldBillLogUtils.LogOnlinePlayer(iAllServerOnlinePlayer);
}
// 统计每个realm的在线数据
public static void TickRealmOnline()
{
var allOnline = WorldServerUtils.GetWorldServerData().realmOnlineAll;
allOnline.Clear();
var gameOnline = WorldServerUtils.GetWorldServerData().realmOnlineGame;
// 把不同gamesvr上的同一个realm的在线人数累加起来
foreach (List<RealmOnline> realmList in gameOnline.Values)
{
foreach (RealmOnline realmOne in realmList)
{
if (! allOnline.ContainsKey(realmOne.realmId))
{
allOnline[realmOne.realmId] = realmOne.onlineNum;
}
else
{
allOnline[realmOne.realmId] += realmOne.onlineNum;
}
}
}
SSRealmOnlinePlayerToOpsvr req = new SSRealmOnlinePlayerToOpsvr();
foreach (KeyValuePair<int, int> kvp in allOnline)
{
RealmOnlineInfo info = new RealmOnlineInfo();
info.RealmID = kvp.Key;
info.OnlinePlayer = kvp.Value;
if (req.RealmList.Count < req.RealmList.GetMaxCount())
{
req.RealmList.Add(info);
}
else
{
// 同步发送到 op
WorldServerUtils.GetPacketSender().Broadcast((int)ServerType.Operation, (int)SSMsgID.RealmOnlineplayerToOpsvr, ref req, 0, 0);
req.RealmList.Clear();
req.RealmList.Add(info);
}
}
if (req.RealmList.Count > 0)
{
// 同步发送到 op
WorldServerUtils.GetPacketSender().Broadcast((int)ServerType.Operation, (int)SSMsgID.RealmOnlineplayerToOpsvr, ref req, 0, 0);
}
}
}
}