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 areaDict = new Dictionary(); // 以world组织的realm信息 public static Dictionary worldDict = new Dictionary(); private static int GetAllRealm(RealmListConfig config, Dictionary 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 realmMapOld = new Dictionary(); Dictionary realmMapNew = new Dictionary(); 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 nameMap = new Dictionary(); 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> worldMap = new Dictionary>(); foreach (var realm in realmMapNew.Values) { if (!worldMap.ContainsKey(realm.worldId)) { Dictionary newworldRealms = new Dictionary(); worldMap.Add(realm.worldId, newworldRealms); } Dictionary 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 newRealList = new List(); 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> bigRealmList = new Dictionary>(); foreach (var it in realmMapNew) { if (!bigRealmList.ContainsKey(it.Value.realmConfig.bigRealmId)) { bigRealmList.Add(it.Value.realmConfig.bigRealmId, new List()); } 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(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 sortedRealm = new SortedList(); 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 realmIdInDBCfg = new List(); 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); } /// /// /// /// /// /// 是否发现新服 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 groupList, string clientVer, string ip, List list, string deviceId) { var nowSec = RealmlistServerUtils.GetTimeSecond(); RealmGroup realmGroup = null; foreach (KeyValuePair 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 list = new List(); 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; } } }