ZoneService.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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. private static readonly string S_BSVersion = "1.0.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.Debug(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. string ext = p.Node.Zone.IsObjectMapNull() ? ", 场景已销毁:" : ", units=" + p.Node.Zone.AllUnitsCount
  143. + ", spells=" + p.Node.Zone.AllSpellsCount + ", items=" + p.Node.Zone.AllItemsCount + ", players: " + p.Node.Zone.AllPlayersCount;
  144. log.Info("PrintAllSceneInfo-ID:" + p.InstanceID + ", " + p.Node.GetBindGameSrvId() + ", 场景ID: " + p.Node.SceneID + ext);
  145. }
  146. catch (Exception e)
  147. {
  148. log.Error("PrintAllSceneInfo: " + p.InstanceID + ", e: " + e);
  149. }
  150. }
  151. }
  152. }
  153. #endregion
  154. //----------------------------------------------------------------------------------------------
  155. public void Start(ZoneConfig zoneConfig)
  156. {
  157. lock (this)
  158. {
  159. try
  160. {
  161. log.Info("startPath:" + zoneConfig.startPath);
  162. log.Info("assetPath:" + zoneConfig.assetPath);
  163. JSGServerProfile.init();
  164. systemUpdateTimer = new Timer(updatePrivateMemory, this, 0, 10000);
  165. zoneNodeManager = new ZoneNodeManager();
  166. zoneNodeManager.Init(zoneConfig.startPath, b2r_proxy, zoneConfig.assetPath);
  167. codec = new BattleCodec(ZoneNodeManager.Templates.Templates);
  168. //日志定时器
  169. logUpdateTimer = new Timer(updateLog, this, 120000, 120000);
  170. }
  171. catch (Exception err)
  172. {
  173. //log.Error("初始化失败");
  174. //log.Error(err.Message, err);
  175. //Environment.Exit(0);
  176. throw err;
  177. }
  178. }
  179. }
  180. /** 网络重置 */
  181. public void onNetReconnect(string connetorId, IFastSession session)
  182. {
  183. try
  184. {
  185. lock (players)
  186. {
  187. foreach (var player in players.Values)
  188. {
  189. player.OnNetReconnect(connetorId, session);
  190. }
  191. }
  192. }
  193. catch(Exception e)
  194. {
  195. log.Error("onNetReconnect catch: " + connetorId + ", " + e);
  196. }
  197. }
  198. public void Stop()
  199. {
  200. this.ClearAllPlayers((e, c) => { });
  201. this.DestoryAllZones((e, c) => { });
  202. lock (this)
  203. {
  204. if (zoneNodeManager != null)
  205. {
  206. b2r_proxy.Dispose();
  207. zoneNodeManager.Shutdown();
  208. systemUpdateTimer.Dispose();
  209. logUpdateTimer.Dispose();
  210. zoneNodeManager = null;
  211. codec = null;
  212. }
  213. }
  214. }
  215. public void SetCallBack(string gameSrvId)
  216. {
  217. //JSGMountainKingModule.Init(gameSrvId);
  218. }
  219. public void CreateZone(string playerId, string gameServerId, int mapTemplateId, string instanceId, bool forceCreate,
  220. string data, Action<int> cb, Action<Exception> err)
  221. {
  222. long lstart = TimeUtil.GetTimestampMS();
  223. int resCode = 0;
  224. if (!forceCreate && playerId != null && playerId.Length > 0)
  225. {
  226. var player = getPlayer(playerId);
  227. if (player != null && player.BindingActor.IsActive && player.BindingActor.Virtual.IsInPVP())
  228. {
  229. resCode = 1;
  230. XmdsVirtual playerVirtual = player.BindingActor.Virtual as XmdsVirtual;
  231. log.Warn("PVP状态下传送2:" + playerVirtual.mUnit.PlayerUUID + ", 场景ID: " + playerVirtual.mUnit.Parent.GetSceneID() + ",hateInfo: "
  232. + playerVirtual.GetHateSystem().GetHatePlayerInfo() + ", 触发PVP玩家:" + playerVirtual.mPvpTriggerPlayerId);
  233. }
  234. }
  235. if (resCode == 0)
  236. {
  237. long private_memory_mb = ProcessPrivateMemoryMB;
  238. if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
  239. {
  240. 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);
  241. log.Error(msg);
  242. throw new OutOfMemoryException(msg);
  243. }
  244. XmdsZoneNode node = new XmdsZoneNode(this, instanceId, gameServerId);
  245. node.Node.Callback = IceManager.instance().getCallback(gameServerId);
  246. lock (nodes)
  247. {
  248. if (nodes.ContainsKey(instanceId))
  249. {
  250. throw new Exception(string.Format("node instance id ({0}) already exist!", instanceId));
  251. }
  252. nodes.Add(node.InstanceID, node);
  253. }
  254. {
  255. node.Start(mapTemplateId, data, (z) =>
  256. {
  257. //监控日志
  258. dynamic logEvent = new ExpandoObject();
  259. logEvent.type = "createZone";
  260. logEvent.mapTemplateId = mapTemplateId;
  261. logEvent.instanceId = instanceId;
  262. monitorLog.Debug(logEvent);
  263. });
  264. }
  265. JSGServerProfile.RecordZoneCreate(mapTemplateId, (int)(TimeUtil.GetTimestampMS() - lstart));
  266. }
  267. else
  268. {
  269. log.Warn("玩家pvp状态创建场景:" + playerId + ", " + mapTemplateId + ", " + data);
  270. }
  271. cb(resCode);
  272. }
  273. public void DestroyZone(string instanceId, Action<Exception, object> cb)
  274. {
  275. XmdsZoneNode node;
  276. lock (nodes)
  277. {
  278. node = this.nodes.RemoveByKey(instanceId);
  279. }
  280. if (node != null)
  281. {
  282. //删除场景实例的所有玩家
  283. lock (players)
  284. {
  285. node.Node.ForEachPlayers((client) =>
  286. {
  287. var player = players.Get(client.PlayerUUID);
  288. if (player != null)
  289. {
  290. if (client.Node == player.Node)
  291. {
  292. players.RemoveByKey(client.PlayerUUID);
  293. }
  294. //else
  295. //{
  296. // log.Warn(client.Node + " destory zone player " + client.PlayerUUID + " in " + player.Node);
  297. //}
  298. }
  299. });
  300. }
  301. node.Stop((z) =>
  302. {
  303. //监控日志
  304. dynamic logEvent = new ExpandoObject();
  305. logEvent.type = "destroyZone";
  306. logEvent.mapTemplateId = z.Node.SceneID;
  307. logEvent.instanceId = instanceId;
  308. monitorLog.Debug(logEvent);
  309. });
  310. }
  311. cb(null, "done");
  312. }
  313. public void DestoryAllZones(Action<Exception, object> cb)
  314. {
  315. lock (nodes)
  316. {
  317. foreach (var p in new List<XmdsZoneNode>(nodes.Values))
  318. {
  319. try
  320. {
  321. this.DestroyZone(p.InstanceID, (e, c) => { });
  322. }
  323. catch (Exception e)
  324. {
  325. log.Error(e);
  326. }
  327. }
  328. }
  329. cb(null, "done");
  330. }
  331. public void PlayerEnter(string playerId, string instanceId, string input, Action<Exception, object> cb)
  332. {
  333. var node = getZoneNode(instanceId);
  334. if (node == null)
  335. {
  336. throw new InstanceNotExistException(instanceId);
  337. }
  338. long private_memory_mb = ProcessPrivateMemoryMB;
  339. if (private_memory_mb > ZoneNodeManager.NodeConfig.SYSTEM_MAX_HEAP_SIZE_MB)
  340. {
  341. 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);
  342. log.Error(msg);
  343. throw new OutOfMemoryException(msg);
  344. }
  345. dynamic data = Json.Decode(input);
  346. string connectServerId = (string)data.connectServerId;
  347. var session = FastStream.instance().GetSessionByID(connectServerId);
  348. if (session == null)
  349. {
  350. throw new Exception("ConnectServerId not exist : " + connectServerId);
  351. }
  352. string uid = (string)data.uid;
  353. bool robot = data.robot != null ? (bool)data.robot : false;
  354. XmdsPlayerEnter enter = null;
  355. if (data["tempData"] != null)
  356. {
  357. int posX = 0;
  358. int posY = 0;
  359. float direction = 0;
  360. string flagName = null;
  361. flagName = data.tempData.flag;
  362. if (data.tempData["x"] != null)
  363. {
  364. posX = (int)data.tempData.x;
  365. }
  366. if (data.tempData["y"] != null)
  367. {
  368. posY = (int)data.tempData.y;
  369. }
  370. if (data.tempData["direction"] != null)
  371. {
  372. direction = (float)data.tempData.direction;
  373. }
  374. int unitTemplateID = (int)data.unitTemplateID;
  375. XmdsUnitProperties unitprop = new XmdsUnitProperties();
  376. XmdsUnitData unitData = XmdsPlayerUtil.instance().createXmdsUnitData(data, playerId);
  377. unitprop.ServerData = unitData;
  378. enter = new XmdsPlayerEnter();
  379. enter.Pos = new CommonLang.Vector.Vector2(posX, posY);
  380. enter.direction = direction;
  381. enter.FlagName = flagName;
  382. enter.UnitData = new CommonAI.ZoneServer.CreateUnitInfoR2B();
  383. enter.UnitData.Force = unitData.BaseInfo.force;
  384. enter.UnitData.alliesForce = unitData.BaseInfo.alliesForce;
  385. enter.UnitData.StartFlag = null;
  386. enter.UnitData.UnitTemplateID = unitTemplateID;
  387. enter.UnitData.UnitPropData = unitprop;
  388. foreach (dynamic obj in data.tasks)
  389. {
  390. int taskId = obj.QuestID;
  391. int state = obj.State;
  392. XmdsQuestData qData = new XmdsQuestData();
  393. qData.TaskID = taskId.ToString();
  394. qData.TaskState = state.ToString();
  395. foreach (dynamic attr in obj.Attributes)
  396. {
  397. qData.AddAttribute(attr.key, attr.value);
  398. }
  399. unitData.Tasks.Add(qData);
  400. }
  401. foreach (dynamic obj in data.flags)
  402. {
  403. XmdsQuestFlag flag = new XmdsQuestFlag();
  404. flag.FlagName = obj[0];
  405. flag.FlagValue = obj[1];
  406. unitData.QuestFlags.Add(flag);
  407. }
  408. unitData.PlayerEntered = data.playerEntered;
  409. }
  410. XmdsPlayer player = new XmdsPlayer(this, playerId, uid, session, node);
  411. lock (players)
  412. {
  413. if (players.ContainsKey(playerId))
  414. {
  415. this.players[playerId] = player;
  416. //string oldInstanceId = players.Get(playerId).InstanceId;
  417. //PlayerLeave(playerId, oldInstanceId, false, (err, ret) =>
  418. //{
  419. // if (err != null)
  420. // {
  421. // log.Error(err);
  422. // }
  423. //});
  424. }
  425. else
  426. {
  427. this.players.Add(playerId, player);
  428. }
  429. node.Node.OnPlayerEnter(player, enter,
  430. (c) =>
  431. {
  432. player.BindingActor.IsRobot = robot;
  433. //监控日志
  434. dynamic logEvent = new ExpandoObject();
  435. logEvent.type = "playerEnter";
  436. logEvent.mapTemplateId = node.Node.SceneID;
  437. logEvent.instanceId = instanceId;
  438. logEvent.playerId = playerId;
  439. monitorLog.Debug(logEvent);
  440. //cb(null, "done");
  441. },
  442. (e) =>
  443. {
  444. log.Error(e.Message, e);
  445. lock (this.players) { this.players.RemoveByKey(playerId); }
  446. //cb(e, null);
  447. });
  448. }
  449. cb(null, "done");
  450. }
  451. public void PlayerLeave(string playerId, string instanceId, bool keepObject, Action<Exception, object> cb)
  452. {
  453. XmdsPlayer player = null;
  454. try
  455. {
  456. lock (players)
  457. {
  458. player = players.Get(playerId);
  459. if (player != null)
  460. {
  461. if (instanceId.Equals(player.InstanceId))
  462. {
  463. this.players.RemoveByKey(playerId);
  464. }
  465. else
  466. {
  467. log.Warn(instanceId + " leave player " + player.InstanceId + player.Node);
  468. }
  469. }
  470. }
  471. var node = getZoneNode(instanceId);
  472. if (node == null)
  473. {
  474. //throw new InstanceNotExistException(instanceId);
  475. cb(null, "done");
  476. return;
  477. }
  478. //玩家已经离开场景
  479. //if (player == null)
  480. //{
  481. // throw new PlayerNotExistException(playerId);
  482. //}
  483. node.Node.OnPlayerLeave(player != null ? player.BindingActor : node.Node.GetPlayer(playerId),
  484. (c) =>
  485. {
  486. //监控日志
  487. dynamic logEvent = new ExpandoObject();
  488. logEvent.type = "playerLeave";
  489. logEvent.mapTemplateId = node.Node.SceneID;
  490. logEvent.playerId = playerId;
  491. monitorLog.Debug(logEvent);
  492. //cb(null, "done");
  493. },
  494. (e) =>
  495. {
  496. //cb(e, null);
  497. log.Error(e.Message, e);
  498. },
  499. keepObject);
  500. cb(null, "done");
  501. }
  502. catch (Exception e)
  503. {
  504. log.Error(e.Message, e);
  505. cb(e, null);
  506. }
  507. finally
  508. {
  509. if (player != null) player.Dispose();
  510. }
  511. }
  512. public void PlayerNetStateChanged(string playerId, string state)
  513. {
  514. var player = getPlayer(playerId);
  515. if (player == null)
  516. {
  517. log.Error("player not exist :" + playerId + " PlayerNetStateChanged");
  518. return;
  519. }
  520. var node = player.Node;
  521. if (node == null)
  522. {
  523. log.Error("zone node not exist :" + player.InstanceId + " PlayerNetStateChanged");
  524. return;
  525. }
  526. log.Debug("player:" + playerId + " PlayerNetStateChanged " + state);
  527. node.OnPlayerNetStateChanged(player, state);
  528. }
  529. public void PlayerReceive(string playerId, byte[] msg)
  530. {
  531. var player = getPlayer(playerId);
  532. if (player == null)
  533. {
  534. log.Debug("fast stream receive not exist player : " + playerId);
  535. return;
  536. }
  537. var node = player.Node;
  538. if (node == null)
  539. {
  540. log.Error("zone node not exist : " + player.InstanceId + " fast stream receive");
  541. return;
  542. }
  543. //log.Debug("player:" + playerId + " socket.receive");
  544. node.OnPlayerReceivedMessage(player, msg);
  545. }
  546. public void GetAllPlayerCount(Action<Exception, int> cb)
  547. {
  548. int count = PlayerCount;
  549. cb(null, count);
  550. }
  551. public void ClearAllPlayers(Action<Exception, object> cb)
  552. {
  553. try
  554. {
  555. lock (players)
  556. {
  557. foreach (var p in new List<XmdsPlayer>(players.Values))
  558. {
  559. this.PlayerLeave(p.PlayerUUID, p.InstanceId, false, (e, c) => { });
  560. }
  561. }
  562. cb(null, "done");
  563. }
  564. catch (Exception e)
  565. {
  566. cb(e, null);
  567. }
  568. }
  569. public void GetAllPlayers(Action<Exception, object> cb)
  570. {
  571. try
  572. {
  573. var ret = new List<string>();
  574. lock (players)
  575. {
  576. foreach (var p in new List<XmdsPlayer>(players.Values))
  577. {
  578. ret.Add(p.PlayerUUID);
  579. }
  580. }
  581. cb(null, ret.ToArray());
  582. }
  583. catch (Exception e)
  584. {
  585. cb(e, null);
  586. }
  587. }
  588. public void GetServerState(string serverID, Action<Exception, object> cb)
  589. {
  590. try
  591. {
  592. int zc = ZoneNodeCount;
  593. int pc = PlayerCount;
  594. int ActiveObjectCount = InstanceZoneObject.ActiveObjectCount;
  595. int AllocObjectCount = InstanceZoneObject.AllocObjectCount;
  596. int ActiveZoneCount = InstanceZone.ActiveZoneCount;
  597. int AllocZoneCount = InstanceZone.AllocZoneCount;
  598. float w = zc * 1000 + pc;
  599. int flag = IceManager.instance().getCallback(serverID) == null ? 0 : 1;
  600. dynamic ret = new
  601. {
  602. weight = w,
  603. memory = ProcessPrivateMemoryMB,
  604. zone_count = zc,
  605. player_count = pc,
  606. ActiveObjectCount = ActiveObjectCount,
  607. AllocObjectCount = AllocObjectCount,
  608. ActiveZoneCount = ActiveZoneCount,
  609. AllocZoneCount = AllocZoneCount,
  610. flag = flag,
  611. };
  612. cb(null, ret);
  613. }
  614. catch (Exception e)
  615. {
  616. log.Error("GetServerState failed, error: " + e.Message, e);
  617. cb(e, e.Message);
  618. }
  619. }
  620. public void RegisterGameServer(int serverId, int crossId, Action<Exception, string> cb)
  621. {
  622. try
  623. {
  624. var str = ConfigurationManager.AppSettings["game.server.id"];
  625. if (!string.IsNullOrEmpty(str) && int.Parse(str) != serverId && int.Parse(str) != crossId)
  626. {
  627. cb(null, "1");
  628. return;
  629. }
  630. }
  631. catch (Exception e)
  632. {
  633. cb(e, "2");
  634. return;
  635. }
  636. cb(null, S_BSVersion);
  637. }
  638. //获取单位血量
  639. public void GetUnitHP(string instanceId, int objectId, Action<Exception, int> cb)
  640. {
  641. try
  642. {
  643. var node = getZoneNode(instanceId);
  644. if (node == null)
  645. {
  646. cb(null, -1);
  647. return;
  648. }
  649. InstanceUnit unit = node.Node.Zone.getUnit((uint)objectId);
  650. if (unit == null)
  651. {
  652. cb(null, -2);
  653. return;
  654. }
  655. cb(null, unit.CurrentHP);
  656. }
  657. catch (Exception e)
  658. {
  659. cb(e, -10);
  660. return;
  661. }
  662. }
  663. //----------------------------------------------------------------------------------------------
  664. }
  665. }