ZoneNode.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. using CommonAI.RTS;
  2. using CommonAI.Zone;
  3. using CommonAI.Zone.Helper;
  4. using CommonAI.Zone.Instance;
  5. using CommonAI.Zone.ZoneEditor;
  6. using CommonAI.ZoneClient;
  7. using CommonLang;
  8. using CommonLang.ByteOrder;
  9. using CommonLang.IO;
  10. using CommonLang.IO.Attribute;
  11. using CommonLang.Log;
  12. using CommonLang.Property;
  13. using CommonLang.Protocol;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Linq;
  17. using System.Text;
  18. using CommonAI.ZoneServer;
  19. using System.Threading;
  20. using CommonLang.Concurrent;
  21. using System.Diagnostics;
  22. using CommonAIServer.Node.Interface;
  23. using CommonLang.Vector;
  24. using CommonAI.Zone.Interface;
  25. namespace CommonAIServer.Node
  26. {
  27. public class ZoneNode : BaseZoneNode
  28. {
  29. //------------------------------------------------------------------------------------------------------------
  30. /// <summary>
  31. /// 存储玩家UUID和场景内单位的对应关系,如果玩家掉线重连,优先从此表内获取单位信息。
  32. /// </summary>
  33. private PlayerClientMap mPlayerObjectMap = new PlayerClientMap();
  34. private bool mEnableAOI = true;
  35. //最后一次场景掉落物时间
  36. private long mCheckDropEndTime;
  37. //------------------------------------------------------------------------------------------------------------
  38. public ZoneNode(EditorTemplates data_root, ZoneNodeConfig cfg)
  39. : base(data_root, cfg)
  40. {
  41. }
  42. public int PlayerCount
  43. {
  44. get { return mPlayerObjectMap.Count; }
  45. }
  46. public bool EnableAOI
  47. {
  48. get { return mEnableAOI; }
  49. set
  50. {
  51. lock (this)
  52. {
  53. if (mEnableAOI != value)
  54. {
  55. mEnableAOI = value;
  56. OnAoiChanged(value);
  57. }
  58. }
  59. }
  60. }
  61. /// <summary>
  62. /// 根据UUID获取单位
  63. /// </summary>
  64. /// <param name="uuid"></param>
  65. /// <returns></returns>
  66. public InstancePlayer GetPlayer(string uuid)
  67. {
  68. return mPlayerObjectMap.GetPlayer(uuid);
  69. }
  70. public PlayerClient GetPlayerClient(string uuid)
  71. {
  72. return mPlayerObjectMap.GetClient(uuid);
  73. }
  74. public bool GetPlayerAndClient(string uuid, out InstancePlayer player, out PlayerClient client)
  75. {
  76. return mPlayerObjectMap.Get(uuid, out player, out client);
  77. }
  78. /// <summary>
  79. /// 遍历所有客户端
  80. /// </summary>
  81. /// <param name="action"></param>
  82. public void ForEachPlayers(Action<PlayerClient> action)
  83. {
  84. mPlayerObjectMap.ForEachPlayers(action);
  85. }
  86. /// <summary>
  87. /// 单位进入场景
  88. /// </summary>
  89. /// <param name="player"></param>
  90. /// <param name="temp"></param>
  91. /// <param name="force"></param>
  92. /// <param name="level"></param>
  93. /// <param name="enterPos"></param>
  94. /// <param name="direction"></param>
  95. /// <param name="callback"></param>
  96. /// <param name="callerror"></param>
  97. public void PlayerEnter(IPlayer player, UnitInfo temp, int force, int alliesForce, int level, Vector2 enterPos,
  98. float direction,Action<PlayerClient> callback, Action<Exception> callerror)
  99. {
  100. // 客户端连接到战斗服 //
  101. QueueTask(() =>
  102. {
  103. try
  104. {
  105. if (mPlayerObjectMap.ContainsKey(player.PlayerUUID))
  106. {
  107. if(player.BindingPlayer == null)
  108. {
  109. log.Warn(this.Name + " Player reconnect : " + player.PlayerUUID);
  110. }
  111. else
  112. {
  113. log.Warn(this.Name + " Player already exist : " + player.BindingPlayer.Actor.Name +"," +player.PlayerUUID);
  114. }
  115. }
  116. // 场景内已有玩家 //
  117. InstancePlayer actor = Zone.getPlayerByUUID(player.PlayerUUID);
  118. if (actor == null)
  119. {
  120. // 有出生点则放入出生点 //
  121. if (enterPos == null)
  122. {
  123. enterPos = new Vector2();
  124. ZoneRegion start = base.Zone.GetEditStartRegion(force);
  125. if (start != null)
  126. {
  127. CMath.RandomPosInRound(Zone.RandomN, start.X, start.Y, start.Radius, ref enterPos);
  128. }
  129. else
  130. {
  131. // 没有出身点,随机一个出生点 //
  132. using (var kvs = ListObjectPool< KeyValuePair < int, ZoneRegion>>.AllocAutoRelease())
  133. {
  134. base.Zone.GetEditStartRegions(kvs);
  135. if (kvs.Count > 0)
  136. {
  137. start = CUtils.GetRandomInArray(kvs, Zone.RandomN).Value;
  138. if (start != null)
  139. {
  140. CMath.RandomPosInRound(Zone.RandomN, start.X, start.Y, start.Radius, ref enterPos);
  141. }
  142. }
  143. }
  144. }
  145. }
  146. AddUnitEvent add;
  147. try
  148. {
  149. actor = base.Zone.AddUnit(
  150. temp,
  151. player.PlayerUUID,
  152. force,
  153. level,
  154. enterPos.X,
  155. enterPos.Y,
  156. direction,
  157. out add, null, "", 0, alliesForce) as InstancePlayer;
  158. if (actor != null)
  159. {
  160. // 初始化 InstanceUnit 各个字段 //
  161. actor.Alias = player.DisplayName;
  162. add.Sync.Name = player.DisplayName;
  163. add.Sync.Level = level;
  164. }
  165. }
  166. catch(Exception e)
  167. {
  168. log.Error("AddUnit catch:" + (player == null ? "player null" : player.PlayerUUID) + ", " +
  169. (enterPos == null ? "pos null" : " pos ok") + ", " + e);
  170. }
  171. }
  172. else
  173. {
  174. actor.OnReconnected(temp, force, level, enterPos);
  175. }
  176. if (actor != null)
  177. {
  178. // 绑定客户端ID和游戏角色 //
  179. //zc.Actor.ClientID = zc.ID;
  180. //绑定关系//
  181. PlayerClient zc = CreatePlayerClient(player, actor);
  182. // 准备发送当前场景信息 //
  183. mPlayerObjectMap.PutPlayer(zc);
  184. zc.Send(new ClientEnterScene(SceneData.ID, Zone.SpaceDivSize, Templates.ResourceVersion), true);
  185. zc.Send(actor.GenLockActorEvent(player.DisplayName, zc.SyncObjectRange, zc.SyncObjectOutRange, base.UpdateInterval), true);
  186. zc.Send(actor.GetSyncSkillActives(), true);
  187. zc.Send(Zone.GetSyncFlagsEvent(), true);
  188. zc.Start();
  189. if (!mEnableAOI)
  190. {
  191. zc.Send(zc.GetSyncObjectsEvent(), true);
  192. }
  193. OnPlayerEntered(zc);
  194. callback(zc);
  195. }
  196. else
  197. {
  198. callerror(new Exception("Can not add player : " + temp));
  199. }
  200. }
  201. catch (Exception err)
  202. {
  203. log.Error(err.Message, err);
  204. OnError(err);
  205. callerror(err);
  206. }
  207. });
  208. }
  209. /// <summary>
  210. /// 单位离开场景
  211. /// </summary>
  212. /// <param name="player"></param>
  213. /// <param name="callback"></param>
  214. /// <param name="callerror"></param>
  215. /// <param name="keep_object">保留单位</param>
  216. public void PlayerLeave(InstancePlayer player, Action<PlayerClient> callback, Action<Exception> callerror, bool keep_object = false)
  217. {
  218. if (player == null) return;
  219. QueueTask(() =>
  220. {
  221. try
  222. {
  223. InstancePlayer out_player;
  224. PlayerClient out_client;
  225. if (mPlayerObjectMap.RemoveByKey(player.PlayerUUID, out out_player, out out_client))
  226. {
  227. try
  228. {
  229. if (!keep_object)
  230. {
  231. player.removeFromParent();
  232. }
  233. else
  234. {
  235. player.OnDisconnected();
  236. }
  237. // 通知客户端清理BattleClient //
  238. out_client.Send(new PlayerLeaveScene(out_player.ID), true);
  239. OnPlayerLeft(out_client);
  240. }
  241. finally
  242. {
  243. out_client.Dispose();
  244. }
  245. callback(out_client);
  246. }
  247. else
  248. {
  249. callerror(new Exception("leave Player not exist : " + player.PlayerUUID + "from " + this.Name));
  250. }
  251. }
  252. catch (Exception err)
  253. {
  254. log.Error(err.Message, err);
  255. OnError(err);
  256. callerror(err);
  257. }
  258. });
  259. }
  260. //------------------------------------------------------------------------------------------------------------
  261. #region _Virtual_And_Override_
  262. protected override void OnZoneUpdate(bool slowRefresh)
  263. {
  264. //客户端更新//
  265. mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
  266. {
  267. c.BeginUpdate(slowRefresh);
  268. });
  269. //向客户端推送实时场景信息//
  270. mPlayerObjectMap.ForEachPlayers((PlayerClient zc) =>
  271. {
  272. foreach (IMessage msg in PostZoneEvents)
  273. {
  274. zc.Send(msg);
  275. }
  276. });
  277. //客户端更新//
  278. mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
  279. {
  280. c.EndUpdate(slowRefresh);
  281. });
  282. }
  283. protected virtual void OnAoiChanged(bool enable)
  284. {
  285. if (!enable)
  286. {
  287. ForEachPlayers((zc) =>
  288. {
  289. zc.Send(zc.GetSyncObjectsEvent(), true);
  290. });
  291. }
  292. }
  293. protected virtual void OnPlayerEntered(PlayerClient client) { }
  294. protected virtual void OnPlayerLeft(PlayerClient client) { }
  295. protected void RecordDropItem()
  296. {
  297. ////场景掉落物最大存活时间,用来降低检测频率
  298. this.mCheckDropEndTime = CommonLang.CUtils.localTimeMS + 120000;
  299. }
  300. public override bool CheckDropItem()
  301. {
  302. return this.mCheckDropEndTime > CommonLang.CUtils.localTimeMS;
  303. }
  304. /// <summary>
  305. /// 过滤消息,过滤掉非知晓消息
  306. /// </summary>
  307. /// <param name="client"></param>
  308. /// <param name="msg"></param>
  309. /// <returns></returns>
  310. protected virtual IMessage FilterSendingMessage(PlayerClient client, CommonLang.Protocol.IMessage msg)
  311. {
  312. if (!mEnableAOI)
  313. {
  314. return msg;
  315. }
  316. InstancePlayer mActor = client.Actor;
  317. if (msg is AddUnitEvent)
  318. {
  319. return null;
  320. }
  321. else if (msg is AddItemEvent)
  322. {
  323. return null;
  324. }
  325. else if (msg is AddSpellEvent)
  326. {
  327. return null;
  328. }
  329. else if (msg is RemoveObjectEvent)
  330. {
  331. return null;
  332. }
  333. // 过滤不是发给自己的聊天指令 //
  334. else if (msg is ChatEvent)
  335. {
  336. ChatEvent chat = msg as ChatEvent;
  337. switch (chat.To)
  338. {
  339. case ChatMessageType.SystemToForce:
  340. case ChatMessageType.PlayerToForce:
  341. if (chat.Force != mActor.Force)
  342. {
  343. return null;
  344. }
  345. break;
  346. case ChatMessageType.SystemToPlayer:
  347. case ChatMessageType.PlayerToPlayer:
  348. if (!string.Equals(chat.ToPlayerUUID, client.PlayerUUID))
  349. {
  350. return null;
  351. }
  352. break;
  353. }
  354. }
  355. else if (msg is UnitHitEvent)
  356. {
  357. //过滤不是自己有关的伤害//
  358. UnitHitEvent he = msg as UnitHitEvent;
  359. //if (he.senderId != mActor.ID && he.object_id != mActor.ID)
  360. //{
  361. // ISummonedUnit summon = Zone.getUnit(he.senderId) as ISummonedUnit;
  362. // if (summon == null || summon.SummonerUnit != mActor)
  363. // {
  364. // summon = Zone.getUnit(he.object_id) as ISummonedUnit;
  365. // if (summon == null || summon.SummonerUnit != mActor)
  366. // {
  367. // return null;
  368. // }
  369. // }
  370. //}
  371. if (he.senderId != mActor.ID && he.object_id != mActor.ID && he.senderMasterId != mActor.ID && he.hitMasterId != mActor.ID)
  372. {
  373. if(he.InViewForceSend && he.sender != null && client.IsInView(he.sender as InstanceZoneObject))
  374. {
  375. return msg;
  376. }
  377. return null;
  378. }
  379. }
  380. else if(msg is PlayerSingleMsg)
  381. {
  382. ObjectEvent talnetInfo = msg as ObjectEvent;
  383. if(talnetInfo.ObjectID != mActor.ID)
  384. {
  385. return null;
  386. }
  387. }
  388. else if (msg is PlayerEvent)
  389. {
  390. // 过滤不是本人的玩家事件 //
  391. PlayerEvent pe = msg as PlayerEvent;
  392. if (pe.object_id != mActor.ID)
  393. {
  394. return null;
  395. }
  396. }
  397. else if (msg is ActorMessage)
  398. {
  399. // 过滤不是本人的玩家事件 //
  400. ActorMessage pe = msg as ActorMessage;
  401. if (pe.ObjectID != mActor.ID)
  402. {
  403. return null;
  404. }
  405. }
  406. else if (msg is ObjectEvent)
  407. {
  408. // 过滤不在自己感兴趣范围内的消息 //
  409. ObjectEvent om = msg as ObjectEvent;
  410. if (om.ObjectID != mActor.ID && om.sender is InstanceZoneObject)
  411. {
  412. InstanceZoneObject obj = om.sender as InstanceZoneObject;
  413. if (!client.IsInView(obj))
  414. {
  415. return null;
  416. }
  417. }
  418. }
  419. else if (msg is ClientEvent)
  420. {
  421. // 过滤不是发给本人的ClientEvent事件 //
  422. ClientEvent cm = msg as ClientEvent;
  423. if (cm.sender != null && cm.sender != mActor)
  424. {
  425. return null;
  426. }
  427. }
  428. else if (msg is PositionMessage)
  429. {
  430. // 过滤不在自己感兴趣范围内的消息 //
  431. PositionMessage pm = msg as PositionMessage;
  432. if (!client.IsLookInRange(pm.X, pm.Y))
  433. {
  434. return null;
  435. }
  436. }
  437. return msg;
  438. }
  439. #endregion
  440. //------------------------------------------------------------------------------------------------------------
  441. //------------------------------------------------------------------------------------------------------------
  442. #region __客户端__
  443. protected virtual PlayerClient CreatePlayerClient(IPlayer client, InstancePlayer actor)
  444. {
  445. return new PlayerClient(client, actor, this, Config.CLIENT_SYNC_OBJECT_IN_RANGE, Config.CLIENT_SYNC_OBJECT_OUT_RANGE);
  446. }
  447. public class PlayerClient : PlayerClientObject
  448. {
  449. private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
  450. private static AtomicInteger s_active_object_count = new AtomicInteger(0);
  451. /// <summary>
  452. /// 未释放实例数量
  453. /// </summary>
  454. public static int ActiveCount { get { return s_active_object_count.Value; } }
  455. /// <summary>
  456. /// 分配实例数量
  457. /// </summary>
  458. public static int AllocCount { get { return s_alloc_object_count.Value; } }
  459. private readonly IPlayer mClient;
  460. private readonly ZoneNode mNode;
  461. private readonly EditorScene mZone;
  462. private readonly InstancePlayer mActor;
  463. private readonly float mSyncObjectInRange;
  464. private readonly float mSyncObjectOutRange;
  465. private bool mDisposed = false;
  466. private long mPreUpdateTime = 0;
  467. // 视野范围内的单位 //
  468. private readonly HashMap<uint, InstanceZoneObject> mInViewList = new HashMap<uint, InstanceZoneObject>();
  469. protected List<uint> m_RemovingList = new List<uint>();
  470. private Pong mSendPong = new Pong();
  471. public float SyncObjectRange { get { return mSyncObjectInRange; } }
  472. public float SyncObjectOutRange { get { return mSyncObjectOutRange; } }
  473. public ZoneNode Node { get { return mNode; } }
  474. public EditorScene Zone { get { return mZone; } }
  475. public InstancePlayer Actor { get { return mActor; } }
  476. public IPlayer Client { get { return mClient; } }
  477. public string PlayerUUID { get { return mClient.PlayerUUID; } }
  478. public long UpdateTime { get { return mPreUpdateTime; } set{mPreUpdateTime = value;}
  479. }
  480. public PlayerClient(IPlayer client, InstancePlayer actor, ZoneNode node, float look_in_range, float look_out_range)
  481. {
  482. s_alloc_object_count++;
  483. s_active_object_count++;
  484. this.mActor = actor;
  485. this.mClient = client;
  486. this.mNode = node;
  487. this.mZone = node.Zone;
  488. this.mSyncObjectInRange = Math.Min(look_in_range, look_out_range);
  489. this.mSyncObjectOutRange = Math.Max(look_in_range, look_out_range);
  490. if ((int)(mSyncObjectOutRange / mZone.SpaceDivSize) <= (int)(mSyncObjectInRange / mZone.SpaceDivSize))
  491. {
  492. mSyncObjectOutRange = mSyncObjectInRange + mZone.SpaceDivSize;
  493. }
  494. this.mInViewList.Add(mActor.ID, mActor);
  495. this.mClient.Listen(RecvInternal);
  496. this.mClient.BindingPlayer = this;
  497. this.mClient.OnConnected(this);
  498. }
  499. ~PlayerClient()
  500. {
  501. s_alloc_object_count--;
  502. }
  503. internal void Dispose()
  504. {
  505. if (mDisposed) { return; }
  506. this.Disposing();
  507. this.mClient.OnDisconnect(this);
  508. this.mClient.BindingPlayer = null;
  509. this.mDisposed = true;
  510. s_active_object_count--;
  511. }
  512. protected virtual void Disposing() { }
  513. protected virtual void OnStart() { }
  514. protected virtual void OnBeginUpdate() { }
  515. protected virtual void OnEndUpdate() { }
  516. internal void Start()
  517. {
  518. OnStart();
  519. BeginUpdate(true);
  520. }
  521. /// <summary>
  522. /// 定时更新Client
  523. /// </summary>
  524. internal void BeginUpdate(bool slowRefresh)
  525. {
  526. OnBeginUpdate();
  527. if (mNode.mEnableAOI && slowRefresh)
  528. {
  529. LookInRange();
  530. }
  531. }
  532. internal void EndUpdate(bool slowRefresh)
  533. {
  534. if (mNode.mEnableAOI)
  535. {
  536. LookOutRange(slowRefresh);
  537. // 一直同步周围单位
  538. SyncPosEvent mSyncPosLocal = GetSyncPosEvent();
  539. if (mSyncPosLocal != null && !mSyncPosLocal.IsEmpty)
  540. {
  541. mClient.Send(mSyncPosLocal);
  542. }
  543. }
  544. OnEndUpdate();
  545. }
  546. /// <summary>
  547. /// 排队发送消息
  548. /// </summary>
  549. /// <param name="msg"></param>
  550. /// <param name="immediately"></param>
  551. public void Send(IMessage msg, bool immediately = false)
  552. {
  553. if (mNode.mEnableAOI)
  554. {
  555. if (immediately)
  556. {
  557. this.mClient.Send(msg);
  558. }
  559. else if (msg is AddSpellEvent)
  560. {
  561. OnLookSpell(msg as AddSpellEvent);
  562. }
  563. else
  564. {
  565. msg = mNode.FilterSendingMessage(this, msg);
  566. if (msg != null)
  567. {
  568. this.mClient.Send(msg);
  569. }
  570. }
  571. }
  572. else
  573. {
  574. this.mClient.Send(msg);
  575. }
  576. }
  577. /// <summary>
  578. /// 从客户端接收消息
  579. /// </summary>
  580. /// <param name="message"></param>
  581. private void RecvInternal(object message)
  582. {
  583. if (message is Ping)
  584. {
  585. var ping = message as Ping;
  586. mSendPong.ClientTimeDayOfMS = ping.DayOfMS;
  587. mClient.Send(mSendPong);
  588. return;
  589. }
  590. else
  591. {
  592. //mNode.QueueTask(() =>
  593. //{
  594. if (mActor.Enable)
  595. {
  596. ObjectAction oa = message as ObjectAction;
  597. if (oa != null)
  598. {
  599. //BaseZoneNode.log.Debug("C2B msg<<<" + oa);
  600. oa.object_id = mActor.ID;
  601. oa.sender = mActor;
  602. if (oa is ActorRequest)
  603. {
  604. mActor.doRequest(oa as ActorRequest);
  605. }
  606. else
  607. {
  608. mZone.pushAction(oa);
  609. }
  610. }
  611. }
  612. //});
  613. }
  614. }
  615. //------------------------------------------------------------------------------------------------------------
  616. //------------------------------------------------------------------------------------------------------------
  617. #region _AOI_视野控制_
  618. /// <summary>
  619. /// 获取当前场景内所有单位,用于同步现有场景中单位
  620. /// </summary>
  621. /// <returns></returns>
  622. public SyncObjectsEvent GetSyncObjectsEvent()
  623. {
  624. if (mNode.mEnableAOI)
  625. {
  626. return mZone.GetSyncObjectsEvent(mInViewList.Values);
  627. }
  628. else
  629. {
  630. return mZone.GetSyncUnitsEvent(mActor);
  631. }
  632. }
  633. public bool IsInView(InstanceZoneObject obj)
  634. {
  635. if (mNode.mEnableAOI)
  636. return mInViewList.ContainsKey(obj.ID);
  637. else
  638. return true;
  639. }
  640. public bool IsLookInRange(float x, float y)
  641. {
  642. if (mNode.mEnableAOI)
  643. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, x, y);
  644. else
  645. return true;
  646. }
  647. public SyncPosEvent GetSyncPosEvent()
  648. {
  649. return mZone.GetSyncPosEvent(mInViewList.Values, this.Actor, this);
  650. }
  651. /// <summary>
  652. /// 判断单位是否进入视野
  653. /// </summary>
  654. /// <param name="obj"></param>
  655. /// <returns>True,进入视野</returns>
  656. protected virtual bool IsLookInRange(InstanceZoneObject obj)
  657. {
  658. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, obj.X, obj.Y);
  659. }
  660. /// <summary>
  661. /// 判断单位是否超出视野
  662. /// </summary>
  663. /// <param name="obj"></param>
  664. /// <returns>True,超出视野</returns>
  665. protected virtual bool IsLookOutRange(InstanceZoneObject obj)
  666. {
  667. return !CMath.includeRoundPoint(mActor.GetX(), mActor.GetY(), mSyncObjectOutRange, obj.GetX(), obj.GetY());
  668. }
  669. protected void ForceAddObjectInView(InstanceZoneObject obj)
  670. {
  671. if (!mInViewList.ContainsKey(obj.ID))
  672. {
  673. mInViewList.Put(obj.ID, obj);
  674. OnEnterView(obj);
  675. }
  676. }
  677. private void LookInRange()
  678. {
  679. mZone.ForEachNearObjects<InstanceZoneObject>(mActor.X, mActor.Y, mSyncObjectInRange, mZone_CheckInRange);
  680. }
  681. private void mZone_CheckInRange(InstanceZoneObject o, ref bool cancel)
  682. {
  683. if ((o != mActor) && o.ClientVisible && !(o is InstanceSpell) && !mInViewList.ContainsKey(o.ID))
  684. {
  685. if (o.Enable && mZone.IsVisibleAOI(mActor, o) && IsLookInRange(o))
  686. {
  687. mInViewList.Put(o.ID, o);
  688. OnEnterView(o);
  689. }
  690. }
  691. }
  692. private void LookOutRange(bool slowRefresh)
  693. {
  694. foreach (InstanceZoneObject o in mInViewList.Values)
  695. {
  696. if (o == mActor)
  697. {
  698. continue;
  699. }
  700. if (!o.Enable || (slowRefresh && (!mZone.IsVisibleAOI(mActor, o) || IsLookOutRange(o))))
  701. {
  702. m_RemovingList.Add(o.ID);
  703. OnLeaveView(o);
  704. }
  705. }
  706. if (m_RemovingList.Count > 0)
  707. {
  708. foreach (uint oid in m_RemovingList)
  709. {
  710. mInViewList.Remove(oid);
  711. }
  712. m_RemovingList.Clear();
  713. }
  714. }
  715. public virtual bool RemoveInRange(InstanceZoneObject o) { return false; }
  716. protected virtual void OnLookSpell(AddSpellEvent em)
  717. {
  718. // 过滤不在自己感兴趣范围内的消息
  719. if (em.sender is InstanceSpell)
  720. {
  721. var sp = em.sender as InstanceSpell;
  722. //作用于自己或者自己发射的//
  723. if (sp.Launcher == mActor || sp.Target == mActor)
  724. {
  725. mInViewList.Put(sp.ID, sp);
  726. mClient.Send(em);
  727. return;
  728. }
  729. if (mZone.IsVisibleAOI(mActor, sp))
  730. {
  731. if (IsLookInRange(em.x, em.y))
  732. {
  733. mInViewList.Put(sp.ID, sp);
  734. mClient.Send(em);
  735. return;
  736. }
  737. }
  738. }
  739. }
  740. protected virtual void OnEnterView(InstanceZoneObject obj)
  741. {
  742. if (obj is InstanceUnit)
  743. {
  744. InstanceUnit u = obj as InstanceUnit;
  745. var sync = u.GenSyncUnitInfo(true);
  746. var add = new AddUnitEvent(sync);
  747. mClient.Send(add);
  748. if(u.Info.SpawnEffect != null && u.CurrentActionStatus == UnitActionStatus.Spawn)
  749. {
  750. u.Parent.queueEvent(new AddEffectEvent(u.ID, u.X, u.Y, u.Direction, u.Info.SpawnEffect));
  751. }
  752. }
  753. else if (obj is InstanceItem)
  754. {
  755. InstanceItem i = obj as InstanceItem;
  756. var sync = i.GenSyncItemInfo(true, this.PlayerUUID);
  757. var add = new AddItemEvent(sync);
  758. mClient.Send(add);
  759. }
  760. }
  761. protected virtual void OnLeaveView(InstanceZoneObject obj)
  762. {
  763. RemoveObjectEvent remove = new RemoveObjectEvent(obj.ID);
  764. mClient.Send(remove);
  765. }
  766. public void ForEachInViewList(Action<InstanceZoneObject> action)
  767. {
  768. using (var list = ListObjectPool<InstanceZoneObject>.AllocAutoRelease(mInViewList.Values))
  769. {
  770. foreach (var obj in list) { action(obj); }
  771. }
  772. }
  773. #endregion
  774. //------------------------------------------------------------------------------------------------------------
  775. // private OnObjectEnterViewHandler event_OnObjectEnterView;
  776. // private OnObjectLeaveViewHandler event_OnObjectLeaveView;
  777. // public delegate void OnObjectEnterViewHandler(PlayerClient sender, InstanceZoneObject obj);
  778. // public delegate void OnObjectLeaveViewHandler(PlayerClient sender, InstanceZoneObject obj);
  779. // public event OnObjectEnterViewHandler OnObjectEnterView { add { event_OnObjectEnterView += value; } remove { event_OnObjectEnterView -= value; } }
  780. // public event OnObjectLeaveViewHandler OnObjectLeaveView { add { event_OnObjectLeaveView += value; } remove { event_OnObjectLeaveView -= value; } }
  781. }
  782. private class PlayerClientMap
  783. {
  784. private HashMap<string, InstancePlayer> mPlayerObjectMap = new HashMap<string, InstancePlayer>();
  785. private HashMap<string, PlayerClient> mPlayerClientMap = new HashMap<string, PlayerClient>();
  786. public int Count
  787. {
  788. get
  789. {
  790. lock (this)
  791. {
  792. return mPlayerClientMap.Count;
  793. }
  794. }
  795. }
  796. public InstancePlayer[] Players
  797. {
  798. get
  799. {
  800. lock (this)
  801. {
  802. return mPlayerObjectMap.Values.ToArray();
  803. }
  804. }
  805. }
  806. public void PutPlayer(PlayerClient client)
  807. {
  808. lock (this)
  809. {
  810. mPlayerObjectMap.Put(client.PlayerUUID, client.Actor);
  811. mPlayerClientMap.Put(client.PlayerUUID, client);
  812. }
  813. }
  814. public InstancePlayer GetPlayer(string uuid)
  815. {
  816. lock (this)
  817. {
  818. return mPlayerObjectMap.Get(uuid);
  819. }
  820. }
  821. public PlayerClient GetClient(string uuid)
  822. {
  823. lock (this)
  824. {
  825. return mPlayerClientMap.Get(uuid);
  826. }
  827. }
  828. public bool Get(string uuid, out InstancePlayer player, out PlayerClient client)
  829. {
  830. lock (this)
  831. {
  832. player = mPlayerObjectMap.Get(uuid);
  833. client = mPlayerClientMap.Get(uuid);
  834. }
  835. return client != null;
  836. }
  837. public bool RemoveByKey(string uuid, out InstancePlayer player, out PlayerClient client)
  838. {
  839. lock (this)
  840. {
  841. player = mPlayerObjectMap.RemoveByKey(uuid);
  842. client = mPlayerClientMap.RemoveByKey(uuid);
  843. }
  844. return client != null;
  845. }
  846. public bool ContainsKey(string uuid)
  847. {
  848. lock (this)
  849. {
  850. return mPlayerObjectMap.ContainsKey(uuid);
  851. }
  852. }
  853. public void ForEachPlayers(Action<PlayerClient> action)
  854. {
  855. lock (this)
  856. {
  857. foreach (PlayerClient c in mPlayerClientMap.Values)
  858. {
  859. action(c);
  860. }
  861. }
  862. }
  863. }
  864. //------------------------------------------------------------------------------------------------------------
  865. #endregion
  866. }
  867. }