ZoneNode.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  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.object_id))
  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 && !client.IsInView(om.ObjectID))
  411. {
  412. return null;
  413. }
  414. }
  415. else if (msg is ClientEvent)
  416. {
  417. // 过滤不是发给本人的ClientEvent事件 //
  418. ClientEvent cm = msg as ClientEvent;
  419. if (cm.sender != null && cm.sender != mActor)
  420. {
  421. return null;
  422. }
  423. }
  424. else if (msg is PositionMessage)
  425. {
  426. // 过滤不在自己感兴趣范围内的消息 //
  427. PositionMessage pm = msg as PositionMessage;
  428. if (!client.IsLookInRange(pm.X, pm.Y))
  429. {
  430. return null;
  431. }
  432. }
  433. return msg;
  434. }
  435. #endregion
  436. //------------------------------------------------------------------------------------------------------------
  437. //------------------------------------------------------------------------------------------------------------
  438. #region __客户端__
  439. protected virtual PlayerClient CreatePlayerClient(IPlayer client, InstancePlayer actor)
  440. {
  441. return new PlayerClient(client, actor, this, Config.CLIENT_SYNC_OBJECT_IN_RANGE, Config.CLIENT_SYNC_OBJECT_OUT_RANGE);
  442. }
  443. public class PlayerClient : PlayerClientObject
  444. {
  445. private static AtomicInteger s_alloc_object_count = new AtomicInteger(0);
  446. private static AtomicInteger s_active_object_count = new AtomicInteger(0);
  447. /// <summary>
  448. /// 未释放实例数量
  449. /// </summary>
  450. public static int ActiveCount { get { return s_active_object_count.Value; } }
  451. /// <summary>
  452. /// 分配实例数量
  453. /// </summary>
  454. public static int AllocCount { get { return s_alloc_object_count.Value; } }
  455. private readonly IPlayer mClient;
  456. private readonly ZoneNode mNode;
  457. private readonly EditorScene mZone;
  458. private readonly InstancePlayer mActor;
  459. private readonly float mSyncObjectInRange;
  460. private readonly float mSyncObjectOutRange;
  461. private bool mDisposed = false;
  462. private long mPreUpdateTime = 0;
  463. // 视野范围内的单位 //
  464. private readonly HashMap<uint, InstanceZoneObject> mInViewList = new HashMap<uint, InstanceZoneObject>();
  465. protected List<uint> m_RemovingList = new List<uint>();
  466. private Pong mSendPong = new Pong();
  467. public float SyncObjectRange { get { return mSyncObjectInRange; } }
  468. public float SyncObjectOutRange { get { return mSyncObjectOutRange; } }
  469. public ZoneNode Node { get { return mNode; } }
  470. public EditorScene Zone { get { return mZone; } }
  471. public InstancePlayer Actor { get { return mActor; } }
  472. public IPlayer Client { get { return mClient; } }
  473. public string PlayerUUID { get { return mClient.PlayerUUID; } }
  474. public long UpdateTime { get { return mPreUpdateTime; } set{mPreUpdateTime = value;}
  475. }
  476. public PlayerClient(IPlayer client, InstancePlayer actor, ZoneNode node, float look_in_range, float look_out_range)
  477. {
  478. s_alloc_object_count++;
  479. s_active_object_count++;
  480. this.mActor = actor;
  481. this.mClient = client;
  482. this.mNode = node;
  483. this.mZone = node.Zone;
  484. this.mSyncObjectInRange = Math.Min(look_in_range, look_out_range);
  485. this.mSyncObjectOutRange = Math.Max(look_in_range, look_out_range);
  486. if ((int)(mSyncObjectOutRange / mZone.SpaceDivSize) <= (int)(mSyncObjectInRange / mZone.SpaceDivSize))
  487. {
  488. mSyncObjectOutRange = mSyncObjectInRange + mZone.SpaceDivSize;
  489. }
  490. this.mInViewList.Add(mActor.ID, mActor);
  491. this.mClient.Listen(RecvInternal);
  492. this.mClient.BindingPlayer = this;
  493. this.mClient.OnConnected(this);
  494. }
  495. ~PlayerClient()
  496. {
  497. s_alloc_object_count--;
  498. }
  499. internal void Dispose()
  500. {
  501. if (mDisposed) { return; }
  502. this.Disposing();
  503. this.mClient.OnDisconnect(this);
  504. this.mClient.BindingPlayer = null;
  505. this.mDisposed = true;
  506. s_active_object_count--;
  507. }
  508. protected virtual void Disposing() { }
  509. protected virtual void OnStart() { }
  510. protected virtual void OnBeginUpdate() { }
  511. protected virtual void OnEndUpdate() { }
  512. internal void Start()
  513. {
  514. OnStart();
  515. BeginUpdate(true);
  516. }
  517. /// <summary>
  518. /// 定时更新Client
  519. /// </summary>
  520. internal void BeginUpdate(bool slowRefresh)
  521. {
  522. OnBeginUpdate();
  523. if (mNode.mEnableAOI && slowRefresh)
  524. {
  525. LookInRange();
  526. }
  527. }
  528. internal void EndUpdate(bool slowRefresh)
  529. {
  530. if (mNode.mEnableAOI)
  531. {
  532. LookOutRange(slowRefresh);
  533. // 一直同步周围单位
  534. SyncPosEvent mSyncPosLocal = GetSyncPosEvent();
  535. if (mSyncPosLocal != null && !mSyncPosLocal.IsEmpty)
  536. {
  537. mClient.Send(mSyncPosLocal);
  538. }
  539. }
  540. OnEndUpdate();
  541. }
  542. /// <summary>
  543. /// 排队发送消息
  544. /// </summary>
  545. /// <param name="msg"></param>
  546. /// <param name="immediately"></param>
  547. public void Send(IMessage msg, bool immediately = false)
  548. {
  549. if (mNode.mEnableAOI)
  550. {
  551. if (immediately)
  552. {
  553. this.mClient.Send(msg);
  554. }
  555. else if (msg is AddSpellEvent)
  556. {
  557. OnLookSpell(msg as AddSpellEvent);
  558. }
  559. else
  560. {
  561. msg = mNode.FilterSendingMessage(this, msg);
  562. if (msg != null)
  563. {
  564. this.mClient.Send(msg);
  565. }
  566. }
  567. }
  568. else
  569. {
  570. this.mClient.Send(msg);
  571. }
  572. }
  573. /// <summary>
  574. /// 从客户端接收消息
  575. /// </summary>
  576. /// <param name="message"></param>
  577. private void RecvInternal(object message)
  578. {
  579. if (message is Ping)
  580. {
  581. var ping = message as Ping;
  582. mSendPong.ClientTimeDayOfMS = ping.DayOfMS;
  583. mClient.Send(mSendPong);
  584. return;
  585. }
  586. else
  587. {
  588. //mNode.QueueTask(() =>
  589. //{
  590. if (mActor.Enable)
  591. {
  592. ObjectAction oa = message as ObjectAction;
  593. if (oa != null)
  594. {
  595. //BaseZoneNode.log.Debug("C2B msg<<<" + oa);
  596. oa.object_id = mActor.ID;
  597. oa.sender = mActor;
  598. if (oa is ActorRequest)
  599. {
  600. mActor.doRequest(oa as ActorRequest);
  601. }
  602. else
  603. {
  604. mZone.pushAction(oa);
  605. }
  606. }
  607. }
  608. //});
  609. }
  610. }
  611. //------------------------------------------------------------------------------------------------------------
  612. //------------------------------------------------------------------------------------------------------------
  613. #region _AOI_视野控制_
  614. /// <summary>
  615. /// 获取当前场景内所有单位,用于同步现有场景中单位
  616. /// </summary>
  617. /// <returns></returns>
  618. public SyncObjectsEvent GetSyncObjectsEvent()
  619. {
  620. if (mNode.mEnableAOI)
  621. {
  622. return mZone.GetSyncObjectsEvent(mInViewList.Values);
  623. }
  624. else
  625. {
  626. return mZone.GetSyncUnitsEvent(mActor);
  627. }
  628. }
  629. public bool IsInView(InstanceZoneObject obj)
  630. {
  631. if (mNode.mEnableAOI)
  632. return mInViewList.ContainsKey(obj.ID);
  633. else
  634. return true;
  635. }
  636. public bool IsInView(uint id)
  637. {
  638. if (mNode.mEnableAOI)
  639. return mInViewList.ContainsKey(id);
  640. else
  641. return true;
  642. }
  643. public bool IsLookInRange(float x, float y)
  644. {
  645. if (mNode.mEnableAOI)
  646. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, x, y);
  647. else
  648. return true;
  649. }
  650. public SyncPosEvent GetSyncPosEvent()
  651. {
  652. return mZone.GetSyncPosEvent(mInViewList.Values, this.Actor, this);
  653. }
  654. /// <summary>
  655. /// 判断单位是否进入视野
  656. /// </summary>
  657. /// <param name="obj"></param>
  658. /// <returns>True,进入视野</returns>
  659. protected virtual bool IsLookInRange(InstanceZoneObject obj)
  660. {
  661. return CMath.includeRoundPoint(mActor.X, mActor.Y, mSyncObjectInRange, obj.X, obj.Y);
  662. }
  663. /// <summary>
  664. /// 判断单位是否超出视野
  665. /// </summary>
  666. /// <param name="obj"></param>
  667. /// <returns>True,超出视野</returns>
  668. protected virtual bool IsLookOutRange(InstanceZoneObject obj)
  669. {
  670. return !CMath.includeRoundPoint(mActor.GetX(), mActor.GetY(), mSyncObjectOutRange, obj.GetX(), obj.GetY());
  671. }
  672. protected void ForceAddObjectInView(InstanceZoneObject obj)
  673. {
  674. if (!mInViewList.ContainsKey(obj.ID))
  675. {
  676. mInViewList.Put(obj.ID, obj);
  677. OnEnterView(obj);
  678. }
  679. }
  680. private void LookInRange()
  681. {
  682. mZone.ForEachNearObjects<InstanceZoneObject>(mActor.X, mActor.Y, mSyncObjectInRange, mZone_CheckInRange);
  683. }
  684. private void mZone_CheckInRange(InstanceZoneObject o, ref bool cancel)
  685. {
  686. if ((o != mActor) && o.ClientVisible && !(o is InstanceSpell) && !mInViewList.ContainsKey(o.ID))
  687. {
  688. if (o.Enable && mZone.IsVisibleAOI(mActor, o) && IsLookInRange(o))
  689. {
  690. mInViewList.Put(o.ID, o);
  691. OnEnterView(o);
  692. }
  693. }
  694. }
  695. private void LookOutRange(bool slowRefresh)
  696. {
  697. foreach (InstanceZoneObject o in mInViewList.Values)
  698. {
  699. if (o == mActor)
  700. {
  701. continue;
  702. }
  703. if (!o.Enable || (slowRefresh && (!mZone.IsVisibleAOI(mActor, o) || IsLookOutRange(o))))
  704. {
  705. m_RemovingList.Add(o.ID);
  706. OnLeaveView(o);
  707. }
  708. }
  709. if (m_RemovingList.Count > 0)
  710. {
  711. foreach (uint oid in m_RemovingList)
  712. {
  713. mInViewList.Remove(oid);
  714. }
  715. m_RemovingList.Clear();
  716. }
  717. }
  718. public virtual bool RemoveInRange(InstanceZoneObject o) { return false; }
  719. protected virtual void OnLookSpell(AddSpellEvent em)
  720. {
  721. // 过滤不在自己感兴趣范围内的消息
  722. if (em.sender is InstanceSpell)
  723. {
  724. var sp = em.sender as InstanceSpell;
  725. //作用于自己或者自己发射的//
  726. if (sp.Launcher == mActor || sp.Target == mActor)
  727. {
  728. mInViewList.Put(sp.ID, sp);
  729. mClient.Send(em);
  730. return;
  731. }
  732. if (mZone.IsVisibleAOI(mActor, sp))
  733. {
  734. if (IsLookInRange(em.x, em.y))
  735. {
  736. mInViewList.Put(sp.ID, sp);
  737. mClient.Send(em);
  738. return;
  739. }
  740. }
  741. log.Debug($"Ignore spell to client: {em.spell_template_id}");
  742. }
  743. }
  744. protected virtual void OnEnterView(InstanceZoneObject obj)
  745. {
  746. if (obj is InstanceUnit)
  747. {
  748. InstanceUnit u = obj as InstanceUnit;
  749. var sync = u.GenSyncUnitInfo(true);
  750. var add = new AddUnitEvent(sync);
  751. mClient.Send(add);
  752. if(u.Info.SpawnEffect != null && u.CurrentActionStatus == UnitActionStatus.Spawn)
  753. {
  754. u.Parent.queueEvent(new AddEffectEvent(u.ID, u.X, u.Y, u.Direction, u.Info.SpawnEffect));
  755. }
  756. }
  757. else if (obj is InstanceItem)
  758. {
  759. InstanceItem i = obj as InstanceItem;
  760. var sync = i.GenSyncItemInfo(true, this.PlayerUUID);
  761. var add = new AddItemEvent(sync);
  762. mClient.Send(add);
  763. }
  764. }
  765. protected virtual void OnLeaveView(InstanceZoneObject obj)
  766. {
  767. RemoveObjectEvent remove = new RemoveObjectEvent(obj.ID);
  768. mClient.Send(remove);
  769. }
  770. public void ForEachInViewList(Action<InstanceZoneObject> action)
  771. {
  772. using (var list = ListObjectPool<InstanceZoneObject>.AllocAutoRelease(mInViewList.Values))
  773. {
  774. foreach (var obj in list) { action(obj); }
  775. }
  776. }
  777. #endregion
  778. //------------------------------------------------------------------------------------------------------------
  779. // private OnObjectEnterViewHandler event_OnObjectEnterView;
  780. // private OnObjectLeaveViewHandler event_OnObjectLeaveView;
  781. // public delegate void OnObjectEnterViewHandler(PlayerClient sender, InstanceZoneObject obj);
  782. // public delegate void OnObjectLeaveViewHandler(PlayerClient sender, InstanceZoneObject obj);
  783. // public event OnObjectEnterViewHandler OnObjectEnterView { add { event_OnObjectEnterView += value; } remove { event_OnObjectEnterView -= value; } }
  784. // public event OnObjectLeaveViewHandler OnObjectLeaveView { add { event_OnObjectLeaveView += value; } remove { event_OnObjectLeaveView -= value; } }
  785. }
  786. private class PlayerClientMap
  787. {
  788. private HashMap<string, InstancePlayer> mPlayerObjectMap = new HashMap<string, InstancePlayer>();
  789. private HashMap<string, PlayerClient> mPlayerClientMap = new HashMap<string, PlayerClient>();
  790. public int Count
  791. {
  792. get
  793. {
  794. lock (this)
  795. {
  796. return mPlayerClientMap.Count;
  797. }
  798. }
  799. }
  800. public InstancePlayer[] Players
  801. {
  802. get
  803. {
  804. lock (this)
  805. {
  806. return mPlayerObjectMap.Values.ToArray();
  807. }
  808. }
  809. }
  810. public void PutPlayer(PlayerClient client)
  811. {
  812. lock (this)
  813. {
  814. mPlayerObjectMap.Put(client.PlayerUUID, client.Actor);
  815. mPlayerClientMap.Put(client.PlayerUUID, client);
  816. }
  817. }
  818. public InstancePlayer GetPlayer(string uuid)
  819. {
  820. lock (this)
  821. {
  822. return mPlayerObjectMap.Get(uuid);
  823. }
  824. }
  825. public PlayerClient GetClient(string uuid)
  826. {
  827. lock (this)
  828. {
  829. return mPlayerClientMap.Get(uuid);
  830. }
  831. }
  832. public bool Get(string uuid, out InstancePlayer player, out PlayerClient client)
  833. {
  834. lock (this)
  835. {
  836. player = mPlayerObjectMap.Get(uuid);
  837. client = mPlayerClientMap.Get(uuid);
  838. }
  839. return client != null;
  840. }
  841. public bool RemoveByKey(string uuid, out InstancePlayer player, out PlayerClient client)
  842. {
  843. lock (this)
  844. {
  845. player = mPlayerObjectMap.RemoveByKey(uuid);
  846. client = mPlayerClientMap.RemoveByKey(uuid);
  847. }
  848. return client != null;
  849. }
  850. public bool ContainsKey(string uuid)
  851. {
  852. lock (this)
  853. {
  854. return mPlayerObjectMap.ContainsKey(uuid);
  855. }
  856. }
  857. public void ForEachPlayers(Action<PlayerClient> action)
  858. {
  859. lock (this)
  860. {
  861. foreach (PlayerClient c in mPlayerClientMap.Values)
  862. {
  863. action(c);
  864. }
  865. }
  866. }
  867. }
  868. //------------------------------------------------------------------------------------------------------------
  869. #endregion
  870. }
  871. }