MapTcpProxy.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. using System;
  2. using MapServer;
  3. using System.Net;
  4. using System.Net.Sockets;
  5. using pb = global::Google.Protobuf;
  6. using NetData;
  7. using Newtonsoft.Json.Linq;
  8. using Newtonsoft.Json;
  9. using System.Diagnostics;
  10. using System.Linq;
  11. using System.Text;
  12. internal class MapTcpProxy : MonoSingleton<MapTcpProxy>
  13. {
  14. const int Port = 2333;
  15. static string IP = "192.168.10.86";
  16. public MapPeer2 Peer { get; set; }
  17. private bool netFailed = false;
  18. protected override void OnAwake()
  19. {
  20. base.OnAwake();
  21. ReConnect();
  22. //if (GlobalConfig.netType != eNetType.LAN)
  23. //{
  24. // var uri = "ylsjtt.game7000.com";
  25. // IPHostEntry entry = Dns.GetHostEntry(uri);
  26. // if (entry != null && entry.AddressList != null && entry.AddressList.Length > 0)
  27. // {
  28. // IPAddress addr = entry.AddressList[0]; //使用时使用AddressList[0]即可
  29. // IP = addr.ToString();
  30. // }
  31. // //IP = "ylsjtt.game7000.com";
  32. //}
  33. //this.Peer = new MapPeer2(IP, GlobalConfig.MapServerPort);
  34. //// todu: 重新登录时怎么处理重新连接的问题? --gwang
  35. //this.Peer.OnConnectClosed += Peer_OnConnectClosed;
  36. //this.Peer.OnReconnect += ()=> { Login(); return true; } ;
  37. }
  38. private void OnDisable()
  39. {
  40. this.Peer.OnConnectClosed -= Peer_OnConnectClosed;
  41. }
  42. private void OnEnable()
  43. {
  44. this.Peer.OnConnectClosed += Peer_OnConnectClosed;
  45. }
  46. private void Peer_OnConnectClosed()
  47. {
  48. LogHelper.Log("连接关闭事件:");
  49. netFailed = true;
  50. }
  51. public event Func<bool> OnReconnect;
  52. public void ReConnect()
  53. {
  54. if (GlobalConfig.netType != eNetType.LAN)
  55. {
  56. var uri = "ylsjtt.game7000.com";
  57. IPHostEntry entry = Dns.GetHostEntry(uri);
  58. if (entry != null && entry.AddressList != null && entry.AddressList.Length > 0)
  59. {
  60. IPAddress addr = entry.AddressList[0]; //使用时使用AddressList[0]即可
  61. IP = addr.ToString();
  62. }
  63. //IP = "ylsjtt.game7000.com";
  64. }
  65. LogHelper.Log("创建连接");
  66. this.Peer = new MapPeer2(IP, GlobalConfig.MapServerPort);
  67. // todu: 重新登录时怎么处理重新连接的问题? --gwang
  68. this.Peer.OnConnectClosed += Peer_OnConnectClosed;
  69. }
  70. private void OnApplicationFocus(bool focus)
  71. {
  72. LogHelper.Log("OnApplicationFocus" + focus);
  73. LogHelper.Log(TraceBack());
  74. }
  75. private void OnApplicationPause(bool pause)
  76. {
  77. //this.Peer.
  78. LogHelper.Log("OnApplicationPause" + pause);
  79. LogHelper.Log(TraceBack());
  80. }
  81. static string TraceBack() // 打印调用到这里的栈信息
  82. {
  83. var sb = new StringBuilder();
  84. StackTrace st = new StackTrace();
  85. StackFrame[] sf = st.GetFrames();
  86. sf.ToList().ForEach(curSf => sb.AppendLine($"{curSf}"));
  87. return sb.ToString();
  88. }
  89. //
  90. public void Login()
  91. {
  92. try
  93. {
  94. netFailed = false;
  95. this.Peer?.Login();
  96. LogHelper.Log("身份认证!");
  97. }
  98. catch(Exception e) {
  99. LogHelper.Log(e.Message);
  100. }
  101. }
  102. public void LogOut()
  103. {
  104. this.Peer.LogOut();
  105. }
  106. public void Update()
  107. {
  108. Peer?.Update();
  109. //LogHelper.Log($"tts: {Peer.tts}ms");
  110. if (netFailed)
  111. {
  112. UI_CueDialog.Instance().Open("与服务器的连接断开, 尝试重新建立连接", "网络故障", E_DialogType.OneButton, () => {
  113. ReConnect();
  114. Login();
  115. });
  116. //UI_CueDialog.Instance().Open("与游戏服务器的连接断开, 请检查网络.", "网络故障", E_DialogType.OneButton, UnityEngine.Application.Quit);
  117. }
  118. }
  119. protected override void DoOnDestroy()
  120. {
  121. base.DoOnDestroy();
  122. this.Peer?.Close();
  123. }
  124. }
  125. /// <summary>
  126. /// 地图长连服务器3代
  127. /// </summary>
  128. internal class MapPeer2 : PeerBase
  129. {
  130. /// <summary>
  131. /// (玩家数据)模块名称
  132. /// </summary>
  133. public enum EModName
  134. {
  135. Unkowm = 0,
  136. MapData = 1,
  137. CmptMgr,
  138. NpcMgr,
  139. SpawnerMgr,
  140. SpawnerMgr_Spawner,
  141. SpawnerMgr_Spawner_Role,
  142. Player = 100,
  143. Player_hero,
  144. }
  145. protected readonly Random r = new Random(); // 随机数
  146. private string ip;
  147. private int port;
  148. public MapPeer2(string Ip, int Port) : base(Ip, Port)
  149. {
  150. ip = Ip;
  151. port = Port;
  152. //OnDisconnect += MapPeer2_OnDisconnect; // 添加重连处理机制
  153. }
  154. #region
  155. //virtual protected bool OnConnectReset()
  156. //{
  157. // if (UnityEngine.Application.isPlaying)
  158. // {
  159. // Log("断线重连");
  160. // Login();
  161. // return true;
  162. // }
  163. // else
  164. // {
  165. // Log("停止播放断线不重连");
  166. // return false;
  167. // }
  168. //}
  169. #endregion
  170. public Info_Map? MapData { get; private set; }
  171. public Info_Map_Player Player { get; private set; }
  172. /// <summary>
  173. /// 注册服务端消息处理逻辑
  174. /// </summary>
  175. protected override void InitDispatch()
  176. {
  177. base.InitDispatch();
  178. this.callbacks[eProtocalCommand.ScMapLoginRet] = On_LoginOk; // 登录成功
  179. this.callbacks[eProtocalCommand.ScMapLogOutRet] = On_GameOver; // 登出成功
  180. this.callbacks[eProtocalCommand.ScMapDataChange] = On_update; // 数据更新
  181. this.callbacks[eProtocalCommand.ScMapSwitchMapRet] = On_SwitchMapReturn; // 地图切换
  182. }
  183. #region 消息处理逻辑
  184. /// <summary>
  185. /// 处理服务端登录成功消息
  186. /// </summary>
  187. /// <param name="data"></param>
  188. void On_LoginOk(byte[] data)
  189. {
  190. var msg = SC_login_ret.Parser.ParseFrom(data);
  191. // todo: 这里目前就只有mapdata一个模块, 后面可以考虑拆分多个模块
  192. var jobj = JObject.Parse(msg.MapJsonData);
  193. this.MapData = jobj.ToObject<Info_Map>();// Newtonsoft.Json.JsonConvert.DeserializeObject<Info_Map>(msg.MapJsonData);
  194. this.Player = JObject.Parse(msg.PlayerJsonData).ToObject<Info_Map_Player>(); // 玩家数据
  195. this.MapData.PropertyChanged += (s, e) => ReportDataChange(this.MapData); // 当数据有变化的时候上报
  196. // todo: 这里是设置一个状态值, 还是说做个message通知给前端?
  197. LogHelper.Log("地图登录成功: " + msg.MapJsonData);
  198. //LogHelper.LogWarning("测试warning文本颜色");
  199. //LogHelper.LogError("测试Error文本颜色");
  200. }
  201. /// <summary>
  202. /// 处理服务端更新数据消息
  203. /// </summary>
  204. void On_update(byte[] data)
  205. {
  206. var msg = SC_DataChange.Parser.ParseFrom(data);
  207. // todo: 这里目前就只有mapdata一个模块, 后面可以考虑拆分多个模块
  208. foreach (var kv in msg.ChangedMods)
  209. {
  210. var mod = Enum.Parse<EModName>(kv.Key);
  211. switch (mod)
  212. {
  213. case EModName.MapData: // 地图数据模块
  214. // this.MapData = Newtonsoft.Json.JsonConvert.DeserializeObject<Info_Map>(kv.Value);
  215. var jobj = JObject.Parse(kv.Value);
  216. this.MapData = jobj.ToObject<Info_Map>();// Newtonsoft.Json.JsonConvert.DeserializeObject<Info_Map>(msg.MapJsonData);
  217. //this.MapData.CheckJsonRaw(jobj);
  218. break;
  219. default:
  220. LogHelper.Log("未知模块!");
  221. break;
  222. }
  223. }
  224. LogHelper.Log("地图数据有更新: " + msg.ChangedMods);
  225. }
  226. /// <summary>
  227. /// 处理服务端返回登出成功消息
  228. /// </summary>
  229. void On_GameOver(byte[] data)
  230. {
  231. var msg = SC_LogOut_ret.Parser.ParseFrom(data);
  232. LogHelper.Log("地图模块退出成功: " + msg.ToString());
  233. Close(); // 通知recv协程退出循环
  234. }
  235. void On_SwitchMapReturn(byte[] data)
  236. {
  237. var msg = SC_SwitchMap_ret.Parser.ParseFrom(data);
  238. LogHelper.Log("切换到新地图成功:" + msg.ToString());
  239. var jobj = JObject.Parse(msg.MapJsonData);
  240. this.MapData = jobj.ToObject<Info_Map>(); // Newtonsoft.Json.JsonConvert.DeserializeObject<Info_Map>(msg.MapJsonData);
  241. this.MapData.PropertyChanged += (s, e) => ReportDataChange(this.MapData); // 当数据有变化的时候上报
  242. this.Player = JsonConvert.DeserializeObject<Info_Map_Player>(msg.PlayerJsonData);
  243. if (OnSwitchedNextMap != null)
  244. {
  245. OnSwitchedNextMap.Invoke(MapData);
  246. OnSwitchedNextMap = null;
  247. }
  248. }
  249. /// <summary>
  250. /// 暂存回调函数.
  251. /// </summary>
  252. private Action<Info_Map> OnSwitchedNextMap;
  253. #endregion
  254. #region 客户端访问接口
  255. public void LogOut()
  256. {
  257. SendMsg(eProtocalCommand.CsMapLogOut, new CS_LogOut());
  258. LogHelper.Log("地图 登出");
  259. }
  260. public void Login()
  261. {
  262. var p = UserProxy.Instance.player;
  263. var msg = new CS_login() { Uid = p.uid, Zoneid = p.zoneid, CurMapId = p.newMap.curMapId };
  264. SendMsg(eProtocalCommand.CsMapLogin, msg);
  265. LogHelper.Log("地图 登录");
  266. }
  267. #region 上报数据接口(多个重载)
  268. /// <summary>
  269. /// 上报数据发生变化
  270. /// </summary>
  271. public void ReportDataChange(Info_Map mapInfo)
  272. {
  273. this.MapData = mapInfo;
  274. this.MapData.PropertyChanged += (s, e) => ReportDataChange(this.MapData); // 当数据有变化的时候上报
  275. if (sm_gate.GetMoById(mapInfo.mapId)?.mapType < 4)
  276. {
  277. var msg = new CS_DataChange();
  278. var kv = new pb.Collections.MapField<string, string>() { { EModName.MapData.ToString(), mapInfo.Json() } };// 地图模块数据
  279. msg.ChangedMods.Add(kv);
  280. LogHelper.Log($"上报地图信息{msg}");
  281. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  282. }
  283. }
  284. /// <summary>
  285. /// 上报数据发生变化
  286. /// </summary>
  287. public void ReportDataChange(Info_Map_CmptMgr cpmMgr)
  288. {
  289. var p = UserProxy.Instance.player;
  290. if (sm_gate.GetMoById(p.newMap.curMapId)?.mapType < 4)
  291. {
  292. var msg = new CS_DataChange();
  293. var kv = new pb.Collections.MapField<string, string>() { { EModName.CmptMgr.ToString(), cpmMgr.Json() } };// 地图模块数据
  294. msg.ChangedMods.Add(kv);
  295. LogHelper.Log($"上报地图信息{msg}");
  296. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  297. MapData.cmptMgr = cpmMgr;
  298. }
  299. }
  300. /// <summary>
  301. /// 上报数据发生变化
  302. /// </summary>
  303. public void ReportDataChange(Info_Map_NpcMgr npcMgr)
  304. {
  305. var p = UserProxy.Instance.player;
  306. if (sm_gate.GetMoById(p.newMap.curMapId)?.mapType < 4)
  307. {
  308. var msg = new CS_DataChange();
  309. var kv = new pb.Collections.MapField<string, string>() { { EModName.NpcMgr.ToString(), npcMgr.Json() } };// 地图模块数据
  310. msg.ChangedMods.Add(kv);
  311. LogHelper.Log($"上报地图信息{msg}");
  312. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  313. MapData.npcMgr = npcMgr;
  314. }
  315. }
  316. /// <summary>
  317. /// 上报数据发生变化
  318. /// </summary>
  319. public void ReportDataChange(Info_Map_SpawnerMgr spwMgr)
  320. {
  321. var p = UserProxy.Instance.player;
  322. if (sm_gate.GetMoById(p.newMap.curMapId)?.mapType < 4)
  323. {
  324. var msg = new CS_DataChange();
  325. var kv = new pb.Collections.MapField<string, string>() { { EModName.SpawnerMgr.ToString(), spwMgr.Json() } };// 地图模块数据
  326. msg.ChangedMods.Add(kv);
  327. LogHelper.Log($"上报地图信息{msg}");
  328. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  329. MapData.spnSys = spwMgr;
  330. }
  331. }
  332. /// <summary>
  333. /// 上报数据发生变化
  334. /// </summary>
  335. public void ReportDataChange(Info_Map_Spawner spwnr)
  336. {
  337. var p = UserProxy.Instance.player;
  338. if (sm_gate.GetMoById(p.newMap.curMapId)?.mapType < 4)
  339. {
  340. var msg = new CS_DataChange();
  341. var kv = new pb.Collections.MapField<string, string>() { { EModName.SpawnerMgr_Spawner.ToString(), spwnr.Json() } };// 地图模块数据
  342. msg.ChangedMods.Add(kv);
  343. LogHelper.Log($"上报地图信息{msg}");
  344. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  345. MapData.spnSys._spawnerDict[spwnr.spawnerId] = spwnr;
  346. }
  347. }
  348. internal class Msg_SwawnerRoleInfo
  349. {
  350. public int SpawnerId;
  351. public int RoleId;
  352. public Info_Map_RoleData roleData;
  353. }
  354. /// <summary>
  355. /// 上报数据发生变化(roleInfo:hp,pos等)
  356. /// </summary>
  357. public void ReportDataChange(int spwnrId, int roleId)
  358. {
  359. var data = new Msg_SwawnerRoleInfo();
  360. data.SpawnerId = spwnrId;
  361. data.RoleId = roleId;
  362. if (MapData.spnSys._spawnerDict.ContainsKey(spwnrId) && MapData.spnSys._spawnerDict[spwnrId].roleDict.ContainsKey(roleId)) // 防御对象已被移除
  363. {
  364. data.roleData = MapData.spnSys._spawnerDict[spwnrId]?.roleDict[roleId] ?? null;
  365. var msg = new CS_DataChange();
  366. var kv = new pb.Collections.MapField<string, string>() { { EModName.SpawnerMgr_Spawner_Role.ToString(), JsonConvert.SerializeObject(data) } };// 地图模块数据
  367. msg.ChangedMods.Add(kv);
  368. LogHelper.Log($"上报地图信息{msg}");
  369. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  370. MapData.spnSys._spawnerDict[spwnrId].roleDict[roleId] = data.roleData;
  371. }
  372. }
  373. /// <summary>
  374. /// 上报数据发生变化(玩家信息)
  375. /// </summary>
  376. /// <param name="player"></param>
  377. public void ReportDataChange(Info_Map_Player player)
  378. {
  379. var p = UserProxy.Instance.player;
  380. var msg = new CS_DataChange();
  381. var kv = new pb.Collections.MapField<string, string>() { { EModName.Player.ToString(), player.Json() } };// 地图模块数据
  382. msg.ChangedMods.Add(kv);
  383. LogHelper.Log($"上报地图信息{msg}");
  384. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  385. this.Player = player;
  386. }
  387. /// <summary>
  388. ///
  389. /// </summary>
  390. /// <param name="hero"></param>
  391. public void ReportDataChange(Info_Map_Player_Hero hero)
  392. {
  393. var p = UserProxy.Instance.player;
  394. var msg = new CS_DataChange();
  395. var kv = new pb.Collections.MapField<string, string>() { { EModName.Player_hero.ToString(), hero.Json() } };// 地图模块数据
  396. msg.ChangedMods.Add(kv);
  397. LogHelper.Log($"上报地图信息{msg}");
  398. SendMsg(eProtocalCommand.CsMapDataChange, msg);
  399. if (hero.hp <= 0)
  400. {
  401. hero.hp = hero.hpMax;
  402. }
  403. Player.heroDict[hero.uid] = hero;
  404. }
  405. #endregion
  406. /// <summary>
  407. /// 切换到下一个地图
  408. /// </summary>
  409. /// <param name="targetMapId"></param>
  410. /// <param name="curPoint">唤灵师当前点位(再回这张地图时用)</param>
  411. /// <param name="callback"></param>
  412. public void SwitchNextMap(int targetMapId, int curPoint, Action<Info_Map> callback)
  413. {
  414. if (callback != null)
  415. {
  416. OnSwitchedNextMap = callback;
  417. }
  418. var msg = new CS_SwitchMap() { TargetMapId = targetMapId, CurBirthPoint = curPoint };
  419. LogHelper.Log($"切换到下一地图{targetMapId}");
  420. SendMsg(eProtocalCommand.CsMapSwitchMap, msg);
  421. }
  422. #endregion
  423. }