using CommonAI; using CommonAI.Zone.Instance; using CommonAI.ZoneServer.JSGModule; using CommonLang; using CommonLang.Concurrent; using CommonLang.Log; using Pomelo; using System; using System.Collections.Generic; using System.Configuration; using System.Diagnostics; using System.Dynamic; using System.Threading; using System.Web.Helpers; using XmdsCommon.Plugin; using XmdsCommonServer.Plugin; using XmdsServerNode.Node; using XmdsServerNode.Node.R2bNotify; using static CommonAI.ZoneServer.JSGModule.JSGServerProfile; namespace XmdsServerEdgeJS.Zone { public abstract class ZoneService : IZone { //战斗服版本号 public static int s_bsVersion = 1; public static ZoneService Instance { get; private set; } protected ZoneService() { Instance = this; updatePrivateMemory(null); } //---------------------------------------------------------------------------------------------- protected Logger log = LoggerFactory.GetLogger(typeof(ZoneService).Name); protected Logger monitorLog = LoggerFactory.GetLogger("monitor"); private ZoneNodeManager zoneNodeManager; private BattleCodec codec; private AtomicLong privateMemoryMB = new AtomicLong(0); private Timer systemUpdateTimer; private Timer logUpdateTimer; protected XmdsServerProxy b2r_proxy = new XmdsServerProxy(); /// /// 副本列表 /// private HashMap nodes = new HashMap(); /// /// 玩家列表 /// private HashMap players = new HashMap(); //---------------------------------------------------------------------------------------------- public int PlayerCount { get { lock (players) { return players.Count; } } } public int ZoneNodeCount { get { lock (nodes) { return nodes.Count; } } } public long ProcessPrivateMemoryMB { get { return privateMemoryMB.Value; } } //---------------------------------------------------------------------------------------------- #region Internal public XmdsPlayer getPlayer(string playerID) { lock (players) { return players.Get(playerID); } } protected XmdsZoneNode getZoneNode(string instanceID) { lock (nodes) { return nodes.Get(instanceID);//[instanceID]; } } //internal void sendToGameServer(string name, Object param) //{ // try // { // //转化为json // string json = Json.Encode(param); // IceManager.instance().eventNotify(name, json); // } // catch (Exception err) // { // log.Error(err.Message, err); // } //} protected void notifyBattleServer(string instanceId, R2BNotifyMessage param) { var node = getZoneNode(instanceId); if (node != null) { //b2r_proxy.SendToBattleServer(node.Node.Zone, param); param.OnHandle(node.Node.Zone); } } private void updatePrivateMemory(object state) { long private_memory_mb = Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024; privateMemoryMB.Value = private_memory_mb; } private void updateLog(object state) { dynamic eventStat = new ExpandoObject(); eventStat.Type = "monitor"; eventStat.Object = InstanceZoneObject.ActiveObjectCount + "/" + InstanceZoneObject.AllocObjectCount; eventStat.Zone = InstanceZone.ActiveZoneCount + "/" + InstanceZone.AllocZoneCount; eventStat.Node = ZoneNodeCount; eventStat.Player = PlayerCount; eventStat.Memory_MB = ProcessPrivateMemoryMB; eventStat.Pool = ObjectPoolStatus.TotalActive + "/" + ObjectPoolStatus.TotalCount; monitorLog.Info(eventStat); // 输出统计日志 if (JSGServerProfile.CheckPrintAllData()) { this.PrintAllSceneInfo(); } } private void PrintAllSceneInfo() { lock (nodes) { foreach (var p in new List(nodes.Values)) { try { log.Info("PrintAllSceneInfo-ID:" + p.InstanceID + ", " + p.Node.GetBindGameSrvId() + ", 场景ID: " + p.Node.SceneID + ", units=" + p.Node.Zone.AllUnitsCount + ", spells=" + p.Node.Zone.AllSpellsCount + ", items=" + p.Node.Zone.AllItemsCount + ", players: " + p.Node.Zone.AllPlayersCount); } catch (Exception e) { log.Error("PrintAllSceneInfo: " + p.InstanceID + ", e: " + e); } } } } #endregion //---------------------------------------------------------------------------------------------- public void Start(ZoneConfig zoneConfig) { lock (this) { try { log.Info("startPath:" + zoneConfig.startPath); log.Info("assetPath:" + zoneConfig.assetPath); JSGServerProfile.init(); systemUpdateTimer = new Timer(updatePrivateMemory, this, 0, 10000); zoneNodeManager = new ZoneNodeManager(); zoneNodeManager.Init(zoneConfig.startPath, b2r_proxy, zoneConfig.assetPath); codec = new BattleCodec(ZoneNodeManager.Templates.Templates); //日志定时器 logUpdateTimer = new Timer(updateLog, this, 30000, 30000); } catch (Exception err) { //log.Error("初始化失败"); //log.Error(err.Message, err); //Environment.Exit(0); throw err; } } } public void Stop() { this.ClearAllPlayers((e, c) => { }); this.DestoryAllZones((e, c) => { }); lock (this) { if (zoneNodeManager != null) { b2r_proxy.Dispose(); zoneNodeManager.Shutdown(); systemUpdateTimer.Dispose(); logUpdateTimer.Dispose(); zoneNodeManager = null; codec = null; } } } public void SetCallBack(string gameSrvId) { JSGMountainKingModule.Init(gameSrvId); } public void CreateZone(string playerId, string gameServerId, int mapTemplateId, string instanceId, bool forceCreate, string data, Action cb, Action err) { long lstart = TimeUtil.GetTimestampMS(); int resCode = 0; if (!forceCreate && playerId != null && playerId.Length > 0) { var player = getPlayer(playerId); if (player != null && player.BindingActor.IsActive && player.BindingActor.Virtual.IsInPVP()) { resCode = 1; XmdsVirtual playerVirtual = player.BindingActor.Virtual as XmdsVirtual; log.Warn("PVP状态下传送2:" + playerVirtual.mUnit.PlayerUUID + ", 场景ID: " + playerVirtual.mUnit.Parent.GetSceneID() + ", " + playerVirtual.GetHateSystem().GetHatePlayerInfo() + ", 触发PVP玩家:" + playerVirtual.mPvpTriggerPlayerId); } } if (resCode == 0) { long private_memory_mb = ProcessPrivateMemoryMB; if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB) { string msg = string.Format("CreateZone failed : Private memory {0}MB out of range {1}MB", private_memory_mb, ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB); log.Error(msg); throw new OutOfMemoryException(msg); } XmdsZoneNode node = new XmdsZoneNode(this, instanceId, gameServerId); node.Node.Callback = IceManager.instance().getCallback(gameServerId); lock (nodes) { if (nodes.ContainsKey(instanceId)) { throw new Exception(string.Format("node instance id ({0}) already exist!", instanceId)); } nodes.Add(node.InstanceID, node); } { node.Start(mapTemplateId, data, (z) => { //监控日志 dynamic logEvent = new ExpandoObject(); logEvent.type = "createZone"; logEvent.mapTemplateId = mapTemplateId; logEvent.instanceId = instanceId; monitorLog.Debug(logEvent); }); } JSGServerProfile.RecordZoneCreate(mapTemplateId, (int)(TimeUtil.GetTimestampMS() - lstart)); } else { log.Warn("玩家pvp状态创建场景:" + playerId + ", " + mapTemplateId + ", " + data); } cb(resCode); } public void DestroyZone(string instanceId, Action cb) { XmdsZoneNode node; lock (nodes) { node = this.nodes.RemoveByKey(instanceId); } if (node != null) { //删除场景实例的所有玩家 lock (players) { node.Node.ForEachPlayers((client) => { var player = players.Get(client.PlayerUUID); if (player != null) { if (client.Node == player.Node) { players.RemoveByKey(client.PlayerUUID); } //else //{ // log.Warn(client.Node + " destory zone player " + client.PlayerUUID + " in " + player.Node); //} } }); } node.Stop((z) => { //监控日志 dynamic logEvent = new ExpandoObject(); logEvent.type = "destroyZone"; logEvent.mapTemplateId = z.Node.SceneID; logEvent.instanceId = instanceId; monitorLog.Debug(logEvent); }); } cb(null, "done"); } public void DestoryAllZones(Action cb) { lock (nodes) { foreach (var p in new List(nodes.Values)) { try { this.DestroyZone(p.InstanceID, (e, c) => { }); } catch (Exception e) { log.Error(e); } } } cb(null, "done"); } public void PlayerEnter(string playerId, string instanceId, string input, Action cb) { var node = getZoneNode(instanceId); if (node == null) { throw new InstanceNotExistException(instanceId); } long private_memory_mb = ProcessPrivateMemoryMB; if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB) { string msg = string.Format("PlayerEnter failed : Private memory {0}MB out of range {1}MB", private_memory_mb, ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB); log.Error(msg); throw new OutOfMemoryException(msg); } dynamic data = Json.Decode(input); string connectServerId = (string)data.connectServerId; var session = FastStream.instance().GetSessionByID(connectServerId); if (session == null) { throw new Exception("ConnectServerId not exist : " + connectServerId); } string uid = (string)data.uid; bool robot = data.robot != null ? (bool)data.robot : false; XmdsPlayerEnter enter = null; if (data["tempData"] != null) { int posX = 0; int posY = 0; float direction = 0; string flagName = null; flagName = data.tempData.flag; if (data.tempData["x"] != null) { posX = (int)data.tempData.x; } if (data.tempData["y"] != null) { posY = (int)data.tempData.y; } if (data.tempData["direction"] != null) { direction = (float)data.tempData.direction; } int unitTemplateID = (int)data.unitTemplateID; XmdsUnitProperties unitprop = new XmdsUnitProperties(); XmdsUnitData unitData = XmdsPlayerUtil.instance().createXmdsUnitData(data, playerId); unitprop.ServerData = unitData; enter = new XmdsPlayerEnter(); enter.Pos = new CommonLang.Vector.Vector2(posX, posY); enter.direction = direction; enter.FlagName = flagName; enter.UnitData = new CommonAI.ZoneServer.CreateUnitInfoR2B(); enter.UnitData.Force = unitData.BaseInfo.force; enter.UnitData.alliesForce = unitData.BaseInfo.alliesForce; enter.UnitData.StartFlag = null; enter.UnitData.UnitTemplateID = unitTemplateID; enter.UnitData.UnitPropData = unitprop; foreach (dynamic obj in data.tasks) { int taskId = obj.QuestID; int state = obj.State; XmdsQuestData qData = new XmdsQuestData(); qData.TaskID = taskId.ToString(); qData.TaskState = state.ToString(); foreach (dynamic attr in obj.Attributes) { qData.AddAttribute(attr.key, attr.value); } unitData.Tasks.Add(qData); } foreach (dynamic obj in data.flags) { XmdsQuestFlag flag = new XmdsQuestFlag(); flag.FlagName = obj[0]; flag.FlagValue = obj[1]; unitData.QuestFlags.Add(flag); } unitData.PlayerEntered = data.playerEntered; } XmdsPlayer player = new XmdsPlayer(this, playerId, uid, session, node); lock (players) { if (players.ContainsKey(playerId)) { this.players[playerId] = player; //string oldInstanceId = players.Get(playerId).InstanceId; //PlayerLeave(playerId, oldInstanceId, false, (err, ret) => //{ // if (err != null) // { // log.Error(err); // } //}); } else { this.players.Add(playerId, player); } node.Node.OnPlayerEnter(player, enter, (c) => { player.BindingActor.IsRobot = robot; //监控日志 dynamic logEvent = new ExpandoObject(); logEvent.type = "playerEnter"; logEvent.mapTemplateId = node.Node.SceneID; logEvent.instanceId = instanceId; logEvent.playerId = playerId; monitorLog.Debug(logEvent); //cb(null, "done"); }, (e) => { log.Error(e.Message, e); lock (this.players) { this.players.RemoveByKey(playerId); } //cb(e, null); }); } cb(null, "done"); } public void PlayerLeave(string playerId, string instanceId, bool keepObject, Action cb) { XmdsPlayer player = null; try { lock (players) { player = players.Get(playerId); if (player != null) { if (instanceId.Equals(player.InstanceId)) { this.players.RemoveByKey(playerId); } else { log.Warn(instanceId + " leave player " + player.InstanceId + player.Node); } } } var node = getZoneNode(instanceId); if (node == null) { //throw new InstanceNotExistException(instanceId); cb(null, "done"); return; } //玩家已经离开场景 //if (player == null) //{ // throw new PlayerNotExistException(playerId); //} node.Node.OnPlayerLeave(player != null ? player.BindingActor : node.Node.GetPlayer(playerId), (c) => { //监控日志 dynamic logEvent = new ExpandoObject(); logEvent.type = "playerLeave"; logEvent.mapTemplateId = node.Node.SceneID; logEvent.playerId = playerId; monitorLog.Debug(logEvent); //cb(null, "done"); }, (e) => { //cb(e, null); log.Error(e.Message, e); }, keepObject); cb(null, "done"); } catch (Exception e) { log.Error(e.Message, e); cb(e, null); } finally { if (player != null) player.Dispose(); } } public void PlayerNetStateChanged(string playerId, string state) { var player = getPlayer(playerId); if (player == null) { log.Error("player not exist :" + playerId + " PlayerNetStateChanged"); return; } var node = player.Node; if (node == null) { log.Error("zone node not exist :" + player.InstanceId + " PlayerNetStateChanged"); return; } log.Debug("player:" + playerId + " PlayerNetStateChanged " + state); node.OnPlayerNetStateChanged(player, state); } public void PlayerReceive(string playerId, byte[] msg) { var player = getPlayer(playerId); if (player == null) { log.Debug("fast stream receive not exist player : " + playerId); return; } var node = player.Node; if (node == null) { log.Error("zone node not exist : " + player.InstanceId + " fast stream receive"); return; } //log.Debug("player:" + playerId + " socket.receive"); node.OnPlayerReceivedMessage(player, msg); } public void GetAllPlayerCount(Action cb) { int count = PlayerCount; cb(null, count); } public void ClearAllPlayers(Action cb) { try { lock (players) { foreach (var p in new List(players.Values)) { this.PlayerLeave(p.PlayerUUID, p.InstanceId, false, (e, c) => { }); } } cb(null, "done"); } catch (Exception e) { cb(e, null); } } public void GetAllPlayers(Action cb) { try { var ret = new List(); lock (players) { foreach (var p in new List(players.Values)) { ret.Add(p.PlayerUUID); } } cb(null, ret.ToArray()); } catch (Exception e) { cb(e, null); } } public void GetServerState(string serverID, Action cb) { try { int zc = ZoneNodeCount; int pc = PlayerCount; int ActiveObjectCount = InstanceZoneObject.ActiveObjectCount; int AllocObjectCount = InstanceZoneObject.AllocObjectCount; int ActiveZoneCount = InstanceZone.ActiveZoneCount; int AllocZoneCount = InstanceZone.AllocZoneCount; float w = zc * 1000 + pc; int flag = IceManager.instance().getCallback(serverID) == null ? 0 : 1; dynamic ret = new { weight = w, memory = ProcessPrivateMemoryMB, zone_count = zc, player_count = pc, ActiveObjectCount = ActiveObjectCount, AllocObjectCount = AllocObjectCount, ActiveZoneCount = ActiveZoneCount, AllocZoneCount = AllocZoneCount, flag = flag, }; cb(null, ret); } catch (Exception e) { log.Error("GetServerState failed, error: " + e.Message, e); cb(e, e.Message); } } public void RegisterGameServer(int serverId, int crossId, Action cb) { try { var str = ConfigurationManager.AppSettings["game.server.id"]; if (!string.IsNullOrEmpty(str) && int.Parse(str) != serverId && int.Parse(str) != crossId) { cb(null, -1); return; } } catch (Exception e) { cb(e, -2); return; } cb(null, s_bsVersion); } //获取单位血量 public void GetUnitHP(string instanceId, int objectId, Action cb) { try { var node = getZoneNode(instanceId); if (node == null) { cb(null, -1); return; } InstanceUnit unit = node.Node.Zone.getUnit((uint)objectId); if (unit == null) { cb(null, -2); return; } cb(null, unit.CurrentHP); } catch (Exception e) { cb(e, -10); return; } } //---------------------------------------------------------------------------------------------- } }