Pārlūkot izejas kodu

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

zhimo 1 mēnesi atpakaļ
vecāks
revīzija
c6366cb97e

+ 69 - 0
game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/pojo/enums/ChatChannelEnum.java

@@ -0,0 +1,69 @@
+package com.zanxiang.game.module.base.pojo.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description : 聊天频道枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum ChatChannelEnum {
+
+    /**
+     * 世界
+     */
+    CHAT_CHANNEL_WORLD("CHAT_CHANNEL_WORLD", "世界"),
+
+    /**
+     * 阵营
+     */
+    CHAT_CHANNEL_FACTION("CHAT_CHANNEL_FACTION", "阵营"),
+
+    /**
+     * 帮派
+     */
+    CHAT_CHANNEL_GUILD("CHAT_CHANNEL_GUILD", "帮派"),
+
+    /**
+     * 队伍
+     */
+    CHAT_CHANNEL_TEAM("CHAT_CHANNEL_TEAM", "队伍"),
+
+    /**
+     * 当前
+     */
+    CHAT_CHANNEL_CURRENT("CHAT_CHANNEL_CURRENT", "当前"),
+
+    /**
+     * 寻师
+     */
+    CHAT_CHANNEL_FIND_TEACHER("CHAT_CHANNEL_FIND_TEACHER", "寻师"),
+
+    /**
+     * 国家
+     */
+    CHAT_CHANNEL_NATION("CHAT_CHANNEL_NATION", "国家"),
+
+    /**
+     * 跨服
+     */
+    CHAT_CHANNEL_CROSS_SERVER("CHAT_CHANNEL_CROSS_SERVER", "跨服"),
+
+    /**
+     * 私聊
+     */
+    CHAT_CHANNEL_PRIVATE("CHAT_CHANNEL_PRIVATE", "私聊");
+
+    /**
+     * 频道
+     */
+    private final String channel;
+
+    /**
+     * 频道名称
+     */
+    private final String name;
+}

+ 1 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java

@@ -23,7 +23,7 @@ public class ManageApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(ManageApplication.class, args);
-        System.out.println("赞象Manage服务启动成功 < (查询渠道接口新增字段修复问题01 ・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 < (游戏聊天记录功能上线 ・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 49 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/GameUserChatController.java

@@ -0,0 +1,49 @@
+package com.zanxiang.game.module.manage.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.module.manage.pojo.params.GameUserChatListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GameUserChatVO;
+import com.zanxiang.game.module.manage.service.IGameUserChatService;
+import com.zanxiang.module.util.pojo.ResultVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-13
+ * @description :
+ */
+@Api(tags = {"游戏分类标签管理接口"})
+@RestController
+@RequestMapping("/game/chat")
+@Slf4j
+public class GameUserChatController {
+
+    @Autowired
+    private IGameUserChatService gameUserChatService;
+
+    @ApiOperation(value = "查询有聊天记录的游戏")
+    @GetMapping(value = "/game/list")
+    @PreAuthorize(permissionKey = "manage:gameChat:gameList")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Map.class)})
+    public ResultVO<Map<Long, String>> listOfPage() {
+        return ResultVO.ok(gameUserChatService.chatGameMap());
+    }
+
+    @ApiOperation(value = "查询游戏聊天记录")
+    @PostMapping(value = "/list")
+    @PreAuthorize(permissionKey = "manage:gameChat:chatList")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = GameUserChatVO.class)})
+    public ResultVO<IPage<GameUserChatVO>> listOfPage(@Validated @RequestBody GameUserChatListParam param) {
+        return ResultVO.ok(gameUserChatService.listOfPage(param));
+    }
+}

+ 45 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/GameUserChatListParam.java

@@ -0,0 +1,45 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import com.zanxiang.game.module.mybatis.entity.GameUserChat;
+import com.zanxiang.module.web.pojo.BaseListDTO;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDate;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-13
+ * @description : 游戏角色聊天记录
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GameUserChatListParam extends BaseListDTO<GameUserChat> {
+
+    /**
+     * 超父游戏id
+     */
+    @NotNull(message = "超父游戏id不可为空")
+    private Long supperGameId;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 角色名称
+     */
+    private String roleName;
+
+    /**
+     * 聊天开始日期
+     */
+    private LocalDate chatStart;
+
+    /**
+     * 聊天结束日期
+     */
+    private LocalDate chatEnd;
+}

+ 59 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/GameUserChatVO.java

