diff --git a/src/CloudGaming/Api/CloudGaming.Api/Controllers/PlayGameController.cs b/src/CloudGaming/Api/CloudGaming.Api/Controllers/PlayGameController.cs index 4e1db35..f05bfc2 100644 --- a/src/CloudGaming/Api/CloudGaming.Api/Controllers/PlayGameController.cs +++ b/src/CloudGaming/Api/CloudGaming.Api/Controllers/PlayGameController.cs @@ -135,7 +135,7 @@ public class PlayGameController : CloudGamingControllerBase /// [HttpPost] [Authorize] - public async Task GetMyScListAsync([FromBody] RequestBaseModel requestBaseModel) + public async Task GetMyScListAsync([FromBody] RequestBaseModel requestBaseModel) { PlayGameBLL playGameBLL = new PlayGameBLL(ServiceProvider, JYApi); return await playGameBLL.GetMyScList(requestBaseModel.Sn); diff --git a/src/CloudGaming/Api/CloudGaming.ExtApi/Dockerfile b/src/CloudGaming/Api/CloudGaming.ExtApi/Dockerfile index 782e2a1..9a479b6 100644 --- a/src/CloudGaming/Api/CloudGaming.ExtApi/Dockerfile +++ b/src/CloudGaming/Api/CloudGaming.ExtApi/Dockerfile @@ -2,6 +2,12 @@ # 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +# 设置时区为北京时间 +RUN apt-get update && apt-get install -y tzdata && \ + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone && \ + dpkg-reconfigure -f noninteractive tzdata && \ + apt-get clean && rm -rf /var/lib/apt/lists/* USER $APP_UID WORKDIR /app EXPOSE 80 diff --git a/src/CloudGaming/Api/CloudGaming.PayApi/Dockerfile b/src/CloudGaming/Api/CloudGaming.PayApi/Dockerfile index 4c4faa6..6e3615f 100644 --- a/src/CloudGaming/Api/CloudGaming.PayApi/Dockerfile +++ b/src/CloudGaming/Api/CloudGaming.PayApi/Dockerfile @@ -2,6 +2,13 @@ # 此阶段用于在快速模式(默认为调试配置)下从 VS 运行时 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +# 设置时区为北京时间 +RUN apt-get update && apt-get install -y tzdata && \ + ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ + echo "Asia/Shanghai" > /etc/timezone && \ + dpkg-reconfigure -f noninteractive tzdata && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + USER $APP_UID WORKDIR /app EXPOSE 80 diff --git a/src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs index 50119e3..a5e72e7 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Game/GameBLL.cs @@ -338,7 +338,7 @@ namespace CloudGaming.Code.Game { //计算用户排名,看看是否进入前50名 var userIndex = list.FindIndex(it => it.UserId == _UserId); - userGamePlayTimeDto.PlayTime = $"{(userGame.PlayTime / 60).ToString("0.##")}小时"; + userGamePlayTimeDto.PlayTime = $"{(userGame.PlayTime / 60.0).ToString("0.##")}小时"; if (userIndex > -1) { userGamePlayTimeDto.Ranking = userIndex + 1; diff --git a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameBLL.cs b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameBLL.cs index 92c4c04..13d2f53 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameBLL.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameBLL.cs @@ -253,10 +253,15 @@ public class PlayGameBLL : CloudGamingBase var (issuccess, currlogId, diamId) = await this.UserPlayGameDiamondConsumeMoney(-gameDiamondNumHour, gameInfoCache.GameName, gameInfoCache.CurrencyLogId, gameInfoCache.DiamondListId, $"{diamondNumHour}/分钟"); if (!issuccess) { + gameInfoCache.GameUserOperation.Add(new PlayGameUserOperation() + { + ActionId = (int)PlayGameStatus.用户扣款错误, + Content = $"扣除费用{gameDiamondNumHour},用户剩余金额{userInfo.Diamond};" + }); + await gameInfoCache.SaveChangesAsync(this); throw MessageBox.ErrorShow("扣款出现错误"); } - //userInfo - //var userPlayGameTime = await Dao.DaoPhone.Context.T_User_PlayGameTime.Where(it => it.UserId == userId).SumAsync(it => (int?)it.PlayTime); + gameInfoCache.SpendingDiamonds += gameDiamondNumHour; userInfo.UserPlayGameTime += minutes; await this.SaveUserInfoCacheChangesAsync(); gameInfoCache.CurrencyLogId = currlogId; @@ -280,7 +285,8 @@ public class PlayGameBLL : CloudGamingBase //重置一下用户钻石 playGameHeartbeatResponse.Diamond = userInfo.Diamond; - gameInfoCache.PlayGameHeartbeat(); + + gameInfoCache.PlayGameHeartbeat($";累计扣除钻石*{gameInfoCache.SpendingDiamonds};当前游戏每分钟消耗钻石*{playGameHeartbeatResponse.GameConsumeDiamond}"); await gameInfoCache.SaveChangesAsync(this); } else @@ -296,7 +302,7 @@ public class PlayGameBLL : CloudGamingBase /// - /// 游戏结束 + /// 用户主动结束游戏 /// /// /// @@ -319,9 +325,9 @@ public class PlayGameBLL : CloudGamingBase PlayGameUserInfo gameInfoCache = await PlayGameExtend.GetPlayGameUserInfoOrNull(this, userInfo, gameInfo); if (gameInfoCache == null) { - throw MessageBox.ErrorShow("未找到游戏信息"); + return new BaseResponse(ResponseCode.Success, "游戏已结束", true); } - if (gameInfoCache.GameStatus != PlayGameStatus.游戏结束) + if (gameInfoCache.GameStatus != PlayGameStatus.用户主动结束游戏) { PlayGameCommonSetting playGameQueue = new PlayGameCommonSetting() { @@ -389,7 +395,7 @@ public class PlayGameBLL : CloudGamingBase } else { - gameInfoCache.PlayGameError(paidui); + gameInfoCache.PlayGameQueueError(paidui); back = new BaseResponse(ResponseCode.Error, "排队出现错误", paidui.Data); } @@ -483,11 +489,13 @@ public class PlayGameBLL : CloudGamingBase if (response.IsSuccess) { gameInfoCache.DisplayGrade = displayGrade; - + gameInfoCache.UserSwitchDisplayGrade(displayGrade, response); await gameInfoCache.SaveChangesAsync(this); } else { + gameInfoCache.UserSwitchDisplayGradeError(displayGrade, response); + await gameInfoCache.SaveChangesAsync(this); throw MessageBox.ErrorShow("切换失败"); } return new BaseResponse(ResponseCode.Success, "", response.Data); @@ -499,7 +507,7 @@ public class PlayGameBLL : CloudGamingBase /// /// /// - public async Task GetMyScList(string sn) + public async Task GetMyScList(string sn) { var requestParmat = new JYRequestParameter(sn, _UserId); var response = await JYApi.MyScList(requestParmat); @@ -510,14 +518,15 @@ public class PlayGameBLL : CloudGamingBase var sess = response.Data?.List[0]; if (sess != null) { - var gameInfo = await PlayGameExtend.PlayGameRecon(this, _UserId, sess.ScId); + //sess.RestTime + var gameInfo = await PlayGameExtend.PlayGameRecon(this, _UserId, sess.ScId, response); if (gameInfo != null) { + await gameInfo.SaveChangesAsync(this); var game = Cache.GameEntityCache[gameInfo.GameId]; if (game != null) { - await gameInfo.SaveChangesAsync(this); - return new GameListDto(game, DtoModel.Epg.EpgEnum.ImageResStyle.小LOGO); + return new PlayGameInfoDto(game, DtoModel.Epg.EpgEnum.ImageResStyle.小LOGO, sess.RestTime); } } diff --git a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameExtend.cs b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameExtend.cs index 6172493..0fdec0f 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameExtend.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameExtend.cs @@ -32,13 +32,14 @@ namespace CloudGaming.Code.Game return builder; } + + public static string GetPlayGameKeyPrefix { get; set; } = $"PlayGame"; /// /// /// /// /// /// - public static string GetPlayGameKeyPrefix { get; set; } = $"PlayGame"; public static string GetPlayGameKey(string gameId, int userId) => $"PlayGame:{gameId}:{userId}"; /// /// 获取用户游戏缓存 @@ -110,7 +111,7 @@ namespace CloudGaming.Code.Game playGameUserInfo.DisplayGrade = playGameSettings.DisplayGrade; if (playGameUserInfo.GameStatus == PlayGameStatus.初始化) { - playGameUserInfo.GameStatus = PlayGameStatus.初始化成功; + playGameUserInfo.GameStatus = PlayGameStatus.启动游戏; } return true; } @@ -126,13 +127,14 @@ namespace CloudGaming.Code.Game public static bool ExitPlayGame(this PlayGameUserInfo playGameUserInfo, IJYApiRespnse jYApiRespnse) { - if (playGameUserInfo.GameStatus != PlayGameStatus.游戏结束) + if (playGameUserInfo.GameStatus != PlayGameStatus.用户主动结束游戏) { - playGameUserInfo.GameStatus = PlayGameStatus.游戏结束; + playGameUserInfo.GameStatus = PlayGameStatus.用户主动结束游戏; playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { OperationDateTime = DateTime.Now, Content = "游戏结束", + ActionId = (int)PlayGameStatus.用户主动结束游戏 }); playGameUserInfo.LastDateTime = DateTime.Now; } @@ -156,8 +158,9 @@ namespace CloudGaming.Code.Game playGameUserInfo.DisplayGrade = display_grade; playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { - Content = "开始游戏", + Content = $"游戏启动成功,开始游戏(scId:{scId});", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.开始游戏 }); playGameUserInfo.PlayGameStartAt = DateTime.Now; playGameUserInfo.PlayGameHeartbeatAt = DateTime.Now; @@ -176,21 +179,12 @@ namespace CloudGaming.Code.Game playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { OperationDateTime = DateTime.Now, - Content = "启动游戏失败", + Content = "启动游戏失败;", + ActionId = (int)PlayGameStatus.游戏启动失败 }); return true; } - /// - /// 游戏启动失败 - /// - /// - /// - public static bool PlayGameClose(this PlayGameUserInfo playGameUserInfo) - { - playGameUserInfo.GameStatus = PlayGameStatus.游戏结束; - return true; - } /// /// 游戏心跳 @@ -208,6 +202,7 @@ namespace CloudGaming.Code.Game { OperationDateTime = DateTime.Now, Content = "用户游戏掉线重连成功", + ActionId = (int)PlayGameStatus.游戏掉线结束 }); } playGameUserInfo.GameStatus = PlayGameStatus.游戏中; @@ -218,6 +213,7 @@ namespace CloudGaming.Code.Game { OperationDateTime = DateTime.Now, Content = $"用户持续游戏中,累计游玩时间{(playGameUserInfo.PlayGameTotalSeconds / 60).ToString("0.##")}分钟{desc};", + ActionId = (int)PlayGameStatus.游戏中 }); return true; } @@ -236,12 +232,13 @@ namespace CloudGaming.Code.Game PlayGameUserOperation? playGameUserOperation = null; if (playGameUserInfo.GameStatus == PlayGameStatus.排队中) { - if (playGameUserInfo.LastWriteQueueAt == null || (playGameUserInfo.LastWriteQueueAt != null && DateTime.Now.Subtract(playGameUserInfo.LastWriteQueueAt ?? DateTime.Now).TotalMinutes > 1)) + if (playGameUserInfo.LastWriteQueueAt == null || (playGameUserInfo.LastWriteQueueAt != null && DateTime.Now.Subtract(playGameUserInfo.LastWriteQueueAt ?? DateTime.Now).TotalSeconds > 30)) { playGameUserOperation = new PlayGameUserOperation(jYApiRespnse) { - Content = $"排队中,排队Id{play_queue_id},前面还有{queue_pos}人", + Content = $"继续排队中,排队Id:{play_queue_id},前面还有{queue_pos}人;", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.排队中 }; playGameUserInfo.LastWriteQueueAt = DateTime.Now; } @@ -249,24 +246,25 @@ namespace CloudGaming.Code.Game { playGameUserOperation = new PlayGameUserOperation() { - Content = $"排队中,排队Id{play_queue_id},前面还有{queue_pos}人", + Content = $"继续排队中,排队Id:{play_queue_id},前面还有{queue_pos}人;", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.排队中 }; } playGameUserInfo.GameUserOperation.Add(playGameUserOperation); - } else { playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { - Content = $"开始排队,排队Id:{play_queue_id},前面还有{queue_pos}人", + Content = $"开始排队,排队Id:{play_queue_id},前面还有{queue_pos}人;", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.排队中 }); - } playGameUserInfo.GameStatus = PlayGameStatus.排队中; + playGameUserInfo.LastPlayQueueAt = DateTime.Now; playGameUserInfo.PlayQueueId = play_queue_id; if (playGameUserInfo.PlayQueueStartAt == null) { @@ -290,7 +288,7 @@ namespace CloudGaming.Code.Game playGameUserInfo.GameStatus = PlayGameStatus.排队成功; playGameUserInfo.PlayQueueSuccessAt = DateTime.Now; var totalSeconds = 0; - if (playGameUserInfo.PlayQueueStart != null) + if (playGameUserInfo.PlayQueueStartAt != null) { totalSeconds = (int)DateTime.Now.Subtract(playGameUserInfo.PlayQueueStartAt ?? DateTime.Now).TotalSeconds; } @@ -298,7 +296,9 @@ namespace CloudGaming.Code.Game { Content = $"排队成功,本次排队耗时{totalSeconds}秒", OperationDateTime = DateTime.Now, + ActionId = (int)playGameUserInfo.GameStatus }); + playGameUserInfo.LastPlayQueueAt = DateTime.Now; } return true; } @@ -314,6 +314,62 @@ namespace CloudGaming.Code.Game { Content = $"用户取消排队", OperationDateTime = DateTime.Now, + ActionId = (int)playGameUserInfo.GameStatus + }); + return true; + } + + /// + /// 用户切换视频等级 + /// + /// + /// + /// + /// + public static bool UserSwitchDisplayGrade(this PlayGameUserInfo playGameUserInfo, int displayGrade, IJYApiRespnse jYApiRespnse) + { + + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) + { + Content = $"用户切换视频等级:{displayGrade};", + OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.切换视频等级 + }); + return true; + } + + /// + /// 用户切换视频等级 + /// + /// + /// + /// + /// + public static bool UserSwitchDisplayGradeError(this PlayGameUserInfo playGameUserInfo, int displayGrade, IJYApiRespnse jYApiRespnse) + { + + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) + { + Content = $"用户切换视频等级失败:{displayGrade};", + OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.切换视频等级 + }); + return true; + } + + /// + /// 排队异常 + /// + /// + /// + public static bool PlayGameQueueError(this PlayGameUserInfo playGameUserInfo, IJYApiRespnse jYApiRespnse) + { + playGameUserInfo.GameStatus = PlayGameStatus.排队异常; + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) + { + OperationDateTime = DateTime.Now, + Content = "排队异常!", + ActionId = (int)PlayGameStatus.排队异常 }); return true; } @@ -337,11 +393,50 @@ namespace CloudGaming.Code.Game { Content = $"用户游戏掉线,上一次心跳时间{playGameUserInfo.PlayGameHeartbeatAt?.ToString("yyyy-MM-dd HH:mm:ss")};", OperationDateTime = DateTime.Now, + ActionId = (int)playGameUserInfo.GameStatus }); } return true; } + /// + /// 游戏掉线 + /// + /// + /// + public static bool PlayGameUserNotQueue(this PlayGameUserInfo playGameUserInfo) + { + + if (playGameUserInfo.GameStatus != PlayGameStatus.排队掉线) + { + playGameUserInfo.GameStatus = PlayGameStatus.排队掉线; + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation() + { + Content = $"用户排队掉线,上一次排队时间{playGameUserInfo.LastPlayQueueAt?.ToString("yyyy-MM-dd HH:mm:ss")};", + OperationDateTime = DateTime.Now, + ActionId = (int)playGameUserInfo.GameStatus + }); + } + return true; + } + + /// + /// 游戏掉线 + /// + /// + /// + public static bool PlayGameUserNotQueueEnd(this PlayGameUserInfo playGameUserInfo, IJYApiRespnse jYApiRespnse) + { + playGameUserInfo.GameStatus = PlayGameStatus.排队掉线结束游戏; + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) + { + Content = $"用户排队掉线,上一次排队时间{playGameUserInfo.LastPlayQueueAt?.ToString("yyyy-MM-dd HH:mm:ss")};准备结束游戏;", + OperationDateTime = DateTime.Now, + ActionId = (int)playGameUserInfo.GameStatus + }); + return true; + } + /// /// 游戏掉线 /// @@ -352,24 +447,26 @@ namespace CloudGaming.Code.Game playGameUserInfo.GameStatus = PlayGameStatus.游戏掉线结束; playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { - Content = $"用户游戏掉线,结束游戏", + Content = $"用户游戏掉线,准备结束游戏", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.游戏掉线 }); return true; } /// - /// 游戏掉线 + /// 用户钻石不足,准备退出游戏 /// /// /// public static bool PlayGameUserNotDiamond(this PlayGameUserInfo playGameUserInfo, IJYApiRespnse jYApiRespnse) { - playGameUserInfo.GameStatus = PlayGameStatus.用户钻石不足; + playGameUserInfo.GameStatus = PlayGameStatus.用户游玩时钻石不足; playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { OperationDateTime = DateTime.Now, - Content = $"用户余额不足,准备退出游戏" + Content = $"用户余额不足,准备退出游戏", + ActionId = (int)PlayGameStatus.用户游玩时钻石不足 }); return true; } @@ -403,7 +500,7 @@ namespace CloudGaming.Code.Game /// /// /// - public static async Task PlayGameRecon(CloudGamingBase cloudGamingBase, int userId, int scId) + public static async Task PlayGameRecon(CloudGamingBase cloudGamingBase, int userId, int scId, IJYApiRespnse jYApiRespnse) { var list = await GetPlayGameUserInfoList(cloudGamingBase.RedisCache, cloudGamingBase.RedisServerCache, $"{GetPlayGameKeyPrefix}:*:{userId}"); if (list != null && list.Count > 0) @@ -415,10 +512,11 @@ namespace CloudGaming.Code.Game } if (playGameUserInfo != null) { - playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation() + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { Content = $"用户获取可连接的游戏列表scId:${scId};", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.排队掉线 }); } return playGameUserInfo; @@ -442,12 +540,13 @@ namespace CloudGaming.Code.Game if (playGameUserInfo.GameStatus != PlayGameStatus.游戏掉线) { playGameUserInfo.GameStatus = PlayGameStatus.游戏中; - + } playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation(jYApiRespnse) { Content = $"用户重连游戏成功,上一次心跳时间{playGameUserInfo.PlayGameHeartbeatAt?.ToString("yyyy-MM-dd HH:mm:ss")};", OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.游戏中 }); } return playGameUserInfo; @@ -475,64 +574,85 @@ namespace CloudGaming.Code.Game { playGameUserInfo.LastDateTime = DateTime.Now; var redisGameKey = GetPlayGameKey(playGameUserInfo.GameId, playGameUserInfo.UserId); - if (playGameUserInfo.GameStatus == PlayGameStatus.取消排队 || playGameUserInfo.GameStatus == PlayGameStatus.游戏启动失败 || playGameUserInfo.GameStatus == PlayGameStatus.游戏结束 || playGameUserInfo.GameStatus == PlayGameStatus.用户钻石不足 || playGameUserInfo.GameStatus == PlayGameStatus.游戏掉线结束) - { - T_User_GameList userGameListLog = null; - if (playGameUserInfo.DiamondListId > 0) - { - //设置游玩记录 - userGameListLog = await dao.DaoPhone.Context.T_User_GameList.FirstOrDefaultAsync(it => it.Id == playGameUserInfo.DiamondListId); - } - if (userGameListLog == null) - { - userGameListLog = new T_User_GameList - { - Channel = playGameUserInfo.Channel, - CreateTime = playGameUserInfo.PlayGameStartAt ?? playGameUserInfo.CreateDateTime, - GameId = playGameUserInfo.GameId, - Status = (int)PlayGameStatus.开始游戏, - UpdateTime = DateTime.Now, - UserId = playGameUserInfo.UserId, - SessionId = playGameUserInfo?.SessionId - }; - await dao.DaoPhone.Context.T_User_GameList.AddAsync(userGameListLog); - } - userGameListLog.Status = (int)PlayGameStatus.游戏结束; + if (playGameUserInfo.GameStatus == PlayGameStatus.取消排队 || + playGameUserInfo.GameStatus == PlayGameStatus.游戏启动失败 || + playGameUserInfo.GameStatus == PlayGameStatus.用户主动结束游戏 + || playGameUserInfo.GameStatus == PlayGameStatus.用户钻石不足 + || playGameUserInfo.GameStatus == PlayGameStatus.用户游玩时钻石不足 + || playGameUserInfo.GameStatus == PlayGameStatus.游戏掉线结束 || + playGameUserInfo.GameStatus == PlayGameStatus.排队异常 || + playGameUserInfo.GameStatus == PlayGameStatus.排队掉线结束游戏 + ) - var t = DateTime.Now.Subtract(playGameUserInfo.PlayGameStartAt ?? playGameUserInfo.CreateDateTime); - var playTime = (int)t.TotalSeconds / 60; - userGameListLog.PlaySeconds = (int)t.TotalSeconds; - userGameListLog.PlayTime = playTime; - userGameListLog.UpdateTime = DateTime.Now; - await dao.DaoPhone.Context.SaveChangesAsync(); - //设置游玩历史 - var userId = playGameUserInfo.UserId; - var gameId = playGameUserInfo.GameId; - if (playGameUserInfo.GameStatus != PlayGameStatus.取消排队 && playGameUserInfo.GameStatus != PlayGameStatus.游戏启动失败) + { + //只有不等于下面这几种状态才记录游玩记录 + if (playGameUserInfo.GameStatus != PlayGameStatus.排队掉线 && playGameUserInfo.GameStatus != PlayGameStatus.取消排队 && playGameUserInfo.GameStatus != PlayGameStatus.排队掉线结束游戏 && playGameUserInfo.GameStatus != PlayGameStatus.排队掉线 && playGameUserInfo.GameStatus != PlayGameStatus.游戏启动失败 && playGameUserInfo.GameStatus != PlayGameStatus.用户钻石不足) { - //设置用户游玩历史 - var playGameTime = await dao.DaoPhone.Context.T_User_PlayGameTime.Where(it => it.UserId == userId && it.GameId == gameId).FirstOrDefaultAsync(); - if (playGameTime == null) + T_User_GameList userGameListLog = null; + if (playGameUserInfo.DiamondListId > 0) { - playGameTime = new T_User_PlayGameTime() - { - Createtime = DateTime.Now, - NightCardPlayTime = 0, - DiamondPlayTime = 0, - FreePlayTime = 0, - GameId = gameId, - PlayTime = 0, - UpdateTime = DateTime.Now, - UserId = userId, - - }; - await dao.DaoPhone.Context.T_User_PlayGameTime.AddAsync(playGameTime); + //设置游玩记录 + userGameListLog = await dao.DaoPhone.Context.T_User_GameList.FirstOrDefaultAsync(it => it.Id == playGameUserInfo.DiamondListId); } - playGameTime.PlayTime += playTime; - playGameTime.UpdateTime = DateTime.Now; - playGameTime.DiamondPlayTime += playTime; + if (userGameListLog == null) + { + userGameListLog = new T_User_GameList + { + Channel = playGameUserInfo.Channel, + CreateTime = playGameUserInfo.PlayGameStartAt ?? playGameUserInfo.CreateDateTime, + GameId = playGameUserInfo.GameId, + Status = (int)PlayGameStatus.开始游戏, + UpdateTime = DateTime.Now, + UserId = playGameUserInfo.UserId, + SessionId = playGameUserInfo?.SessionId + }; + await dao.DaoPhone.Context.T_User_GameList.AddAsync(userGameListLog); + } + userGameListLog.Status = (int)PlayGameStatus.游戏结束; + + var t = DateTime.Now.Subtract(playGameUserInfo.PlayGameStartAt ?? playGameUserInfo.CreateDateTime); + var playTime = (int)t.TotalSeconds / 60; + userGameListLog.PlaySeconds = (int)t.TotalSeconds; + userGameListLog.PlayTime = playTime; + userGameListLog.UpdateTime = DateTime.Now; await dao.DaoPhone.Context.SaveChangesAsync(); + //设置游玩历史 + var userId = playGameUserInfo.UserId; + var gameId = playGameUserInfo.GameId; + if (playGameUserInfo.GameStatus != PlayGameStatus.取消排队 && playGameUserInfo.GameStatus != PlayGameStatus.游戏启动失败 && playGameUserInfo.GameStatus != PlayGameStatus.排队掉线) + { + //设置用户游玩历史 + var playGameTime = await dao.DaoPhone.Context.T_User_PlayGameTime.Where(it => it.UserId == userId && it.GameId == gameId).FirstOrDefaultAsync(); + if (playGameTime == null) + { + playGameTime = new T_User_PlayGameTime() + { + Createtime = DateTime.Now, + NightCardPlayTime = 0, + DiamondPlayTime = 0, + FreePlayTime = 0, + GameId = gameId, + PlayTime = 0, + UpdateTime = DateTime.Now, + UserId = userId, + + }; + await dao.DaoPhone.Context.T_User_PlayGameTime.AddAsync(playGameTime); + } + playGameTime.PlayTime += playTime; + playGameTime.UpdateTime = DateTime.Now; + playGameTime.DiamondPlayTime += playTime; + await dao.DaoPhone.Context.SaveChangesAsync(); + } + } + + playGameUserInfo.GameUserOperation.Add(new PlayGameUserOperation() + { + Content = "游戏结束", + OperationDateTime = DateTime.Now, + ActionId = (int)PlayGameStatus.游戏结束 + }); var playGameLog = playGameUserInfo.ToGamePlayGameLog(); if (playGameLog != null) { diff --git a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs index 1740107..51fb518 100644 --- a/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs +++ b/src/CloudGaming/Code/CloudGaming.Code/Game/PlayGameProcessor.cs @@ -61,7 +61,10 @@ public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcess { var userNotActionDisconnect = DateTime.Now.AddSeconds(-appConfig.GameConfig.UserNotActionDisconnect); var userNotActionEndGame = DateTime.Now.AddSeconds(-appConfig.GameConfig.UserNotActionEndGame); - + //30 秒检测不到排队信息,则判断排队掉线 + var userNotQueue = DateTime.Now.AddSeconds(-30); + //60 秒检查不到排队,则判断排队结束 + var userNotQueueEnd = DateTime.Now.AddSeconds(-60); using var scope = serviceProvider.CreateScope(); var app = scope.ServiceProvider.GetRequiredService(); appConfig.ToAppConfig(app); @@ -101,6 +104,27 @@ public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcess user.PlayGameUserNotAction(); await user.SaveChangesAsync(dao, redis).ConfigureAwait(false); } + + //用户排队掉线人 + var userPlayGameNotQueueEndGame = gameInfoList + .Where(it => it.GameStatus == PlayGameStatus.游戏掉线 && it.PlayGameHeartbeatAt < userNotQueueEnd) + .ToList(); + if (userPlayGameNotQueueEndGame.Count > 0) + foreach (var user in userPlayGameNotQueueEndGame) + { + await EndGameQueueAsync(user, appConfig, dao, redis).ConfigureAwait(false); + gameInfoList.Remove(user); + } + + var userPlayGameNotQueue = gameInfoList + .Where(it => it.GameStatus == PlayGameStatus.排队中 && it.LastDateTime < userNotQueue) + .ToList(); + if (userPlayGameNotQueue.Count > 0) + foreach (var user in userPlayGameNotQueue) + { + user.PlayGameUserNotQueue(); + await user.SaveChangesAsync(dao, redis).ConfigureAwait(false); + } } /// @@ -123,4 +147,24 @@ public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcess user.PlayGameDiaoXian(jyResponse); await user.SaveChangesAsync(dao, redis).ConfigureAwait(false); } + + /// + /// 排队掉线结束游戏逻辑 + /// + private async Task EndGameQueueAsync(PlayGameUserInfo user, AppConfig appConfig, DAO dao, IDatabase redis) + { + HttpClient httpClient = new HttpClient(new JYApiAppConfigHandler(appConfig, user.Ip)); + httpClient.BaseAddress = new Uri(appConfig.GameConfig.BsUrl); + var jyApi = RestService.For(httpClient); + + var playGameCommonSetting = new PlayGameQueue(user.Sn, user.UserId) + { + PlayQueueId = user.ScId, + Sn = user.Sn + }; + + var jyResponse = await jyApi.CancelQueue(playGameCommonSetting).ConfigureAwait(false); + user.PlayGameUserNotQueueEnd(jyResponse); + await user.SaveChangesAsync(dao, redis).ConfigureAwait(false); + } } diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameInfoDto.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameInfoDto.cs new file mode 100644 index 0000000..40ca86e --- /dev/null +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameInfoDto.cs @@ -0,0 +1,27 @@ +using CloudGaming.DtoModel.Epg; +using CloudGaming.DtoModel.Game; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudGaming.DtoModel.PlayGame +{ + /// + /// + /// + public class PlayGameInfoDto : GameListDto + { + public PlayGameInfoDto(GameInfo gameInfo, EpgEnum.ImageResStyle imageResStyle, int restTime) : base(gameInfo, imageResStyle) + { + this.RestTime = restTime; + } + + /// + /// 剩余时间,秒 + /// + public int RestTime { get; set; } + } +} diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameStatus.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameStatus.cs index 5b84f6e..3555b4d 100644 --- a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameStatus.cs +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameStatus.cs @@ -4,66 +4,141 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace CloudGaming.DtoModel.PlayGame +namespace CloudGaming.DtoModel.PlayGame; + +/// +/// 游戏状态枚举 +/// 初始化相关状态放在前面,按顺序排列(如初始化、初始化成功等)。 +/// 排队相关状态接着排列,确保排队的流程是连贯的(如排队中、排队成功等)。 +/// 游戏进行中状态按开始、进行、结束的顺序排列。 +/// 错误或异常状态(如游戏启动失败、钻石不足等)在适当位置按流程排序。 +/// +public enum PlayGameStatus { + /// + /// 游戏初始化状态 + /// + 初始化 = 0, + + /// + /// 游戏初始化成功 + /// + 启动游戏 = 1, + + // ---------------------------------------- + // 初始化和排队相关状态:0 到 6,占用了较低的范围,留有空间(例如 7-9)供未来扩展。 + // ---------------------------------------- + + /// + /// 排队中 + /// + 排队中 = 2, + + /// + /// 排队成功 + /// + 排队成功 = 3, + + /// + /// 取消排队 + /// + 取消排队 = 4, + + /// + /// 排队过程中掉线 + /// + 排队掉线 = 5, + + /// + /// 排队掉线已结束 + /// + 排队掉线结束游戏 = 6, + + // ---------------------------------------- + // 异常状态占用了10到19 + // ---------------------------------------- + + /// + /// 游戏启动失败 + /// + 游戏启动失败 = 10, + + /// + /// 用户钻石不足 + /// + 用户钻石不足 = 11, + /// + /// 用户游玩时钻石不足 + /// + + 用户游玩时钻石不足 = 12, + /// /// /// - public enum PlayGameStatus - { - /// - /// 正常 - /// - 初始化 = 0, - /// - /// 初始化成功 - /// - 初始化成功 = 1, - /// - /// 开始游戏 - /// - 开始游戏 = 2, - /// - /// 游戏中 - /// - 游戏中 = 3, - /// - /// 游戏结束 - /// - 游戏结束 = 4, - /// - /// - /// - 排队中 = 5, - /// - /// - /// - 排队成功 = 6, - /// - /// - /// - 取消排队 = 7, + 用户游玩时钻石不足退出游戏 = 13, - /// - /// 游戏掉线 - /// - 游戏掉线 = 8, + /// + /// 排队异常 + /// + 排队异常 = 14, + /// + /// + /// + 用户扣款错误 = 15, - /// - /// - /// - 游戏掉线结束 = 10, + // ---------------------------------------- + // 游戏进行中的状态 (预留空间: 20-39) + // ---------------------------------------- - /// - /// 游戏启动失败 - /// - 游戏启动失败 = 9, + /// + /// 游戏开始 + /// + 开始游戏 = 20, - /// - /// - /// - 用户钻石不足 = 11, + /// + /// 游戏正在进行 + /// + 游戏中 = 21, + + /// + /// 用户主动结束游戏 + /// + 用户主动结束游戏 = 22, + + /// + /// 游戏掉线 + /// + 游戏掉线 = 23, + + /// + /// 游戏掉线已结束 + /// + 游戏掉线结束 = 24, + + // ---------------------------------------- + // 游戏结束状态 (预留空间: 40-49) + // ---------------------------------------- + + /// + /// 游戏结束 + /// + 游戏结束 = 40, + + // ---------------------------------------- + // 未来扩展的状态 (预留空间: 50-99) + // ---------------------------------------- - } + /// + /// 游戏暂停 (示例) + /// + 游戏暂停 = 50, + /// + /// 切换视频等级 + /// + 切换视频等级 = 51 + } + + diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserInfo.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserInfo.cs index b3f790b..7aa01d0 100644 --- a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserInfo.cs +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserInfo.cs @@ -115,6 +115,12 @@ public class PlayGameUserInfo /// public DateTime? PlayQueueStartAt { get; set; } + + /// + /// 最后一次排队时间 + /// + public DateTime? LastPlayQueueAt { get; set; } + /// /// 最后写入排队时间 /// @@ -157,6 +163,10 @@ public class PlayGameUserInfo /// public T_Game_PlayGameLog ToGamePlayGameLog() { + JsonSerializerSettings settings = new JsonSerializerSettings + { + DateFormatString = "yyyy-MM-dd HH:mm:ss" + }; var log = new T_Game_PlayGameLog { GameId = GameId, @@ -184,7 +194,7 @@ public class PlayGameUserInfo CurrencyLogId = CurrencyLogId, DiamondListId = DiamondListId, GameStatus = (int)GameStatus, - GameUserOperationJson = GameUserOperation == null ? "" : JsonConvert.SerializeObject(GameUserOperation), + GameUserOperationJson = GameUserOperation == null ? "" : JsonConvert.SerializeObject(GameUserOperation, settings), }; return log; } diff --git a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserOperation.cs b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserOperation.cs index 29ee602..98dde99 100644 --- a/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserOperation.cs +++ b/src/CloudGaming/Model/CloudGaming.DtoModel/PlayGame/PlayGameUserOperation.cs @@ -23,7 +23,10 @@ namespace CloudGaming.DtoModel.PlayGame TotalMilliseconds = jYApiRespnse?.TotalMilliseconds; } - + /// + /// 动作id + /// + public int ActionId { get; set; } /// /// 操作时间