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.
 
 
 
 
 
 

1136 lines
46 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using Org.BouncyCastle.Ocsp;
using ProtoCSStruct;
using Sog;
namespace Realmlist
{
public class RealmConfigOneForCheck
{
public RealmConfigOne realmConfig;
public int worldId;
public string area;
}
public static class RealmlistSvc
{
public static string defaultAreaName = "SEA";
public static int realmNumPerPage = 10;
// realm 配置
public static RealmListConfig realmListConfig;
// 以大区组织的realm信息
public static Dictionary<string, AreaRealm> areaDict = new Dictionary<string, AreaRealm>();
// 以world组织的realm信息
public static Dictionary<int, WorldInfo> worldDict = new Dictionary<int, WorldInfo>();
private static int GetAllRealm(RealmListConfig config, Dictionary<int, RealmConfigOneForCheck> realmMap)
{
if(config == null)
{
return 0;
}
foreach (var area in config.areaRealmList)
{
if(area.worldList == null)
{
continue;
}
foreach(var world in area.worldList)
{
if(world.realmList == null)
{
continue;
}
foreach(var realm in world.realmList)
{
if (realmMap.ContainsKey(realm.realmId))
{
TraceLog.Error("RealmListSvc.GetAllRealm realm id {0} repeated!", realm.realmId);
return -1;
}
RealmConfigOneForCheck configForCheck = new RealmConfigOneForCheck();
configForCheck.realmConfig = realm;
configForCheck.area = area.areaName;
configForCheck.worldId = world.worldId;
realmMap.Add(realm.realmId, configForCheck);
}
}
}
return 0;
}
private static int CheckRealmListConfig(RealmListConfig config, RealmListConfig oldconfig, out int allRealmCount)
{
allRealmCount = 0;
Dictionary<int, RealmConfigOneForCheck> realmMapOld = new Dictionary<int, RealmConfigOneForCheck>();
Dictionary<int, RealmConfigOneForCheck> realmMapNew = new Dictionary<int, RealmConfigOneForCheck>();
int ret = 0;
ret = GetAllRealm(oldconfig, realmMapOld);
if(ret != 0)
{
TraceLog.Error("CheckRealmListConfig GetAllRealm old error {0}", ret);
return -1;
}
ret = GetAllRealm(config, realmMapNew);
if (ret != 0)
{
TraceLog.Error("CheckRealmListConfig GetAllRealm new error {0}", ret);
return -1;
}
allRealmCount = realmMapNew.Count;
if (!RealmlistServerUtils.GetServerConfig().checkRealmListFile)
{
TraceLog.Debug("CheckRealmListConfig checkRealmListFile is false, need not to check");
return 0;
}
TraceLog.Debug("CheckRealmListConfig checkRealmListFile is true, need to check");
TraceLog.Debug("begin check realm ");
Dictionary<string, RealmConfigOneForCheck> nameMap = new Dictionary<string, RealmConfigOneForCheck>();
foreach (var realm in realmMapNew.Values)
{
if (nameMap.ContainsKey(realm.realmConfig.name))
{
TraceLog.Error("CheckRealmListConfig check name {0} repeated", realm.realmConfig.name);
return -1;
}
nameMap.Add(realm.realmConfig.name, realm);
}
//worldid, seq
Dictionary<int, Dictionary<int, RealmConfigOneForCheck>> worldMap = new Dictionary<int, Dictionary<int, RealmConfigOneForCheck>>();
foreach (var realm in realmMapNew.Values)
{
if (!worldMap.ContainsKey(realm.worldId))
{
Dictionary<int, RealmConfigOneForCheck> newworldRealms = new Dictionary<int, RealmConfigOneForCheck>();
worldMap.Add(realm.worldId, newworldRealms);
}
Dictionary<int, RealmConfigOneForCheck> worldRealms = worldMap[realm.worldId];
if(worldRealms.ContainsKey(realm.realmConfig.showSeq))
{
TraceLog.Error("CheckRealmListConfig check seq {0} repeated realmId {1} name {2}",
realm.realmConfig.showSeq, realm.realmConfig.realmId, realm.realmConfig.name);
return -1;
}
worldRealms.Add(realm.realmConfig.showSeq, realm);
}
List<RealmConfigOneForCheck> newRealList = new List<RealmConfigOneForCheck>();
foreach(var realm in realmMapNew)
{
if(realmMapOld.ContainsKey(realm.Key) == false)
{
newRealList.Add(realm.Value);
}
}
//这个是新添加的realm
foreach (var realmForCheck in newRealList)
{
var realm = realmForCheck.realmConfig;
//注释掉的原因:老玩家回流到特定服务器需要指定特定名称
// if (realm.name.Contains(realm.showSeq.ToString()) == false)
// {
// TraceLog.Error("realm {0} {1} showSeq {2} must == name id", realm.realmId, realm.name, realm.showSeq);
// return -1;
// }
if(string.IsNullOrEmpty(realm.visibleTime))
{
TraceLog.Error("realm {0} {1} visibleTime must config", realm.realmId, realm.name);
return -1;
}
// string jp_openTime = "00:00:00";
// if (realm.openTime.Contains(jp_openTime) == false)
// {
// TraceLog.Error("realm {0} {1} openTime {2} must be {3}", realm.realmId, realm.name, realm.openTime, jp_openTime);
// return -1;
// }
long openTime = ConfigStringTimeParse.ParseConfigTime(realm.openTime);
long visiableTime = ConfigStringTimeParse.ParseConfigTime(realm.visibleTime);
if(visiableTime < openTime)
{
TraceLog.Error("realm {0} {1} openTime {2} must < visiableTime {3}", realm.realmId, realm.name, realm.openTime, realm.visibleTime);
return -1;
}
if(openTime == 0)
{
TraceLog.Error("realm {0} {1} openTime {2} invalid", realm.realmId, realm.name, realm.openTime);
return -1;
}
if(realm.bdcName != realm.realmId.ToString())
{
TraceLog.Error("realm {0} {1} bdcName {2} must == realmId", realm.realmId, realm.name, realm.bdcName);
return -1;
}
//新增加的realmId必须和worldId匹配,老的配置可以不管
if (realm.realmId / 1000 != realmForCheck.worldId)
{
TraceLog.Error("realm {0} {1} realmId must match worldId {2}", realm.realmId, realm.name, realmForCheck.worldId);
return -1;
}
//logicWorld配置有问题
if (realm.logicWorldId / 100 != realmForCheck.worldId)
{
TraceLog.Error("realm {0} {1} logicWorldId {2} error worldId {3}", realm.realmId, realm.name, realm.logicWorldId, realmForCheck.worldId);
return -1;
}
int minBigRealmId = 1000000;
if (realm.bigRealmId < minBigRealmId)
{
TraceLog.Error("realm {0} {1} bigRealmId {2} must > {3}", realm.realmId, realm.name, realm.bigRealmId, minBigRealmId);
return -1;
}
//判断一下开服时间,是不是最近才配置上的
bool newAddRealm = false;
if(RealmlistServerUtils.GetTimeSecond() - openTime < 3600 * 24)
{
newAddRealm = true;
}
//新加的bigrealmId必须符合规则,老的就算了
if (newAddRealm && realm.bigRealmId / 10000 != realmForCheck.worldId)
{
TraceLog.Error("realm {0} {1} bigRealmId must match worldId {2}", realm.realmId, realm.name, realmForCheck.worldId);
return -1;
}
}
//检查bigRealm
Dictionary<int, List<int>> bigRealmList = new Dictionary<int, List<int>>();
foreach (var it in realmMapNew)
{
if (!bigRealmList.ContainsKey(it.Value.realmConfig.bigRealmId))
{
bigRealmList.Add(it.Value.realmConfig.bigRealmId, new List<int>());
}
bigRealmList[it.Value.realmConfig.bigRealmId].Add(it.Value.realmConfig.realmId);
}
foreach (var oneBigRealmList in bigRealmList.Values)
{
int logicWorldId = 0;
int worldId = 0;
foreach(int oneRealmId in oneBigRealmList)
{
if (realmMapNew.ContainsKey(oneRealmId))
{
int tmpWorldId = realmMapNew[oneRealmId].worldId;
if (worldId == 0)
{
worldId = tmpWorldId;
}
if (tmpWorldId == 0 || worldId != tmpWorldId)
{
TraceLog.Error("Check BigRealm realm {0} error worldId {1} head worldId {2}", oneRealmId, tmpWorldId, worldId);
return -1;
}
int tmpLogicWorldId = realmMapNew[oneRealmId].realmConfig.logicWorldId;
if (logicWorldId == 0)
{
logicWorldId = tmpLogicWorldId;
}
if(tmpLogicWorldId == 0 || logicWorldId != tmpLogicWorldId)
{
TraceLog.Error("Check BigRealm realm {0} error logicWorldId {1} head logicWorldId {2}", oneRealmId, tmpLogicWorldId, logicWorldId);
return -1;
}
}
}
}
TraceLog.Debug("end check realm ");
return 0;
}
// 读取realmlist.json配置
public static void ReadRealmListConfig(ServerApp app, string path, bool notSave = false)
{
var svrData = RealmlistServerUtils.GetRealmlistServerData();
RealmListConfig newConfig = JsonConfig.ParseAppConfigFileAndReplaceVariable<RealmListConfig>(app, path);
int ret = CheckRealmListConfig(newConfig, realmListConfig, out int allRealmCount);
if (ret != 0)
{
string strErrorMessage = string.Format("**************RealmlistSvc.ReadRealmListConfig CheckRealmListConfig failed ret {0}", ret);
TraceLog.Error(strErrorMessage);
RealmlistServerUtils.GetApp().Alerter.AlertMsg(strErrorMessage);
//启动的时候,检查出错,直接异常
if(realmListConfig == null)
{
throw new Exception(strErrorMessage);
}
return;
}
SSRealmBriefRes realmBriefRes = new SSRealmBriefRes();
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig ream count {0} realmBriefRes.RealmList.GetMaxCount() {1}"
, allRealmCount, realmBriefRes.RealmList.GetMaxCount());
realmListConfig = newConfig;
// reloadconfig 时重新生成索引数据
areaDict.Clear();
worldDict.Clear();
foreach (AreaRealmList area in realmListConfig.areaRealmList)
{
if (string.IsNullOrEmpty(area.areaName))
{
TraceLog.Error("RealmlistSvc.ReadRealmListConfig error, areaName is null, use default {0}", defaultAreaName);
area.areaName = defaultAreaName;
}
if (! areaDict.TryGetValue(area.areaName, out AreaRealm areaRealm))
{
areaRealm = new AreaRealm {
areaName = area.areaName,
timezone = area.timezone,
visibleOnlyCliVersion = area.visibleOnlyCliVersion,
visibleOnlyWhiteList = area.visibleOnlyWhiteList,
shareShowAreaRealmList = area.shareShowAreaRealmList,
invisibleAreaForNewUser = area.invisibleAreaForNewUser,
maintenanceMode = area.maintenanceMode
};
areaDict[area.areaName] = areaRealm;
if(areaRealm.maintenanceMode)
{
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig ream {0} is on maintenanceMode", areaRealm.areaName);
}
}
SortedList<int, RealmInfo> sortedRealm = new SortedList<int, RealmInfo>();
foreach (WorldRealmInfo world in area.worldList)
{
// 每个大区的world信息
if (! areaRealm.areaWorldDict.TryGetValue(world.worldId, out var worldInfo))
{
worldInfo = new WorldInfo {areaName = area.areaName, worldId = world.worldId};
for (int i = 0; i < world.gate.Length; i++)
{
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig worldId {0} game gate {1} url {2}",
world.worldId, i, world.gate[i]);
uint gateId = ServerIDUtils.MakeServerID(world.worldId, (int)ServerType.GameGate, i + 1);
GameGateInfo gateInfo = new GameGateInfo { url = world.gate[i], index = i, gatesvrId = gateId};
// 这么写其实有点风险, 需要gate instId 跟随监听端口自增, 但目前只能这么处理
if (svrData.gateOnlineDict.TryGetValue(gateId, out int online))
{
gateInfo.online = online;
}
worldInfo.gameGates.Add(gateInfo);
}
for (int i = 0; i < world.chatGate.Length; i++)
{
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig worldId {0} chat gate {1} url {2}",
world.worldId, i, world.chatGate[i]);
uint gateId = ServerIDUtils.MakeServerID(world.worldId, (int)ServerType.ChatGate, i + 1);
GameGateInfo gateInfo = new GameGateInfo{ url = world.chatGate[i], index = i, gatesvrId = gateId };
// 这么写其实有点风险, 需要gate instId 跟随监听端口自增, 但目前只能这么处理
if (svrData.gateOnlineDict.TryGetValue(gateId, out int online))
{
gateInfo.online = online;
}
worldInfo.chatGates.Add(gateInfo);
}
// 大区的world信息
areaRealm.areaWorldDict[world.worldId] = worldInfo;
//允许不同的大区配置在同一个world
if (worldDict.ContainsKey(world.worldId) == false)
// 全服的world信息
{
worldDict[world.worldId] = worldInfo;
}
}
WorldInfo globleWorldInfo = worldDict[world.worldId];
List<int> realmIdInDBCfg = new List<int>();
if (svrData.dbRealmConfigs != null && svrData.dbRealmConfigs.Count > 0)
{
foreach( var dbcfgOne in svrData.dbRealmConfigs.Values)
{
if (string.IsNullOrEmpty(dbcfgOne.AreaName.ToString()))
{
TraceLog.Error("RealmlistSvc.ReadRealmListConfig error, areaName is null, use default {0}", defaultAreaName);
dbcfgOne.AreaName.SetString(defaultAreaName);
}
if (dbcfgOne.AreaName.ToString() != areaRealm.areaName
|| dbcfgOne.WorldId != worldInfo.worldId)
{
continue;
}
RealmConfigOne NewConfig = new RealmConfigOne()
{
realmId = dbcfgOne.RealmId,
name = dbcfgOne.RealmName.ToString(),
showSeq = dbcfgOne.ShowSeq,
status = dbcfgOne.Status,
bdcName = dbcfgOne.BdcName.ToString(),
openTime = dbcfgOne.OpenTime.ToString(),
visibleOnlyWhiteList = dbcfgOne.VisibleOnlyWhiteList,
visibleTime = dbcfgOne.VisibleTime.ToString(),
bigRealmId = dbcfgOne.BigRealmId,
logicWorldId = dbcfgOne.LogicWorldId,
regMax = dbcfgOne.RegMax,
};
RealmInfo realmInfo = new RealmInfo
{
realmId = dbcfgOne.RealmId,
logicWorldId = dbcfgOne.LogicWorldId,
worldId = dbcfgOne.WorldId,
config = NewConfig,
ip = area.areaIP,
runtimeState = 1, // 初始都是open
openTimeSec = ConfigStringTimeParse.ParseConfigTimeWithTimeZone(
dbcfgOne.OpenTime.ToString(), AppTime.TimeZone, area.timezone),
visibleTimeSec = ConfigStringTimeParse.ParseConfigTimeWithTimeZone(
dbcfgOne.VisibleTime.ToString(), AppTime.TimeZone, area.timezone),
};
realmIdInDBCfg.Add(realmInfo.config.realmId);
// 记录每个world上的realmInfo
worldInfo.worldRealms.Add(realmInfo.config.realmId, realmInfo);
if (globleWorldInfo.worldRealms.ContainsKey(realmInfo.config.realmId) == false)
{
globleWorldInfo.worldRealms.Add(realmInfo.config.realmId, realmInfo);
}
// 记录同一时间可见的realmInfo
if (!areaRealm.visibleRealmGroup.TryGetValue(realmInfo.visibleTimeSec, out RealmGroup realmGroup))
{
realmGroup = new RealmGroup { visibleTime = realmInfo.visibleTimeSec };
areaRealm.visibleRealmGroup.Add(realmInfo.visibleTimeSec, realmGroup);
}
realmGroup.realmList.Add(realmInfo);
// 根据realmId排序的realmInfo, 用于分页拉取
sortedRealm.Add(realmInfo.config.showSeq, realmInfo);
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig realmId {0} worldId {1} name {2} cliVer {3} whiteList {4} openTime {5} visableTime {6}",
realmInfo.realmId,
realmInfo.worldId,
realmInfo.config.name,
realmInfo.config.visibleOnlyCliVersion,
realmInfo.config.visibleOnlyWhiteList,
realmInfo.config.openTime,
realmInfo.config.visibleTime);
}
}
foreach (RealmConfigOne realmCfg in world.realmList)
{
//用DB里面的数据
if (realmIdInDBCfg.Contains(realmCfg.realmId))
{
continue;
}
RealmInfo realmInfo = new RealmInfo
{
realmId = realmCfg.realmId,
logicWorldId = realmCfg.logicWorldId,
worldId = world.worldId,
config = realmCfg,
ip = area.areaIP,
runtimeState = 1, // 初始都是open
openTimeSec = ConfigStringTimeParse.ParseConfigTimeWithTimeZone(
realmCfg.openTime, AppTime.TimeZone, area.timezone),
visibleTimeSec = ConfigStringTimeParse.ParseConfigTimeWithTimeZone(
realmCfg.visibleTime, AppTime.TimeZone, area.timezone),
};
//if (svrData.realmOnlineDict.TryGetValue(realmCfg.realmId, out int online))
//{
// realmInfo.online = online;
//}
// 记录每个world上的realmInfo
worldInfo.worldRealms.Add(realmInfo.config.realmId, realmInfo);
if(globleWorldInfo.worldRealms.ContainsKey(realmInfo.config.realmId) == false)
{
globleWorldInfo.worldRealms.Add(realmInfo.config.realmId, realmInfo);
//TraceLog.Debug("RealmlistSvc.ReadRealmListConfig add globleWorldInfo world {0} realm {1}", world.worldId, realmInfo.realmId);
}
// 记录同一时间可见的realmInfo
if (! areaRealm.visibleRealmGroup.TryGetValue(realmInfo.visibleTimeSec, out RealmGroup realmGroup))
{
realmGroup = new RealmGroup {visibleTime = realmInfo.visibleTimeSec };
areaRealm.visibleRealmGroup.Add(realmInfo.visibleTimeSec, realmGroup);
}
realmGroup.realmList.Add(realmInfo);
if (!notSave)
{
OneDBRealmConfig configOne = new OneDBRealmConfig()
{
//AreaName = area.areaName,
WorldId = worldInfo.worldId,
RealmId = realmInfo.config.realmId,
//RealmName = realmInfo.config.name,
ShowSeq = realmInfo.config.showSeq,
Status = realmInfo.config.status,
//BdcName = realmInfo.config.bdcName,
//OpenTime = realmInfo.config.openTime,
VisibleOnlyWhiteList = realmInfo.config.visibleOnlyWhiteList,
//VisibleTime = realmInfo.config.visibleTime,
BigRealmId = realmInfo.config.bigRealmId,
LogicWorldId = realmInfo.config.logicWorldId,
RegMax = realmInfo.config.regMax,
};
configOne.AreaName.SetString(area.areaName);
configOne.RealmName.SetString(realmInfo.config.name);
configOne.BdcName.SetString(realmInfo.config.bdcName);
configOne.OpenTime.SetString(realmInfo.config.openTime);
configOne.VisibleTime.SetString(realmInfo.config.visibleTime);
RealmlistDBSvc.AutoSaveRealmInFile(configOne);
}
// group总在线人数
//realmGroup.groupOnline += realmInfo.online;
// group平均在线人数
//realmGroup.avgOnline = realmGroup.groupOnline / realmGroup.realmList.Count;
//// group最少在线
//if (realmGroup.minOnline == null || realmInfo.online < realmGroup.minOnline.online)
//{
// realmGroup.minOnline = realmInfo;
//}
//// group最多在线
//if (realmGroup.maxOnline == null || realmInfo.online > realmGroup.maxOnline.online)
//{
// realmGroup.maxOnline = realmInfo;
//}
// 根据realmId排序的realmInfo, 用于分页拉取
sortedRealm.Add(realmInfo.config.showSeq, realmInfo);
TraceLog.Debug("RealmlistSvc.ReadRealmListConfig realmId {0} worldId {1} name {2} cliVer {3} whiteList {4} openTime {5} visableTime {6}",
realmInfo.realmId,
realmInfo.worldId,
realmInfo.config.name,
realmInfo.config.visibleOnlyCliVersion,
realmInfo.config.visibleOnlyWhiteList,
realmInfo.config.openTime,
realmInfo.config.visibleTime);
}
}
// 更新信息
foreach (RealmInfo realm in sortedRealm.Values)
{
AddRealm(areaRealm, realm);
}
}
//读取完了设置一下共享area, 屏蔽area
foreach(var area in areaDict.Values)
{
if(string.IsNullOrEmpty(area.shareShowAreaRealmList) == false)
{
var shareArea = areaDict[area.shareShowAreaRealmList];
if(shareArea == null)
{
TraceLog.Error("can not find area.addShowAreaRealmList {0} in config", area.shareShowAreaRealmList);
continue;
}
area.shareShowAreaRealm = shareArea;
}
if (string.IsNullOrEmpty(area.invisibleAreaForNewUser) == false)
{
string[] invisibleAreas = area.invisibleAreaForNewUser.Split('|');
foreach (var invisibleArea in invisibleAreas)
{
foreach (var otherarea in areaDict.Values)
{
if (otherarea.areaName == invisibleArea)
{
area.invisibleAreaForNewUserList.Add(otherarea);
break;
}
}
}
}
}
long nowSec = RealmlistServerUtils.GetTimeSecond();
UpdateRealmStatus(nowSec);
}
/// <summary>
///
/// </summary>
/// <param name="nowSec"></param>
/// <param name="area"></param>
/// <returns>是否发现新服</returns>
private static bool UpdateRealmStatus(long nowSec, AreaRealm area)
{
int newFlag = 0;
foreach (RealmGroup group in area.visibleRealmGroup.Values)
{
// 至少要找到1个不在白名单限制中的realm, 该组才进行new的判断, 否则白名单中的区服会影响普通玩家的new显示
if (nowSec >= group.visibleTime
&& group.realmList.FirstOrDefault(r => r.config.visibleOnlyWhiteList == 0) != null)
{
if (newFlag == 0)
{
foreach (RealmInfo realm in group.realmList)
{
realm.runtimeState |= (uint)RealmState.New;
}
newFlag = 1;
}
else
{
foreach (RealmInfo realm in group.realmList)
{
realm.runtimeState &= (~((uint)RealmState.New));
}
}
}
}
return newFlag == 1;
}
// 1. 有新服开启时, 把老服的new flag去掉
// 2. realm的维护标记
public static void UpdateRealmStatus(long nowSec)
{
foreach (AreaRealm area in areaDict.Values)
{
bool hasFindNewFlagAlready = false;
if (area.shareShowAreaRealm != null)
{
hasFindNewFlagAlready = UpdateRealmStatus(nowSec, area.shareShowAreaRealm);
}
if(hasFindNewFlagAlready == false)
{
UpdateRealmStatus(nowSec, area);
}
else
{
//共享里找到新服了,那么这个area肯定全部是老服
foreach (RealmGroup group in area.visibleRealmGroup.Values)
{
if (nowSec >= group.visibleTime)
{
foreach (RealmInfo realm in group.realmList)
{
realm.runtimeState &= (~((uint)RealmState.New));
}
}
}
}
UpdateRealmStatusOpen(area);
}
}
private static void UpdateRealmStatusOpen(AreaRealm area)
{
foreach (RealmGroup group in area.visibleRealmGroup.Values)
{
foreach (RealmInfo realm in group.realmList)
{
if(area.maintenanceMode)
{
realm.runtimeState &= (~((uint)RealmState.Open));
}
else
{
realm.runtimeState |= (uint)RealmState.Open;
if (RealmlistServerUtils.GetRealmlistServerData().dbRealmConfigs.ContainsKey(realm.realmId))
{
if (RealmlistServerUtils.GetRealmlistServerData().dbRealmConfigs[realm.realmId].RegNum >=
RealmlistServerUtils.GetRealmlistServerData().dbRealmConfigs[realm.realmId].RegMax)
{
realm.runtimeState |= (uint)RealmState.Full;
}
}
}
}
}
}
public static AreaRealm GetAreaByTimezone(int timezone, string ip,string deviceId)
{
AreaRealm select = null;
int min = int.MaxValue;
foreach (AreaRealm area in areaDict.Values)
{
//ip白名单判断
if (area.visibleOnlyWhiteList == 1 && !LimitIPList.IsInWhiteList(ip, deviceId))
{
continue;
}
int diff = Math.Abs(timezone - area.timezone);
if (diff < min)
{
min = diff;
select = area;
}
}
return select;
}
public static int AddRealm(AreaRealm area, RealmInfo realm)
{
if (area.realmIndex.TryGetValue(realm.config.realmId, out int idx))
{
TraceLog.Error("RealmlistSvc.AddRealm area {0} dumplicate realmId {1}"
, area.areaName, realm.config.realmId);
return -1;
}
area.sortedRealms.Add(realm);
area.realmIndex.Add(realm.config.realmId, area.sortedRealms.Count - 1);
return 0;
}
public static RealmInfo GetRealm(AreaRealm area, int realmId)
{
if (area.realmIndex.TryGetValue(realmId, out int realmIdx))
{
var realm = area.sortedRealms[realmIdx];
if (realm.realmId == realmId)
{
return realm;
}
TraceLog.Error("RealmlistSvc.GetRealm realmId {0} req {1} not match", realm.realmId, realmId);
}
return null;
}
public static RealmInfo GetRealm(int realmId)
{
foreach (AreaRealm area in areaDict.Values)
{
if (area.realmIndex.TryGetValue(realmId, out int realmIdx))
{
var realm = area.sortedRealms[realmIdx];
if (realm.realmId == realmId)
{
return realm;
}
}
}
TraceLog.Error("RealmlistSvc.GetRealm realmId {0} not exist", realmId);
return null;
}
public static AreaRealm GetAreaByRealmId(int realmId)
{
foreach (AreaRealm area in areaDict.Values)
{
if (area.realmIndex.TryGetValue(realmId, out int realmIdx))
{
return area;
}
}
return null;
}
public static bool CheckCanVisibleRealmByClintVerIp(RealmInfo realm, string clientVer, string ip, string deviceId)
{
//如果配置了特殊版本
if (!string.IsNullOrEmpty(realm.config.visibleOnlyCliVersion)
&& realm.config.visibleOnlyCliVersion != clientVer)
{
return false;
}
//如果强制配置成ip白名单可见,那么不在名单里的肯定不可见
if (realm.config.visibleOnlyWhiteList == 1 && !LimitIPList.IsInWhiteList(ip, deviceId))
{
return false;
}
return true;
}
private static RealmGroup FindLastVisibleGroup(SortedList<long, RealmGroup> groupList, string clientVer, string ip, List<RealmInfo> list, string deviceId)
{
var nowSec = RealmlistServerUtils.GetTimeSecond();
RealmGroup realmGroup = null;
foreach (KeyValuePair<long, RealmGroup> pair in groupList)
{
if (nowSec >= pair.Key)
{
realmGroup = pair.Value;
for (int i = 0; i < realmGroup.realmList.Count; i++)
{
var realm = realmGroup.realmList[i];
if(CheckCanVisibleRealmByClintVerIp(realm, clientVer, ip, deviceId) == false)
{
continue;
}
list.Add(realm);
}
if (list.Count > 0)
{
break;
}
}
}
return realmGroup;
}
// newUser 是否是新用户
public static RealmInfo GetRecommendRealm(AreaRealm area, string clientVer, string ip, bool newUser, string deviceId)
{
//这个是根据时间从晚到早排序的,就是开服时间从大到小
List<RealmInfo> list = new List<RealmInfo>();
RealmGroup realmGroup = null;
//先处理共享,现在的逻辑是共享的开服时间一定在后面,如果以后改成任意配置添加(一会儿共享加个服,一个原来的区加个服,那么再改代码)
if(area.shareShowAreaRealm != null)
{
realmGroup = FindLastVisibleGroup(area.shareShowAreaRealm.visibleRealmGroup, clientVer, ip, list, deviceId);
}
//共享area里找不到,再找原来的area
if (realmGroup == null || list.Count == 0)
{
realmGroup = FindLastVisibleGroup(area.visibleRealmGroup, clientVer, ip, list, deviceId);
}
// 没有服务器可见, 都没开服?
if (realmGroup == null || list.Count == 0)
{
TraceLog.Error("RealmlistSvc.GetRecommendRealm area {0} no realm visible now", area.areaName);
return null;
}
TraceLog.Trace("RealmlistSvc.GetRecommendRealm area {0} realmGroup orderIdxForNewUser {1} orderIdxForOldUser {2} visibleTime {3}"
, area.areaName, realmGroup.orderIdxForNewUser, realmGroup.orderIdxForOldUser, realmGroup.visibleTime);
// 只有一个区
if (list.Count == 1)
{
return list[0];
}
// 人数最少的区小于平均值90%, 推荐人数最少的区, avgOnlineDiff每分钟更新一次
//if (realmGroup.avgOnlineDiff > 0)
//{
// realmGroup.avgOnlineDiff--;
// return realmGroup.minOnline;
//}
for (int i = 0; i < list.Count; i++)
{
//获取负载均衡idx
int orderIdx = GetLoadBalancingOrderIdx(realmGroup, newUser);
int _realmIdx = orderIdx % list.Count;
var realm = list[_realmIdx];
//关闭推荐的跳过
if (realm.config != null && realm.config.isCloseRecommend > 0)
{
continue;
}
return realm;
}
//一般不会走到这里
TraceLog.Error("RealmlistSvc.GetRecommendRealm err area {0} list {1}"
, area.areaName, list.Count);
//这里给个推荐区,客户端没推荐区服会卡死
return list[0];
}
private static int GetLoadBalancingOrderIdx(RealmGroup realmGroup, bool newUser)
{
//// 顺序推荐,新老用户分开
int orderIdx = 0;
if (newUser)
{
orderIdx = realmGroup.orderIdxForNewUser;
realmGroup.orderIdxForNewUser++;
if (realmGroup.orderIdxForNewUser < 0) //防止溢出
{
realmGroup.orderIdxForNewUser = 0;
}
}
else
{
orderIdx = realmGroup.orderIdxForOldUser;
realmGroup.orderIdxForOldUser++;
if (realmGroup.orderIdxForOldUser < 0) //防止溢出
{
realmGroup.orderIdxForOldUser = 0;
}
}
return orderIdx;
}
public static int GetTotalRealmPage(AreaRealm area)
{
int count = 0;
//如果配置了共享,要加上共享area的服务器
if(area.shareShowAreaRealm != null)
{
count += area.shareShowAreaRealm.sortedRealms.Count;
}
count += area.sortedRealms.Count;
if (count == 0)
{
return 0;
}
int page = count / realmNumPerPage;
if (count % realmNumPerPage != 0)
{
page++;
}
return page;
}
// 根据传入信息填充CSRealmInfo
public static void FillCSRealmInfo(AreaRealm area, RealmInfo realmInfo,
PlayerRealmInfo player, ref CSRealmInfo csrealm, bool noCloseStatusWhiteList)
{
bool isShareShow = false;
area.areaWorldDict.TryGetValue(realmInfo.worldId, out var worldInfo);
if(worldInfo == null && area.shareShowAreaRealm != null)
{
area.shareShowAreaRealm.areaWorldDict.TryGetValue(realmInfo.worldId, out worldInfo);
isShareShow = true;
}
FillCSRealmInfo(worldInfo, realmInfo, player, ref csrealm, isShareShow, noCloseStatusWhiteList);
}
// 根据传入信息填充CSRealmInfo, isShareShow表示是否是共享显示的区服,如果是,那么ShowSeq需要进行修改
public static void FillCSRealmInfo(WorldInfo worldInfo, RealmInfo realmInfo,
PlayerRealmInfo player, ref CSRealmInfo csrealm, bool isShareShow, bool noCloseStatusWhiteList)
{
csrealm.RealmId = realmInfo.config.realmId;
csrealm.Name.SetString(realmInfo.config.name);
csrealm.OnlinePlayer = 0;
csrealm.SvrStatus = (int)realmInfo.runtimeState;
csrealm.ConfigStatus = realmInfo.config.status;
csrealm.OpenTime = (int)realmInfo.openTimeSec;
csrealm.RealmBdcName.SetString(realmInfo.config.bdcName);
csrealm.ShowSeq = realmInfo.config.showSeq;
if(isShareShow)
{
csrealm.ShowSeq += 10000;
}
//白名单的去掉维护状态,要不然登录不了了
if(noCloseStatusWhiteList)
{
csrealm.SvrStatus |= (int)RealmState.Open;
}
// 选择gate, 已经有的用原来的,没有的话选人最少的
string gateUrl = null;
if (player.gateGameServerIDDict.ContainsKey(csrealm.RealmId))
{
int gateIndex = player.gateGameServerIDDict[csrealm.RealmId];
if (gateIndex < worldInfo.gameGates.Count)
{
gateUrl = worldInfo.gameGates[gateIndex].url;
}
}
if (gateUrl == null)
{
GameGateInfo gate = SelectPlayerGameGate(worldInfo, player);
player.gateGameServerIDDict.Add(csrealm.RealmId, gate.index);
gateUrl = gate.url;
}
csrealm.GateUrl.SetString(gateUrl);
//选择ChatGate
string chatGateUrl = null;
if (player.gateChatServerIDDict.ContainsKey(csrealm.RealmId))
{
int gateIndex = player.gateChatServerIDDict[csrealm.RealmId];
if (gateIndex < worldInfo.chatGates.Count)
{
chatGateUrl = worldInfo.chatGates[gateIndex].url;
}
}
if (chatGateUrl == null)
{
GameGateInfo gate = SelectMinPlayerGate(worldInfo, ServerType.ChatGate);
player.gateChatServerIDDict.Add(csrealm.RealmId, gate.index);
chatGateUrl = gate.url;
}
csrealm.ChatGateUrl.SetString(chatGateUrl);
}
public static void FillCSRealmBrief(string areaName, RealmInfo realm, ref CSRealmBrief brief, int timeZone=0)
{
brief.RealmId = realm.realmId;
brief.LogicWorldId = realm.logicWorldId;
brief.State = (int)realm.runtimeState;
brief.OpenTime = (int)realm.openTimeSec;
brief.WorldId = realm.worldId;
brief.RealmName.SetString(realm.config.name);
brief.RealmBdcName.SetString(realm.config.bdcName);
brief.VisibleOnlyCliVersion.SetString(realm.config.visibleOnlyCliVersion);
brief.VisibleOnlyWhiteList = realm.config.visibleOnlyWhiteList;
brief.VisibleTime = (int)realm.visibleTimeSec;
brief.BigRealmId = realm.config.bigRealmId;
brief.Ip.SetString(realm.ip);
brief.TimeZone = timeZone;
brief.ShowSeq = realm.config.showSeq;
brief.RegMax = realm.config.regMax;
brief.AreaName.SetString(areaName);
}
public static GameGateInfo SelectMinPlayerGate(WorldInfo world, ServerType serverType)
{
GameGateInfo select = null;
if (serverType == ServerType.ChatGate)
{
foreach (var gate in world.chatGates)
{
if (select == null)
{
select = gate;
}
else
{
if (gate.online < select.online)
{
select = gate;
}
}
}
}
else
{
foreach (var gate in world.gameGates)
{
if (select == null)
{
select = gate;
}
else
{
if (gate.online < select.online)
{
select = gate;
}
}
}
}
return select;
}
//根据账号选gate,正常玩家这个逻辑和GameServerSelect.SelectGameServer算出来应该一致(这样的好处是保证大部分玩家连接gate之后直接就是对应instid的那个game)
//除非有改过账号和uid对应关系,比如
//内部使用玩家账号登录的情况,或者由于各种原因改过账号的uid
public static GameGateInfo SelectPlayerGameGate(WorldInfo world, PlayerRealmInfo player)
{
// 1 ~ 100, uid根据同样的算法是一样的
int index = TableIndexCalc.CalcAccountTableIndex(player.AccountType, player.AccountID);
int gateindex = index % world.gameGates.Count;
if(gateindex == 0)
{
gateindex = world.gameGates.Count;
}
var gate = world.gameGates[gateindex - 1];
TraceLog.Trace("SelectPlayerGameGate accType {0} accountId {1} tableindex {2} gateIndex from 1 {3} url {4}",
player.AccountType, player.AccountID, index, gateindex, gate.url);
return gate;
}
}
}