修改玩游戏逻辑
This commit is contained in:
parent
84b0beda2b
commit
5381ffe387
|
|
@ -135,7 +135,7 @@ public class PlayGameController : CloudGamingControllerBase
|
|||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<GameListDto> GetMyScListAsync([FromBody] RequestBaseModel requestBaseModel)
|
||||
public async Task<PlayGameInfoDto> GetMyScListAsync([FromBody] RequestBaseModel requestBaseModel)
|
||||
{
|
||||
PlayGameBLL playGameBLL = new PlayGameBLL(ServiceProvider, JYApi);
|
||||
return await playGameBLL.GetMyScList(requestBaseModel.Sn);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// 游戏结束
|
||||
/// 用户主动结束游戏
|
||||
/// </summary>
|
||||
/// <param name="gameId"></param>
|
||||
/// <returns></returns>
|
||||
|
|
@ -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<bool>(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<PlayQueueInfoModel>(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<object>(ResponseCode.Success, "", response.Data);
|
||||
|
|
@ -499,7 +507,7 @@ public class PlayGameBLL : CloudGamingBase
|
|||
/// </summary>
|
||||
/// <param name="sn"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<GameListDto> GetMyScList(string sn)
|
||||
public async Task<PlayGameInfoDto> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,13 +32,14 @@ namespace CloudGaming.Code.Game
|
|||
return builder;
|
||||
|
||||
}
|
||||
|
||||
public static string GetPlayGameKeyPrefix { get; set; } = $"PlayGame";
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="gameId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetPlayGameKeyPrefix { get; set; } = $"PlayGame";
|
||||
public static string GetPlayGameKey(string gameId, int userId) => $"PlayGame:{gameId}:{userId}";
|
||||
/// <summary>
|
||||
/// 获取用户游戏缓存
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏启动失败
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool PlayGameClose(this PlayGameUserInfo playGameUserInfo)
|
||||
{
|
||||
playGameUserInfo.GameStatus = PlayGameStatus.游戏结束;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏心跳
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户切换视频等级
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <param name="displayGrade"></param>
|
||||
/// <param name="jYApiRespnse"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户切换视频等级
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <param name="displayGrade"></param>
|
||||
/// <param name="jYApiRespnse"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 排队异常
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// </summary>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// 用户钻石不足,准备退出游戏
|
||||
/// </summary>
|
||||
/// <param name="playGameUserInfo"></param>
|
||||
/// <returns></returns>
|
||||
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
|
|||
/// <param name="userId"></param>
|
||||
/// <param name="scId"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<PlayGameUserInfo> PlayGameRecon(CloudGamingBase cloudGamingBase, int userId, int scId)
|
||||
public static async Task<PlayGameUserInfo> 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -123,4 +147,24 @@ public class PlayGameProcessor(IServiceProvider serviceProvider) : ThreadProcess
|
|||
user.PlayGameDiaoXian(jyResponse);
|
||||
await user.SaveChangesAsync(dao, redis).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 排队掉线结束游戏逻辑
|
||||
/// </summary>
|
||||
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<IJYApi>(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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class PlayGameInfoDto : GameListDto
|
||||
{
|
||||
public PlayGameInfoDto(GameInfo gameInfo, EpgEnum.ImageResStyle imageResStyle, int restTime) : base(gameInfo, imageResStyle)
|
||||
{
|
||||
this.RestTime = restTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 剩余时间,秒
|
||||
/// </summary>
|
||||
public int RestTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -4,66 +4,141 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CloudGaming.DtoModel.PlayGame
|
||||
namespace CloudGaming.DtoModel.PlayGame;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏状态枚举
|
||||
/// 初始化相关状态放在前面,按顺序排列(如初始化、初始化成功等)。
|
||||
/// 排队相关状态接着排列,确保排队的流程是连贯的(如排队中、排队成功等)。
|
||||
/// 游戏进行中状态按开始、进行、结束的顺序排列。
|
||||
/// 错误或异常状态(如游戏启动失败、钻石不足等)在适当位置按流程排序。
|
||||
/// </summary>
|
||||
public enum PlayGameStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏初始化状态
|
||||
/// </summary>
|
||||
初始化 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 游戏初始化成功
|
||||
/// </summary>
|
||||
启动游戏 = 1,
|
||||
|
||||
// ----------------------------------------
|
||||
// 初始化和排队相关状态:0 到 6,占用了较低的范围,留有空间(例如 7-9)供未来扩展。
|
||||
// ----------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 排队中
|
||||
/// </summary>
|
||||
排队中 = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 排队成功
|
||||
/// </summary>
|
||||
排队成功 = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 取消排队
|
||||
/// </summary>
|
||||
取消排队 = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 排队过程中掉线
|
||||
/// </summary>
|
||||
排队掉线 = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 排队掉线已结束
|
||||
/// </summary>
|
||||
排队掉线结束游戏 = 6,
|
||||
|
||||
// ----------------------------------------
|
||||
// 异常状态占用了10到19
|
||||
// ----------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 游戏启动失败
|
||||
/// </summary>
|
||||
游戏启动失败 = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 用户钻石不足
|
||||
/// </summary>
|
||||
用户钻石不足 = 11,
|
||||
/// <summary>
|
||||
/// 用户游玩时钻石不足
|
||||
/// </summary>
|
||||
|
||||
用户游玩时钻石不足 = 12,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum PlayGameStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 正常
|
||||
/// </summary>
|
||||
初始化 = 0,
|
||||
/// <summary>
|
||||
/// 初始化成功
|
||||
/// </summary>
|
||||
初始化成功 = 1,
|
||||
/// <summary>
|
||||
/// 开始游戏
|
||||
/// </summary>
|
||||
开始游戏 = 2,
|
||||
/// <summary>
|
||||
/// 游戏中
|
||||
/// </summary>
|
||||
游戏中 = 3,
|
||||
/// <summary>
|
||||
/// 游戏结束
|
||||
/// </summary>
|
||||
游戏结束 = 4,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
排队中 = 5,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
排队成功 = 6,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
取消排队 = 7,
|
||||
用户游玩时钻石不足退出游戏 = 13,
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// </summary>
|
||||
游戏掉线 = 8,
|
||||
/// <summary>
|
||||
/// 排队异常
|
||||
/// </summary>
|
||||
排队异常 = 14,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
用户扣款错误 = 15,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
游戏掉线结束 = 10,
|
||||
// ----------------------------------------
|
||||
// 游戏进行中的状态 (预留空间: 20-39)
|
||||
// ----------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 游戏启动失败
|
||||
/// </summary>
|
||||
游戏启动失败 = 9,
|
||||
/// <summary>
|
||||
/// 游戏开始
|
||||
/// </summary>
|
||||
开始游戏 = 20,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
用户钻石不足 = 11,
|
||||
/// <summary>
|
||||
/// 游戏正在进行
|
||||
/// </summary>
|
||||
游戏中 = 21,
|
||||
|
||||
/// <summary>
|
||||
/// 用户主动结束游戏
|
||||
/// </summary>
|
||||
用户主动结束游戏 = 22,
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线
|
||||
/// </summary>
|
||||
游戏掉线 = 23,
|
||||
|
||||
/// <summary>
|
||||
/// 游戏掉线已结束
|
||||
/// </summary>
|
||||
游戏掉线结束 = 24,
|
||||
|
||||
// ----------------------------------------
|
||||
// 游戏结束状态 (预留空间: 40-49)
|
||||
// ----------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 游戏结束
|
||||
/// </summary>
|
||||
游戏结束 = 40,
|
||||
|
||||
// ----------------------------------------
|
||||
// 未来扩展的状态 (预留空间: 50-99)
|
||||
// ----------------------------------------
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 游戏暂停 (示例)
|
||||
/// </summary>
|
||||
游戏暂停 = 50,
|
||||
/// <summary>
|
||||
/// 切换视频等级
|
||||
/// </summary>
|
||||
切换视频等级 = 51
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,12 @@ public class PlayGameUserInfo
|
|||
/// </summary>
|
||||
public DateTime? PlayQueueStartAt { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 最后一次排队时间
|
||||
/// </summary>
|
||||
public DateTime? LastPlayQueueAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后写入排队时间
|
||||
/// </summary>
|
||||
|
|
@ -157,6 +163,10 @@ public class PlayGameUserInfo
|
|||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ namespace CloudGaming.DtoModel.PlayGame
|
|||
TotalMilliseconds = jYApiRespnse?.TotalMilliseconds;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 动作id
|
||||
/// </summary>
|
||||
public int ActionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作时间
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user