BaseNetClient.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. 
  2. using CommonLang;
  3. using System;
  4. using System.IO;
  5. using System.Collections.Generic;
  6. using CommonAI.Zone.ZoneEditor;
  7. using CommonLang.Log;
  8. using CommonAI.Zone.Attributes;
  9. using CommonAI;
  10. using CommonAI.ZoneClient;
  11. using System.Threading;
  12. namespace Pomelo.DotNetClient.NetClient
  13. {
  14. public interface INetClient
  15. {
  16. EditorTemplates DataRoot { get; }
  17. void SendBattleMessage(CommonAI.Zone.Action action);
  18. }
  19. public abstract class BaseNetClient<GATE, GAME, BATTLE> : IDisposable, INetClient
  20. where GATE : PomeloClient
  21. where GAME : PomeloClient
  22. where BATTLE : BaseBattleClient
  23. {
  24. public GATE GateSocket { get; private set; }
  25. public GAME GameSocket { get; private set; }
  26. public BATTLE BattleClient { get; protected set; }
  27. public CommonAI.ZoneClient.ZoneActor BattleActor { get { if (BattleClient != null) { return BattleClient.Actor; } return null; } }
  28. public abstract EditorTemplates DataRoot { get; }
  29. protected readonly Logger log;
  30. protected readonly List<object> mUnhandledList = new List<object>();
  31. protected BATTLE NextBattleClient;
  32. protected SynchronizedBattleCodec mBattleCodec;
  33. //协同类任务列表//
  34. private readonly SyncMessageQueue<Action> mTasks = new SyncMessageQueue<Action>();
  35. public BaseNetClient(GATE gate, GAME game)
  36. {
  37. this.log = LoggerFactory.GetLogger(GetType().Name);
  38. this.GateSocket = gate;
  39. this.GameSocket = game;
  40. this.GameSocket.NetWorkHandlePushImmediately += notify_OnBattleMessageReceivedImmediately;
  41. //this.QueueTask(InitCodec);
  42. InitCodec();
  43. }
  44. public void InitCodec()
  45. {
  46. if (this.DataRoot != null && this.DataRoot.Templates != null)
  47. {
  48. this.mBattleCodec = new SynchronizedBattleCodec(this.DataRoot.Templates);
  49. }
  50. }
  51. //-------------------------------------------------------------------------------------------------
  52. #region _主动调用_
  53. /// <summary>
  54. /// 提交一个任务让主线程处理,协同程序
  55. /// </summary>
  56. /// <param name="action"></param>
  57. public void QueueTask(Action action)
  58. {
  59. mTasks.Enqueue(action);
  60. }
  61. public void UpdateSocket(float delTime)
  62. {
  63. mTasks.ProcessMessages((act) => { act.Invoke(); });
  64. this.GateSocket.update(delTime);
  65. this.GameSocket.update(delTime);
  66. }
  67. public void DoUpdateSend()
  68. {
  69. this.GateSocket.DoSendUpdate();
  70. this.GameSocket.DoSendUpdate();
  71. }
  72. public void UpdateBattleClient(int intervalMS)
  73. {
  74. if (BattleClient != null)
  75. {
  76. BattleClient.BeginUpdate(intervalMS);
  77. BattleClient.Update();
  78. }
  79. }
  80. public void CreateNextBattleClient()
  81. {
  82. this.NextBattleClient = CreateBattle();
  83. }
  84. public void Disconnect()
  85. {
  86. log.Debug("====socket ==BaseNetClient== Disconnect");
  87. try
  88. {
  89. ClearBattle();
  90. }
  91. catch (Exception err)
  92. {
  93. log.Error(err.Message, err);
  94. }
  95. if (this.GateSocket.IsConnected)
  96. {
  97. try
  98. {
  99. this.GateSocket.disconnect();
  100. }
  101. catch (Exception err)
  102. {
  103. log.Error(err.Message, err);
  104. }
  105. }
  106. if (this.GameSocket.IsConnected)
  107. {
  108. try
  109. {
  110. this.GameSocket.disconnect();
  111. }
  112. catch (Exception err)
  113. {
  114. log.Error(err.Message, err);
  115. }
  116. }
  117. }
  118. public void Dispose()
  119. {
  120. this.mOnBeginEnterScene = null;
  121. this.mOnEnterScene = null;
  122. this.mOnLeaveScene = null;
  123. this.mOnBattlePlayerReady = null;
  124. this.Disconnect();
  125. try
  126. {
  127. this.GateSocket.Dispose();
  128. }
  129. catch (Exception err)
  130. {
  131. log.Error(err.Message, err);
  132. }
  133. try
  134. {
  135. this.GameSocket.Dispose();
  136. }
  137. catch (Exception err)
  138. {
  139. log.Error(err.Message, err);
  140. }
  141. }
  142. #endregion
  143. //-------------------------------------------------------------------------------------------------
  144. #region _Events_
  145. private Action<BATTLE> mOnBeginEnterScene;
  146. private Action<BATTLE> mOnEnterScene;
  147. private Action<BATTLE> mOnLeaveScene;
  148. private Action<CommonAI.ZoneClient.ZoneLayer, CommonAI.ZoneClient.ZoneActor> mOnBattlePlayerReady;
  149. [EventTriggerDescAttribute("BattleClient已创建,一般用于开始加载场景操作,场景加载完毕,调用GameSocket.Invoke_ChangeScene")]
  150. public event Action<BATTLE> OnBeginEnterScene { add { mOnBeginEnterScene += value; } remove { mOnBeginEnterScene -= value; } }
  151. [EventTriggerDescAttribute("当单位已经进入场景时触发【角色已经进入战斗服】")]
  152. public event Action<BATTLE> OnEnterScene { add { mOnEnterScene += value; } remove { mOnEnterScene -= value; } }
  153. [EventTriggerDescAttribute("当单离开场景时触发【收到PlayerLeaveScene】")]
  154. public event Action<BATTLE> OnLeaveScene { add { mOnLeaveScene += value; } remove { mOnLeaveScene -= value; } }
  155. [EventTriggerDescAttribute("玩家单位已准备完毕【确保战斗服和游戏服可操作】")]
  156. public event Action<CommonAI.ZoneClient.ZoneLayer, CommonAI.ZoneClient.ZoneActor> OnBattlePlayerReady { add { mOnBattlePlayerReady += value; } remove { mOnBattlePlayerReady -= value; } }
  157. #endregion
  158. //-------------------------------------------------------------------------------------------------
  159. #region _Request Http_
  160. /// <summary>
  161. /// HTTP同步请求.
  162. /// </summary>
  163. /// <param name="url"></param>
  164. /// <param name="args"></param>
  165. /// <returns></returns>
  166. public string RequestHttpPost(string url, Dictionary<string, string> args)
  167. {
  168. string requestUrl = url + '?';
  169. foreach (KeyValuePair<string, string> arg in args)
  170. {
  171. requestUrl += arg.Key + '=' + arg.Value + '&';
  172. }
  173. requestUrl = requestUrl.Remove(requestUrl.Length - 1);
  174. System.Uri uri = new System.Uri(requestUrl);
  175. string result = CommonNetwork.Http.WebClient.Post(uri);
  176. return result;
  177. }
  178. /// <summary>
  179. /// HTTP异步请求.
  180. /// </summary>
  181. /// <param name="url"></param>
  182. /// <param name="args"></param>
  183. /// <param name="handler"></param>
  184. public void RequestHttpPostAsync(string url, Dictionary<string, string> args, CommonNetwork.Http.HttpPostHandler handler)
  185. {
  186. string requestUrl = url + '?';
  187. foreach (KeyValuePair<string, string> arg in args)
  188. {
  189. requestUrl += arg.Key + '=' + arg.Value + '&';
  190. }
  191. requestUrl = requestUrl.Remove(requestUrl.Length - 1);
  192. System.Uri uri = new System.Uri(requestUrl);
  193. CommonNetwork.Http.WebClient.PostAsync(uri, System.Text.Encoding.UTF8, (string result) =>
  194. {
  195. if (handler != null)
  196. {
  197. QueueTask(() =>
  198. {
  199. handler.Invoke(result);
  200. });
  201. }
  202. });
  203. }
  204. #endregion
  205. //-------------------------------------------------------------------------------------------------
  206. #region _BattleClient_
  207. public abstract BATTLE CreateBattle();
  208. public virtual void ClearBattle()
  209. {
  210. if (this.NextBattleClient != null)
  211. {
  212. this.NextBattleClient.Dispose();
  213. this.NextBattleClient = null;
  214. }
  215. mUnhandledList.Clear();
  216. }
  217. public abstract void SendBattleMessage(CommonAI.Zone.Action action);
  218. /// <summary>
  219. /// ChangeAreaPush 或 BindPlayer 后回调
  220. /// 进入战斗场景开始.
  221. /// </summary>
  222. public void BattleClientInitBegin()
  223. {
  224. if (this.BattleClient != null)
  225. {
  226. this.BattleClient.Dispose();
  227. this.BattleClient = null;
  228. }
  229. if (NextBattleClient == null)
  230. {
  231. BattleClient = this.CreateBattle();
  232. }
  233. else
  234. {
  235. BattleClient = NextBattleClient;
  236. }
  237. NextBattleClient = null;
  238. if (mUnhandledList.Count > 0)
  239. {
  240. foreach (var msg in mUnhandledList)
  241. {
  242. this.BattleClient.OnReceivedBattleMessage(msg as CommonLang.Protocol.IMessage);
  243. }
  244. mUnhandledList.Clear();
  245. }
  246. if (mOnBeginEnterScene != null)
  247. {
  248. mOnBeginEnterScene.Invoke(BattleClient);
  249. }
  250. }
  251. /// <summary>
  252. /// Request_EnterScene 回调
  253. /// 进入战斗场景完成.(客户端加载完成)
  254. /// </summary>
  255. public void BattleClientInitFinish()
  256. {
  257. if (BattleClient != null)
  258. {
  259. if (mOnEnterScene != null)
  260. {
  261. mOnEnterScene.Invoke(BattleClient);
  262. }
  263. BattleClient.QueueTask(BattlePlayerReady);
  264. }
  265. }
  266. private void BattlePlayerReady(CommonAIClient.Client.AbstractBattle battle)
  267. {
  268. if (!battle.Layer.IsDesposed)
  269. {
  270. if (battle.Actor != null)
  271. {
  272. if (mOnBattlePlayerReady != null)
  273. {
  274. mOnBattlePlayerReady.Invoke(battle.Layer, battle.Actor);
  275. }
  276. }
  277. else
  278. {
  279. BattleClient.QueueTask(BattlePlayerReady);
  280. }
  281. }
  282. }
  283. /// <summary>
  284. /// 战斗协议回调.(直接从网络线程回调)
  285. /// </summary>
  286. /// <param name="msg"></param>
  287. protected virtual bool notify_OnBattleMessageReceivedImmediately(string route, Stream msg)
  288. {
  289. //log.Debug("socket ===== notify_OnBattleMessageReceivedImmediately ThreadID: " + Thread.CurrentThread.ManagedThreadId);
  290. if (route == "area.playerPush.battleClearPush")
  291. {
  292. this.NextBattleClient = this.CreateBattle();
  293. if (mOnLeaveScene != null) { mOnLeaveScene.Invoke(BattleClient); }
  294. return true;
  295. }
  296. else if (route == "area.playerPush.battleEventPush")
  297. {
  298. object data;
  299. try
  300. {
  301. if (mBattleCodec == null)
  302. {
  303. log.Error("decode err: mBattleCodec is null");
  304. return false;
  305. }
  306. if (msg == null)
  307. {
  308. log.Error("decode err: msg is null!");
  309. return false;
  310. }
  311. if (mBattleCodec.doDecode(msg, out data))
  312. {
  313. if (data is PlayerLeaveScene)
  314. {
  315. //this.NextBattleClient = this.CreateBattle();
  316. //this.QueueTask(() => { if (mOnLeaveScene != null) { mOnLeaveScene.Invoke(BattleClient); } });
  317. }
  318. else
  319. {
  320. if (NextBattleClient != null || this.BattleClient == null)
  321. {
  322. mUnhandledList.Add(data);
  323. }
  324. else
  325. {
  326. this.BattleClient.OnReceivedBattleMessage(data as CommonLang.Protocol.IMessage);
  327. }
  328. }
  329. }
  330. else
  331. {
  332. log.Error("[doDecodeBin] error:" + msg.ToString());
  333. }
  334. }
  335. catch (Exception err)
  336. {
  337. log.Error("[doDecodeBin] error:" + err.Message, err);
  338. }
  339. return true;
  340. }
  341. return false;
  342. }
  343. #endregion
  344. }
  345. }