Sfoglia il codice sorgente

Merge branch 'package' of GameCenter/game-center into dev

zhimo 1 anno fa
parent
commit
bf5dc8f24b
15 ha cambiato i file con 272 aggiunte e 86 eliminazioni
  1. 18 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSServerRetentionVO.java
  2. 3 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameListServiceImpl.java
  3. 27 11
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameServerServiceImpl.java
  4. 35 27
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java
  5. 1 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java
  6. 8 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/UserController.java
  7. 5 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/KafkaEventTrackEnum.java
  8. 10 3
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/handler/GlobalExceptionHandler.java
  9. 57 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleSubmitParam.java
  10. 0 31
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleUpdateParam.java
  11. 8 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameUserRoleService.java
  12. 21 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserTokenService.java
  13. 9 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java
  14. 66 8
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java
  15. 4 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/UserTokenServiceImpl.java

+ 18 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSServerRetentionVO.java

@@ -49,4 +49,22 @@ public class GSServerRetentionVO {
      * 付费总人数
      */
     private String totalAmountNum;
+    /**
+     * 小r人数
+     */
+    private String smallRNum;
+    /**
+     * 中r人数
+     */
+    private String mediumRNum;
+    /**
+     * 大r人数
+     */
+    private String largeRNum;
+    /**
+     * 超大r人数
+     */
+    private String superRNum;
+
+
 }

+ 3 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameListServiceImpl.java

