private void OnMessage(byte[] buffer, int length) { try { MajsoulMessage message = majsoulHelper.decode(buffer, 0, length); HandleMessage(message); } catch (Exception ex) { Trace.TraceError(ex.ToString()); Close(true); } }
public MajsoulMessage parseResult(string str, string rawData) { MajsoulMessage res; try { JObject obj = JObject.Parse(str); if ((bool)obj["success"]) { res = new MajsoulMessage { Success = true, Type = (MajsoulMessageType)Enum.Parse(typeof(MajsoulMessageType), (string)obj["type"], true), MethodName = (string)obj["methodName"], Json = obj["data"], }; Trace.TraceInformation("Recv: {0}", JsonConvert.SerializeObject(res)); } else if (!obj.ContainsKey("error")) { res = new MajsoulMessage { Success = false, Type = (MajsoulMessageType)Enum.Parse(typeof(MajsoulMessageType), (string)obj["type"], true), MethodName = (string)obj["methodName"], Data = rawData, }; Trace.TraceInformation("Recv: {0}", JsonConvert.SerializeObject(res)); } else { res = new MajsoulMessage { Success = false, Data = rawData, }; Trace.TraceInformation("Error parsing server message: Node: {0} (data = {1})", (string)obj["error"], rawData); } } catch (Exception ex) { res = new MajsoulMessage { Success = false, Data = rawData, }; Trace.TraceInformation("Error parsing server message: {0} (data = {1})", ex.Message, rawData); } return(res); }
public byte[] encode(MajsoulMessage message) { Trace.TraceInformation("Send: {0}", JsonConvert.SerializeObject(message)); send(JsonConvert.SerializeObject(new { action = "encode", methodName = message.MethodName, data = message.Data, })); string hex = recv(); return(StringToByteArray(hex)); }
private async Task OnMessage(MessageEventArgs args) { try { int length = await args.Data.ReadAsync(buffer, 0, buffer.Length); MajsoulMessage message = majsoulHelper.decode(buffer, 0, length); HandleMessage(message); } catch (Exception ex) { Trace.TraceError(ex.ToString()); Close(true); } }
public MajsoulMessage parseResult(string str, string rawData) { MajsoulMessage res; try { JObject obj = JObject.Parse(str); if ((bool)obj["success"]) { res = new MajsoulMessage { Success = true, Type = (MajsoulMessageType)Enum.Parse(typeof(MajsoulMessageType), (string)obj["type"], true), MethodName = (string)obj["methodName"], Json = obj["data"], }; } else { res = new MajsoulMessage { Success = false, MethodName = (string)obj["methodName"], Data = rawData, }; } } catch (Exception) { res = new MajsoulMessage { Success = false, Data = rawData, }; } Trace.TraceInformation("Recv: {0}", JsonConvert.SerializeObject(res)); return(res); }
private void HandleMessage(MajsoulMessage message, bool forSync = false) { if (syncing && !forSync && message.MethodName != ".lq.FastTest.fetchGamePlayerState") { pendingActions.Enqueue(message); return; } if (timers.ContainsKey(message.MethodName)) { timers[message.MethodName].Dispose(); } if (!message.Success && message.MethodName != ".lq.FastTest.authGame") { return; } if (message.MethodName == ".lq.Lobby.login" || message.MethodName == ".lq.Lobby.oauth2Login") { accountId = (int)message.Json["account_id"]; if (message.Json["error"] != null && message.Json["error"]["code"] != null) { InvokeOnLogin(resume: false, succeeded: false); } else if (message.Json["game_info"] != null) { continued = true; InvokeOnLogin(resume: true, succeeded: true); StartGame(message.Json["game_info"], true); } else { InvokeOnLogin(resume: false, succeeded: true); } } if (message.MethodName == ".lq.NotifyRoomGameStart" || message.MethodName == ".lq.NotifyMatchGameStart") { StartGame(message.Json, false); } else if (message.MethodName == ".lq.FastTest.authGame") { gameStarted = true; InvokeOnGameStart(continued); if (!continued) { Send(wsGame, ".lq.FastTest.enterGame", new { }).Wait(); } else { Send(wsGame, ".lq.FastTest.syncGame", new { round_id = "-1", step = 1000000 }).Wait(); continued = false; } } else if (message.MethodName == ".lq.NotifyPlayerLoadGameReady") { playerSeat = message.Json["ready_id_list"].Select(t => (int)t).ToList().IndexOf(accountId); } else if (message.MethodName == "ActionMJStart") { gameEnded = false; } else if (message.MethodName == ".lq.NotifyGameEndResult") { Bye(); gameEnded = true; InvokeOnGameEnd(); } else if (message.MethodName == "ActionHule") { int[] points = message.Json["scores"].Select(t => (int)t).ToArray(); int[] rawPointDeltas = message.Json["delta_scores"].Select(t => (int)t).ToArray(); int[] pointDeltas = new int[4]; for (var i = 0; i < 4; i++) { gameData.players[NormalizedPlayerId(i)].point = points[i]; pointDeltas[NormalizedPlayerId(i)] = rawPointDeltas[i]; } foreach (var agari in message.Json["hules"]) { Player who = gameData.players[NormalizedPlayerId((int)agari["seat"])]; Player fromWho = pointDeltas.Count(s => s < 0) == 1 ? gameData.players[Array.FindIndex(pointDeltas, s => s < 0)] : who; int point = !(bool)agari["zimo"] ? (int)agari["point_rong"] : (bool)agari["qinjia"] ? (int)agari["point_zimo_xian"] * 3 : (int)agari["point_zimo_xian"] * 2 + (int)agari["point_zimo_qin"]; if (gameData.lastTile != null) { gameData.lastTile.IsTakenAway = true; } if ((bool)agari["yiman"]) { SaveReplayTag("Yakuman"); } InvokeOnAgari(who, fromWho, point, pointDeltas, gameData.players); } DelayedNextReady(); } else if (message.MethodName == "ActionLiuJu") { InvokeOnAgari(null, null, 0, new[] { 0, 0, 0, 0 }, gameData.players); DelayedNextReady(); } else if (message.MethodName == "ActionNoTile") { var scoreObj = message.Json["scores"][0]; int[] rawPointDeltas = scoreObj["delta_scores"] != null ? scoreObj["delta_scores"].Select(t => (int)t).ToArray() : new[] { 0, 0, 0, 0 }; int[] pointDeltas = new int[4]; for (var i = 0; i < 4; i++) { gameData.players[NormalizedPlayerId(i)].point = (int)scoreObj["old_scores"][i] + rawPointDeltas[i]; pointDeltas[NormalizedPlayerId(i)] = rawPointDeltas[i]; } InvokeOnAgari(null, null, 0, pointDeltas, gameData.players); DelayedNextReady(); } else if (message.MethodName == "ActionNewRound") { Tile.Reset(); gameData = new GameData(); HandleInit(message.Json); if (!syncing) { InvokeOnInit(/* continued */ false, gameData.direction, gameData.seq, gameData.seq2, gameData.players); } if (player.hand.Count > 13) { operationList = message.Json["operation"]["operation_list"]; if (!syncing) { Thread.Sleep(2000); // 等待发牌动画结束 stopwatch.Restart(); InvokeOnDraw(player.hand.Last()); } } } else if (message.MethodName == ".lq.FastTest.syncGame") { syncing = true; continuedBetweenGames = (int)message.Json["step"] == 0; Send(wsGame, ".lq.FastTest.fetchGamePlayerState", new { }).Wait(); if (message.Json["game_restore"]["actions"] != null) { foreach (var action in message.Json["game_restore"]["actions"]) { var bytes = Convert.FromBase64String((string)action["data"]); var actionMessage = majsoulHelper.decodeActionPrototype((string)action["name"], bytes); pendingActions.Enqueue(actionMessage); } } } else if (message.MethodName == ".lq.FastTest.fetchGamePlayerState") { bool inited = false; playerSeat = message.Json["state_list"].ToList().IndexOf("SYNCING") - 2; while (pendingActions.Count > 1) { var actionMessage = pendingActions.Dequeue(); if (actionMessage.MethodName == "ActionNewRound") { inited = true; } HandleMessage(actionMessage, forSync: true); } Send(wsGame, ".lq.FastTest.finishSyncGame", new { }).Wait(); syncing = false; if (inited) { InvokeOnInit(/* continued */ true, gameData.direction, gameData.seq, gameData.seq2, gameData.players); } // Queue里的最后一个action需要响应 if (pendingActions.Count > 0) { HandleMessage(pendingActions.Dequeue()); } if (continuedBetweenGames) { NextReady(); } } else if (message.MethodName == "ActionDealTile") { gameData.remainingTile = (int)message.Json["left_tile_count"]; if (message.Json["doras"] != null) { var doras = message.Json["doras"].Select(t => (string)t); foreach (var dora in doras.Skip(gameData.dora.Count)) { gameData.dora.Add(new Tile(dora)); } } if (NormalizedPlayerId((int)message.Json["seat"]) == 0) { Tile tile = new Tile((string)message.Json["tile"]); player.hand.Add(tile); gameData.lastTile = tile; operationList = message.Json["operation"]["operation_list"]; if (!syncing) { stopwatch.Restart(); InvokeOnDraw(tile); } } } else if (message.MethodName == "ActionDiscardTile") { Player currentPlayer = gameData.players[NormalizedPlayerId((int)message.Json["seat"])]; if (!(bool)message.Json["moqie"]) { currentPlayer.safeTiles.Clear(); } var tileName = (string)message.Json["tile"]; if (currentPlayer == player) { if (lastDiscardedTile == null || lastDiscardedTile.OfficialName != tileName) { lastDiscardedTile = player.hand.First(t => t.OfficialName == tileName); } player.hand.Remove(lastDiscardedTile); } Tile tile = currentPlayer == player ? lastDiscardedTile : new Tile(tileName); lastDiscardedTile = null; currentPlayer.graveyard.Add(tile); gameData.lastTile = tile; foreach (var p in gameData.players) { p.safeTiles.Add(tile); } if ((bool)message.Json["is_liqi"] || (bool)message.Json["is_wliqi"]) { currentPlayer.reached = true; currentPlayer.safeTiles.Clear(); if (!syncing) { InvokeOnReach(currentPlayer); } } if (!syncing) { InvokeOnDiscard(currentPlayer, tile); } JToken keyValuePairs = message.Json; if (keyValuePairs["doras"] != null) { var doras = message.Json["doras"].Select(t => (string)t); foreach (var dora in doras.Skip(gameData.dora.Count)) { gameData.dora.Add(new Tile(dora)); } } if (keyValuePairs["operation"] != null) { operationList = message.Json["operation"]["operation_list"]; if (!syncing) { stopwatch.Restart(); InvokeOnWait(tile, currentPlayer); } } } else if (message.MethodName == "ActionChiPengGang") { Player currentPlayer = gameData.players[NormalizedPlayerId((int)message.Json["seat"])]; var fuuro = HandleFuuro(currentPlayer, (int)message.Json["type"], message.Json["tiles"].Select(t => (string)t), message.Json["froms"].Select(t => (int)t)); if (!syncing) { InvokeOnNaki(currentPlayer, fuuro); } } else if (message.MethodName == "ActionAnGangAddGang") { Player currentPlayer = gameData.players[NormalizedPlayerId((int)message.Json["seat"])]; FuuroGroup fuuro = null; if ((int)message.Json["type"] == 2) { fuuro = HandleKakan(currentPlayer, (string)message.Json["tiles"]); } else if ((int)message.Json["type"] == 3) { fuuro = HandleAnkan(currentPlayer, (string)message.Json["tiles"]); } if (!syncing) { InvokeOnNaki(currentPlayer, fuuro); } } }