|
@@ -4,36 +4,35 @@ import com.alibaba.fastjson.JSON;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.izouma.meta.config.Constants;
|
|
import com.izouma.meta.config.Constants;
|
|
|
import com.izouma.meta.domain.MetaMMOLoginInfo;
|
|
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.MMOMessage;
|
|
|
import com.izouma.meta.dto.MMOSingleMessage;
|
|
import com.izouma.meta.dto.MMOSingleMessage;
|
|
|
import com.izouma.meta.dto.MetaRestResult;
|
|
import com.izouma.meta.dto.MetaRestResult;
|
|
|
import com.izouma.meta.dto.MetaServiceResult;
|
|
import com.izouma.meta.dto.MetaServiceResult;
|
|
|
-import com.izouma.meta.enums.MoveType;
|
|
|
|
|
import com.izouma.meta.repo.MetaMMOLoginInfoRepo;
|
|
import com.izouma.meta.repo.MetaMMOLoginInfoRepo;
|
|
|
-import com.izouma.meta.repo.MetaObjectMoveRepo;
|
|
|
|
|
import com.izouma.meta.utils.ApplicationContextUtil;
|
|
import com.izouma.meta.utils.ApplicationContextUtil;
|
|
|
import com.izouma.meta.utils.ObjUtils;
|
|
import com.izouma.meta.utils.ObjUtils;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
|
|
+import org.springframework.dao.DataAccessException;
|
|
|
|
|
+import org.springframework.data.redis.core.RedisOperations;
|
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
|
+import org.springframework.data.redis.core.SessionCallback;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
import javax.websocket.*;
|
|
import javax.websocket.*;
|
|
|
import javax.websocket.server.PathParam;
|
|
import javax.websocket.server.PathParam;
|
|
|
import javax.websocket.server.ServerEndpoint;
|
|
import javax.websocket.server.ServerEndpoint;
|
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
|
-import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
import java.util.Objects;
|
|
|
|
|
+import java.util.Optional;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
-import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@Service
|
|
@Service
|
|
|
-@ServerEndpoint(value = "/websocket/mmo/{nickName}/{userId}")
|
|
|
|
|
|
|
+@ServerEndpoint(value = "/websocket/mmo/{nickname}/{userId}")
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
public class MMOWebSocket {
|
|
public class MMOWebSocket {
|
|
|
|
|
|
|
@@ -45,7 +44,7 @@ public class MMOWebSocket {
|
|
|
private RedisTemplate redisTemplate;
|
|
private RedisTemplate redisTemplate;
|
|
|
private MetaMMOLoginInfoRepo metaMMOLoginInfoRepo;
|
|
private MetaMMOLoginInfoRepo metaMMOLoginInfoRepo;
|
|
|
private WebsocketCommon websocketCommon;
|
|
private WebsocketCommon websocketCommon;
|
|
|
- private MetaObjectMoveRepo metaObjectMoveRepo;
|
|
|
|
|
|
|
+ private WebsocketHandle websocketHandle;
|
|
|
|
|
|
|
|
private void init() {
|
|
private void init() {
|
|
|
if (Objects.isNull(redisTemplate)) {
|
|
if (Objects.isNull(redisTemplate)) {
|
|
@@ -57,47 +56,78 @@ public class MMOWebSocket {
|
|
|
if (Objects.isNull(websocketCommon)) {
|
|
if (Objects.isNull(websocketCommon)) {
|
|
|
websocketCommon = (WebsocketCommon) ApplicationContextUtil.getBean("websocketCommon");
|
|
websocketCommon = (WebsocketCommon) ApplicationContextUtil.getBean("websocketCommon");
|
|
|
}
|
|
}
|
|
|
- if (Objects.isNull(metaObjectMoveRepo)) {
|
|
|
|
|
- metaObjectMoveRepo = (MetaObjectMoveRepo) ApplicationContextUtil.getBean("metaObjectMoveRepo");
|
|
|
|
|
|
|
+ if (Objects.isNull(websocketHandle)) {
|
|
|
|
|
+ websocketHandle = (WebsocketHandle) ApplicationContextUtil.getBean("websocketHandle");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@OnOpen
|
|
@OnOpen
|
|
|
- public void onOpen(@PathParam("nickName") String nickName, @PathParam("userId") String userId, Session session) {
|
|
|
|
|
|
|
+ public void onOpen(@PathParam("nickname") String nickname,
|
|
|
|
|
+ @PathParam("userId") String userId, Session session) {
|
|
|
init();
|
|
init();
|
|
|
- // 判断当前玩家是否在其他地方登陆
|
|
|
|
|
- if (clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
|
|
|
|
|
- log.info(String.format("当前玩家: %s 已经在别处登陆, sessionId为: %s", userId, session.getId()));
|
|
|
|
|
- // 关闭连接
|
|
|
|
|
- MMOSingleMessage mmoSingleMessage = new MMOSingleMessage();
|
|
|
|
|
- mmoSingleMessage.setMessageType(6);
|
|
|
|
|
- mmoSingleMessage.setMessage("您已在其他地方登录,已为您关闭上次登陆信息");
|
|
|
|
|
- websocketCommon.sendMessageTo(clients, JSON.toJSONString(mmoSingleMessage), Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- try {
|
|
|
|
|
- log.info("关闭上次登陆的session连接");
|
|
|
|
|
- clients.get(Constants.REDIS_PREFIX.concat(userId)).close();
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("session close throw exception:", e);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- log.info("现在来连接的sessionId:" + session.getId() + "玩家id:" + userId + "玩家昵称" + nickName);
|
|
|
|
|
|
|
+ handleOtherLogin(userId, session);
|
|
|
|
|
+ log.info("现在来连接的sessionId:" + session.getId() + "玩家id:" + userId + "玩家昵称" + nickname);
|
|
|
clients.put(Constants.REDIS_PREFIX.concat(userId), session);
|
|
clients.put(Constants.REDIS_PREFIX.concat(userId), session);
|
|
|
- // 获取上次登录的信息
|
|
|
|
|
|
|
+ MetaMMOLoginInfo metaMMOLoginInfo = saveLoginInfo(nickname, userId, session.getId());
|
|
|
|
|
+ sendLoginMessage(userId, metaMMOLoginInfo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重复登录处理
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 用户id
|
|
|
|
|
+ * @param session session信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private void handleOtherLogin(String userId, Session session) {
|
|
|
|
|
+ if (!clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info(String.format("当前玩家: %s 已经在别处登陆, sessionId为: %s", userId, session.getId()));
|
|
|
|
|
+ MMOSingleMessage mmoSingleMessage = new MMOSingleMessage();
|
|
|
|
|
+ mmoSingleMessage.setMessageType(6);
|
|
|
|
|
+ mmoSingleMessage.setMessage("您已在其他地方登录,已为您关闭上次登陆信息");
|
|
|
|
|
+ websocketCommon.sendMessageToSingle(clients, JSON.toJSONString(mmoSingleMessage), Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
+ try {
|
|
|
|
|
+ log.info("关闭上次登陆的session连接");
|
|
|
|
|
+ clients.get(Constants.REDIS_PREFIX.concat(userId)).close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("session close throw exception:", e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存登录信息
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param nickname 昵称
|
|
|
|
|
+ * @param userId 用户id
|
|
|
|
|
+ * @param sessionId session id
|
|
|
|
|
+ * @return 登录信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private MetaMMOLoginInfo saveLoginInfo(String nickname, String userId, String sessionId) {
|
|
|
MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findLastByUserId(Long.parseLong(userId));
|
|
MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findLastByUserId(Long.parseLong(userId));
|
|
|
- // 玩家登陆信息入库
|
|
|
|
|
MetaMMOLoginInfo metaMMOLoginInfo = MetaMMOLoginInfo.initMetaMMOLoginInfo(dbMetaMMOLoginInfo);
|
|
MetaMMOLoginInfo metaMMOLoginInfo = MetaMMOLoginInfo.initMetaMMOLoginInfo(dbMetaMMOLoginInfo);
|
|
|
- metaMMOLoginInfo.setNickname(nickName);
|
|
|
|
|
|
|
+ metaMMOLoginInfo.setNickname(nickname);
|
|
|
metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
|
metaMMOLoginInfo.setOnLineTime(LocalDateTime.now());
|
|
metaMMOLoginInfo.setOnLineTime(LocalDateTime.now());
|
|
|
- metaMMOLoginInfo.setSessionId(session.getId());
|
|
|
|
|
- MetaMMOLoginInfo save = metaMMOLoginInfoRepo.save(metaMMOLoginInfo);
|
|
|
|
|
|
|
+ metaMMOLoginInfo.setSessionId(sessionId);
|
|
|
|
|
+ return metaMMOLoginInfoRepo.save(metaMMOLoginInfo);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 发送登录通知给用户
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param userId 用户id
|
|
|
|
|
+ * @param loginInfo 登录信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private void sendLoginMessage(String userId, MetaMMOLoginInfo loginInfo) {
|
|
|
MMOMessage mmoMessage = new MMOMessage();
|
|
MMOMessage mmoMessage = new MMOMessage();
|
|
|
mmoMessage.setMessageType(5);
|
|
mmoMessage.setMessageType(5);
|
|
|
- mmoMessage.setMessage(save);
|
|
|
|
|
|
|
+ mmoMessage.setMessage(loginInfo);
|
|
|
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));
|
|
|
|
|
|
|
+ websocketCommon.sendMessageToSingle(clients, JSON.toJSONString(mmoMessage), Constants.REDIS_PREFIX.concat(userId));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
@OnError
|
|
@OnError
|
|
|
public void onError(Session session, Throwable error) {
|
|
public void onError(Session session, Throwable error) {
|
|
|
// 异常处理
|
|
// 异常处理
|
|
@@ -107,22 +137,23 @@ public class MMOWebSocket {
|
|
|
@OnClose
|
|
@OnClose
|
|
|
public void onClose(@PathParam("userId") String userId) {
|
|
public void onClose(@PathParam("userId") String userId) {
|
|
|
init();
|
|
init();
|
|
|
- // 查询地图中玩家信息
|
|
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
|
|
- // 如果缓存中玩家信息为空,根据userId和sessionId查询数据库
|
|
|
|
|
- MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findByUserIdAndSessionIdAndDel(Long.parseLong(userId), clients.get(Constants.REDIS_PREFIX.concat(userId)).getId(), false);
|
|
|
|
|
- dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
|
|
|
- // 更新离线时间
|
|
|
|
|
- metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
|
|
- clients.remove(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
|
|
+ String redisKey = Constants.REDIS_PREFIX.concat(userId);
|
|
|
|
|
+ MetaMMOLoginInfo metaMMOLoginInfo = Optional.ofNullable(redisTemplate.opsForValue().get(redisKey))
|
|
|
|
|
+ .map(MetaMMOLoginInfo.class::cast)
|
|
|
|
|
+ .orElseGet(() -> {
|
|
|
|
|
+ MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findByUserIdAndSessionIdAndDel(Long.parseLong(userId), clients.get(redisKey).getId(), false);
|
|
|
|
|
+ dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
|
|
|
+ metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
|
|
+ clients.remove(redisKey);
|
|
|
|
|
+ return null;
|
|
|
|
|
+ });
|
|
|
|
|
+ if (metaMMOLoginInfo == null) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- String key = String.valueOf(metaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(metaMMOLoginInfo.getRegionId()));
|
|
|
|
|
- List<String> otherUserIds = remove(key, userId);
|
|
|
|
|
- if (CollectionUtils.isNotEmpty(otherUserIds)) {
|
|
|
|
|
- // 分发下线消息给区域内其他玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 3, metaMMOLoginInfo);
|
|
|
|
|
|
|
+ String key = String.format("%d:%d", metaMMOLoginInfo.getCityId(), metaMMOLoginInfo.getRegionId());
|
|
|
|
|
+ List<String> userIds = websocketHandle.allUserIdExcept(key, userId);
|
|
|
|
|
+ if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
|
|
+ websocketCommon.sendMessageToMultiple(clients, JSON.toJSONString(new MMOMessage(3, metaMMOLoginInfo, null)), userIds);
|
|
|
}
|
|
}
|
|
|
MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElse(null);
|
|
MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElse(null);
|
|
|
if (Objects.isNull(dbMetaMMOLoginInfo)) {
|
|
if (Objects.isNull(dbMetaMMOLoginInfo)) {
|
|
@@ -132,15 +163,12 @@ public class MMOWebSocket {
|
|
|
ObjUtils.merge(dbMetaMMOLoginInfo, metaMMOLoginInfo);
|
|
ObjUtils.merge(dbMetaMMOLoginInfo, metaMMOLoginInfo);
|
|
|
dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
|
metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
- clients.remove(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- // 删除redis中自己的信息
|
|
|
|
|
- redisTemplate.delete(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- // 移除地图中自己的信息
|
|
|
|
|
- redisTemplate.opsForList().remove(Constants.REDIS_PREFIX.concat(key), 0, Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
|
|
+ clients.remove(redisKey);
|
|
|
|
|
+ closeExecute(key, userId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@OnMessage
|
|
@OnMessage
|
|
|
- public void onMessage(@PathParam("nickName") String nickName, @PathParam("userId") String userId, String message, Session session) {
|
|
|
|
|
|
|
+ public void onMessage(@PathParam("userId") String userId, String message, Session session) {
|
|
|
init();
|
|
init();
|
|
|
if (StringUtils.isBlank(message)) {
|
|
if (StringUtils.isBlank(message)) {
|
|
|
log.error("Illegal parameter : message can not be null");
|
|
log.error("Illegal parameter : message can not be null");
|
|
@@ -148,7 +176,7 @@ public class MMOWebSocket {
|
|
|
}
|
|
}
|
|
|
if (Constants.HEART_RECEIVE.equals(message)) {
|
|
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));
|
|
|
|
|
|
|
+ websocketCommon.sendMessageToSingle(clients, Constants.HEART_RETURN, Constants.REDIS_PREFIX.concat(userId));
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
JSONObject jsonObject = JSON.parseObject(message);
|
|
JSONObject jsonObject = JSON.parseObject(message);
|
|
@@ -157,283 +185,43 @@ public class MMOWebSocket {
|
|
|
log.error(result.getMessage());
|
|
log.error(result.getMessage());
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+ log.info(String.format("来自客户端消息:%s 客户端的id是:%s", message, Objects.isNull(session) ? null : session.getId()));
|
|
|
int type = Integer.parseInt(jsonObject.getString("type"));
|
|
int type = Integer.parseInt(jsonObject.getString("type"));
|
|
|
- // type = 9 广播物体坐标信息
|
|
|
|
|
if (type == 9) {
|
|
if (type == 9) {
|
|
|
- log.info(String.format("来自客户端消息: %s", message));
|
|
|
|
|
- Long objectId;
|
|
|
|
|
- try {
|
|
|
|
|
- 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);
|
|
|
|
|
- if (CollectionUtils.isEmpty(otherUserIds)) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- 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);
|
|
|
|
|
- log.error(errMsg);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.isNull(metaObjectMoveCoordinate)) {
|
|
|
|
|
- log.error(String.format("物体: %s 坐标信息不存在", metaObjectMove.getObjectId()));
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 9, metaObjectMoveCoordinate);
|
|
|
|
|
|
|
+ log.info("当前操作类型为: 9 -> 广播物体坐标信息");
|
|
|
|
|
+ websocketHandle.handleTypeNine(clients, jsonObject, userId);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- log.info(String.format("来自客户端消息:%s 客户端的id是:%s", message, session.getId()));
|
|
|
|
|
String cityId = jsonObject.getString("cityId");
|
|
String cityId = jsonObject.getString("cityId");
|
|
|
String regionId = jsonObject.getString("regionId");
|
|
String regionId = jsonObject.getString("regionId");
|
|
|
String key = cityId.concat(":").concat(regionId);
|
|
String key = cityId.concat(":").concat(regionId);
|
|
|
- List<String> otherUserIds = remove(key, userId);
|
|
|
|
|
|
|
+ List<String> otherUserIds = websocketHandle.allUserIdExcept(key, userId);
|
|
|
MetaMMOLoginInfo metaMMOLoginInfo;
|
|
MetaMMOLoginInfo metaMMOLoginInfo;
|
|
|
List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(otherUserIds);
|
|
List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(otherUserIds);
|
|
|
switch (type) {
|
|
switch (type) {
|
|
|
case 1:
|
|
case 1:
|
|
|
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)) {
|
|
|
|
|
- if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
|
|
|
|
|
- // 分发区域内其他玩家信息给自己
|
|
|
|
|
- buildMessageForSendingToUser(Constants.REDIS_PREFIX.concat(userId), 1, metaMMOLoginInfos);
|
|
|
|
|
- // 分发自己信息给区域内其他玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 4, metaMMOLoginInfo);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // 将自己信息存到redis中
|
|
|
|
|
- redisTemplate.opsForValue().set(Constants.REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
|
|
- redisTemplate.opsForList().leftPush(Constants.REDIS_PREFIX.concat(key), Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
|
|
+ metaMMOLoginInfo = websocketHandle.buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId), userId);
|
|
|
|
|
+ websocketHandle.handleTypeOne(clients, otherUserIds, metaMMOLoginInfos, metaMMOLoginInfo, userId, key);
|
|
|
break;
|
|
break;
|
|
|
case 2:
|
|
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)) {
|
|
|
|
|
- // 分发自己信息给区域内其他玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 4, metaMMOLoginInfo);
|
|
|
|
|
- // 分发区域内其他玩家信息给自己
|
|
|
|
|
- buildMessageForSendingToUser(Constants.REDIS_PREFIX.concat(userId), 1, metaMMOLoginInfos);
|
|
|
|
|
- }
|
|
|
|
|
- MetaMMOLoginInfo oldMetaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- if (Objects.isNull(oldMetaMMOLoginInfo)) {
|
|
|
|
|
- log.error("缺失玩家上次区域的地图缓存信息");
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- String oldKey = String.valueOf(oldMetaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(oldMetaMMOLoginInfo.getRegionId()));
|
|
|
|
|
- List<String> oldUserIds = redisTemplate.opsForList().range(Constants.REDIS_PREFIX.concat(oldKey), 0, -1);
|
|
|
|
|
- if (CollectionUtils.isEmpty(oldUserIds)) {
|
|
|
|
|
- log.error("查询不到上次所进入的区域的玩家信息");
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- // 分发消息给之前区域的玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(oldUserIds, 3, oldMetaMMOLoginInfo);
|
|
|
|
|
- // 清除玩家上次缓存的地图信息
|
|
|
|
|
- redisTemplate.opsForList().remove(Constants.REDIS_PREFIX.concat(oldKey), 0, Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- // 缓存玩家新的地图信息
|
|
|
|
|
- redisTemplate.opsForValue().set(Constants.REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
|
|
- redisTemplate.opsForList().leftPush(Constants.REDIS_PREFIX.concat(key), Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
|
|
+ metaMMOLoginInfo = websocketHandle.buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId), userId);
|
|
|
|
|
+ websocketHandle.handleTypeTwo(clients, otherUserIds, metaMMOLoginInfos, metaMMOLoginInfo, userId, key);
|
|
|
break;
|
|
break;
|
|
|
case 3:
|
|
case 3:
|
|
|
log.info(String.format("当前操作类型为: %s -> 玩家在地图内移动", type));
|
|
log.info(String.format("当前操作类型为: %s -> 玩家在地图内移动", type));
|
|
|
metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
|
|
- log.error("缓存中不存在本玩家信息");
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- // 更新玩家位置信息
|
|
|
|
|
- buildCommonProperty(metaMMOLoginInfo, jsonObject);
|
|
|
|
|
- // 分发玩家信息给区域内其他玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 2, metaMMOLoginInfo);
|
|
|
|
|
- redisTemplate.opsForValue().set(Constants.REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
|
|
|
|
+ websocketHandle.handleTypeThree(clients, otherUserIds, jsonObject, metaMMOLoginInfo, userId);
|
|
|
break;
|
|
break;
|
|
|
case 4:
|
|
case 4:
|
|
|
log.info(String.format("当前操作类型为: %s -> 玩家进入大厅", type));
|
|
log.info(String.format("当前操作类型为: %s -> 玩家进入大厅", type));
|
|
|
metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(Constants.REDIS_PREFIX.concat(userId));
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
|
|
- log.error("缓存中不存在本玩家信息");
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- // 分发玩家信息给区域内其他玩家
|
|
|
|
|
- buildMessageForSendingToAllOther(otherUserIds, 3, metaMMOLoginInfo);
|
|
|
|
|
- // 更新库中玩家位置信息
|
|
|
|
|
- MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElse(null);
|
|
|
|
|
- if (Objects.isNull(dbMetaMMOLoginInfo)) {
|
|
|
|
|
- log.error(String.format("数据库不存在id: %s 的记录", metaMMOLoginInfo.getId()));
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- dbMetaMMOLoginInfo.setAxisX(metaMMOLoginInfo.getAxisX());
|
|
|
|
|
- dbMetaMMOLoginInfo.setAxisY(metaMMOLoginInfo.getAxisY());
|
|
|
|
|
- dbMetaMMOLoginInfo.setAxisZ(metaMMOLoginInfo.getAxisZ());
|
|
|
|
|
- dbMetaMMOLoginInfo.setEulerX(metaMMOLoginInfo.getEulerX());
|
|
|
|
|
- dbMetaMMOLoginInfo.setEulerY(metaMMOLoginInfo.getEulerY());
|
|
|
|
|
- dbMetaMMOLoginInfo.setEulerZ(metaMMOLoginInfo.getEulerZ());
|
|
|
|
|
- dbMetaMMOLoginInfo.setCityId(metaMMOLoginInfo.getCityId());
|
|
|
|
|
- dbMetaMMOLoginInfo.setRegionId(metaMMOLoginInfo.getRegionId());
|
|
|
|
|
- dbMetaMMOLoginInfo.setTop(metaMMOLoginInfo.getTop());
|
|
|
|
|
- dbMetaMMOLoginInfo.setHat(metaMMOLoginInfo.getHat());
|
|
|
|
|
- dbMetaMMOLoginInfo.setShoes(metaMMOLoginInfo.getShoes());
|
|
|
|
|
- dbMetaMMOLoginInfo.setDown(metaMMOLoginInfo.getDown());
|
|
|
|
|
- dbMetaMMOLoginInfo.setJewelry(metaMMOLoginInfo.getJewelry());
|
|
|
|
|
- dbMetaMMOLoginInfo.setEmoji(metaMMOLoginInfo.getEmoji());
|
|
|
|
|
- dbMetaMMOLoginInfo.setAnim(metaMMOLoginInfo.getAnim());
|
|
|
|
|
- dbMetaMMOLoginInfo.setRole(metaMMOLoginInfo.getRole());
|
|
|
|
|
- dbMetaMMOLoginInfo.setMoveType(metaMMOLoginInfo.getMoveType());
|
|
|
|
|
- dbMetaMMOLoginInfo.setTurnedId(metaMMOLoginInfo.getTurnedId());
|
|
|
|
|
- dbMetaMMOLoginInfo.setVehicleId(metaMMOLoginInfo.getVehicleId());
|
|
|
|
|
- metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
|
|
|
|
+ websocketHandle.handleTypeFour(clients, otherUserIds, metaMMOLoginInfo);
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
|
log.error(String.format("不存在的操作类型: %s", type));
|
|
log.error(String.format("不存在的操作类型: %s", type));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 分发玩家信息给区域内其他玩家
|
|
|
|
|
- *
|
|
|
|
|
- * @param userIds 玩家id集合
|
|
|
|
|
- * @param messageType 消息类型
|
|
|
|
|
- * @param data 消息体
|
|
|
|
|
- */
|
|
|
|
|
- private void buildMessageForSendingToAllOther(List<String> userIds, int messageType, Object data) {
|
|
|
|
|
- MMOMessage mmoMessage = new MMOMessage();
|
|
|
|
|
- mmoMessage.setMessageType(messageType);
|
|
|
|
|
- mmoMessage.setMessage(data);
|
|
|
|
|
- // 进行类型转换和判断
|
|
|
|
|
- if (data instanceof MetaMMOLoginInfo) {
|
|
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) data;
|
|
|
|
|
- if (!clients.containsKey(Constants.REDIS_PREFIX.concat(String.valueOf(metaMMOLoginInfo.getUserId())))) {
|
|
|
|
|
- log.error("session信息不存在");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- userIds.forEach(id -> {
|
|
|
|
|
- try {
|
|
|
|
|
- if (!clients.containsKey(id)) {
|
|
|
|
|
- log.error("session信息不存在");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- 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));
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 分发区域内其他玩家信息给自己
|
|
|
|
|
- *
|
|
|
|
|
- * @param userId 玩家id
|
|
|
|
|
- * @param messageType 消息类型
|
|
|
|
|
- * @param metaMMOLoginInfos 消息体(其他玩家信息)
|
|
|
|
|
- */
|
|
|
|
|
- private void buildMessageForSendingToUser(String userId, int messageType, List<MetaMMOLoginInfo> metaMMOLoginInfos) {
|
|
|
|
|
- MMOMessage mmoMessage = new MMOMessage();
|
|
|
|
|
- mmoMessage.setMessageType(messageType);
|
|
|
|
|
- mmoMessage.setMap(metaMMOLoginInfos);
|
|
|
|
|
- websocketCommon.sendMessageTo(clients, JSON.toJSONString(mmoMessage), userId);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 构建玩家登陆信息
|
|
|
|
|
- *
|
|
|
|
|
- * @param jsonObject 玩家位置等信息json对象
|
|
|
|
|
- * @param cityId 城市id
|
|
|
|
|
- * @param regionId 区域id
|
|
|
|
|
- * @return 玩家位置信息
|
|
|
|
|
- */
|
|
|
|
|
- private MetaMMOLoginInfo buildMetaMMOLoginInfo(JSONObject jsonObject, Long cityId, Long regionId, String nickName, String userId) {
|
|
|
|
|
- // 获取到进入地图时自己的信息
|
|
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = new MetaMMOLoginInfo();
|
|
|
|
|
- buildCommonProperty(metaMMOLoginInfo, jsonObject);
|
|
|
|
|
- metaMMOLoginInfo.setCityId(cityId);
|
|
|
|
|
- metaMMOLoginInfo.setRegionId(regionId);
|
|
|
|
|
- metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
|
|
|
- metaMMOLoginInfo.setNickname(nickName);
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("role"))) {
|
|
|
|
|
- metaMMOLoginInfo.setRole(jsonObject.getString("role"));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("id"))) {
|
|
|
|
|
- metaMMOLoginInfo.setId(Long.parseLong(jsonObject.getString("id")));
|
|
|
|
|
- }
|
|
|
|
|
- metaMMOLoginInfo.setCityId(cityId);
|
|
|
|
|
- return metaMMOLoginInfo;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 根据jsonObject构建玩家位置信息
|
|
|
|
|
- *
|
|
|
|
|
- * @param metaMMOLoginInfo 玩家登陆信息
|
|
|
|
|
- * @param jsonObject 玩家位置信息json对象
|
|
|
|
|
- */
|
|
|
|
|
- private void buildCommonProperty(MetaMMOLoginInfo metaMMOLoginInfo, JSONObject jsonObject) {
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("axisX"))) {
|
|
|
|
|
- metaMMOLoginInfo.setAxisX(Float.parseFloat(jsonObject.getString("axisX")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("axisY"))) {
|
|
|
|
|
- metaMMOLoginInfo.setAxisY(Float.parseFloat(jsonObject.getString("axisY")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("axisZ"))) {
|
|
|
|
|
- metaMMOLoginInfo.setAxisZ(Float.parseFloat(jsonObject.getString("axisZ")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("eulerX"))) {
|
|
|
|
|
- metaMMOLoginInfo.setEulerX(Float.parseFloat(jsonObject.getString("eulerX")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("eulerY"))) {
|
|
|
|
|
- metaMMOLoginInfo.setEulerY(Float.parseFloat(jsonObject.getString("eulerY")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("eulerZ"))) {
|
|
|
|
|
- metaMMOLoginInfo.setEulerZ(Float.parseFloat(jsonObject.getString("eulerZ")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("top"))) {
|
|
|
|
|
- metaMMOLoginInfo.setTop(Integer.parseInt(jsonObject.getString("top")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("hat"))) {
|
|
|
|
|
- metaMMOLoginInfo.setHat(Integer.parseInt(jsonObject.getString("hat")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("down"))) {
|
|
|
|
|
- metaMMOLoginInfo.setDown(Integer.parseInt(jsonObject.getString("down")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("shoes"))) {
|
|
|
|
|
- metaMMOLoginInfo.setShoes(Integer.parseInt(jsonObject.getString("shoes")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("jewelry"))) {
|
|
|
|
|
- metaMMOLoginInfo.setJewelry(Integer.parseInt(jsonObject.getString("jewelry")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("anim"))) {
|
|
|
|
|
- metaMMOLoginInfo.setAnim(Integer.parseInt(jsonObject.getString("anim")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("emoji"))) {
|
|
|
|
|
- metaMMOLoginInfo.setEmoji(Integer.parseInt(jsonObject.getString("emoji")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("moveType"))) {
|
|
|
|
|
- metaMMOLoginInfo.setMoveType(MoveType.valueOf(jsonObject.getString("moveType")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("vehicleId"))) {
|
|
|
|
|
- metaMMOLoginInfo.setVehicleId(Long.parseLong(jsonObject.getString("vehicleId")));
|
|
|
|
|
- }
|
|
|
|
|
- if (Objects.nonNull(jsonObject.getString("turnedId"))) {
|
|
|
|
|
- metaMMOLoginInfo.setTurnedId(Long.parseLong(jsonObject.getString("turnedId")));
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -468,16 +256,6 @@ public class MMOWebSocket {
|
|
|
return MetaServiceResult.returnSuccess("check success");
|
|
return MetaServiceResult.returnSuccess("check success");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private List<String> remove(String key, String userId) {
|
|
|
|
|
- List<String> userIds = redisTemplate.opsForList().range(Constants.REDIS_PREFIX.concat(key), 0, -1);
|
|
|
|
|
- // 去除当前玩家id
|
|
|
|
|
- List<String> otherUserIds = new ArrayList<>();
|
|
|
|
|
- if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
|
|
- otherUserIds = userIds.stream().filter(id -> !Objects.equals(id, Constants.REDIS_PREFIX.concat(userId))).collect(Collectors.toList());
|
|
|
|
|
- }
|
|
|
|
|
- return otherUserIds;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
public MetaRestResult<Void> clearMMO(String userId, String regionId, String cityId) {
|
|
public MetaRestResult<Void> clearMMO(String userId, String regionId, String cityId) {
|
|
|
init();
|
|
init();
|
|
|
if (clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
|
|
if (clients.containsKey(Constants.REDIS_PREFIX.concat(userId))) {
|
|
@@ -486,8 +264,22 @@ public class MMOWebSocket {
|
|
|
return MetaRestResult.returnError(errMsg);
|
|
return MetaRestResult.returnError(errMsg);
|
|
|
}
|
|
}
|
|
|
String key = cityId.concat(":").concat(regionId);
|
|
String key = cityId.concat(":").concat(regionId);
|
|
|
- redisTemplate.delete(Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
- redisTemplate.opsForList().remove(Constants.REDIS_PREFIX.concat(key), 0, Constants.REDIS_PREFIX.concat(userId));
|
|
|
|
|
|
|
+ closeExecute(key, userId);
|
|
|
return MetaRestResult.returnSuccess("清除成功");
|
|
return MetaRestResult.returnSuccess("清除成功");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private void closeExecute(String key, String userId) {
|
|
|
|
|
+ String userKey = Constants.REDIS_PREFIX.concat(userId);
|
|
|
|
|
+ redisTemplate.execute(new SessionCallback<>() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Object execute(@NotNull RedisOperations operations) throws DataAccessException {
|
|
|
|
|
+ operations.multi();
|
|
|
|
|
+ redisTemplate.delete(userKey);
|
|
|
|
|
+ redisTemplate.opsForList().remove(Constants.REDIS_PREFIX.concat(key), 0, userKey);
|
|
|
|
|
+ redisTemplate.delete(Constants.REDIS_USER_KEY.concat(userId));
|
|
|
|
|
+ return operations.exec();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|