ZoneService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. using CommonAI;
  2. using CommonAI.Zone.Instance;
  3. using CommonAI.ZoneServer.JSGModule;
  4. using CommonLang;
  5. using CommonLang.Concurrent;
  6. using CommonLang.Log;
  7. using Pomelo;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Configuration;
  11. using System.Diagnostics;
  12. using System.Dynamic;
  13. using System.Threading;
  14. using System.Web.Helpers;
  15. using XmdsCommon.Plugin;
  16. using XmdsCommonServer.Plugin;
  17. using XmdsServerNode.Node;
  18. using XmdsServerNode.Node.R2bNotify;
  19. using static CommonAI.ZoneServer.JSGModule.JSGServerProfile;
  20. namespace XmdsServerEdgeJS.Zone
  21. {
  22. public abstract class ZoneService : IZone
  23. {
  24. //战斗服版本号
  25. public static int s_bsVersion = 1;
  26. public static ZoneService Instance { get; private set; }
  27. protected ZoneService()
  28. {
  29. Instance = this;
  30. updatePrivateMemory(null);
  31. }
  32. //----------------------------------------------------------------------------------------------
  33. protected Logger log = LoggerFactory.GetLogger(typeof(ZoneService).Name);
  34. protected Logger monitorLog = LoggerFactory.GetLogger("monitor");
  35. private ZoneNodeManager zoneNodeManager;
  36. private BattleCodec codec;
  37. private AtomicLong privateMemoryMB = new AtomicLong(0);
  38. private Timer systemUpdateTimer;
  39. private Timer logUpdateTimer;
  40. protected XmdsServerProxy b2r_proxy = new XmdsServerProxy();
  41. /// <summary>
  42. /// 副本列表
  43. /// </summary>
  44. private HashMap<string, XmdsZoneNode> nodes = new HashMap<string, XmdsZoneNode>();
  45. /// <summary>
  46. /// 玩家列表
  47. /// </summary>
  48. private HashMap<string, XmdsPlayer> players = new HashMap<string, XmdsPlayer>();
  49. //----------------------------------------------------------------------------------------------
  50. public int PlayerCount
  51. {
  52. get
  53. {
  54. lock (players)
  55. {
  56. return players.Count;
  57. }
  58. }
  59. }
  60. public int ZoneNodeCount
  61. {
  62. get
  63. {
  64. lock (nodes)
  65. {
  66. return nodes.Count;
  67. }
  68. }
  69. }
  70. public long ProcessPrivateMemoryMB
  71. {
  72. get { return privateMemoryMB.Value; }
  73. }
  74. //----------------------------------------------------------------------------------------------
  75. #region Internal
  76. public XmdsPlayer getPlayer(string playerID)
  77. {
  78. lock (players)
  79. {
  80. return players.Get(playerID);
  81. }
  82. }
  83. protected XmdsZoneNode getZoneNode(string instanceID)
  84. {
  85. lock (nodes)
  86. {
  87. return nodes.Get(instanceID);//[instanceID];
  88. }
  89. }
  90. //internal void sendToGameServer(string name, Object param)
  91. //{
  92. // try
  93. // {
  94. // //转化为json
  95. // string json = Json.Encode(param);
  96. // IceManager.instance().eventNotify(name, json);
  97. // }
  98. // catch (Exception err)
  99. // {
  100. // log.Error(err.Message, err);
  101. // }
  102. //}
  103. protected void notifyBattleServer(string instanceId, R2BNotifyMessage param)
  104. {
  105. var node = getZoneNode(instanceId);
  106. if (node != null)
  107. {
  108. //b2r_proxy.SendToBattleServer(node.Node.Zone, param);
  109. param.OnHandle(node.Node.Zone);
  110. }
  111. }
  112. private void updatePrivateMemory(object state)
  113. {
  114. long private_memory_mb = Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024;
  115. privateMemoryMB.Value = private_memory_mb;
  116. }
  117. private void updateLog(object state)
  118. {
  119. dynamic eventStat = new ExpandoObject();
  120. eventStat.Type = "monitor";
  121. eventStat.Object = InstanceZoneObject.ActiveObjectCount + "/" + InstanceZoneObject.AllocObjectCount;
  122. eventStat.Zone = InstanceZone.ActiveZoneCount + "/" + InstanceZone.AllocZoneCount;
  123. eventStat.Node = ZoneNodeCount;
  124. eventStat.Player = PlayerCount;
  125. eventStat.Memory_MB = ProcessPrivateMemoryMB;
  126. eventStat.Pool = ObjectPoolStatus.TotalActive + "/" + ObjectPoolStatus.TotalCount;
  127. //monitorLog.Warn(eventStat);
  128. // 输出统计日志
  129. if (JSGServerProfile.CheckPrintAllData())
  130. {
  131. this.PrintAllSceneInfo();
  132. }
  133. }
  134. private void PrintAllSceneInfo()
  135. {
  136. lock (nodes)
  137. {
  138. foreach (var p in new List<XmdsZoneNode>(nodes.Values))
  139. {
  140. try
  141. {
  142. log.Info("场景ID:" + p.InstanceID + ", " + p.Node.GetBindGameSrvId() + ", 场景ID: " + p.Node.SceneID + ", units=" + p.Node.Zone.AllUnitsCount
  143. + ", spells=" + p.Node.Zone.AllSpellsCount + ", items=" + p.Node.Zone.AllItemsCount);
  144. }
  145. catch (Exception e)
  146. {
  147. log.Error("PrintAllSceneInfo: " + p.InstanceID + ", e: " + e);
  148. }
  149. }
  150. }
  151. }
  152. #endregion
  153. //----------------------------------------------------------------------------------------------
  154. public void Start(ZoneConfig zoneConfig)
  155. {
  156. lock (this)
  157. {
  158. try
  159. {
  160. log.Info("startPath:" + zoneConfig.startPath);
  161. log.Info("assetPath:" + zoneConfig.assetPath);
  162. JSGServerProfile.init();
  163. systemUpdateTimer = new Timer(updatePrivateMemory, this, 0, 10000);
  164. zoneNodeManager = new ZoneNodeManager();
  165. zoneNodeManager.Init(zoneConfig.startPath, b2r_proxy, zoneConfig.assetPath);
  166. codec = new BattleCodec(ZoneNodeManager.Templates.Templates);
  167. //日志定时器
  168. logUpdateTimer = new Timer(updateLog, this, 30000, 30000);
  169. }
  170. catch (Exception err)
  171. {
  172. //log.Error("初始化失败");
  173. //log.Error(err.Message, err);
  174. //Environment.Exit(0);
  175. throw err;
  176. }
  177. }
  178. }
  179. public void Stop()
  180. {
  181. this.ClearAllPlayers((e, c) => { });
  182. this.DestoryAllZones((e, c) => { });
  183. lock (this)
  184. {
  185. if (zoneNodeManager != null)
  186. {
  187. b2r_proxy.Dispose();
  188. zoneNodeManager.Shutdown();
  189. systemUpdateTimer.Dispose();
  190. logUpdateTimer.Dispose();
  191. zoneNodeManager = null;
  192. codec = null;
  193. }
  194. }
  195. }
  196. public void SetCallBack(string gameSrvId)
  197. {
  198. JSGMountainKingModule.Init(gameSrvId);
  199. }
  200. public void CreateZone(string playerId, string gameServerId, int mapTemplateId, string instanceId, bool forceCreate,
  201. string data, Action<int> cb, Action<Exception> err)
  202. {
  203. long lstart = TimeUtil.GetTimestampMS();
  204. int resCode = 0;
  205. if (!forceCreate && playerId != null && playerId.Length > 0)
  206. {
  207. var player = getPlayer(playerId);
  208. if (player != null && player.BindingActor.IsActive && player.BindingActor.Virtual.IsInPVP())
  209. {
  210. resCode = 1;
  211. XmdsVirtual playerVirtual = player.BindingActor.Virtual as XmdsVirtual;
  212. log.Warn("PVP状态下传送2:" + playerVirtual.mUnit.PlayerUUID + ", 场景ID: " + playerVirtual.mUnit.Parent.GetSceneID() + ", "
  213. + playerVirtual.GetHateSystem().GetHatePlayerInfo() + ", 触发PVP玩家:" + playerVirtual.mPvpTriggerPlayerId);
  214. }
  215. }
  216. if (resCode == 0)
  217. {
  218. long private_memory_mb = ProcessPrivateMemoryMB;
  219. if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
  220. {
  221. 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);
  222. log.Error(msg);
  223. throw new OutOfMemoryException(msg);
  224. }
  225. XmdsZoneNode node = new XmdsZoneNode(this, instanceId, gameServerId);
  226. node.Node.Callback = IceManager.instance().getCallback(gameServerId);
  227. lock (nodes)
  228. {
  229. if (nodes.ContainsKey(instanceId))
  230. {
  231. throw new Exception(string.Format("node instance id ({0}) already exist!", instanceId));
  232. }
  233. nodes.Add(node.InstanceID, node);
  234. }
  235. {
  236. node.Start(mapTemplateId, data, (z) =>
  237. {
  238. //监控日志
  239. dynamic logEvent = new ExpandoObject();
  240. logEvent.type = "createZone";
  241. logEvent.mapTemplateId = mapTemplateId;
  242. logEvent.instanceId = instanceId;
  243. monitorLog.Debug(logEvent);
  244. });
  245. }
  246. JSGServerProfile.RecordZoneCreate(mapTemplateId, (int)(TimeUtil.GetTimestampMS() - lstart));
  247. }
  248. else
  249. {
  250. log.Warn("玩家pvp状态创建场景:" + playerId + ", " + mapTemplateId + ", " + data);
  251. }
  252. cb(resCode);
  253. }
  254. public void DestroyZone(string instanceId, Action<Exception, object> cb)
  255. {
  256. XmdsZoneNode node;
  257. lock (nodes)
  258. {
  259. node = this.nodes.RemoveByKey(instanceId);
  260. }
  261. if (node != null)
  262. {
  263. //删除场景实例的所有玩家
  264. lock (players)
  265. {
  266. node.Node.ForEachPlayers((client) =>
  267. {
  268. var player = players.Get(client.PlayerUUID);
  269. if (player != null)
  270. {
  271. if (client.Node == player.Node)
  272. {
  273. players.RemoveByKey(client.PlayerUUID);
  274. }
  275. //else
  276. //{
  277. // log.Warn(client.Node + " destory zone player " + client.PlayerUUID + " in " + player.Node);
  278. //}
  279. }
  280. });
  281. }
  282. node.Stop((z) =>
  283. {
  284. //监控日志
  285. dynamic logEvent = new ExpandoObject();
  286. logEvent.type = "destroyZone";
  287. logEvent.mapTemplateId = z.Node.SceneID;
  288. logEvent.instanceId = instanceId;
  289. monitorLog.Debug(logEvent);
  290. });
  291. }
  292. cb(null, "done");
  293. }
  294. public void DestoryAllZones(Action<Exception, object> cb)
  295. {
  296. lock (nodes)
  297. {
  298. foreach (var p in new List<XmdsZoneNode>(nodes.Values))
  299. {
  300. try
  301. {
  302. this.DestroyZone(p.InstanceID, (e, c) => { });
  303. }
  304. catch (Exception e)
  305. {
  306. log.Error(e);
  307. }
  308. }
  309. }
  310. cb(null, "done");
  311. }
  312. public void PlayerEnter(string playerId, string instanceId, string input, Action<Exception, object> cb)
  313. {
  314. var node = getZoneNode(instanceId);
  315. if (node == null)
  316. {
  317. throw new InstanceNotExistException(instanceId);
  318. }
  319. long private_memory_mb = ProcessPrivateMemoryMB;
  320. if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
  321. {
  322. 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);
  323. log.Error(msg);
  324. throw new OutOfMemoryException(msg);
  325. }
  326. dynamic data = Json.Decode(input);
  327. string connectServerId = (string)data.connectServerId;
  328. var session = FastStream.instance().GetSessionByID(connectServerId);
  329. if (session == null)
  330. {
  331. throw new Exception("ConnectServerId not exist : " + connectServerId);
  332. }
  333. string uid = (string)data.uid;
  334. bool robot = data.robot != null ? (bool)data.robot : false;
  335. XmdsPlayerEnter enter = null;
  336. if (data["tempData"] != null)
  337. {
  338. int posX = 0;
  339. int posY = 0;
  340. float direction = 0;
  341. string flagName = null;
  342. flagName = data.tempData.flag;
  343. if (data.tempData["x"] != null)
  344. {
  345. posX = (int)data.tempData.x;
  346. }
  347. if (data.tempData["y"] != null)
  348. {
  349. posY = (int)data.tempData.y;
  350. }
  351. if (data.tempData["direction"] != null)
  352. {
  353. direction = (float)data.tempData.direction;
  354. }
  355. int unitTemplateID = (int)data.unitTemplateID;
  356. XmdsUnitProperties unitprop = new XmdsUnitProperties();
  357. XmdsUnitData unitData = XmdsPlayerUtil.instance().createXmdsUnitData(data, playerId);
  358. unitprop.ServerData = unitData;
  359. enter = new XmdsPlayerEnter();
  360. enter.Pos = new CommonLang.Vector.Vector2(posX, posY);
  361. enter.direction = direction;
  362. enter.FlagName = flagName;
  363. enter.UnitData = new CommonAI.ZoneServer.CreateUnitInfoR2B();
  364. enter.UnitData.Force = unitData.BaseInfo.force;
  365. enter.UnitData.alliesForce = unitData.BaseInfo.alliesForce;
  366. enter.UnitData.StartFlag = null;
  367. enter.UnitData.UnitTemplateID = unitTemplateID;
  368. enter.UnitData.UnitPropData = unitprop;
  369. foreach (dynamic obj in data.tasks)
  370. {
  371. int taskId = obj.QuestID;
  372. int state = obj.State;
  373. XmdsQuestData qData = new XmdsQuestData();
  374. qData.TaskID = taskId.ToString();
  375. qData.TaskState = state.ToString();
  376. foreach (dynamic attr in obj.Attributes)
  377. {
  378. qData.AddAttribute(attr.key, attr.value);
  379. }
  380. unitData.Tasks.Add(qData);
  381. }
  382. foreach (dynamic obj in data.flags)
  383. {
  384. XmdsQuestFlag flag = new XmdsQuestFlag();
  385. flag.FlagName = obj[0];
  386. flag.FlagValue = obj[1];
  387. unitData.QuestFlags.Add(flag);
  388. }
  389. unitData.PlayerEntered = data.playerEntered;
  390. }
  391. XmdsPlayer player = new XmdsPlayer(this, playerId, uid, session, node);
  392. lock (players)
  393. {
  394. if (players.ContainsKey(playerId))
  395. {
  396. this.players[playerId] = player;
  397. //string oldInstanceId = players.Get(playerId).InstanceId;
  398. //PlayerLeave(playerId, oldInstanceId, false, (err, ret) =>
  399. //{
  400. // if (err != null)
  401. // {
  402. // log.Error(err);
  403. // }
  404. //});
  405. }
  406. else
  407. {
  408. this.players.Add(playerId, player);
  409. }
  410. node.Node.OnPlayerEnter(player, enter,
  411. (c) =>
  412. {
  413. player.BindingActor.IsRobot = robot;
  414. //监控日志
  415. dynamic logEvent = new ExpandoObject();
  416. logEvent.type = "playerEnter";
  417. logEvent.mapTemplateId = node.Node.SceneID;
  418. logEvent.instanceId = instanceId;
  419. logEvent.playerId = playerId;
  420. monitorLog.Debug(logEvent);
  421. //cb(null, "done");
  422. },
  423. (e) =>
  424. {
  425. log.Error(e.Message, e);
  426. lock (this.players) { this.players.RemoveByKey(playerId); }
  427. //cb(e, null);
  428. });
  429. }
  430. cb(null, "done");
  431. }
  432. public void PlayerLeave(string playerId, string instanceId, bool keepObject, Action<Exception, object> cb)
  433. {
  434. XmdsPlayer player = null;
  435. try
  436. {
  437. lock (players)
  438. {
  439. player = players.Get(playerId);
  440. if (player != null)
  441. {
  442. if (instanceId.Equals(player.InstanceId))
  443. {
  444. this.players.RemoveByKey(playerId);
  445. }
  446. else
  447. {
  448. log.Warn(instanceId + " leave player " + player.InstanceId + player.Node);
  449. }
  450. }
  451. }
  452. var node = getZoneNode(instanceId);
  453. if (node == null)
  454. {
  455. //throw new InstanceNotExistException(instanceId);
  456. cb(null, "done");
  457. return;
  458. }
  459. //玩家已经离开场景
  460. //if (player == null)
  461. //{
  462. // throw new PlayerNotExistException(playerId);
  463. //}
  464. node.Node.OnPlayerLeave(player != null ? player.BindingActor : node.Node.GetPlayer(playerId),
  465. (c) =>
  466. {
  467. //监控日志
  468. dynamic logEvent = new ExpandoObject();
  469. logEvent.type = "playerLeave";
  470. logEvent.mapTemplateId = node.Node.SceneID;
  471. logEvent.playerId = playerId;
  472. monitorLog.Debug(logEvent);
  473. //cb(null, "done");
  474. },
  475. (e) =>
  476. {
  477. //cb(e, null);
  478. log.Error(e.Message, e);
  479. },
  480. keepObject);
  481. cb(null, "done");
  482. }
  483. catch (Exception e)
  484. {
  485. log.Error(e.Message, e);
  486. cb(e, null);
  487. }
  488. finally
  489. {
  490. if (player != null) player.Dispose();
  491. }
  492. }
  493. public void PlayerNetStateChanged(string playerId, string state)
  494. {
  495. var player = getPlayer(playerId);
  496. if (player == null)
  497. {
  498. log.Error("player not exist :" + playerId + " PlayerNetStateChanged");
  499. return;
  500. }
  501. var node = player.Node;
  502. if (node == null)
  503. {
  504. log.Error("zone node not exist :" + player.InstanceId + " PlayerNetStateChanged");
  505. return;
  506. }
  507. log.Debug("player:" + playerId + " PlayerNetStateChanged " + state);
  508. node.OnPlayerNetStateChanged(player, state);
  509. }
  510. public void PlayerReceive(string playerId, byte[] msg)
  511. {
  512. var player = getPlayer(playerId);
  513. if (player == null)
  514. {
  515. log.Debug("fast stream receive not exist player : " + playerId);
  516. return;
  517. }
  518. var node = player.Node;
  519. if (node == null)
  520. {
  521. log.Error("zone node not exist : " + player.InstanceId + " fast stream receive");
  522. return;
  523. }
  524. //log.Debug("player:" + playerId + " socket.receive");
  525. node.OnPlayerReceivedMessage(player, msg);
  526. }
  527. public void GetAllPlayerCount(Action<Exception, int> cb)
  528. {
  529. int count = PlayerCount;
  530. cb(null, count);
  531. }
  532. public void ClearAllPlayers(Action<Exception, object> cb)
  533. {
  534. try
  535. {
  536. lock (players)
  537. {
  538. foreach (var p in new List<XmdsPlayer>(players.Values))
  539. {
  540. this.PlayerLeave(p.PlayerUUID, p.InstanceId, false, (e, c) => { });
  541. }
  542. }
  543. cb(null, "done");
  544. }
  545. catch (Exception e)
  546. {
  547. cb(e, null);
  548. }
  549. }
  550. public void GetAllPlayers(Action<Exception, object> cb)
  551. {
  552. try
  553. {
  554. var ret = new List<string>();
  555. lock (players)
  556. {
  557. foreach (var p in new List<XmdsPlayer>(players.Values))
  558. {
  559. ret.Add(p.PlayerUUID);
  560. }
  561. }
  562. cb(null, ret.ToArray());
  563. }
  564. catch (Exception e)
  565. {
  566. cb(e, null);
  567. }
  568. }
  569. public void GetServerState(string serverID, Action<Exception, object> cb)
  570. {
  571. try
  572. {
  573. int zc = ZoneNodeCount;
  574. int pc = PlayerCount;
  575. int ActiveObjectCount = InstanceZoneObject.ActiveObjectCount;
  576. int AllocObjectCount = InstanceZoneObject.AllocObjectCount;
  577. int ActiveZoneCount = InstanceZone.ActiveZoneCount;
  578. int AllocZoneCount = InstanceZone.AllocZoneCount;
  579. float w = zc * 1000 + pc;
  580. int flag = IceManager.instance().getCallback(serverID) == null ? 0 : 1;
  581. dynamic ret = new
  582. {
  583. weight = w,
  584. memory = ProcessPrivateMemoryMB,
  585. zone_count = zc,
  586. player_count = pc,
  587. ActiveObjectCount = ActiveObjectCount,
  588. AllocObjectCount = AllocObjectCount,
  589. ActiveZoneCount = ActiveZoneCount,
  590. AllocZoneCount = AllocZoneCount,
  591. flag = flag,
  592. };
  593. cb(null, ret);
  594. }
  595. catch (Exception e)
  596. {
  597. log.Error("GetServerState failed, error: " + e.Message, e);
  598. cb(e, e.Message);
  599. }
  600. }
  601. public void RegisterGameServer(int serverId, int crossId, Action<Exception, int> cb)
  602. {
  603. try
  604. {
  605. var str = ConfigurationManager.AppSettings["game.server.id"];
  606. if (!string.IsNullOrEmpty(str) && int.Parse(str) != serverId && int.Parse(str) != crossId)
  607. {
  608. cb(null, -1);
  609. return;
  610. }
  611. }
  612. catch (Exception e)
  613. {
  614. cb(e, -2);
  615. return;
  616. }
  617. cb(null, s_bsVersion);
  618. }
  619. //获取单位血量
  620. public void GetUnitHP(string instanceId, int objectId, Action<Exception, int> cb)
  621. {
  622. try
  623. {
  624. var node = getZoneNode(instanceId);
  625. if (node == null)
  626. {
  627. cb(null, -1);
  628. return;
  629. }
  630. InstanceUnit unit = node.Node.Zone.getUnit((uint)objectId);
  631. if (unit == null)
  632. {
  633. cb(null, -2);
  634. return;
  635. }
  636. cb(null, unit.CurrentHP);
  637. }
  638. catch (Exception e)
  639. {
  640. cb(e, -10);
  641. return;
  642. }
  643. }
  644. //----------------------------------------------------------------------------------------------
  645. }
  646. }