Example #1
0
        /// <summary>
        /// 辅助子过程。检查异步的网络请求是否成功、对服务器的操作请求是否实现,并返回实现了的操作的结果,或错误信息。
        /// </summary>
        /// <typeparam name="T">代表结果数据的泛型参数。</typeparam>
        /// <param name="respTask">代表异步的网络请求。</param>
        /// <param name="deserializer">对网络请求结果的反序列化器。</param>
        /// <returns>操作的结果。</returns>
        private static async Task <GameOperation <T> > OperationFromResponseAsync <T>(Task <HttpResponseMessage> respTask, Func <string, T> deserializer)
        {
            string msg = "";

            try
            {
                var resp = await respTask.ConfigureAwait(false);

                // 如果是 404 BadRequest,我们最好看看服务器提供了哪些错误信息。
                if (resp.IsSuccessStatusCode || resp.StatusCode == HttpStatusCode.BadRequest)
                {
                    var respStr = await resp.Content.ReadAsStringAsync();

                    if (resp.IsSuccessStatusCode)
                    {
                        return(GameOperation <T> .Succ(deserializer(respStr)));
                    }
                    else
                    {
                        // 404。服务器会将错误信息放在 JSON 数据的 Message 字段里。
                        var deserialized = JsonConvert.DeserializeAnonymousType(respStr, new { Message = "" });
                        msg = deserialized.Message;
                    }
                }
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }

            return(GameOperation <T> .Fail(msg));
        }
Example #2
0
        /// <summary>
        /// 开启一个新游戏。
        /// </summary>
        /// <param name="roomIdToStart">这个游戏实例要连接到的房间号。若为null或空,则为默认的0号房间。</param>
        /// <param name="userId">参与这个游戏的玩家ID。若为null或空,会生成新ID。</param>
        /// <returns>创建游戏的操作结果。</returns>
        public static async Task <GameOperation <CreateGameResult> > OpenRoomAsync(string roomIdToStart, string userId)
        {
            // ConfigureAwait(false) 可以避免对特定的线程进行调度,比如只能序列化访问的UI线程。
            // 该函数内的操作都不需要 UI 线程。
            var stateOp = await QueryStateAsync(userId, roomIdToStart).ConfigureAwait(false);

            if (!stateOp.Succeeded)
            {
                // 如果查询状态失败了,创建游戏也就失败了。
                return(GameOperation <CreateGameResult> .Fail(stateOp.ErrorMessage));
            }

            var state = stateOp.OperationResult;

            if (string.IsNullOrEmpty(state.UserId))
            {
                // User ID 是必要的。
                return(GameOperation <CreateGameResult> .Fail("No valid User ID."));
            }

            var mode = ConvertNumberMode(state.Numbers);

            if (mode == RoomNumberMode.Unknown)
            {
                // 不支持的游戏模式。
                return(GameOperation <CreateGameResult> .Fail($"Unsupported number mode {mode}."));
            }

            var game = new Game
            {
                UserId     = state.UserId,
                RoomId     = state.RoomId,
                Nickname   = state.NickName,
                NumberMode = mode,
            };

            // 启动游戏主循环,用于倒计时和推进游戏轮数。
            // 由于我们用 async/await的形式包装了主循环,故其返回 Task。不过我们不需要用这个 Task。
            var ignored = game.StartAsync(state.RoundId, state.LeftTime);

            return(GameOperation <CreateGameResult> .Succ(new CreateGameResult(game, TimeSpan.FromSeconds(state.LeftTime), ConvertStateToNewRound(state))));
        }