@@ -0,0 +1,59 @@
+package com.zanxiang.game.module.manage.pojo.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description : 聊天记录
+ */
+@Data
+public class GameUserChatVO {
+
+    /**
+     * 主键id
+     */
+    private Long id;
+
+    /**
+     * 游戏名称
+     */
+    private Long gameName;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 区服名称
+     */
+    private String serverName;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 角色名称
+     */
+    private String roleName;
+
+    /**
+     * 公会名称
+     */
+    private String guildName;
+
+    /**
+     * 聊天内容
+     */
+    private String content;
+
+    /**
+     * 聊天时间
+     */
+    private LocalDateTime chatTime;
+}

+ 24 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IGameUserChatService.java

@@ -0,0 +1,24 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
+import com.zanxiang.game.module.manage.pojo.params.GameUserChatListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GameUserChatVO;
+import com.zanxiang.game.module.mybatis.entity.GameUserChat;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description :
+ */
+public interface IGameUserChatService extends IService<GameUserChat> {
+
+    Map<Long, String> chatGameMap();
+
+    IPage<GameUserChatVO> listOfPage(GameUserChatListParam param);
+
+    void addGameUserChat(ChatSubmitParam param);
+}

+ 23 - 7
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/api/CpServerApiService.java

@@ -6,6 +6,7 @@ import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
 import com.zanxiang.game.module.manage.pojo.params.OpenGameServerParam;
 import com.zanxiang.game.module.manage.service.IGameServerService;
 import com.zanxiang.game.module.manage.service.IGameSupperService;
+import com.zanxiang.game.module.manage.service.IGameUserChatService;
 import com.zanxiang.game.module.manage.service.IListenCallService;
 import com.zanxiang.game.module.manage.utils.SignUtil;
 import com.zanxiang.game.module.mybatis.entity.GameServer;
