PageRenderTime 60ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/ZeroKLobby_NET4.0/LobbyClient/TasClient.cs

https://github.com/db81/Zero-K-Infrastructure
C# | 893 lines | 716 code | 165 blank | 12 comment | 152 complexity | 7eea2938296676a5ea4861e118208c13 MD5 | raw file
Possible License(s): GPL-3.0, MIT
  1. #region using
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Net.NetworkInformation;
  9. using System.Net.Sockets;
  10. using System.Text;
  11. using System.Text.RegularExpressions;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using ZkData;
  15. using ZkData.UnitSyncLib;
  16. using Timer = System.Timers.Timer;
  17. #endregion
  18. namespace LobbyClient
  19. {
  20. public class TasClient:Connection
  21. {
  22. public const int MaxAlliances = 16;
  23. public const int MaxTeams = 16;
  24. public ProtocolExtension Extensions { get; private set; }
  25. public delegate void Invoker();
  26. public delegate void Invoker<TArg>(TArg arg);
  27. readonly string appName = "UnknownClient";
  28. Dictionary<int, Battle> existingBattles = new Dictionary<int, Battle>();
  29. Dictionary<string, User> existingUsers = new Dictionary<string, User>();
  30. readonly bool forcedLocalIP = false;
  31. bool isLoggedIn;
  32. Dictionary<string, Channel> joinedChannels = new Dictionary<string, Channel>();
  33. int lastUdpSourcePort;
  34. int lastUserStatus;
  35. readonly string localIp;
  36. int pingInterval = 30; // how often to ping server (in seconds)
  37. readonly Timer pingTimer;
  38. public string serverHost { get; private set; }
  39. int serverPort;
  40. public Dictionary<int, Battle> ExistingBattles { get { return existingBattles; } set { existingBattles = value; } }
  41. public Dictionary<string, User> ExistingUsers { get { return existingUsers; } set { existingUsers = value; } }
  42. public override async Task OnConnected()
  43. {
  44. MyBattle = null;
  45. ExistingUsers = new Dictionary<string, User>();
  46. joinedChannels = new Dictionary<string, Channel>();
  47. existingBattles = new Dictionary<int, Battle>();
  48. isLoggedIn = false;
  49. }
  50. public override async Task OnConnectionClosed(bool wasRequested)
  51. {
  52. ExistingUsers = new Dictionary<string, User>();
  53. joinedChannels = new Dictionary<string, Channel>();
  54. existingBattles = new Dictionary<int, Battle>();
  55. MyBattle = null;
  56. isLoggedIn = false;
  57. ConnectionLost(this, new TasEventArgs(string.Format("Connection {0}", wasRequested ? "closed on user request" : "disconnected")));
  58. }
  59. public override async Task OnLineReceived(string line)
  60. {
  61. try {
  62. dynamic obj = CommandJsonSerializer.DeserializeLine(line);
  63. await Process(obj);
  64. } catch (Exception ex) {
  65. Trace.TraceError("Error processing line {0} : {1}", line, ex);
  66. }
  67. }
  68. public async Task SendCommand<T>(T data)
  69. {
  70. try {
  71. var line = CommandJsonSerializer.SerializeToLine(data);
  72. await SendString(line);
  73. } catch (Exception ex) {
  74. Trace.TraceError("Error sending {0} : {1}", data,ex);
  75. }
  76. }
  77. static CommandJsonSerializer CommandJsonSerializer = new CommandJsonSerializer();
  78. public bool IsLoggedIn { get { return isLoggedIn; } }
  79. public Dictionary<string, Channel> JoinedChannels { get { return joinedChannels; } }
  80. public Battle MyBattle { get; protected set; }
  81. //public int MyBattleID { get { return MyBattle != null ? MyBattle.BattleID : 0; } }
  82. public UserBattleStatus MyBattleStatus
  83. {
  84. get
  85. {
  86. if (MyBattle != null) {
  87. UserBattleStatus ubs;
  88. MyBattle.Users.TryGetValue(UserName, out ubs);
  89. return ubs;
  90. }
  91. return null;
  92. }
  93. }
  94. public int MyBattleID
  95. {
  96. get
  97. {
  98. var bat = MyBattle;
  99. if (bat != null) return bat.BattleID;
  100. else return 0;
  101. }
  102. }
  103. public User MyUser
  104. {
  105. get
  106. {
  107. User us;
  108. ExistingUsers.TryGetValue(UserName, out us);
  109. return us;
  110. }
  111. }
  112. public int PingInterval
  113. {
  114. get { return pingInterval; }
  115. set
  116. {
  117. pingInterval = value;
  118. pingTimer.Interval = pingInterval*1000;
  119. }
  120. }
  121. public string ServerSpringVersion {get { return ServerWelcome != null ? ServerWelcome.Engine : null; } }
  122. public string UserName { get; private set; }
  123. public string UserPassword { get; private set; }
  124. public event EventHandler<EventArgs<User>> UserAdded = delegate { };
  125. public event EventHandler<EventArgs<UserDisconnected>> UserRemoved = delegate { };
  126. public event EventHandler<EventArgs<OldNewPair<User>>> UserStatusChanged = delegate { };
  127. public event EventHandler<EventArgs<Battle>> BattleFound = delegate { };
  128. public event EventHandler<EventArgs<ChannelUserInfo>> ChannelUserAdded = delegate { };
  129. public event EventHandler<EventArgs<ChannelUserRemovedInfo>> ChannelUserRemoved = delegate { };
  130. public event EventHandler<EventArgs<Welcome>> Connected = delegate { };
  131. public event EventHandler<EventArgs<JoinChannelResponse>> ChannelJoinFailed = delegate { };
  132. public event EventHandler<TasEventArgs> LoginAccepted = delegate { };
  133. public event EventHandler<EventArgs<LoginResponse>> LoginDenied = delegate { };
  134. public event EventHandler<TasSayEventArgs> Said = delegate { }; // this is fired when any kind of say message is recieved
  135. public event EventHandler<SayingEventArgs> Saying = delegate { }; // this client is trying to say somethign
  136. public event EventHandler<BattleUserEventArgs> BattleUserJoined = delegate { };
  137. public event EventHandler<BattleUserEventArgs> BattleUserLeft = delegate { };
  138. public event EventHandler<CancelEventArgs<Channel>> PreviewChannelJoined = delegate { };
  139. public event EventHandler<TasEventArgs> RegistrationAccepted = delegate { };
  140. public event EventHandler<EventArgs<RegisterResponse>> RegistrationDenied = delegate { };
  141. public event EventHandler<EventArgs<Battle>> BattleRemoved = delegate { }; // raised just after the battle is removed from the battle list
  142. public event EventHandler<EventArgs<Battle>> MyBattleRemoved = delegate { }; // raised just after the battle is removed from the battle list
  143. public event EventHandler<EventArgs<Battle>> BattleClosed = delegate { };
  144. public event EventHandler<EventArgs<Battle>> BattleOpened = delegate { };
  145. public event EventHandler<EventArgs<Battle>> BattleJoined = delegate { };
  146. public event EventHandler<EventArgs<UserBattleStatus>> BattleUserStatusChanged = delegate { };
  147. public event EventHandler<EventArgs<UserBattleStatus>> BattleMyUserStatusChanged = delegate { };
  148. public event EventHandler<EventArgs<Channel>> ChannelJoined = delegate { };
  149. public event EventHandler<EventArgs<Channel>> ChannelLeft = delegate { };
  150. public event EventHandler<EventArgs<BotBattleStatus>> BattleBotAdded = delegate { };
  151. public event EventHandler<EventArgs<BotBattleStatus>> BattleBotUpdated = delegate { };
  152. public event EventHandler<EventArgs<BotBattleStatus>> BattleBotRemoved = delegate { };
  153. public event EventHandler<TasEventArgs> ConnectionLost = delegate { };
  154. public event EventHandler<EventArgs<Say>> Rang = delegate { };
  155. public event EventHandler<CancelEventArgs<TasSayEventArgs>> PreviewSaid = delegate { };
  156. public event EventHandler<EventArgs<Battle>> MyBattleHostExited = delegate { };
  157. public event EventHandler<EventArgs<Battle>> MyBattleStarted = delegate { };
  158. public event EventHandler<EventArgs<SetRectangle>> StartRectAdded = delegate { };
  159. public event EventHandler<EventArgs<SetRectangle>> StartRectRemoved = delegate { };
  160. public event EventHandler<EventArgs<OldNewPair<Battle>>> BattleInfoChanged = delegate { };
  161. public event EventHandler<EventArgs<OldNewPair<Battle>>> BattleMapChanged = delegate { };
  162. public event EventHandler<EventArgs<OldNewPair<Battle>>> MyBattleMapChanged = delegate { };
  163. public event EventHandler<EventArgs<Battle>> ModOptionsChanged = delegate { };
  164. public event EventHandler<TasEventArgs> ChannelTopicChanged = delegate { };
  165. public event EventHandler<EventArgs<User>> UserExtensionsChanged = delegate { };
  166. public event EventHandler<EventArgs<User>> MyExtensionsChanged = delegate { };
  167. public TasClient(string appName, Login.ClientTypes? clientTypes = null, string ipOverride = null)
  168. {
  169. if (clientTypes.HasValue) this.clientType = clientTypes.Value;
  170. this.appName = appName;
  171. if (!string.IsNullOrEmpty(ipOverride))
  172. {
  173. localIp = ipOverride;
  174. forcedLocalIP = true;
  175. }
  176. else
  177. {
  178. var addresses = Dns.GetHostAddresses(Dns.GetHostName());
  179. localIp = addresses[0].ToString();
  180. foreach (var adr in addresses)
  181. {
  182. if (adr.AddressFamily == AddressFamily.InterNetwork)
  183. {
  184. localIp = adr.ToString();
  185. break;
  186. }
  187. }
  188. }
  189. Extensions = new ProtocolExtension(this, (user, data) => {
  190. User u;
  191. if (ExistingUsers.TryGetValue(user, out u))
  192. {
  193. UserExtensionsChanged(this, new EventArgs<User>(u));
  194. }
  195. });
  196. pingTimer = new Timer(pingInterval*1000) { AutoReset = true };
  197. pingTimer.Elapsed += OnPingTimer;
  198. }
  199. public async Task AddBattleRectangle(int allyno, BattleRect rect)
  200. {
  201. {
  202. if (allyno < Spring.MaxAllies && allyno >= 0) {
  203. await SendCommand(new SetRectangle() { Number = allyno, Rectangle = rect });
  204. }
  205. }
  206. }
  207. private async Task Process(SetRectangle rect)
  208. {
  209. var bat = MyBattle;
  210. if (bat != null) {
  211. if (rect.Rectangle == null) {
  212. BattleRect org;
  213. bat.Rectangles.TryRemove(rect.Number, out org);
  214. StartRectAdded(this, new EventArgs<SetRectangle>(rect));
  215. } else {
  216. bat.Rectangles[rect.Number] = rect.Rectangle;
  217. StartRectRemoved(this, new EventArgs<SetRectangle>(rect));
  218. }
  219. }
  220. }
  221. private async Task Process(SetModOptions options)
  222. {
  223. var bat = MyBattle;
  224. if (bat != null) {
  225. bat.ModOptions = options.Options;
  226. ModOptionsChanged(this, new EventArgs<Battle>(bat));
  227. }
  228. }
  229. public Task AddBot(string name, string aiDll, int? allyNumber= null, int? teamNumber= null)
  230. {
  231. var u = new UpdateBotStatus();
  232. if (aiDll != null) u.AiLib = aiDll;
  233. if (name != null) u.Name = name;
  234. if (allyNumber != null) u.AllyNumber = allyNumber;
  235. if (teamNumber != null) u.TeamNumber = teamNumber;
  236. return SendCommand(u);
  237. }
  238. public Task ChangeMap(string name)
  239. {
  240. return SendCommand(new BattleUpdate() { Header = new BattleHeader() { BattleID = MyBattleID, Map = name } });
  241. }
  242. public async Task ChangeMyBattleStatus(bool? spectate = null,
  243. SyncStatuses? syncStatus = null,
  244. int? ally = null,
  245. int? team = null)
  246. {
  247. var ubs = MyBattleStatus;
  248. if (ubs != null) {
  249. var status = new UpdateUserBattleStatus() { IsSpectator = spectate, Sync = syncStatus, AllyNumber = ally, TeamNumber = team, Name = UserName};
  250. await SendCommand(status);
  251. }
  252. }
  253. public Task ChangeMyUserStatus(bool? isAway = null, bool? isInGame = null)
  254. {
  255. return SendCommand(new ChangeUserStatus() { IsAfk = isAway, IsInGame = isInGame });
  256. }
  257. SynchronizationContext context;
  258. public void Connect(string host, int port)
  259. {
  260. context = SynchronizationContext.Current;
  261. serverHost = host;
  262. serverPort = port;
  263. WasDisconnectRequested = false;
  264. pingTimer.Start();
  265. Connect(host, port, forcedLocalIP ? localIp : null);
  266. }
  267. public bool WasDisconnectRequested { get; private set; }
  268. public void RequestDisconnect()
  269. {
  270. WasDisconnectRequested = true;
  271. RequestClose();
  272. }
  273. public async Task ForceAlly(string username, int ally)
  274. {
  275. if (MyBattle != null && MyBattle.Users.ContainsKey(username)) {
  276. var ubs = new UpdateUserBattleStatus() { Name = username, AllyNumber = ally };
  277. await SendCommand(ubs);
  278. }
  279. }
  280. public async Task ForceSpectator(string username, bool spectatorState = true)
  281. {
  282. if (MyBattle != null && MyBattle.Users.ContainsKey(username))
  283. {
  284. var ubs = new UpdateUserBattleStatus() { Name = username, IsSpectator = spectatorState };
  285. await SendCommand(ubs);
  286. }
  287. }
  288. public async Task ForceTeam(string username, int team)
  289. {
  290. if (MyBattle != null && MyBattle.Users.ContainsKey(username))
  291. {
  292. var ubs = new UpdateUserBattleStatus() { Name = username, TeamNumber = team };
  293. await SendCommand(ubs);
  294. }
  295. }
  296. public void GameSaid(string username, string text)
  297. {
  298. InvokeSaid(new TasSayEventArgs(SayPlace.Game, "", username, text, false));
  299. }
  300. public bool GetExistingUser(string name, out User u)
  301. {
  302. return ExistingUsers.TryGetValue(name, out u);
  303. }
  304. public User GetUserCaseInsensitive(string userName)
  305. {
  306. return ExistingUsers.Values.FirstOrDefault(u => String.Equals(u.Name, userName, StringComparison.InvariantCultureIgnoreCase));
  307. }
  308. public Task JoinBattle(int battleID, string password = null)
  309. {
  310. return SendCommand(new JoinBattle() { BattleID = battleID, Password = password });
  311. }
  312. public Task JoinChannel(string channelName, string key=null)
  313. {
  314. return SendCommand(new JoinChannel() { ChannelName = channelName, Password = key });
  315. }
  316. public Task Kick(string username, int? battleID=null, string reason = null)
  317. {
  318. return SendCommand(new KickFromBattle() { Name = username, BattleID = battleID, Reason = reason });
  319. }
  320. public Task AdminKickFromLobby(string username,string reason)
  321. {
  322. return SendCommand(new KickFromServer() { Name = username, Reason = reason });
  323. }
  324. public void AdminSetTopic(string channel, string topic) {
  325. Say(SayPlace.User, "ChanServ", string.Format("!topic #{0} {1}", channel, topic.Replace("\n","\\n")),false);
  326. }
  327. public void AdminSetChannelPassword(string channel, string password) {
  328. if (string.IsNullOrEmpty(password)) {
  329. Say(SayPlace.User, "ChanServ",string.Format("!lock #{0} {1}", channel, password),false);
  330. } else {
  331. Say(SayPlace.User, "ChanServ", string.Format("!unlock #{0}", channel), false);
  332. }
  333. }
  334. public async Task LeaveBattle()
  335. {
  336. if (MyBattle != null) {
  337. await SendCommand(new LeaveBattle() { BattleID = MyBattle.BattleID });
  338. }
  339. }
  340. public async Task LeaveChannel(string channelName)
  341. {
  342. if (joinedChannels.ContainsKey(channelName)) {
  343. await SendCommand(new LeaveChannel() { ChannelName = channelName });
  344. }
  345. }
  346. public static long GetMyUserID() {
  347. var nics = NetworkInterface.GetAllNetworkInterfaces().Where(x=> !String.IsNullOrWhiteSpace(x.GetPhysicalAddress().ToString())
  348. && x.NetworkInterfaceType != NetworkInterfaceType.Loopback && x.NetworkInterfaceType != NetworkInterfaceType.Tunnel);
  349. var wantedNic = nics.FirstOrDefault();
  350. if (wantedNic != null)
  351. {
  352. return Crc.Crc32(wantedNic.GetPhysicalAddress().GetAddressBytes());
  353. }
  354. return 0;
  355. }
  356. public Task Login(string userName, string password)
  357. {
  358. UserName = userName;
  359. UserPassword = password;
  360. return SendCommand(new Login() { Name = userName, PasswordHash = Utils.HashLobbyPassword(password), ClientType = clientType, UserID = GetMyUserID()});
  361. }
  362. Login.ClientTypes clientType = LobbyClient.Login.ClientTypes.ZeroKLobby | (Environment.OSVersion.Platform == PlatformID.Unix ? LobbyClient.Login.ClientTypes.Linux : 0);
  363. public Task OpenBattle(Battle nbattle)
  364. {
  365. if (MyBattle != null) LeaveBattle();
  366. return SendCommand(new OpenBattle() {
  367. Header =
  368. new BattleHeader() {
  369. Engine = nbattle.EngineVersion,
  370. Game = nbattle.ModName,
  371. Ip = nbattle.Ip ?? localIp,
  372. Port = nbattle.HostPort,
  373. Map = nbattle.MapName,
  374. Password = nbattle.Password,
  375. MaxPlayers = nbattle.MaxPlayers,
  376. Title = nbattle.Title
  377. }
  378. });
  379. }
  380. public Task Register(string username, string password)
  381. {
  382. return SendCommand(new Register() { Name = username, PasswordHash = Utils.HashLobbyPassword(password) });
  383. }
  384. public async Task RemoveBattleRectangle(int allyno)
  385. {
  386. if (MyBattle.Rectangles.ContainsKey(allyno)) {
  387. await SendCommand(new SetRectangle() { Number = allyno, Rectangle = null });
  388. }
  389. }
  390. public async Task RemoveBot(string name)
  391. {
  392. var bat = MyBattle;
  393. if (bat != null && bat.Bots.ContainsKey(name)) await SendCommand(new RemoveBot{Name = name});
  394. }
  395. public Task Ring(SayPlace place, string channel, string text = null)
  396. {
  397. return Say(place, channel, text ?? ("Ringing " + channel), false, isRing: true);
  398. }
  399. public async Task ForceJoinBattle(string name, string battleHostName) {
  400. var battle = ExistingBattles.Values.FirstOrDefault(x => x.Founder.Name == battleHostName);
  401. if (battle != null) await ForceJoinBattle(name, battle.BattleID);
  402. }
  403. public Task ForceJoinBattle(string name, int battleID)
  404. {
  405. return SendCommand(new ForceJoinBattle() { Name = name, BattleID = battleID });
  406. }
  407. public Task ForceJoinChannel(string user, string channel)
  408. {
  409. return SendCommand(new ForceJoinChannel() { UserName = user, ChannelName = channel });
  410. }
  411. public Task ForceLeaveChannel(string user, string channel, string reason = null)
  412. {
  413. return SendCommand(new KickFromChannel() { ChannelName = channel, UserName = user, Reason = reason });
  414. }
  415. /// <summary>
  416. /// Say something through chat system
  417. /// </summary>
  418. /// <param Name="place">Pick user (private message) channel or battle</param>
  419. /// <param Name="channel">Channel or User Name</param>
  420. /// <param Name="inputtext">chat text</param>
  421. /// <param Name="isEmote">is message emote? (channel or battle only)</param>
  422. /// <param Name="linePrefix">text to be inserted in front of each line (example: "!pm xyz")</param>
  423. public async Task Say(SayPlace place, string channel, string inputtext, bool isEmote, string linePrefix = "", bool isRing = false)
  424. {
  425. if (String.IsNullOrEmpty(inputtext)) return;
  426. var lines = inputtext.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
  427. foreach (var text in lines)
  428. {
  429. if (String.IsNullOrEmpty(text)) continue;
  430. var sentText = linePrefix + text;
  431. var args = new SayingEventArgs(place, channel, sentText, isEmote);
  432. Saying(this, args);
  433. if (args.Cancel) continue;
  434. if (args.SayPlace == SayPlace.Channel && !JoinedChannels.ContainsKey(args.Channel)) {
  435. await JoinChannel(args.Channel);
  436. }
  437. var say = new Say() { Target = args.Channel, Place = args.SayPlace, Text = args.Text, IsEmote = args.IsEmote, Ring = isRing};
  438. await SendCommand(say);
  439. }
  440. }
  441. public Task SendRaw(string text)
  442. {
  443. if (!text.EndsWith("\n")) text += "\n";
  444. return SendString(text);
  445. }
  446. public Task SetModOptions(Dictionary<string,string> data)
  447. {
  448. return SendCommand(new SetModOptions() { Options = data });
  449. }
  450. public Task UpdateModOptions(Dictionary<string, string> data)
  451. {
  452. var cur = new Dictionary<string, string>(MyBattle.ModOptions);
  453. foreach (var d in data) {
  454. cur[d.Key] = d.Value;
  455. }
  456. return SetModOptions(cur);
  457. }
  458. /// <summary>
  459. /// Starts game and automatically does hole punching if necessary
  460. /// </summary>
  461. public void StartGame()
  462. {
  463. ChangeMyUserStatus(false, true);
  464. }
  465. public async Task UpdateBot(string name, string aiDll, int? allyNumber = null, int? teamNumber = null)
  466. {
  467. var bat = MyBattle;
  468. if (bat != null && bat.Bots.ContainsKey(name)) {
  469. await AddBot(name, aiDll, allyNumber, teamNumber);
  470. }
  471. }
  472. public async Task Process(UpdateBotStatus status)
  473. {
  474. var bat = MyBattle;
  475. if (bat != null)
  476. {
  477. BotBattleStatus ubs;
  478. bat.Bots.TryGetValue(status.Name, out ubs);
  479. if (ubs != null) {
  480. ubs.UpdateWith(status);
  481. BattleBotUpdated(this, new EventArgs<BotBattleStatus>(ubs));
  482. } else {
  483. var nubs = new BotBattleStatus(status.Name, status.Owner, status.AiLib);
  484. nubs.UpdateWith(status);
  485. bat.Bots[status.Name] = nubs;
  486. BattleBotAdded(this, new EventArgs<BotBattleStatus>(nubs));
  487. }
  488. }
  489. }
  490. public async Task Process(RemoveBot status)
  491. {
  492. var bat = MyBattle;
  493. if (bat != null)
  494. {
  495. BotBattleStatus ubs;
  496. if (bat.Bots.TryRemove(status.Name, out ubs)) {
  497. BattleBotRemoved(this, new EventArgs<BotBattleStatus>(ubs));
  498. }
  499. }
  500. }
  501. User UserGetter(string n)
  502. {
  503. User us;
  504. if (existingUsers.TryGetValue(n, out us)) return us;
  505. else return new User() { Name = n };
  506. }
  507. async Task Process(BattleAdded bat)
  508. {
  509. var newBattle = new Battle();
  510. newBattle.UpdateWith(bat.Header, UserGetter);
  511. existingBattles[newBattle.BattleID] = newBattle;
  512. newBattle.Founder.IsInBattleRoom = true;
  513. BattleFound(this, new EventArgs<Battle>(newBattle));
  514. }
  515. async Task Process(JoinedBattle bat)
  516. {
  517. User user;
  518. existingUsers.TryGetValue(bat.User, out user);
  519. Battle battle;
  520. ExistingBattles.TryGetValue(bat.BattleID, out battle);
  521. if (user != null && battle != null) {
  522. battle.Users[user.Name] = new UserBattleStatus(user.Name, user);
  523. user.IsInBattleRoom = true;
  524. BattleUserJoined(this, new BattleUserEventArgs(user.Name, bat.BattleID));
  525. if (user.Name == UserName) {
  526. MyBattle = battle;
  527. if (battle.Founder.Name == UserName) BattleOpened(this, new EventArgs<Battle>(battle));
  528. BattleJoined(this, new EventArgs<Battle>(MyBattle));
  529. }
  530. }
  531. }
  532. async Task Process(LeftBattle left)
  533. {
  534. User user;
  535. Battle bat;
  536. existingUsers.TryGetValue(left.User, out user);
  537. existingBattles.TryGetValue(left.BattleID, out bat);
  538. if (bat != null && user != null) {
  539. user.IsInBattleRoom = false;
  540. UserBattleStatus removed;
  541. bat.Users.TryRemove(left.User, out removed);
  542. if (MyBattle != null && left.BattleID == MyBattleID) {
  543. if (UserName == left.User) {
  544. bat.Rectangles.Clear();
  545. bat.Bots.Clear();
  546. bat.ModOptions.Clear();
  547. MyBattle = null;
  548. BattleClosed(this, new EventArgs<Battle>(bat));
  549. }
  550. }
  551. BattleUserLeft(this, new BattleUserEventArgs(user.Name, left.BattleID));
  552. }
  553. }
  554. async Task Process(BattleRemoved br)
  555. {
  556. Battle battle;
  557. if (!existingBattles.TryGetValue(br.BattleID, out battle)) return;
  558. foreach (var u in battle.Users.Keys)
  559. {
  560. User user;
  561. if (ExistingUsers.TryGetValue(u, out user)) user.IsInBattleRoom = false;
  562. }
  563. existingBattles.Remove(br.BattleID);
  564. if (battle == MyBattle)
  565. {
  566. BattleClosed(this, new EventArgs<Battle>(battle));
  567. MyBattleRemoved(this, new EventArgs<Battle>(battle));
  568. }
  569. BattleRemoved(this, new EventArgs<Battle>(battle));
  570. }
  571. async Task Process(LoginResponse loginResponse)
  572. {
  573. if (loginResponse.ResultCode == LoginResponse.Code.Ok) {
  574. isLoggedIn = true;
  575. LoginAccepted(this, new TasEventArgs());
  576. } else {
  577. isLoggedIn = false;
  578. LoginDenied(this, new EventArgs<LoginResponse>(loginResponse));
  579. }
  580. }
  581. async Task Process(Ping ping)
  582. {
  583. lastPing = DateTime.UtcNow;
  584. }
  585. async Task Process(User userUpdate)
  586. {
  587. User user;
  588. User old = null;
  589. existingUsers.TryGetValue(userUpdate.Name, out user);
  590. if (user != null) {
  591. old = user.Clone();
  592. user.UpdateWith(userUpdate);
  593. } else user = userUpdate;
  594. existingUsers[user.Name] = user;
  595. if (old == null) UserAdded(this, new EventArgs<User>(user));
  596. if (old != null) {
  597. var bat = MyBattle;
  598. if (bat != null && bat.Founder.Name == user.Name)
  599. {
  600. if (user.IsInGame && !old.IsInGame) MyBattleStarted(this,new EventArgs<Battle>(bat) );
  601. if (!user.IsInGame && old.IsInGame) MyBattleHostExited(this, new EventArgs<Battle>(bat));
  602. }
  603. }
  604. UserStatusChanged(this, new EventArgs<OldNewPair<User>>(new OldNewPair<User>(old, user)));
  605. }
  606. async Task Process(RegisterResponse registerResponse)
  607. {
  608. if (registerResponse.ResultCode == RegisterResponse.Code.Ok)
  609. {
  610. RegistrationAccepted(this, new TasEventArgs());
  611. }
  612. else
  613. {
  614. RegistrationDenied(this, new EventArgs<RegisterResponse>(registerResponse));
  615. }
  616. }
  617. async Task Process(Say say)
  618. {
  619. InvokeSaid(new TasSayEventArgs(say.Place, say.Target,say.User, say.Text, say.IsEmote));
  620. if (say.Ring) Rang(this, new EventArgs<Say>(say));
  621. }
  622. public Welcome ServerWelcome = new Welcome();
  623. async Task Process(Welcome welcome)
  624. {
  625. ServerWelcome = welcome;
  626. Connected(this, new EventArgs<Welcome>(welcome));
  627. }
  628. async Task Process(JoinChannelResponse response)
  629. {
  630. if (response.Success) {
  631. var chan = new Channel() {
  632. Name = response.Channel.ChannelName,
  633. Topic = response.Channel.Topic,
  634. TopicSetBy = response.Channel.TopicSetBy,
  635. TopicSetDate = response.Channel.TopicSetDate,
  636. };
  637. JoinedChannels[response.ChannelName] = chan;
  638. foreach (var u in response.Channel.Users) {
  639. User user;
  640. if (existingUsers.TryGetValue(u, out user)) chan.Users[u] = user;
  641. }
  642. var cancelEvent = new CancelEventArgs<Channel>(chan);
  643. PreviewChannelJoined(this, cancelEvent);
  644. if (!cancelEvent.Cancel) {
  645. ChannelJoined(this, new EventArgs<Channel>(chan));
  646. ChannelUserAdded(this, new EventArgs<ChannelUserInfo>(new ChannelUserInfo() {Channel = chan, Users = chan.Users.Values.ToList()}));
  647. }
  648. } else {
  649. ChannelJoinFailed(this, new EventArgs<JoinChannelResponse>(response));
  650. }
  651. }
  652. async Task Process(ChannelUserAdded arg)
  653. {
  654. Channel chan;
  655. if (joinedChannels.TryGetValue(arg.ChannelName, out chan)) {
  656. if (!chan.Users.ContainsKey(arg.UserName)) {
  657. User user;
  658. if (existingUsers.TryGetValue(arg.UserName, out user)) {
  659. chan.Users[arg.UserName] = user;
  660. ChannelUserAdded(this, new EventArgs<ChannelUserInfo>(new ChannelUserInfo() { Channel = chan, Users = new List<User>(){user}}));
  661. }
  662. }
  663. }
  664. }
  665. async Task Process(ChannelUserRemoved arg)
  666. {
  667. Channel chan;
  668. if (joinedChannels.TryGetValue(arg.ChannelName, out chan)) {
  669. User org;
  670. if (chan.Users.TryRemove(arg.UserName, out org))
  671. {
  672. if (arg.UserName == UserName) ChannelLeft(this, new EventArgs<Channel>(chan));
  673. ChannelUserRemoved(this, new EventArgs<ChannelUserRemovedInfo>(new ChannelUserRemovedInfo() { Channel = chan, User = org }));
  674. }
  675. }
  676. }
  677. async Task Process(UserDisconnected arg)
  678. {
  679. existingUsers.Remove(arg.Name);
  680. UserRemoved(this, new EventArgs<UserDisconnected>(arg));
  681. }
  682. async Task Process(UpdateUserBattleStatus status)
  683. {
  684. var bat = MyBattle;
  685. if (bat != null) {
  686. UserBattleStatus ubs;
  687. bat.Users.TryGetValue(status.Name, out ubs);
  688. if (ubs != null) {
  689. ubs.UpdateWith(status);
  690. if (status.Name == UserName) BattleMyUserStatusChanged(this, new EventArgs<UserBattleStatus>(ubs));
  691. BattleUserStatusChanged(this, new EventArgs<UserBattleStatus>(ubs));
  692. }
  693. }
  694. }
  695. async Task Process(BattleUpdate batUp)
  696. {
  697. var h = batUp.Header;
  698. Battle bat;
  699. if (existingBattles.TryGetValue(h.BattleID.Value, out bat)) {
  700. var org = bat.Clone();
  701. bat.UpdateWith(h, UserGetter);
  702. var pair = new OldNewPair<Battle>(org, bat);
  703. if (org.MapName != bat.MapName) {
  704. if (bat == MyBattle) MyBattleMapChanged(this, new EventArgs<OldNewPair<Battle>>(pair));
  705. BattleMapChanged(this, new EventArgs<OldNewPair<Battle>>(pair));
  706. }
  707. BattleInfoChanged(this, new EventArgs<OldNewPair<Battle>>(pair));
  708. }
  709. }
  710. void InvokeSaid(TasSayEventArgs sayArgs)
  711. {
  712. var previewSaidEventArgs = new CancelEventArgs<TasSayEventArgs>(sayArgs);
  713. PreviewSaid(this, previewSaidEventArgs);
  714. if (!previewSaidEventArgs.Cancel) Said(this, sayArgs);
  715. }
  716. DateTime lastPing;
  717. void OnPingTimer(object sender, EventArgs args)
  718. {
  719. if (context != null) context.Post(x=>PingTimerInternal(),null);
  720. else PingTimerInternal();
  721. }
  722. private void PingTimerInternal()
  723. {
  724. if (IsConnected) SendCommand(new Ping());
  725. else if(!WasDisconnectRequested) Connect(serverHost, serverPort);
  726. }
  727. }
  728. }