ZoneNode.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  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. public override void ZoneUpdate(int intervalMS)
  263. {
  264. Zone.SyncPos = !mEnableAOI;
  265. base.ZoneUpdate(intervalMS);
  266. }
  267. protected override void OnZoneUpdate(bool slowRefresh)
  268. {
  269. //客户端更新//
  270. mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
  271. {
  272. c.BeginUpdate(slowRefresh);
  273. });
  274. //向客户端推送实时场景信息//
  275. mPlayerObjectMap.ForEachPlayers((PlayerClient zc) =>
  276. {
  277. foreach (IMessage msg in PostZoneEvents)
  278. {
  279. zc.Send(msg);
  280. }
  281. });
  282. //客户端更新//
  283. mPlayerObjectMap.ForEachPlayers((PlayerClient c) =>
  284. {
  285. c.EndUpdate(slowRefresh);
  286. });
  287. }
  288. protected virtual void OnAoiChanged(bool enable)
  289. {
  290. if (!enable)
  291. {
  292. ForEachPlayers((zc) =>
  293. {
  294. zc.Send(zc.GetSyncObjectsEvent(), true);
  295. });
  296. }
  297. }
  298. protected virtual void OnPlayerEntered(PlayerClient client) { }
  299. protected virtual void OnPlayerLeft(PlayerClient client) { }
  300. protected void RecordDropItem()
  301. {
  302. ////场景掉落物最大存活时间,用来降低检测频率
  303. this.mCheckDropEndTime = CommonLang.CUtils.localTimeMS + 300000;
  304. }
  305. public override bool CheckDropItem()
  306. {
  307. return this.mCheckDropEndTime > CommonLang.CUtils.localTimeMS;
  308. }
  309. /// <summary>
  310. /// 过滤消息,过滤掉非知晓消息
  311. /// </summary>
  312. /// <param name="client"></param>
  313. /// <param name="msg"></param>
  314. /// <returns></returns>
  315. protected virtual IMessage FilterSendingMessage(PlayerClient client, CommonLang.Protocol.IMessage msg)
  316. {
  317. if (!mEnableAOI)
  318. {
  319. return msg;
  320. }
  321. InstancePlayer mActor = client.Actor;
  322. if (msg is AddUnitEvent)
  323. {
  324. return null;
  325. }
  326. else if (msg is AddItemEvent)
  327. {
  328. return null;
  329. }
  330. else if (msg is AddSpellEvent)
  331. {
  332. return null;
  333. }
  334. else if (msg is RemoveObjectEvent)
  335. {
  336. return null;
  337. }
  338. // 过滤不是发给自己的聊天指令 //
  339. else if (msg is ChatEvent)
  340. {
  341. ChatEvent chat = msg as ChatEvent;
  342. switch (chat.To)
  343. {
  344. case ChatMessageType.SystemToForce:
  345. case ChatMessageType.PlayerToForce:
  346. if (chat.Force != mActor.Force)
  347. {
  348. return null;
  349. }
  350. break;
  351. case ChatMessageType.SystemToPlayer:
  352. case ChatMessageType.PlayerToPlayer:
  353. if (!string.Equals(chat.ToPlayerUUID, client.PlayerUUID))
  354. {
  355. return null;
  356. }
  357. break;
  358. }
  359. }
  360. else if (msg is UnitHitEvent)
  361. {
  362. //过滤不是自己有关的伤害//
  363. UnitHitEvent he = msg as UnitHitEvent;
  364. //if (he.senderId != mActor.ID && he.object_id != mActor.ID)
  365. //{
  366. // ISummonedUnit summon = Zone.getUnit(he.senderId) as ISummonedUnit;
  367. // if (summon == null || summon.SummonerUnit != mActor)
  368. // {
  369. // summon = Zone.getUnit(he.object_id) as ISummonedUnit;
  370. // if (summon == null || summon.SummonerUnit != mActor)
  371. // {
  372. // return null;
  373. // }
  374. // }
  375. //}
  376. if (he.senderId != mActor.ID && he.object_id != mActor.ID && he.senderMasterId != mActor.ID && he.hitMasterId != mActor.ID)
  377. {
  378. if(he.InViewForceSend && he.sender != null && client.IsInView(he.sender as InstanceZoneObject))
  379. {
  380. return msg;
  381. }
  382. return null;
  383. }
  384. }
  385. else if(msg is PlayerSingleMsg)
  386. {
  387. ObjectEvent talnetInfo = msg as ObjectEvent;
  388. if(talnetInfo.ObjectID != mActor.ID)
  389. {
  390. return null;
  391. }
  392. }
  393. else if (msg is PlayerEvent)
  394. {
  395. // 过滤不是本人的玩家事件 //
  396. PlayerEvent pe = msg as PlayerEvent;
  397. if (pe.object_id != mActor.ID)
  398. {
  399. return null;
  400. }
  401. }
  402. else if (msg is ActorMessage)
  403. {
  404. // 过滤不是本人的玩家事件 //
  405. ActorMessage pe = msg as ActorMessage;
  406. if (pe.ObjectID != mActor.ID)
  407. {
  408. return null;
  409. }
  410. }
  411. else if (msg is ObjectEvent)
  412. {
  413. // 过滤不在自己感兴趣范围内的消息 //
  414. ObjectEvent om = msg as ObjectEvent;
  415. if (om.ObjectID != mActor.ID && om.sender is InstanceZoneObject)
  416. {
  417. InstanceZoneObject obj = om.sender as InstanceZoneObject;
  418. if (!client.IsInView(obj))
  419. {
  420. return null;
  421. }
  422. }
  423. }
  424. else if (msg is ClientEvent)
  425. {
  426. // 过滤不是发给本人的ClientEvent事件 //
  427. ClientEvent cm = msg as ClientEvent;
  428. if (cm.sender != null && cm.sender != mActor)
  429. {
  430. return null;
  431. }
  432. }
  433. else if (msg is PositionMessage)
  434. {
  435. // 过滤不在自己感兴趣范围内的消息 //
  436. PositionMessage pm = msg as PositionMessage;
  437. if (!client.IsLookInRange(pm.X, pm.Y))
  438. {
  439. return null;
  440. }
  441. }
  442. return msg;
  443. }
  444. #endregion
  445. //------------------------------------------------------------------------------------------------------------
  446. //------------------------------------------------------------------------------------------------------------
  447. #region __客户端__
  448. protected virtual PlayerClient CreatePlayerClient(IPlayer client, InstancePlayer actor)
  449. {
  450. return new PlayerClient(client, actor, this, Config.CLIENT_SYNC_OBJECT_IN_RANGE, Config.CLIENT_SYNC_OBJECT_OUT_RANGE);
  451. }
  452. public class PlayerClient : PlayerClientObject
  453. {
  454. private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
  455. private static AtomicInteger s_active_object_count = new AtomicInteger(0);
  456. /// <summary>
  457. /// 未释放实例数量
  458. /// </summary>
  459. public static int ActiveCount { get { return s_active_object_count.Value; } }
  460. /// <summary>
  461. /// 分配实例数量
  462. /// </summary>
  463. public static int AllocCount { get { return s_alloc_object_count.Value; } }
  464. private readonly IPlayer mClient;
  465. private readonly ZoneNode mNode;
  466. private readonly EditorScene mZone;
  467. private readonly InstancePlayer mActor;
  468. private readonly float mSyncObjectInRange;
  469. private readonly float mSyncObjectOutRange;
  470. private bool mDisposed = false;
  471. private long mPreUpdateTime = 0;
  472. // 视野范围内的单位 //
  473. private readonly HashMap<uint, InstanceZoneObject> mInViewList = new HashMap<uint, InstanceZoneObject>();
  474. protected List<uint> m_RemovingList = new List<uint>();
  475. private Pong mSendPong = new Pong();
  476. public float SyncObjectRange { get { return mSyncObjectInRange; } }
  477. public float SyncObjectOutRange { get { return mSyncObjectOutRange; } }
  478. public ZoneNode Node { get { return mNode; } }
  479. public EditorScene Zone { get { return mZone; } }
  480. public InstancePlayer Actor { get { return mActor; } }
  481. public IPlayer Client { get { return mClient; } }
  482. public string PlayerUUID { get { return mClient.PlayerUUID; } }
  483. public long UpdateTime { get { return mPreUpdateTime; } set{mPreUpdateTime = value;}
  484. }
  485. public PlayerClient(IPlayer client, InstancePlayer actor, ZoneNode node, float look_in_range, float look_out_range)
  486. {
  487. s_alloc_object_count++;
  488. s_active_object_count++;
  489. this.mActor = actor;
  490. this.mClient = client;
  491. this.mNode = node;
  492. this.mZone = node.Zone;
  493. this.mSyncObjectInRange = Math.Min(look_in_range, look_out_range);
  494. this.mSyncObjectOutRange = Math.Max(look_in_range, look_out_range);
  495. if ((int)(mSyncObjectOutRange / mZone.SpaceDivSize) <= (int)(mSyncObjectInRange / mZone.SpaceDivSize))
  496. {
  497. mSyncObjectOutRange = mSyncObjectInRange + mZone.SpaceDivSize;
  498. }
  499. this.mInViewList.Add(mActor.ID, mActor);
  500. this.mClient.Listen(RecvInternal);
  501. this.mClient.BindingPlayer = this;
  502. this.mClient.OnConnected(this);
  503. }
  504. ~PlayerClient()
  505. {
  506. s_alloc_object_count--;
  507. }
  508. internal void Dispose()
  509. {
  510. if (mDisposed) { return; }
  511. this.Disposing();
  512. this.mClient.OnDisconnect(this);
  513. this.mClient.BindingPlayer = null;
  514. this.mDisposed = true;
  515. s_active_object_count--;
  516. }
  517. protected virtual void Disposing() { }
  518. protected virtual void OnStart() { }
  519. protected virtual void OnBeginUpdate() { }
  520. protected virtual void OnEndUpdate() { }
  521. internal void Start()
  522. {
  523. OnStart();
  524. BeginUpdate(true);
  525. }
  526. /// <summary>
  527. /// 定时更新Client
  528. /// </summary>
  529. internal void BeginUpdate(bool slowRefresh)
  530. {
  531. OnBeginUpdate();
  532. if (mNode.mEnableAOI && slowRefresh)
  533. {
  534. LookInRange();
  535. }
  536. }
  537. internal void EndUpdate(bool slowRefresh)
  538. {
  539. if (mNode.mEnableAOI)
  540. {
  541. LookOutRange(slowRefresh);
  542. // 一直同步周围单位
  543. SyncPosEvent mSyncPosLocal = GetSyncPosEvent();
  544. if (mSyncPosLocal != null && !mSyncPosLocal.IsEmpty)
  545. {
  546. mClient.Send(mSyncPosLocal);
  547. }
  548. }
  549. OnEndUpdate();
  550. }
  551. /// <summary>
  552. /// 排队发送消息
  553. /// </summary>
  554. /// <param name="msg"></param>
  555. /// <param name="immediately"></param>
  556. public void Send(IMessage msg, bool immediately = false)
  557. {
  558. if (mNode.mEnableAOI)
  559. {
  560. if (immediately)
  561. {
  562. this.mClient.Send(msg);
  563. }
  564. else if (msg is AddSpellEvent)
  565. {
  566. OnLookSpell(msg as AddSpellEvent);
  567. }
  568. else
  569. {
  570. msg = mNode.FilterSendingMessage(this, msg);
  571. if (msg != null)
  572. {
  573. this.mClient.Send(msg);
  574. }
  575. }
  576. }
  577. else
  578. {
  579. this.mClient.Send(msg);
  580. }
  581. }
  582. /// <summary>
  583. /// 从客户端接收消息
  584. /// </summary>
  585. /// <param name="message"></param>
  586. private void RecvInternal(object message)
  587. {
  588. if (message is Ping)
  589. {
  590. var ping = message as Ping;
  591. mSendPong.ClientTimeDayOfMS = ping.DayOfMS;
  592. mClient.Send(mSendPong);
  593. return;
  594. }
  595. else
  596. {
  597. //mNode.QueueTask(() =>
  598. //{
  599. if (mActor.Enable)
  600. {
  601. ObjectAction oa = message as ObjectAction;
  602. if (oa != null)
  603. {
  604. BaseZoneNode.log.Debug("C2B msg<<<" + oa);
  605. oa.object_id = mActor.ID;
  606. oa.sender = mActor;
  607. if (oa is ActorRequest)
  608. {
  609. mActor.doRequest(oa as ActorRequest);
  610. }
  611. else
  612. {
  613. mZone.pushAction(oa);
  614. }
  615. }
  616. }
  617. //});
  618. }
  619. }
  620. //------------------------------------------------------------------------------------------------------------
  621. //------------------------------------------------------------------------------------------------------------
  622. #region _AOI_视野控制_
  623. /// <summary>
  624. /// 获取当前场景内所有单位,用于同步现有场景中单位
  625. /// </summary>
  626. /// <returns></returns>
  627. public SyncObjectsEvent GetSyncObjectsEvent()
  628. {
  629. if (mNode.mEnableAOI)
  630. {
  631. return mZone.GetSyncObjectsEvent(mInViewList.Values);
  632. }
  633. else
  634. {
  635. return mZone.GetSyncUnitsEvent(mActor);
  636. }
  637. }
  638. public bool IsInView(InstanceZoneObject obj)
  639. {
  640. if (mNode.mEnableAOI)
  641. return mInViewList.ContainsKey(obj.ID);
  642. else
  643. return true;
  644. }
  645. public bool IsLookInRange(float x, float y)
  646. {
  647. if (mNode.mEnableAOI)
  648. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, x, y);
  649. else
  650. return true;
  651. }
  652. public SyncPosEvent GetSyncPosEvent()
  653. {
  654. return mZone.GetSyncPosEvent(mInViewList.Values, this.Actor, this);
  655. }
  656. /// <summary>
  657. /// 判断单位是否进入视野
  658. /// </summary>
  659. /// <param name="obj"></param>
  660. /// <returns>True,进入视野</returns>
  661. protected virtual bool IsLookInRange(InstanceZoneObject obj)
  662. {
  663. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, obj.X, obj.Y);
  664. }
  665. /// <summary>
  666. /// 判断单位是否超出视野
  667. /// </summary>
  668. /// <param name="obj"></param>
  669. /// <returns>True,超出视野</returns>
  670. protected virtual bool IsLookOutRange(InstanceZoneObject obj)
  671. {
  672. return !CMath.includeRoundPoint(mActor.GetX(), mActor.GetY(), mSyncObjectOutRange, obj.GetX(), obj.GetY());
  673. }
  674. protected void ForceAddObjectInView(InstanceZoneObject obj)
  675. {
  676. if (!mInViewList.ContainsKey(obj.ID))
  677. {
  678. mInViewList.Put(obj.ID, obj);
  679. OnEnterView(obj);
  680. }
  681. }
  682. private void LookInRange()
  683. {
  684. mZone.ForEachNearObjects<InstanceZoneObject>(mActor.X, mActor.Y, mSyncObjectInRange, mZone_CheckInRange);
  685. }
  686. private void mZone_CheckInRange(InstanceZoneObject o, ref bool cancel)
  687. {
  688. if ((o != mActor) && o.ClientVisible && !(o is InstanceSpell) && !mInViewList.ContainsKey(o.ID))
  689. {
  690. if (o.Enable && mZone.IsVisibleAOI(mActor, o) && IsLookInRange(o))
  691. {
  692. mInViewList.Put(o.ID, o);
  693. OnEnterView(o);
  694. }
  695. }
  696. }
  697. private void LookOutRange(bool slowRefresh)
  698. {
  699. foreach (InstanceZoneObject o in mInViewList.Values)
  700. {
  701. if (o == mActor)
  702. {
  703. continue;
  704. }
  705. if (!o.Enable || (slowRefresh && (!mZone.IsVisibleAOI(mActor, o) || IsLookOutRange(o))))
  706. {
  707. m_RemovingList.Add(o.ID);
  708. OnLeaveView(o);
  709. }
  710. }
  711. if (m_RemovingList.Count > 0)
  712. {
  713. foreach (uint oid in m_RemovingList)
  714. {
  715. mInViewList.Remove(oid);
  716. }
  717. m_RemovingList.Clear();
  718. }
  719. }
  720. public virtual bool RemoveInRange(InstanceZoneObject o) { return false; }
  721. protected virtual void OnLookSpell(AddSpellEvent em)
  722. {
  723. // 过滤不在自己感兴趣范围内的消息
  724. if (em.sender is InstanceSpell)
  725. {
  726. var sp = em.sender as InstanceSpell;
  727. //作用于自己或者自己发射的//
  728. if (sp.Launcher == mActor || sp.Target == mActor)
  729. {
  730. mInViewList.Put(sp.ID, sp);
  731. mClient.Send(em);
  732. return;
  733. }
  734. if (mZone.IsVisibleAOI(mActor, sp))
  735. {
  736. if (IsLookInRange(em.x, em.y))
  737. {
  738. mInViewList.Put(sp.ID, sp);
  739. mClient.Send(em);
  740. return;
  741. }
  742. }
  743. }
  744. }
  745. protected virtual void OnEnterView(InstanceZoneObject obj)
  746. {
  747. if (obj is InstanceUnit)
  748. {
  749. InstanceUnit u = obj as InstanceUnit;
  750. var sync = u.GenSyncUnitInfo(true);
  751. var add = new AddUnitEvent(sync);
  752. mClient.Send(add);
  753. if(u.Info.SpawnEffect != null && u.CurrentActionStatus == UnitActionStatus.Spawn)
  754. {
  755. u.Parent.queueEvent(new AddEffectEvent(u.ID, u.X, u.Y, u.Direction, u.Info.SpawnEffect));
  756. }
  757. }
  758. else if (obj is InstanceItem)
  759. {
  760. InstanceItem i = obj as InstanceItem;
  761. var sync = i.GenSyncItemInfo(true, this.PlayerUUID);
  762. var add = new AddItemEvent(sync);
  763. mClient.Send(add);
  764. }
  765. }
  766. protected virtual void OnLeaveView(InstanceZoneObject obj)
  767. {
  768. RemoveObjectEvent remove = new RemoveObjectEvent(obj.ID);
  769. mClient.Send(remove);
  770. }
  771. public void ForEachInViewList(Action<InstanceZoneObject> action)
  772. {
  773. using (var list = ListObjectPool<InstanceZoneObject>.AllocAutoRelease(mInViewList.Values))
  774. {
  775. foreach (var obj in list) { action(obj); }
  776. }
  777. }
  778. #endregion
  779. //------------------------------------------------------------------------------------------------------------
  780. // private OnObjectEnterViewHandler event_OnObjectEnterView;
  781. // private OnObjectLeaveViewHandler event_OnObjectLeaveView;
  782. // public delegate void OnObjectEnterViewHandler(PlayerClient sender, InstanceZoneObject obj);
  783. // public delegate void OnObjectLeaveViewHandler(PlayerClient sender, InstanceZoneObject obj);
  784. // public event OnObjectEnterViewHandler OnObjectEnterView { add { event_OnObjectEnterView += value; } remove { event_OnObjectEnterView -= value; } }
  785. // public event OnObjectLeaveViewHandler OnObjectLeaveView { add { event_OnObjectLeaveView += value; } remove { event_OnObjectLeaveView -= value; } }
  786. }
  787. private class PlayerClientMap
  788. {
  789. private HashMap<string, InstancePlayer> mPlayerObjectMap = new HashMap<string, InstancePlayer>();
  790. private HashMap<string, PlayerClient> mPlayerClientMap = new HashMap<string, PlayerClient>();
  791. public int Count
  792. {
  793. get
  794. {
  795. lock (this)
  796. {
  797. return mPlayerClientMap.Count;
  798. }
  799. }
  800. }
  801. public InstancePlayer[] Players
  802. {
  803. get
  804. {
  805. lock (this)
  806. {
  807. return mPlayerObjectMap.Values.ToArray();
  808. }
  809. }
  810. }
  811. public void PutPlayer(PlayerClient client)
  812. {
  813. lock (this)
  814. {
  815. mPlayerObjectMap.Put(client.PlayerUUID, client.Actor);
  816. mPlayerClientMap.Put(client.PlayerUUID, client);
  817. }
  818. }
  819. public InstancePlayer GetPlayer(string uuid)
  820. {
  821. lock (this)
  822. {
  823. return mPlayerObjectMap.Get(uuid);
  824. }
  825. }
  826. public PlayerClient GetClient(string uuid)
  827. {
  828. lock (this)
  829. {
  830. return mPlayerClientMap.Get(uuid);
  831. }
  832. }
  833. public bool Get(string uuid, out InstancePlayer player, out PlayerClient client)
  834. {
  835. lock (this)
  836. {
  837. player = mPlayerObjectMap.Get(uuid);
  838. client = mPlayerClientMap.Get(uuid);
  839. }
  840. return client != null;
  841. }
  842. public bool RemoveByKey(string uuid, out InstancePlayer player, out PlayerClient client)
  843. {
  844. lock (this)
  845. {
  846. player = mPlayerObjectMap.RemoveByKey(uuid);
  847. client = mPlayerClientMap.RemoveByKey(uuid);
  848. }
  849. return client != null;
  850. }
  851. public bool ContainsKey(string uuid)
  852. {
  853. lock (this)
  854. {
  855. return mPlayerObjectMap.ContainsKey(uuid);
  856. }
  857. }
  858. public void ForEachPlayers(Action<PlayerClient> action)
  859. {
  860. lock (this)
  861. {
  862. foreach (PlayerClient c in mPlayerClientMap.Values)
  863. {
  864. action(c);
  865. }
  866. }
  867. }
  868. }
  869. //------------------------------------------------------------------------------------------------------------
  870. #endregion
  871. }
  872. }