@@ -41,6 +42,9 @@ public class CpServerApiService {
     @Autowired
     private IListenCallService listenCallService;
 
+    @Autowired
+    private IGameUserChatService gameUserChatService;
+
     @Autowired
     private RestTemplate restTemplate;
 
@@ -50,8 +54,25 @@ public class CpServerApiService {
         if (gameSupper == null) {
             throw new BaseException("参数错误");
         }
+        //签名验证
         this.signCheck(gameSupper.getCpServerKey(), param.getGameId(), param.getServerId(),
                 param.getSignTime(), param.getSign());
+        //调武哥接口, 监测聊天通知
+        try {
+            this.chatContentCheck(gameSupper, param);
+        } catch (Exception e) {
+            log.error("调武哥接口通知消息异常, chatContentMap : {}, e : {}", JsonUtil.toString(param), e.getMessage());
+        }
+        //保存聊天数据到数据库
+        try {
+            gameUserChatService.addGameUserChat(param);
+        } catch (Exception e) {
+            log.error("保存聊天数据到数据库异常, param : {}, e : {}", JsonUtil.toString(param), e.getMessage());
+        }
+        return Boolean.TRUE;
+    }
+
+    private void chatContentCheck(GameSupper gameSupper, ChatSubmitParam param) {
         //查询区服信息
         GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
                 .eq(GameServer::getGameId, param.getGameId())
@@ -66,12 +87,7 @@ public class CpServerApiService {
         Map<String, Object> paramMap = new HashMap<>(1);
         paramMap.put("data", chatContentMap);
         //调武哥接口通知消息
-        try {
-            restTemplate.postForObject("http://47.99.157.216:9000/game/roleChat", paramMap, Object.class);
-        } catch (Exception e) {
-            log.error("调武哥接口通知消息异常, chatContentMap : {}, e : {}", JsonUtil.toString(paramMap), e.getMessage());
-        }
-        return Boolean.TRUE;
+        restTemplate.postForObject("http://47.99.157.216:9000/game/roleChat", paramMap, Object.class);
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -101,7 +117,7 @@ public class CpServerApiService {
         //区服添加或者更新
         gameServerService.saveOrUpdate(gameServer);
         //钉钉通知
-        String content = LocalDateTime.now().toString() + "游戏开服通知\n游戏名称 : " + gameSupper.getName()
+        String content = LocalDateTime.now() + "游戏开服通知\n游戏名称 : " + gameSupper.getName()
                 + "\n区服名称:" + param.getServerName() + "\n开服时间:" + param.getStartTime().toString();
         listenCallService.sendDingTalkMsg(param.getGameId(), Boolean.TRUE, content);
         return Boolean.TRUE;

+ 153 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GameUserChatServiceImpl.java

@@ -0,0 +1,153 @@
+package com.zanxiang.game.module.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
+import com.zanxiang.game.module.manage.pojo.params.GameUserChatListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GameUserChatVO;
+import com.zanxiang.game.module.manage.service.IGameService;
+import com.zanxiang.game.module.manage.service.IGameUserChatService;
+import com.zanxiang.game.module.manage.service.IGameUserRoleService;
+import com.zanxiang.game.module.mybatis.entity.Game;
+import com.zanxiang.game.module.mybatis.entity.GameUserChat;
+import com.zanxiang.game.module.mybatis.entity.GameUserRole;
+import com.zanxiang.game.module.mybatis.mapper.GameUserChatMapper;
+import com.zanxiang.module.util.DateUtil;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.bean.BeanUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description : 角色聊天记录
+ */
+@Slf4j
+@Service
+public class GameUserChatServiceImpl extends ServiceImpl<GameUserChatMapper, GameUserChat> implements IGameUserChatService {
+
+    @Autowired
+    private IGameService gameService;
+
+    @Autowired
+    private IGameUserRoleService gameUserRoleService;
+
+    @Override
+    public Map<Long, String> chatGameMap() {
+        return Collections.singletonMap(12L, "仙剑奇侠传");
+    }
+
+    @Override
+    public IPage<GameUserChatVO> listOfPage(GameUserChatListParam param) {
+        return super.page(param.toPage(), new LambdaQueryWrapper<GameUserChat>()
+                .eq(Strings.isNotBlank(param.getRoleId()), GameUserChat::getRoleId, param.getRoleId())
+                .like(Strings.isNotBlank(param.getRoleName()), GameUserChat::getRoleName, param.getRoleName())
+                .ge(param.getChatStart() != null, GameUserChat::getChatTime,
+                        param.getChatStart() == null ? null : LocalDateTime.of(param.getChatStart(), LocalTime.MIN))
+                .le(param.getChatEnd() != null, GameUserChat::getChatTime,
+                        param.getChatEnd() == null ? null : LocalDateTime.of(param.getChatEnd(), LocalTime.MAX))
+                .orderByDesc(GameUserChat::getCreateTime)
+        ).convert(this::toVO);
+    }
+
+    private GameUserChatVO toVO(GameUserChat gameUserChat) {
+        if (gameUserChat == null) {
+            return null;
+        }
+        return BeanUtil.copy(gameUserChat, GameUserChatVO.class);
+    }
+
+    @Override
+    public void addGameUserChat(ChatSubmitParam param) {
+        List<Long> gameIdList = getGameIdBySuperGameId(param.getGameId());
+        if (CollectionUtils.isEmpty(gameIdList)) {
+            return;
+        }
+        //构造聊天记录对象
+        GameUserChat chat = this.transform(param);
+        //补充玩家公会信息, 区服信息
+        this.processRoleInfo(gameIdList, chat.getRoleId(), chat::setGuildId, chat::setGuildName,
+                role -> {
+                    chat.setServerName(role.getServerName());
+                    if (Strings.isBlank(chat.getRoleName())) {
+                        chat.setRoleName(role.getRoleName());
+                    }
+                });
+        //补充被私聊玩家公会信息, 区服信息
+        this.processRoleInfo(gameIdList, chat.getChatRoleId(), chat::setChatRoleGuildId, chat::setChatRoleGuildName,
+                role -> {
+                    chat.setChatRoleName(role.getRoleName());
+                    chat.setChatRoleServerName(role.getServerName());
+                    if (Strings.isBlank(chat.getServerId())) {
+                        chat.setChatRoleServerId(role.getServerId());
+                    }
+                });
+        //保存聊天记录
+        super.save(chat);
+    }
+
+    private void processRoleInfo(List<Long> gameIds, String roleId, Consumer<String> guildIdSetter,
+                                 Consumer<String> guildNameSetter, Consumer<GameUserRole> serverInfoSetter) {
+        if (Strings.isBlank(roleId)) {
+            return;
+        }
+        Optional.ofNullable(this.getGameUserRole(gameIds, roleId)).ifPresent(gameUserRole -> {
+            Optional.ofNullable(JsonUtil.toMap(gameUserRole.getExtra(), Map.class, String.class))
+                    .ifPresent(extraMap -> {
+                        Optional.ofNullable(extraMap.get("countryId"))
+                                .filter(Strings::isNotBlank)
+                                .ifPresent(guildIdSetter);
+                        Optional.ofNullable(extraMap.get("country"))
+                                .filter(Strings::isNotBlank)
+                                .ifPresent(guildNameSetter);
+                    });
+            serverInfoSetter.accept(gameUserRole);
+        });
+    }
+
+    private List<Long> getGameIdBySuperGameId(Long superGameId) {
+        return gameService.list(new LambdaQueryWrapper<Game>()
+                .select(Game::getId)
+                .eq(Game::getSuperGameId, superGameId)
+        ).stream().map(Game::getId).collect(Collectors.toList());
+    }
+
+    private GameUserRole getGameUserRole(List<Long> gameIdList, String roleId) {
+        return gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
+                .eq(GameUserRole::getRoleId, roleId)
+                .in(GameUserRole::getGameId, gameIdList)
+                .orderByDesc(GameUserRole::getUpdateTime)
+                .last("LIMIT 1"));
+    }
+
+    private GameUserChat transform(ChatSubmitParam param) {
+        Map<String, Object> chatContentMap = param.getChatContentMap();
+        return GameUserChat.builder()
+                .supperGameId(param.getGameId())
+                .serverId(param.getServerId())
+                .roleId(chatContentMap.containsKey("role_id") ? chatContentMap.get("role_id").toString() : null)
+                .roleName(chatContentMap.containsKey("role_name") ? chatContentMap.get("role_name").toString() : null)
+                .chatTime(chatContentMap.containsKey("chatTime") ? DateUtil.parseLocalDateTime(chatContentMap.get("chatTime").toString()) : null)
+                .content(chatContentMap.containsKey("content") ? chatContentMap.get("content").toString() : null)
+                .channel(chatContentMap.containsKey("channel") ? chatContentMap.get("channel").toString() : null)
+                .chatRoleId(chatContentMap.containsKey("chat_role_id") ? chatContentMap.get("chat_role_id").toString() : null)
+                .chatRoleServerId(chatContentMap.containsKey("chat_role_server_id") ? chatContentMap.get("chat_role_server_id").toString() : null)
+                .sourceData(JsonUtil.toString(param))
+                .createTime(LocalDateTime.now())
+                .build();
+    }
+}

+ 40 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/task/GameUserChatClearTask.java

@@ -0,0 +1,40 @@
+package com.zanxiang.game.module.manage.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.module.manage.service.IGameUserChatService;
+import com.zanxiang.game.module.mybatis.entity.GameUserChat;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-13
+ * @description : 聊天记录定时删除任务
+ */
+@Slf4j
+@Component
+@RefreshScope
+public class GameUserChatClearTask {
+
+    @Autowired
+    private IGameUserChatService gameUserChatService;
+
+    /**
+     * 每天凌晨2点清理一次7天前的聊天记录
+     */
+    @Scheduled(cron = "0 0 2 * * ?")
+    public void execute() {
+        try {
+            gameUserChatService.remove(new LambdaQueryWrapper<GameUserChat>()
+                    .lt(GameUserChat::getChatTime, LocalDateTime.now().minusDays(7))
+            );
+        } catch (Exception e) {
+            log.error("每天凌晨2点清理一次7天前的聊天记录异常, e : {}", e.getMessage(), e);
+        }
+    }
+}

+ 122 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameUserChat.java

@@ -0,0 +1,122 @@
+package com.zanxiang.game.module.mybatis.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description : 游戏玩家聊天记录
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_game_user_chat")
+public class GameUserChat implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 超父游戏id
+     */
+    private Long supperGameId;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 区服名称
+     */
+    private String serverName;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 角色名称
+     */
+    private String roleName;
+
+    /**
+     * 公会id
+     */
+    private String guildId;
+
+    /**
+     * 公会名称
+     */
+    private String guildName;
+
+    /**
+     * 聊天时间
+     */
+    private LocalDateTime chatTime;
+
+    /**
+     * 聊天内容
+     */
+    private String content;
+
+    /**
+     * 聊天频道
+     */
+    private String channel;
+
+    /**
+     * 私聊角色id
+     */
+    private String chatRoleId;
+
+    /**
+     * 私聊角色名称
+     */
+    private String chatRoleName;
+
+    /**
+     * 私聊角色区服id
+     */
+    private String chatRoleServerId;
+
+    /**
+     * 私聊角色区服名称
+     */
+    private String chatRoleServerName;
+
+    /**
+     * 私聊角色公会id
+     */
+    private String chatRoleGuildId;
+
+    /**
+     * 私聊角色公会名称
+     */
+    private String chatRoleGuildName;
+
+    /**
+     * 源数据
+     */
+    private String sourceData;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+}

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/GameUserChatMapper.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.mybatis.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.module.mybatis.entity.GameUserChat;
+
+/**
+ * @author : lingfeng
+ * @time : 2025-03-12
+ * @description : ${description}
+ */
+public interface GameUserChatMapper extends BaseMapper<GameUserChat> {
+}