Procházet zdrojové kódy

Merge branch 'dev' of sunkean/raex_mmo into master

sunkean před 2 roky
rodič
revize
27072335c0

+ 10 - 0
src/main/java/com/izouma/meta/config/Constants.java

@@ -45,6 +45,16 @@ public interface Constants {
 
     String REDIS_PREFIX = "meta:";
 
+    String META_ROBOT_NICK_NAME = "metaRobot";
+
+    String META_ROBOT_USER_ID = "7970191";
+
+    String META_ROBOT_MESSAGE_BODY = "{type:9,objectId:%S}";
+
+    long META_ROBOT_SEND_MSG_DELAY_MS = 0;
+
+    long META_ROBOT_SEND_MSG_PERIOD_MS = 200;
+
     interface MetaRestCode {
 
         int success = 200;

+ 43 - 0
src/main/java/com/izouma/meta/domain/MetaObjectMove.java

@@ -0,0 +1,43 @@
+package com.izouma.meta.domain;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Entity;
+import java.time.LocalDateTime;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@ApiModel("元宇宙物体移动配置")
+public class MetaObjectMove extends BaseEntity {
+
+    @ApiModelProperty("物体id")
+    @ExcelProperty("物体id")
+    private Long objectId;
+
+    @ApiModelProperty("物体开始移动时间")
+    @ExcelProperty("物体开始移动时间")
+    private LocalDateTime startTime;
+
+    @ApiModelProperty("总移动时间")
+    @ExcelProperty("总移动时间")
+    private Long totalTime;
+
+    @ApiModelProperty("是否运行")
+    @ExcelProperty("是否运行")
+    private boolean run;
+
+    @ApiModelProperty("区域id")
+    @ExcelProperty("区域id")
+    private Long regionId;
+
+    @ApiModelProperty("城市id")
+    @ExcelProperty("城市id")
+    private Long cityId;
+}

+ 16 - 0
src/main/java/com/izouma/meta/repo/MetaObjectMoveRepo.java

@@ -0,0 +1,16 @@
+package com.izouma.meta.repo;
+
+import com.izouma.meta.domain.MetaObjectMove;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.List;
+
+public interface MetaObjectMoveRepo extends JpaRepository<MetaObjectMove, Long>, JpaSpecificationExecutor<MetaObjectMove> {
+
+    @Query("select m.objectId from MetaObjectMove m where m.del = false and m.run = true ")
+    List<Long> findAllRunningObjectId();
+
+    MetaObjectMove findByObjectIdAndDel(Long objectId, boolean del);
+}

+ 75 - 0
src/main/java/com/izouma/meta/web/MMOWebSocketController.java

@@ -0,0 +1,75 @@
+package com.izouma.meta.web;
+
+import com.izouma.meta.config.Constants;
+import com.izouma.meta.repo.MetaObjectMoveRepo;
+import com.izouma.meta.websocket.MMOWebSocket;
+import lombok.AllArgsConstructor;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/mmo/websocket")
+@AllArgsConstructor
+@CrossOrigin(origins = {"http://localhost:8081", "https://raex.vip", "https://test.raex.vip"})
+public class MMOWebSocketController {
+
+    private MMOWebSocket       mmoWebSocket;
+    private MetaObjectMoveRepo metaObjectMoveRepo;
+
+    private final Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
+
+    @GetMapping("/{objectId}/start")
+    public synchronized void startSendingMessages(@PathVariable String objectId) {
+        if (tasks.containsKey(objectId)) {
+            throw new IllegalArgumentException(String.format("Task with id %S is already running", objectId));
+        }
+        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
+        ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> sendMessage(objectId), Constants.META_ROBOT_SEND_MSG_DELAY_MS, Constants.META_ROBOT_SEND_MSG_PERIOD_MS, TimeUnit.MILLISECONDS);
+        tasks.put(objectId, future);
+    }
+
+    @GetMapping("/{objectId}/stop")
+    public synchronized void stopSendingMessages(@PathVariable String objectId) {
+        ScheduledFuture<?> future = tasks.get(objectId);
+        if (future != null) {
+            future.cancel(false);
+            tasks.remove(objectId);
+        }
+    }
+
+    private void sendMessage(String objectId) {
+        if (mmoWebSocket != null) {
+            mmoWebSocket.onMessage(Constants.META_ROBOT_NICK_NAME, Constants.META_ROBOT_USER_ID, String.format(Constants.META_ROBOT_MESSAGE_BODY, objectId), null);
+        }
+    }
+
+    @GetMapping("/check")
+    public synchronized String check() {
+        List<Long> objectId = metaObjectMoveRepo.findAllRunningObjectId();
+        if (CollectionUtils.isEmpty(objectId)) {
+            if (tasks.isEmpty()) {
+                return "success";
+            }
+            return String.format("物体: %s 未结束广播坐标任务,请联系管理员处理", String.join(",", tasks.keySet()));
+        }
+        if (tasks.isEmpty()) {
+            return String.format("物体: %s 未开启广播坐标任务,请联系管理员处理", objectId.stream().map(Object::toString).collect(Collectors.toList()));
+        }
+        StringBuffer str = new StringBuffer();
+        objectId.forEach(id -> {
+            if (!tasks.containsKey(String.valueOf(id))) {
+                str.append(",").append(id);
+            }
+        });
+        if (StringUtils.isNotBlank(str)) {
+            return String.format("物体: %s 未开启广播坐标任务,请联系管理员处理", str);
+        }
+        return "success";
+    }
+}

+ 58 - 30
src/main/java/com/izouma/meta/websocket/MMOWebSocket.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.izouma.meta.config.Constants;
 import com.izouma.meta.domain.MetaMMOLoginInfo;
+import com.izouma.meta.domain.MetaObjectMove;
 import com.izouma.meta.domain.MetaObjectMoveCoordinate;
 import com.izouma.meta.dto.MMOMessage;
 import com.izouma.meta.dto.MMOSingleMessage;
@@ -11,6 +12,7 @@ import com.izouma.meta.dto.MetaRestResult;
 import com.izouma.meta.dto.MetaServiceResult;
 import com.izouma.meta.enums.MoveType;
 import com.izouma.meta.repo.MetaMMOLoginInfoRepo;
+import com.izouma.meta.repo.MetaObjectMoveRepo;
 import com.izouma.meta.utils.ApplicationContextUtil;
 import com.izouma.meta.utils.ObjUtils;
 import lombok.extern.slf4j.Slf4j;
@@ -43,6 +45,7 @@ public class MMOWebSocket {
     private RedisTemplate        redisTemplate;
     private MetaMMOLoginInfoRepo metaMMOLoginInfoRepo;
     private WebsocketCommon      websocketCommon;
+    private MetaObjectMoveRepo   metaObjectMoveRepo;
 
     private void init() {
         if (Objects.isNull(redisTemplate)) {
@@ -54,6 +57,9 @@ public class MMOWebSocket {
         if (Objects.isNull(websocketCommon)) {
             websocketCommon = (WebsocketCommon) ApplicationContextUtil.getBean("websocketCommon");
         }
+        if (Objects.isNull(metaObjectMoveRepo)) {
+            metaObjectMoveRepo = (MetaObjectMoveRepo) ApplicationContextUtil.getBean("metaObjectMoveRepo");
+        }
     }
 
     @OnOpen
@@ -61,7 +67,7 @@ public class MMOWebSocket {
         init();
         // 判断当前玩家是否在其他地方登陆
         if (clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
-            log.info(String.format("当前玩家[%S]已经在别处登陆,sessionId为[%S]", userId, session.getId()));
+            log.info(String.format("当前玩家: %s 已经在别处登陆, sessionId为: %s", userId, session.getId()));
             // 关闭连接
             MMOSingleMessage mmoSingleMessage = new MMOSingleMessage();
             mmoSingleMessage.setMessageType(6);
@@ -88,14 +94,14 @@ public class MMOWebSocket {
         MMOMessage mmoMessage = new MMOMessage();
         mmoMessage.setMessageType(5);
         mmoMessage.setMessage(save);
-        log.info(String.format("通知玩家[%S],本次登陆信息[%S]", userId, JSON.toJSONString(mmoMessage)));
+        log.info(String.format("通知玩家: %s, 本次登陆信息: %s", userId, JSON.toJSONString(mmoMessage)));
         websocketCommon.sendMessageTo(clients, JSON.toJSONString(mmoMessage), Constants.REDIS_PREFIX.concat(userId));
     }
 
     @OnError
     public void onError(Session session, Throwable error) {
         // 异常处理
-        log.error(String.format("sessionId[%S]的服务端发生了错误:[%S]", session.getId(), error.getMessage()));
+        log.error(String.format("sessionId: %s 的服务端发生了错误, 错误信息为: %s", session.getId(), error.getMessage()));
     }
 
     @OnClose
@@ -120,7 +126,7 @@ public class MMOWebSocket {
         }
         MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElse(null);
         if (Objects.isNull(dbMetaMMOLoginInfo)) {
-            log.error(String.format("数据库中不存在id[%S]的记录", metaMMOLoginInfo.getId()));
+            log.error(String.format("数据库中不存在id: %s 的记录", metaMMOLoginInfo.getId()));
             return;
         }
         ObjUtils.merge(dbMetaMMOLoginInfo, metaMMOLoginInfo);
@@ -141,7 +147,7 @@ public class MMOWebSocket {
             return;
         }
         if (Constants.HEART_RECEIVE.equals(message)) {
-            log.info(String.format("sessionId:[%S] userId:[%S] 连接正常", session.getId(), userId));
+            log.info(String.format("sessionId: %s , userId: %s 连接正常", session.getId(), userId));
             websocketCommon.sendMessageTo(clients, Constants.HEART_RETURN, Constants.REDIS_PREFIX.concat(userId));
             return;
         }
@@ -151,34 +157,56 @@ public class MMOWebSocket {
             log.error(result.getMessage());
             return;
         }
-        log.info("来自客户端消息:" + message + "客户端的id是:" + session.getId());
         int type = Integer.parseInt(jsonObject.getString("type"));
-        String cityId = jsonObject.getString("cityId");
-        String regionId = jsonObject.getString("regionId");
-        String key = cityId.concat(":").concat(regionId);
-        List<String> otherUserIds = remove(key, userId);
+        // type = 9 广播物体坐标信息
         if (type == 9) {
-            String objectId = jsonObject.getString("objectId");
-            MetaObjectMoveCoordinate metaObjectMoveCoordinate = null;
+            log.info(String.format("来自客户端消息: %s", message));
+            Long objectId;
             try {
-                String str = websocketCommon.getRequest("/metaObjectMove/".concat(objectId).concat("/queryCoordinate"));
+                objectId = Long.parseLong(jsonObject.getString("objectId"));
+            } catch (Exception e) {
+                log.error(String.format("objectId parse to long throw exception: %s", e.getMessage()));
+                return;
+            }
+            MetaObjectMove metaObjectMove = metaObjectMoveRepo.findByObjectIdAndDel(objectId, false);
+            if (Objects.isNull(metaObjectMove)) {
+                log.error(String.format("物体: %s 不存在", objectId));
+                return;
+            }
+            if (!metaObjectMove.isRun()) {
+                log.error(String.format("物体: %s 已经停运", objectId));
+                return;
+            }
+            String cityId = String.valueOf(metaObjectMove.getCityId());
+            String regionId = String.valueOf(metaObjectMove.getRegionId());
+            String key = cityId.concat(":").concat(regionId);
+            List<String> otherUserIds = remove(key, userId);
+            MetaObjectMoveCoordinate metaObjectMoveCoordinate;
+            try {
+                String str = websocketCommon.getRequest("/metaObjectMove/".concat(String.valueOf(metaObjectMove.getObjectId())).concat("/queryCoordinate"));
                 metaObjectMoveCoordinate = JSONObject.parseObject(str, MetaObjectMoveCoordinate.class);
             } catch (Exception e) {
-                String errMsg = String.format("MetaObjectMoveCoordinate JSON parse throw exception:[%S]", e);
+                String errMsg = String.format("MetaObjectMoveCoordinate JSON parse throw exception: %s", e);
                 log.error(errMsg);
+                return;
             }
             if (Objects.isNull(metaObjectMoveCoordinate)) {
-                log.error(String.format("物体[%S]坐标不存在", objectId));
+                log.error(String.format("物体: %s 坐标信息不存在", metaObjectMove.getObjectId()));
                 return;
             }
             buildMessageForSendingToAllOther(otherUserIds, 9, metaObjectMoveCoordinate);
             return;
         }
+        log.info(String.format("来自客户端消息:%s 客户端的id是:%s", message, session.getId()));
+        String cityId = jsonObject.getString("cityId");
+        String regionId = jsonObject.getString("regionId");
+        String key = cityId.concat(":").concat(regionId);
+        List<String> otherUserIds = remove(key, userId);
         MetaMMOLoginInfo metaMMOLoginInfo;
         List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(otherUserIds);
         switch (type) {
             case 1:
-                log.info("当前操作类型为1 -> 玩家进入地图");
+                log.info(String.format("当前操作类型为: %s -> 玩家进入地图", type));
                 metaMMOLoginInfo = buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId), nickName, userId);
                 if (CollectionUtils.isNotEmpty(otherUserIds)) {
                     if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
@@ -193,7 +221,7 @@ public class MMOWebSocket {
                 redisTemplate.opsForList().leftPush(Constants.REDIS_PREFIX.concat(key), Constants.REDIS_PREFIX.concat(userId));
                 break;
             case 2:
-                log.info(String.format("当前操作类型为[%S] -> 玩家切换区域", type));
+                log.info(String.format("当前操作类型为: %s -> 玩家切换区域", type));
                 metaMMOLoginInfo = buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId), nickName, userId);
                 if (CollectionUtils.isNotEmpty(otherUserIds)) {
                     // 分发自己信息给区域内其他玩家
@@ -221,7 +249,7 @@ public class MMOWebSocket {
                 redisTemplate.opsForList().leftPush(Constants.REDIS_PREFIX.concat(key), Constants.REDIS_PREFIX.concat(userId));
                 break;
             case 3:
-                log.info(String.format("当前操作类型为[%S] -> 玩家在地图内移动", type));
+                log.info(String.format("当前操作类型为: %s -> 玩家在地图内移动", type));
                 metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
                 if (Objects.isNull(metaMMOLoginInfo)) {
                     log.error("缓存中不存在本玩家信息");
@@ -234,7 +262,7 @@ public class MMOWebSocket {
                 redisTemplate.opsForValue().set(Constants.REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
                 break;
             case 4:
-                log.info(String.format("当前操作类型为[%S] -> 玩家进入大厅", type));
+                log.info(String.format("当前操作类型为: %s -> 玩家进入大厅", type));
                 metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
                 if (Objects.isNull(metaMMOLoginInfo)) {
                     log.error("缓存中不存在本玩家信息");
@@ -245,7 +273,7 @@ public class MMOWebSocket {
                 // 更新库中玩家位置信息
                 MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElse(null);
                 if (Objects.isNull(dbMetaMMOLoginInfo)) {
-                    log.error(String.format("数据库不存在id[%S]的记录", metaMMOLoginInfo.getId()));
+                    log.error(String.format("数据库不存在id: %s 的记录", metaMMOLoginInfo.getId()));
                     break;
                 }
                 dbMetaMMOLoginInfo.setAxisX(metaMMOLoginInfo.getAxisX());
@@ -270,7 +298,7 @@ public class MMOWebSocket {
                 metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
                 break;
             default:
-                log.error(String.format("不存在的操作类型[%S]", type));
+                log.error(String.format("不存在的操作类型: %s", type));
         }
 
     }
@@ -296,10 +324,10 @@ public class MMOWebSocket {
         }
         userIds.forEach(id -> {
             try {
-                log.info(String.format("服务器给所有当前区域内在线用户发送消息,当前在线人员为[%S]。消息:[%S]", id, JSON.toJSONString(mmoMessage)));
+                log.info(String.format("服务器给所有当前区域内在线用户发送消息, 当前在线人员为: %s, 消息内容: %s", id, JSON.toJSONString(mmoMessage)));
                 clients.get(id).getBasicRemote().sendText(JSON.toJSONString(mmoMessage));
             } catch (Exception e) {
-                log.error(String.format("send message [%S] to [%S] throw exception [%S]:", JSON.toJSONString(mmoMessage), id, e));
+                log.error(String.format("send message %s to %s throw exception %s:", JSON.toJSONString(mmoMessage), id, e));
             }
         });
     }
@@ -414,12 +442,6 @@ public class MMOWebSocket {
         if (Objects.isNull(jsonObject.getString("type"))) {
             return MetaServiceResult.returnError("Illegal parameter : type can not be null");
         }
-        if (Objects.isNull(jsonObject.getString("cityId"))) {
-            return MetaServiceResult.returnError("Illegal parameter : cityId can not be null");
-        }
-        if (Objects.isNull(jsonObject.getString("regionId"))) {
-            return MetaServiceResult.returnError("Illegal parameter : regionId can not be null");
-        }
         int type = Integer.parseInt(jsonObject.getString("type"));
         if (type == 9) {
             if (Objects.isNull(jsonObject.getString("objectId"))) {
@@ -427,6 +449,12 @@ public class MMOWebSocket {
             }
             return MetaServiceResult.returnSuccess("check success");
         }
+        if (Objects.isNull(jsonObject.getString("cityId"))) {
+            return MetaServiceResult.returnError("Illegal parameter : cityId can not be null");
+        }
+        if (Objects.isNull(jsonObject.getString("regionId"))) {
+            return MetaServiceResult.returnError("Illegal parameter : regionId can not be null");
+        }
         if (Objects.isNull(jsonObject.getString("id"))) {
             return MetaServiceResult.returnError("Illegal parameter : id can not be null");
         }
@@ -446,7 +474,7 @@ public class MMOWebSocket {
     public MetaRestResult<Void> clearMMO(String userId, String regionId, String cityId) {
         init();
         if (clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
-            String errMsg = String.format("userId[%S]用户mmo连接正常,无法清除缓存!", userId);
+            String errMsg = String.format("userId: %s 用户mmo连接正常,无法清除缓存!", userId);
             log.info(errMsg);
             return MetaRestResult.returnError(errMsg);
         }