Example #1
0
 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);
     }
 }
Example #2
0
        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);
        }
Example #3
0
        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));
        }
Example #4
0
        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);
            }
        }
Example #5
0
        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);
        }
Example #6
0
        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);
                }
            }
        }