@@ -114,11 +114,12 @@ public class GameListServiceImpl implements IGameListService {
                 FROM (
                 	SELECT
                 		a.source_system ,
-                		IFNULL(a.super_game_id, a.id) as super_game_id ,
-                		IFNULL(b.name, a.game_name ) as super_game_name
+                		a.super_game_id as super_game_id ,
+                     	b.name as super_game_name
                 	FROM dm_game_order.t_game a
                 	LEFT JOIN dm_game_order.t_game_super b
                 	on a.source_system = b.source_system AND a.super_game_id = b.id
+                	where a.super_game_id is not null
                 ) a
                 """ + cri +
                 """

+ 27 - 11
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameServerServiceImpl.java

@@ -551,7 +551,7 @@ public class GameServerServiceImpl implements IGameServerService {
                         GSGameServerDayRVO gsGameServerDayRVO = rDataList.get(i);
                         rData = getRDataStr(gsGameServerDayRVO, vo);
                     } else {
-                        rData = "0/0/0/0";
+                        rData = "0/0/0/0/0/0/0/0";
                     }
                     value += "/" + rData;
 //                    field.set(vo, value + "/" + rData);
@@ -564,7 +564,12 @@ public class GameServerServiceImpl implements IGameServerService {
                             .smallR(split[4])
                             .mediumR(split[5])
                             .largeR(split[6])
-                            .superR(split[7]).build();
+                            .superR(split[7])
+                            .smallRNum(split[8])
+                            .mediumRNum(split[9])
+                            .largeRNum(split[10])
+                            .superRNum(split[11])
+                            .build();
                     fieldObjectList.get(i).set(vo, retentionVO);
                 } catch (IllegalAccessException e) {
                     throw new RuntimeException(e);
@@ -652,7 +657,12 @@ public class GameServerServiceImpl implements IGameServerService {
                         .smallR(split[4])
                         .mediumR(split[5])
                         .largeR(split[6])
-                        .superR(split[7]).build();
+                        .superR(split[7])
+                        .smallRNum(split[8])
+                        .mediumRNum(split[9])
+                        .largeRNum(split[10])
+                        .superRNum(split[11])
+                        .build();
                 fieldObjectList.get(i).set(vo, retentionVO);
 //                field.set(vo, value + "/" + rData);
             } catch (IllegalAccessException e) {
@@ -702,13 +712,19 @@ public class GameServerServiceImpl implements IGameServerService {
         if (rvo != null && vo.getTotalAmountNum() != null && vo.getTotalAmountNum() != 0) {
             //充值总人数
             BigDecimal totalAmountNum = new BigDecimal(vo.getTotalAmountNum());
-            BigDecimal smallR = new BigDecimal(rvo.getSmallR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal mediumR = new BigDecimal(rvo.getMediumR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal largeR = new BigDecimal(rvo.getLargeR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal superR = new BigDecimal(rvo.getSuperR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            return smallR + "/" + mediumR + "/" + largeR + "/" + superR;
+            //R人数
+            Long smallRCount = rvo.getSmallR();
+            Long mediumRCount = rvo.getMediumR();
+            Long largeRCont = rvo.getLargeR();
+            Long superRCount = rvo.getSuperR();
+            //R留存率
+            BigDecimal smallR = new BigDecimal(smallRCount).divide(totalAmountNum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal mediumR = new BigDecimal(mediumRCount).divide(totalAmountNum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal largeR = new BigDecimal(largeRCont).divide(totalAmountNum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal superR = new BigDecimal(superRCount).divide(totalAmountNum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            return smallR + "/" + mediumR + "/" + largeR + "/" + superR + "/" + smallRCount + "/" + mediumRCount + "/" + largeRCont + "/" + superRCount;
         } else {
-            return "0/0/0/0";
+            return "0/0/0/0/0/0/0/0";
         }
     }
 
@@ -825,7 +841,7 @@ public class GameServerServiceImpl implements IGameServerService {
         StringBuilder sql = new StringBuilder(StringUtils.EMPTY);
         for (int i = 1; i <= 90; i++) {
             sql.append("""
-                    concat(ifnull(round(c.da%d_active_num / e.new_da%d_total_num,4),0),'/',round(ifnull((d.new_da%d_num + d.old_da%d_num) / d.new_da%d_total_num,0),4),'/',IFNULL(c.da%d_reg_num,0),'/',IFNULL(c.da%d_num,0)) as da_str%d,
+                    concat(ifnull(round(c.da%d_active_num / e.new_da%d_total_num,4),0),'/',round(ifnull((d.new_da%d_num + d.old_da%d_num) / d.new_da%d_total_num,0),4),'/',IFNULL(c.da%d_role_num,0),'/',IFNULL(c.da%d_num,0)) as da_str%d,
                      """.formatted(i, i, i, i, i, i, i, i));
 
         }
@@ -839,7 +855,7 @@ public class GameServerServiceImpl implements IGameServerService {
         StringBuilder sql = new StringBuilder(StringUtils.EMPTY);
         for (int i = 1; i <= 90; i++) {
             sql.append("""
-                    concat(ifnull(round(SUM(c.da%d_active_num) / SUM(e.new_da%d_total_num) ,4),0),'/',ifnull(round(((SUM(d.new_da%d_num) + SUM(d.old_da%d_num)) / SUM(d.new_da%d_total_num)),4),0),'/',IFNULL(SUM(c.da%d_reg_num),0),'/',IFNULL(SUM(c.da%d_num),0)) as da_str%d,
+                    concat(ifnull(round(SUM(c.da%d_active_num) / SUM(e.new_da%d_total_num) ,4),0),'/',ifnull(round(((SUM(d.new_da%d_num) + SUM(d.old_da%d_num)) / SUM(d.new_da%d_total_num)),4),0),'/',IFNULL(SUM(c.da%d_role_num),0),'/',IFNULL(SUM(c.da%d_num),0)) as da_str%d,
                      """.formatted(i, i, i, i, i, i, i, i));
         }
         return sql.toString();

+ 35 - 27
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java

@@ -37,8 +37,6 @@ public class GameMonitorAlarmTask {
     @Resource
     private AliSmsService aliSmsService;
 
-    private ExecutorService taskScheduler = Executors.newSingleThreadExecutor();
-
 
     @Value("${sys-config.task_is_run}")
     private boolean run;
@@ -49,34 +47,44 @@ public class GameMonitorAlarmTask {
     @Scheduled(cron = "0 */5 * * * *")
     public void run() {
         log.info("游戏监控告警定时任务开始.");
-        log.info("run{}", run);
-        Future<?> future =  taskScheduler.submit(()->{
-            try {
-                log.info("游戏监控在线程里开始执行");
-                if (!run) {
-                    log.info("游戏监控告警定时任务本地不执行.");
-                    return;
-                }
-                try {
-                    log.info("进入告警方法");
-                    gameMonitorAlarmService.sendMsgToUser();
-                    log.info("游戏监控告警定时任务结束.");
-                } catch (Exception e) {
-                    log.info("定时任务游戏监控告警出错", e);
-                }
-            }catch (Exception e){
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+        Runnable task = ()->{
+           try {
+               log.info("游戏监控在线程里开始执行");
+               if (!run) {
+                   log.info("游戏监控告警定时任务本地不执行.");
+                   return;
+               }
+               try {
+                   log.info("进入告警方法");
+                   gameMonitorAlarmService.sendMsgToUser();
+                   log.info("游戏监控告警定时任务结束.");
+               } catch (Exception e) {
+                   log.info("定时任务游戏监控告警出错", e);
+               }
+           }catch (Exception e){
 
-                log.error("定时任务游戏监控告警出错", e);
-            }
-        });
+               log.error("定时任务游戏监控告警出错", e);
+           }
+        };
+        scheduler.submit(task);
+        // 使用shutdown()优雅关闭
+        scheduler.shutdown();
         try {
-            //两分钟执行不完就超时
-            future.get(120, TimeUnit.SECONDS);
-        } catch (Exception e) {
-            sendMsg("定时任务游戏监控告警超时");
-            log.error("定时任务游戏监控告警超时", e);
-            future.cancel(true);
+            // 等待所有任务完成,最多等待120秒
+            if (!scheduler.awaitTermination(120, TimeUnit.SECONDS)) {
+                log.info("线程池关闭超时,可能有任务未完成");
+            }
+        } catch (InterruptedException e) {
+            // 当前线程被中断,通常应重新中断自己
+            log.info("线程池关闭时当前线程被中断");
+            Thread.currentThread().interrupt();
+
         }
+
+        // 或使用shutdownNow()强制关闭
+        List<Runnable> notStartedTasks = scheduler.shutdownNow();
+        log.info("已取消 " + notStartedTasks.size() + " 个任务");
     }
 
     private void sendMsg(String msg) {

+ 1 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java

@@ -23,7 +23,7 @@ public class SDKApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(SDKApplication.class, args);
-        System.out.println("赞象SDK服务启动成功 <解决头条转端回传的问题> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象SDK服务启动成功 <解决修仙游戏漏上报角色的问题> ( ´・・)ノ(._.`) \n" +
                 " ___________ _   __\n" +
                 "/  ___|  _  \\ | / /\n" +
                 "\\ `--.| | | | |/ / \n" +

+ 8 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/UserController.java

@@ -99,6 +99,14 @@ public class UserController {
         return ResultVO.ok(userService.getUserCustomer(userData));
     }
 
+    @UnSignCheck
+    @ApiOperation(value = "CP服务端上传角色信息")
+    @PostMapping("/cp/server/update/game/role")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> updateUserGameRole(@Validated @RequestBody GameUserRoleSubmitParam param) {
+        return ResultVO.ok(gameUserRoleService.updateUserGameRole(param));
+    }
+
     @ApiOperation(value = "上传角色信息")
     @PostMapping("/update/game/role")
     @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})

+ 5 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/KafkaEventTrackEnum.java

@@ -17,6 +17,11 @@ public enum KafkaEventTrackEnum {
      */
     KAFKA_EVENT_TRACK_REG("KAFKA_EVENT_TRACK_REG"),
 
+    /**
+     * 渠道变更
+     */
+    KAFKA_EVENT_TRACK_AGENT_UPDATE("KAFKA_EVENT_TRACK_AGENT_UPDATE"),
+
     /**
      * 登录
      */

+ 10 - 3
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/handler/GlobalExceptionHandler.java

@@ -70,13 +70,20 @@ public class GlobalExceptionHandler {
 
     /**
      * 参数类型不匹配导致转换异常
-     *
-     * @param e
-     * @return
      */
     @ExceptionHandler(MethodArgumentTypeMismatchException.class)
     public ResultVO<?> mismatchErrorHandler(MethodArgumentTypeMismatchException e) {
         log.error("方法:{},字段:{},参数:{},错误信息:{}", e.getParameter().getMethod(), e.getName(), e.getValue(), e.getMessage());
         return ResultVO.fail("请求参数异常,请勿非法操作");
     }
+
+    /**
+     * 空指针异常全局处理
+     */
+    @ExceptionHandler(NullPointerException.class)
+    public ResultVO<?> validExceptionHandler(NullPointerException e) {
+        log.error(e.getMessage(), e);
+        e.printStackTrace();
+        return ResultVO.fail("空指针异常,请勿非法操作");
+    }
 }

+ 57 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleSubmitParam.java

@@ -0,0 +1,57 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-17
+ * @description : 角色信息提交接口
+ */
+@Data
+public class GameUserRoleSubmitParam {
+
+    /**
+     * 游戏id
+     */
+    @ApiModelProperty("游戏id")
+    @NotBlank(message = "游戏id不可为空")
+    private String gameId;
+
+    /**
+     * 玩家id
+     */
+    @ApiModelProperty("玩家id")
+    @NotNull(message = "玩家id不可为空")
+    private Long userId;
+
+    /**
+     * 操作系统
+     */
+    @NotNull(message = "操作系统不可为空")
+    private String os;
+
+    /**
+     * 接口token
+     */
+    @ApiModelProperty("接口token")
+    @NotBlank(message = "接口token不可为空")
+    private String token;
+
+    /**
+     * 加密参数
+     */
+    @ApiModelProperty("加密参数")
+    @NotBlank(message = "加密参数不可为空")
+    private String sign;
+
+    /**
+     * 角色信息参数
+     */
+    @ApiModelProperty("角色信息")
+    @NotNull(message = "角色信息不可为null")
+    private GameUserRoleUpdateParam gameUserRoleParam;
+}

+ 0 - 31
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleUpdateParam.java

@@ -5,7 +5,6 @@ import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
-import java.math.BigDecimal;
 
 /**
  * 游戏角色
@@ -44,24 +43,6 @@ public class GameUserRoleUpdateParam {
     @NotNull(message = "角色等级不可为空")
     private Long roleLevel;
 
-    /**
-     * 角色等级描述
-     */
-    @ApiModelProperty("角色等级描述")
-    private String roleGradeDesc;
-
-    /**
-     * 角色创建时间, 当TYPE_CREATE_ROLE为必须,时间戳
-     */
-    @ApiModelProperty("角色创建时间, 当TYPE_CREATE_ROLE为必须,时间戳")
-    private Long roleCreateTime;
-
-    /**
-     * 角色等级变化时间,时间戳
-     */
-    @ApiModelProperty("角色等级变化时间,时间戳")
-    private Long roleGradeUpdateTime;
-
     /**
      * 游戏服务器id
      */
@@ -88,18 +69,6 @@ public class GameUserRoleUpdateParam {
     @ApiModelProperty("玩家角色战力")
     private Long rolePower;
 
-    /**
-     * 角色余额
-     */
-    @ApiModelProperty("角色余额")
-    private BigDecimal platformCoin;
-
-    /**
-     * 游戏在线时长
-     */
-    @ApiModelProperty("游戏在线时长")
-    private Long totalOnlineTime;
-
     /**
      * 角色拓展属性
      */

+ 8 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameUserRoleService.java

@@ -4,12 +4,20 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.game.module.mybatis.entity.GameUserRole;
 import com.zanxiang.game.module.mybatis.entity.User;
 import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
+import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleSubmitParam;
 import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleUpdateParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 
 
 public interface IGameUserRoleService extends IService<GameUserRole> {
 
+    /**
+     * CP 服务端玩家角色提交
+     *
+     * @param param : 提交参数
+     */
+    Boolean updateUserGameRole(GameUserRoleSubmitParam param);
+
     /**
      * 更新用户游戏角色
      *

+ 21 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserTokenService.java

@@ -1,11 +1,13 @@
 package com.zanxiang.game.module.sdk.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.GameExt;
 import com.zanxiang.game.module.mybatis.entity.UserToken;
 import com.zanxiang.game.module.sdk.pojo.dto.UserTokenDTO;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.pojo.vo.CpTokenCheckVO;
 import com.zanxiang.module.util.pojo.ResultVO;
+import reactor.util.function.Tuple2;
 
 /**
  * @author : lingfeng
@@ -36,6 +38,25 @@ public interface IUserTokenService extends IService<UserToken> {
      */
     ResultVO<Long> cpTokenCheck(String appId, Long userId, String token, String sign);
 
+    /**
+     * CP服务端加密方法
+     *
+     * @param gameExt : 游戏信息
+     * @param userId  : 玩家id
+     * @param token   : 令牌
+     * @return
+     */
+    Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token);
+
+    /**
+     * 获取玩家token
+     *
+     * @param userId : 玩家id
+     * @param token  : 令牌
+     * @return : 返回token信息
+     */
+    UserToken getCheckUserToken(Long userId, String token);
+
     /**
      * 用户活跃token更新
      *

+ 9 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
 import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.mybatis.mapper.AgentMapper;
+import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.service.*;
 import com.zanxiang.module.util.DateUtil;
@@ -50,6 +51,9 @@ public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements
     @Autowired
     private IGameExtService gameExtService;
 
+    @Autowired
+    private IKafkaService kafkaService;
+
     @Override
     public void userAgentUpdate(User user, String channel) {
         log.error("用户登录接收到的渠道参数 userId : {}, channel : {}", user.getId(), channel);
@@ -79,18 +83,22 @@ public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements
             if (agent == null) {
                 return;
             }
+            LocalDateTime localDateTime = LocalDateTime.now();
             //更新用户信息
             userService.update(new LambdaUpdateWrapper<User>()
                     .set(User::getAgentId, agent.getId())
                     .set(User::getChannel, channel)
-                    .set(User::getUpdateTime, LocalDateTime.now())
+                    .set(User::getUpdateTime, localDateTime)
                     .eq(User::getId, user.getId()));
             //添加渠道变更记录
             userAgentLogService.agentUpdateLog(user, agent.getId(), channel);
             //回传用户信息
             user.setAgentId(agent.getId());
             user.setChannel(channel);
+            user.setUpdateTime(localDateTime);
             callBackService.userCallBack(user, urlParamMap);
+            //注册信息埋点数据发送到卡夫卡
+            kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_AGENT_UPDATE, JsonUtil.toString(user));
         } catch (Exception e) {
             log.error("用户渠道更新异常, userId : {}, channel : {}, e : {}", user.getId(), channel, e.getMessage());
         }

+ 66 - 8
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java

@@ -4,26 +4,28 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.zanxiang.game.module.mybatis.entity.GameUser;
-import com.zanxiang.game.module.mybatis.entity.GameUserRole;
-import com.zanxiang.game.module.mybatis.entity.User;
+import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.mybatis.mapper.GameUserRoleMapper;
 import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
 import com.zanxiang.game.module.sdk.enums.DataTypeEnum;
 import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
 import com.zanxiang.game.module.sdk.enums.LoginTypeEnum;
 import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
+import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleSubmitParam;
 import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleUpdateParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.service.*;
 import com.zanxiang.module.redis.service.IDistributedLockComponent;
 import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
+import reactor.util.function.Tuple2;
 
 import java.time.LocalDateTime;
 import java.util.*;
@@ -64,6 +66,56 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
     @Autowired
     private IDistributedLockComponent distributedLockComponent;
 
+    @Autowired
+    private IGameExtService gameExtService;
+
+    @Override
+    public Boolean updateUserGameRole(GameUserRoleSubmitParam param) {
+        //查询游戏信息
+        GameExt gameExt = gameExtService.getByGameAppId(param.getGameId());
+        if (gameExt == null || Strings.isBlank(gameExt.getLoginKey())) {
+            log.error("参数错误, 游戏信息不存在, param : {}", JsonUtil.toString(param));
+            throw new BaseException("参数错误, 游戏信息不存在");
+        }
+        //根据token检验
+        UserToken userToken = userTokenService.getCheckUserToken(param.getUserId(), param.getToken());
+        if (userToken == null) {
+            log.error("参数错误, token令牌无效, param : {}", JsonUtil.toString(param));
+            throw new BaseException("参数错误, token令牌无效");
+        }
+        //验证签名
+        Tuple2<String, String> tuple2 = userTokenService.getMySign(gameExt, param.getUserId(), param.getToken());
+        if (!Objects.equals(tuple2.getT2(), param.getSign())) {
+            log.error("参数错误 , str : {}, mySign : {}, sign : {}", tuple2.getT1(), tuple2.getT2(), param.getSign());
+            throw new BaseException("参数错误, sign验证失败, str : " + tuple2.getT1() + ", mySign : " + tuple2.getT2());
+        }
+        //提交的角色信息
+        GameUserRoleUpdateParam gameUserRoleParam = param.getGameUserRoleParam();
+        //查询玩家信息
+        User user = userService.getById(userToken.getUserId());
+        //构建 userData
+        UserData userData = new UserData();
+        userData.setUserId(user.getId());
+        userData.setGameId(user.getGameId());
+        userData.setDeviceSystem(param.getOs());
+        //判断角色是否存在
+        GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
+                .eq(GameUserRole::getUserId, user.getId())
+                .eq(GameUserRole::getGameId, user.getGameId())
+                .eq(GameUserRole::getRoleId, gameUserRoleParam.getRoleId()));
+        //更新游戏角色
+        if (gameUserRole != null) {
+            this.gameRoleUpdate(gameUserRoleParam, gameUserRole, userData);
+            return Boolean.TRUE;
+        }
+        //新建游戏角色
+        this.gameRoleCreate(gameUserRoleParam, userData);
+        //创建角色通知监听服务
+        this.callListenIn(gameUserRoleParam, userData);
+        //返回结果
+        return Boolean.TRUE;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean updateUserGameRole(GameUserRoleUpdateParam param, UserData userData) {
@@ -78,7 +130,8 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
             //新建游戏角色
             this.gameRoleCreate(param, userData);
             //插入用户登录记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_IN.getLoginType());
         }
         //判断角色是否存在
         GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
@@ -97,7 +150,8 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         //进入游戏
         if (Objects.equals(dataType, DataTypeEnum.TYPE_ENTER_GAME.getDateType())) {
             //插入用户登录记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_IN.getLoginType());
         }
         //等级提升更新
         if (Objects.equals(dataType, DataTypeEnum.TYPE_LEVEL_UP.getDateType())) {
@@ -106,14 +160,16 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         //退出游戏
         if (Objects.equals(dataType, DataTypeEnum.TYPE_EXIT_GAME.getDateType())) {
             //插入用户退出记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_OUT.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_OUT.getLoginType());
         }
         return Boolean.FALSE;
     }
 
     private boolean gameRoleUpdate(GameUserRoleUpdateParam param, GameUserRole gameUserRole, UserData userData) {
         //更新频率限制, 20秒更新一次, 避免游戏实时战力高频上报
-        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + userData.getUserId(), 0L, 20L, TimeUnit.SECONDS)) {
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + userData.getUserId(),
+                0L, 20L, TimeUnit.SECONDS)) {
             return Boolean.TRUE;
         }
         //玩家角色信息更新
@@ -142,13 +198,15 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
     private void gameRoleCreate(GameUserRoleUpdateParam param, UserData userData) {
         //查询玩家角色信息
         GameUserRole userRole = this.getOne(new LambdaQueryWrapper<GameUserRole>()
+                .eq(GameUserRole::getUserId, userData.getUserId())
                 .eq(GameUserRole::getGameId, userData.getGameId())
                 .eq(GameUserRole::getRoleId, param.getRoleId()));
         if (userRole != null) {
             return;
         }
         //上锁
-        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + param.getRoleId(), 0L, 3L, TimeUnit.MINUTES)) {
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + param.getRoleId(),
+                0L, 3L, TimeUnit.MINUTES)) {
             return;
         }
         //查询玩家信息

+ 4 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/UserTokenServiceImpl.java

@@ -125,7 +125,8 @@ public class UserTokenServiceImpl extends ServiceImpl<UserTokenMapper, UserToken
         return ResultVO.ok(userId);
     }
 
-    private Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token) {
+    @Override
+    public Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token) {
         //计算用户签名
         StringBuilder sb = new StringBuilder();
         sb.append("loginKey=").append(gameExt.getLoginKey());
@@ -142,7 +143,8 @@ public class UserTokenServiceImpl extends ServiceImpl<UserTokenMapper, UserToken
         return Tuples.of(sb.toString(), mySign);
     }
 
-    private UserToken getCheckUserToken(Long userId, String token) {
+    @Override
+    public UserToken getCheckUserToken(Long userId, String token) {
         //非导量用户
         UserToken userToken = super.getOne(new LambdaQueryWrapper<UserToken>()
                 .eq(UserToken::getToken, token)