|
|
@@ -5,9 +5,11 @@ import com.alibaba.fastjson.JSONObject;
|
|
|
import com.izouma.nineth.domain.MetaMMOLoginInfo;
|
|
|
import com.izouma.nineth.dto.MMOMessage;
|
|
|
import com.izouma.nineth.dto.MMOSingleMessage;
|
|
|
+import com.izouma.nineth.dto.MetaServiceResult;
|
|
|
import com.izouma.nineth.exception.BusinessException;
|
|
|
import com.izouma.nineth.repo.MetaMMOLoginInfoRepo;
|
|
|
import com.izouma.nineth.utils.ApplicationContextUtil;
|
|
|
+import com.izouma.nineth.utils.ObjUtils;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
@@ -19,7 +21,10 @@ import javax.websocket.server.PathParam;
|
|
|
import javax.websocket.server.ServerEndpoint;
|
|
|
import java.io.IOException;
|
|
|
import java.time.LocalDateTime;
|
|
|
-import java.util.*;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -31,118 +36,45 @@ public class WebSocket {
|
|
|
/**
|
|
|
* 当前在线的客户端map
|
|
|
*/
|
|
|
- private static Map<String, WebSocket> clients = new ConcurrentHashMap();
|
|
|
+ private static final Map<String, Session> clients = new ConcurrentHashMap();
|
|
|
|
|
|
- /**
|
|
|
- * session
|
|
|
- */
|
|
|
- private Session session;
|
|
|
-
|
|
|
- /**
|
|
|
- * 用户id
|
|
|
- */
|
|
|
- private String userId;
|
|
|
-
|
|
|
- /**
|
|
|
- * uuid
|
|
|
- */
|
|
|
- private String uuid;
|
|
|
-
|
|
|
- /**
|
|
|
- * key
|
|
|
- */
|
|
|
- private String key;
|
|
|
-
|
|
|
- /**
|
|
|
- * cityId
|
|
|
- */
|
|
|
- private Long cityId;
|
|
|
-
|
|
|
- /**
|
|
|
- * 区域id
|
|
|
- */
|
|
|
- private Long regionId;
|
|
|
-
|
|
|
- private RedisTemplate redisTemplate;
|
|
|
-
|
|
|
- Session getSession() {
|
|
|
- return this.session;
|
|
|
- }
|
|
|
+ private final String REDIS_PREFIX = "meta:";
|
|
|
|
|
|
- private MetaMMOLoginInfoRepo metaMMOLoginInfoRepo;
|
|
|
+ private final RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
|
|
|
|
|
|
- public void init() {
|
|
|
- if (this.metaMMOLoginInfoRepo == null) {
|
|
|
- metaMMOLoginInfoRepo = (MetaMMOLoginInfoRepo) ApplicationContextUtil.getBean("metaMMOLoginInfoRepo");
|
|
|
- }
|
|
|
- if (this.redisTemplate == null) {
|
|
|
- redisTemplate = (RedisTemplate) ApplicationContextUtil.getBean("redisTemplate");
|
|
|
- }
|
|
|
- }
|
|
|
+ private final MetaMMOLoginInfoRepo metaMMOLoginInfoRepo = (MetaMMOLoginInfoRepo) ApplicationContextUtil.getBean("metaMMOLoginInfoRepo");
|
|
|
|
|
|
@OnOpen
|
|
|
public void onOpen(@PathParam("nickName") String nickName, @PathParam("userId") String userId, Session session) {
|
|
|
- init();
|
|
|
try {
|
|
|
- // 判断当前玩家是否在线
|
|
|
- if (clients.containsKey(userId)) {
|
|
|
- WebSocket webSocket = clients.get(userId);
|
|
|
- // 关闭当前的链接
|
|
|
+ // 判断当前玩家是否在其他地方登陆
|
|
|
+ if (clients.containsKey(REDIS_PREFIX.concat(userId))) {
|
|
|
+ log.info(String.format("当前玩家[%S]已经在别处登陆,sessionId为[%S]", userId, session.getId()));
|
|
|
+ WebSocket webSocket = new WebSocket();
|
|
|
+ // 关闭连接
|
|
|
MMOSingleMessage mmoSingleMessage = new MMOSingleMessage();
|
|
|
mmoSingleMessage.setMessageType(6);
|
|
|
mmoSingleMessage.setMessage("您已在其他地方登录");
|
|
|
- webSocket.sendMessageTo(JSON.toJSONString(mmoSingleMessage), userId);
|
|
|
- try {
|
|
|
- webSocket.getSession().close();
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("close session error", e);
|
|
|
- }
|
|
|
- }
|
|
|
- // 获取上次登录的信息
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = metaMMOLoginInfoRepo.findLastByUserId(Long.parseLong(userId));
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
- // 首次登陆 初始化玩家信息
|
|
|
- metaMMOLoginInfo = new MetaMMOLoginInfo();
|
|
|
- metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
|
- metaMMOLoginInfo.setNickname(nickName);
|
|
|
- metaMMOLoginInfo.setRegionId(0L);
|
|
|
- metaMMOLoginInfo.setCityId(0L);
|
|
|
- metaMMOLoginInfo.setAxisX(0F);
|
|
|
- metaMMOLoginInfo.setAxisY(0F);
|
|
|
- metaMMOLoginInfo.setAxisZ(0F);
|
|
|
- metaMMOLoginInfo.setEulerX(0F);
|
|
|
- metaMMOLoginInfo.setEulerY(0F);
|
|
|
- metaMMOLoginInfo.setEulerZ(0F);
|
|
|
+ webSocket.sendMessageTo(JSON.toJSONString(mmoSingleMessage), REDIS_PREFIX.concat(userId));
|
|
|
+ log.info("关闭当前session连接");
|
|
|
+ session.close();
|
|
|
}
|
|
|
log.info("现在来连接的sessionId:" + session.getId() + "玩家id:" + userId + "玩家昵称" + nickName);
|
|
|
- this.userId = userId;
|
|
|
- this.session = session;
|
|
|
- // 生成缓存key 规则 --> cityId:regionId
|
|
|
- this.key = String.valueOf(metaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(metaMMOLoginInfo.getRegionId()));
|
|
|
- this.cityId = metaMMOLoginInfo.getCityId();
|
|
|
- this.regionId = metaMMOLoginInfo.getRegionId();
|
|
|
- // 玩家信息存入websocket
|
|
|
- clients.put(userId, this);
|
|
|
+ clients.put(REDIS_PREFIX.concat(userId), session);
|
|
|
+ // 获取上次登录的信息
|
|
|
+ MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findLastByUserId(Long.parseLong(userId));
|
|
|
+ // 玩家登陆信息入库
|
|
|
+ MetaMMOLoginInfo metaMMOLoginInfo = MetaMMOLoginInfo.initMetaMMOLoginInfo(dbMetaMMOLoginInfo);
|
|
|
+ metaMMOLoginInfo.setNickname(nickName);
|
|
|
+ metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
|
+ metaMMOLoginInfo.setOnLineTime(LocalDateTime.now());
|
|
|
+ metaMMOLoginInfo.setSessionId(session.getId());
|
|
|
+ MetaMMOLoginInfo save = metaMMOLoginInfoRepo.save(metaMMOLoginInfo);
|
|
|
MMOMessage mmoMessage = new MMOMessage();
|
|
|
mmoMessage.setMessageType(5);
|
|
|
- mmoMessage.setMessage(metaMMOLoginInfo);
|
|
|
- sendMessageTo(JSON.toJSONString(mmoMessage), userId);
|
|
|
- this.uuid = UUID.randomUUID().toString();
|
|
|
- // 玩家信息入库
|
|
|
- MetaMMOLoginInfo newMetaMMOLoginInfo = new MetaMMOLoginInfo();
|
|
|
- newMetaMMOLoginInfo.setNickname(metaMMOLoginInfo.getNickname());
|
|
|
- newMetaMMOLoginInfo.setUserId(metaMMOLoginInfo.getUserId());
|
|
|
- newMetaMMOLoginInfo.setCityId(metaMMOLoginInfo.getCityId());
|
|
|
- newMetaMMOLoginInfo.setRegionId(metaMMOLoginInfo.getRegionId());
|
|
|
- newMetaMMOLoginInfo.setAxisX(metaMMOLoginInfo.getAxisX());
|
|
|
- newMetaMMOLoginInfo.setAxisY(metaMMOLoginInfo.getAxisY());
|
|
|
- newMetaMMOLoginInfo.setAxisZ(metaMMOLoginInfo.getAxisZ());
|
|
|
- newMetaMMOLoginInfo.setEulerX(metaMMOLoginInfo.getEulerX());
|
|
|
- newMetaMMOLoginInfo.setEulerY(metaMMOLoginInfo.getEulerY());
|
|
|
- newMetaMMOLoginInfo.setEulerZ(metaMMOLoginInfo.getEulerZ());
|
|
|
- newMetaMMOLoginInfo.setOnLineTime(LocalDateTime.now());
|
|
|
- newMetaMMOLoginInfo.setUUID(uuid);
|
|
|
- metaMMOLoginInfoRepo.save(newMetaMMOLoginInfo);
|
|
|
+ mmoMessage.setMessage(save);
|
|
|
+ log.info(String.format("通知玩家[%S],本次登陆信息[%S]", userId, JSON.toJSONString(mmoMessage)));
|
|
|
+ sendMessageTo(JSON.toJSONString(mmoMessage), REDIS_PREFIX.concat(userId));
|
|
|
} catch (Exception e) {
|
|
|
String errMsg = String.format("[%S]上线的时候发生了错误,错误信息[%S]", userId, e.getMessage());
|
|
|
log.error(errMsg, e);
|
|
|
@@ -153,164 +85,155 @@ public class WebSocket {
|
|
|
@OnError
|
|
|
public void onError(Session session, Throwable error) {
|
|
|
// 异常处理
|
|
|
- log.info(String.format("服务端发生了错误:[%S]", error.getMessage()));
|
|
|
+ log.error(String.format("sessionId[%S]的服务端发生了错误:[%S]", session.getId(), error.getMessage()));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@OnClose
|
|
|
- public void onClose() {
|
|
|
- init();
|
|
|
+ public void onClose(@PathParam("userId") String userId) {
|
|
|
// 查询地图中玩家信息
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(this.userId);
|
|
|
+ MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(REDIS_PREFIX.concat(userId));
|
|
|
if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
- // 如果缓存中玩家信息为空,根据UUID查询数据库
|
|
|
- MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findByUUID(uuid);
|
|
|
+ // 如果缓存中玩家信息为空,根据userId和sessionId查询数据库
|
|
|
+ MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findByUserIdAndSessionIdAndDel(Long.parseLong(userId), clients.get(userId).getId(), false);
|
|
|
dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
|
// 更新离线时间
|
|
|
metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
- clients.remove(userId);
|
|
|
+ clients.remove(REDIS_PREFIX.concat(userId));
|
|
|
return;
|
|
|
}
|
|
|
String key = String.valueOf(metaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(metaMMOLoginInfo.getRegionId()));
|
|
|
- List<String> userIds = redisTemplate.opsForList().range(key, 0, -1);
|
|
|
- // 分发下线消息给区域内其他玩家
|
|
|
- buildMessageForSendingToAllOther(userIds, 3, metaMMOLoginInfo);
|
|
|
- MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findLastByUserId(metaMMOLoginInfo.getUserId());
|
|
|
+ List<String> otherUserIds = remove(key, userId);
|
|
|
+ if(CollectionUtils.isNotEmpty(otherUserIds)) {
|
|
|
+ // 分发下线消息给区域内其他玩家
|
|
|
+ buildMessageForSendingToAllOther(otherUserIds, 3, metaMMOLoginInfo);
|
|
|
+ }
|
|
|
+ MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElseThrow(new BusinessException(String.format("数据库不存在id[%S]的记录", metaMMOLoginInfo.getId())));
|
|
|
+ ObjUtils.merge(dbMetaMMOLoginInfo, metaMMOLoginInfo);
|
|
|
dbMetaMMOLoginInfo.setOffLineTime(LocalDateTime.now());
|
|
|
metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
- clients.remove(userId);
|
|
|
+ clients.remove(REDIS_PREFIX.concat(userId));
|
|
|
// 删除redis中自己的信息
|
|
|
- redisTemplate.delete(userId);
|
|
|
+ redisTemplate.delete(REDIS_PREFIX.concat(userId));
|
|
|
// 移除地图中自己的信息
|
|
|
- redisTemplate.opsForList().remove(key, 0, userId);
|
|
|
+ redisTemplate.opsForList().remove(REDIS_PREFIX.concat(key), 0, REDIS_PREFIX.concat(userId));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
@OnMessage
|
|
|
- public void onMessage(String message, Session session) {
|
|
|
- init();
|
|
|
- log.info("来自客户端消息:" + message + "客户端的id是:" + session.getId());
|
|
|
+ public void onMessage(@PathParam("nickName") String nickName, @PathParam("userId") String userId, String message, Session session) {
|
|
|
if (StringUtils.isBlank(message)) {
|
|
|
- log.info("message is null");
|
|
|
- return;
|
|
|
- }
|
|
|
- JSONObject jsonObject = JSON.parseObject(message);
|
|
|
- if (Objects.isNull(jsonObject.getString("type"))) {
|
|
|
- String errMsg = "操作类型为空";
|
|
|
- log.error(errMsg);
|
|
|
- throw new BusinessException(errMsg);
|
|
|
- }
|
|
|
- if (Objects.isNull(jsonObject.getString("cityId"))) {
|
|
|
- String errMsg = "cityId为空";
|
|
|
+ String errMsg = "Illegal parameter : message can not be null";
|
|
|
log.error(errMsg);
|
|
|
throw new BusinessException(errMsg);
|
|
|
}
|
|
|
- if (Objects.isNull(jsonObject.getString("regionId"))) {
|
|
|
- String errMsg = "regionId为空";
|
|
|
- log.error(errMsg);
|
|
|
- throw new BusinessException(errMsg);
|
|
|
+ JSONObject jsonObject = JSON.parseObject(message);
|
|
|
+ MetaServiceResult result = checkParams(jsonObject);
|
|
|
+ if (!result.isSuccess()) {
|
|
|
+ log.error(result.getMessage());
|
|
|
+ throw new BusinessException(result.getMessage());
|
|
|
}
|
|
|
+ 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> userIds = redisTemplate.opsForList().range(key, 0, -1);
|
|
|
- // 进入地图 把自己位置信息通知别人,获取其他人的位置信息
|
|
|
- if (type == 1) {
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId));
|
|
|
- // 判断地图中是否存在玩家
|
|
|
- if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
- List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(userIds);
|
|
|
- if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
|
|
|
- // 过滤自己
|
|
|
- metaMMOLoginInfos = remove(metaMMOLoginInfos);
|
|
|
+ List<String> otherUserIds = remove(key, userId);
|
|
|
+ MetaMMOLoginInfo metaMMOLoginInfo;
|
|
|
+ List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(otherUserIds);
|
|
|
+ switch (type) {
|
|
|
+ case 1:
|
|
|
+ log.info("当前操作类型为1 -> 玩家进入地图");
|
|
|
+ metaMMOLoginInfo = buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId), nickName, userId);
|
|
|
+ if (CollectionUtils.isNotEmpty(otherUserIds)) {
|
|
|
if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
|
|
|
// 分发区域内其他玩家信息给自己
|
|
|
- buildMessageForSendingToUser(userId, 1, metaMMOLoginInfos);
|
|
|
+ buildMessageForSendingToUser(REDIS_PREFIX.concat(userId), 1, metaMMOLoginInfos);
|
|
|
// 分发自己信息给区域内其他玩家
|
|
|
- buildMessageForSendingToAllOther(userIds, 4, metaMMOLoginInfo);
|
|
|
+ buildMessageForSendingToAllOther(otherUserIds, 4, metaMMOLoginInfo);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- // 将自己信息存到redis中
|
|
|
- redisTemplate.opsForValue().set(userId, metaMMOLoginInfo);
|
|
|
- redisTemplate.opsForList().leftPush(key, userId);
|
|
|
- }
|
|
|
- // 如果是区域直接切换区域
|
|
|
- if (type == 2) {
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = buildMetaMMOLoginInfo(jsonObject, Long.parseLong(cityId), Long.parseLong(regionId));
|
|
|
- if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
+ // 将自己信息存到redis中
|
|
|
+ redisTemplate.opsForValue().set(REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
+ redisTemplate.opsForList().leftPush(REDIS_PREFIX.concat(key), REDIS_PREFIX.concat(userId));
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ 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(REDIS_PREFIX.concat(userId), 1, metaMMOLoginInfos);
|
|
|
+ }
|
|
|
+ MetaMMOLoginInfo oldMetaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(REDIS_PREFIX.concat(userId));
|
|
|
+ if (Objects.isNull(oldMetaMMOLoginInfo)) {
|
|
|
+ String errMsg = "缺失玩家上次区域的地图缓存信息";
|
|
|
+ log.error(errMsg);
|
|
|
+ throw new BusinessException(errMsg);
|
|
|
+ }
|
|
|
+ String oldKey = String.valueOf(oldMetaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(oldMetaMMOLoginInfo.getRegionId()));
|
|
|
+ List<String> oldUserIds = redisTemplate.opsForList().range(REDIS_PREFIX.concat(oldKey), 0, -1);
|
|
|
+ if (CollectionUtils.isEmpty(oldUserIds)) {
|
|
|
+ String errMsg = "查询不到上次所进入的区域的玩家信息";
|
|
|
+ log.error(errMsg);
|
|
|
+ throw new BusinessException(errMsg);
|
|
|
+ }
|
|
|
+ // 分发消息给之前区域的玩家
|
|
|
+ buildMessageForSendingToAllOther(oldUserIds, 3, oldMetaMMOLoginInfo);
|
|
|
+ // 清除玩家上次缓存的地图信息
|
|
|
+ redisTemplate.opsForList().remove(REDIS_PREFIX.concat(oldKey), 0, REDIS_PREFIX.concat(userId));
|
|
|
+ // 缓存玩家新的地图信息
|
|
|
+ redisTemplate.opsForValue().set(REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
+ redisTemplate.opsForList().leftPush(REDIS_PREFIX.concat(key), REDIS_PREFIX.concat(userId));
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ log.info(String.format("当前操作类型为[%S] -> 玩家在地图内移动", type));
|
|
|
+ metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(REDIS_PREFIX.concat(userId));
|
|
|
+ if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
+ String errMsg = "缓存中不存在本玩家信息";
|
|
|
+ log.error(errMsg);
|
|
|
+ throw new BusinessException(errMsg);
|
|
|
+ }
|
|
|
+ // 更新玩家位置信息
|
|
|
+ buildCommonProperty(metaMMOLoginInfo, jsonObject);
|
|
|
// 分发玩家信息给区域内其他玩家
|
|
|
- buildMessageForSendingToAllOther(userIds, 4, metaMMOLoginInfo);
|
|
|
- // 分发区域内其他玩家信息给自己
|
|
|
- List<MetaMMOLoginInfo> metaMMOLoginInfos = redisTemplate.opsForValue().multiGet(userIds);
|
|
|
- if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
|
|
|
- // 过滤自己
|
|
|
- metaMMOLoginInfos = remove(metaMMOLoginInfos);
|
|
|
- if (CollectionUtils.isNotEmpty(metaMMOLoginInfos)) {
|
|
|
- buildMessageForSendingToUser(userId, 1, metaMMOLoginInfos);
|
|
|
- }
|
|
|
+ buildMessageForSendingToAllOther(otherUserIds, 2, metaMMOLoginInfo);
|
|
|
+ redisTemplate.opsForValue().set(REDIS_PREFIX.concat(userId), metaMMOLoginInfo);
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ log.info(String.format("当前操作类型为[%S] -> 玩家进入大厅", type));
|
|
|
+ metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(REDIS_PREFIX.concat(userId));
|
|
|
+ if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
+ String errMsg = "缓存中不存在本玩家信息";
|
|
|
+ log.error(errMsg);
|
|
|
+ throw new BusinessException(errMsg);
|
|
|
}
|
|
|
- }
|
|
|
- // 分发玩家信息给之前区域内其他玩家
|
|
|
- MetaMMOLoginInfo oldMetaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(userId);
|
|
|
- if (Objects.isNull(oldMetaMMOLoginInfo)) {
|
|
|
- String errMsg = "缺失玩家上次区域的地图缓存信息";
|
|
|
- log.error(errMsg);
|
|
|
- throw new BusinessException(errMsg);
|
|
|
- }
|
|
|
- String oldKey = String.valueOf(oldMetaMMOLoginInfo.getCityId()).concat(":").concat(String.valueOf(oldMetaMMOLoginInfo.getRegionId()));
|
|
|
- List<String> oldUserIds = redisTemplate.opsForList().range(oldKey, 0, -1);
|
|
|
- if (CollectionUtils.isEmpty(oldUserIds)) {
|
|
|
- String errMsg = "查询不到上次所进入的区域的玩家信息";
|
|
|
- log.error(errMsg);
|
|
|
- throw new BusinessException(errMsg);
|
|
|
- }
|
|
|
- // 分发消息给之前区域的玩家
|
|
|
- buildMessageForSendingToAllOther(oldUserIds, 3, oldMetaMMOLoginInfo);
|
|
|
- // 清除玩家上次缓存的地图信息
|
|
|
- redisTemplate.opsForList().remove(oldKey, 0, userId);
|
|
|
- // 缓存玩家新的地图信息
|
|
|
- redisTemplate.opsForValue().set(userId, metaMMOLoginInfo);
|
|
|
- redisTemplate.opsForList().leftPush(key, userId);
|
|
|
- }
|
|
|
- // 玩家在地图内移动
|
|
|
- if (type == 3) {
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(userId);
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
- String errMsg = "缓存中不存在本玩家信息";
|
|
|
- log.error(errMsg);
|
|
|
- throw new BusinessException(errMsg);
|
|
|
- }
|
|
|
- // 分发玩家信息给区域内其他玩家
|
|
|
- buildMessageForSendingToAllOther(userIds, 2, metaMMOLoginInfo);
|
|
|
- // 更新缓存中玩家位置信息
|
|
|
- buildMetaMMOLoginInfo(metaMMOLoginInfo, jsonObject);
|
|
|
- redisTemplate.opsForValue().set(userId, metaMMOLoginInfo);
|
|
|
- }
|
|
|
- // 进入大厅
|
|
|
- if (type == 4) {
|
|
|
- MetaMMOLoginInfo metaMMOLoginInfo = (MetaMMOLoginInfo) redisTemplate.opsForValue().get(userId);
|
|
|
- if (Objects.isNull(metaMMOLoginInfo)) {
|
|
|
- String errMsg = "缓存中不存在本玩家信息";
|
|
|
+ // 分发玩家信息给区域内其他玩家
|
|
|
+ buildMessageForSendingToAllOther(otherUserIds, 3, metaMMOLoginInfo);
|
|
|
+ // 更新库中玩家位置信息
|
|
|
+ MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findById(metaMMOLoginInfo.getId()).orElseThrow(new BusinessException(String.format("数据库不存在id[%S]的记录", metaMMOLoginInfo.getId())));
|
|
|
+ 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.setEmoji(metaMMOLoginInfo.getEmoji());
|
|
|
+ dbMetaMMOLoginInfo.setAnim(metaMMOLoginInfo.getAnim());
|
|
|
+ dbMetaMMOLoginInfo.setRole(metaMMOLoginInfo.getRole());
|
|
|
+ metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ String errMsg = String.format("不存在的操作类型[%S]", type);
|
|
|
log.error(errMsg);
|
|
|
throw new BusinessException(errMsg);
|
|
|
- }
|
|
|
- // 分发玩家信息给区域内其他玩家
|
|
|
- buildMessageForSendingToAllOther(userIds, 3, metaMMOLoginInfo);
|
|
|
- // 更新库中玩家位置信息
|
|
|
- MetaMMOLoginInfo dbMetaMMOLoginInfo = metaMMOLoginInfoRepo.findByUUID(uuid);
|
|
|
- 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());
|
|
|
- metaMMOLoginInfoRepo.save(dbMetaMMOLoginInfo);
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -324,7 +247,17 @@ public class WebSocket {
|
|
|
MMOMessage mmoMessage = new MMOMessage();
|
|
|
mmoMessage.setMessageType(messageType);
|
|
|
mmoMessage.setMessage(metaMMOLoginInfo);
|
|
|
- sendMessageAllOther(userIds, JSON.toJSONString(mmoMessage));
|
|
|
+ if (!clients.containsKey(REDIS_PREFIX.concat(String.valueOf(metaMMOLoginInfo.getUserId())))) {
|
|
|
+ throw new BusinessException("session信息不存在");
|
|
|
+ }
|
|
|
+ userIds.forEach(id -> {
|
|
|
+ try {
|
|
|
+ log.info(String.format("服务器给所有当前区域内在线用户发送消息,当前在线人员为[%S]。消息:[%S]", id, JSON.toJSONString(mmoMessage)));
|
|
|
+ clients.get(id).getBasicRemote().sendText(JSON.toJSONString(mmoMessage));
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -341,17 +274,6 @@ public class WebSocket {
|
|
|
sendMessageTo(JSON.toJSONString(mmoMessage), userId);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 移除自己信息
|
|
|
- *
|
|
|
- * @param metaMMOLoginInfos 信息集合
|
|
|
- * @return 非自己信息集合
|
|
|
- */
|
|
|
- private List<MetaMMOLoginInfo> remove(List<MetaMMOLoginInfo> metaMMOLoginInfos) {
|
|
|
- return metaMMOLoginInfos.stream()
|
|
|
- .filter(mmoLoginInfo -> !Objects.equals(mmoLoginInfo.getUserId(), userId)).collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 给指定用户分发消息
|
|
|
*
|
|
|
@@ -359,70 +281,50 @@ public class WebSocket {
|
|
|
* @param toUserId 用户id
|
|
|
*/
|
|
|
public void sendMessageTo(String message, String toUserId) {
|
|
|
- clients.values().forEach(webSocket -> {
|
|
|
- if (webSocket.userId.equals(toUserId)) {
|
|
|
- log.info(String.format("给指定的在线用户发送消息,当前在线人员为[%S]。消息:[%S]", webSocket.userId.toString(), message));
|
|
|
- try {
|
|
|
- webSocket.session.getBasicRemote().sendText(message);
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("sendMessageTo error", e);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 分发下线消息给当前城市当前区域中其他玩家
|
|
|
- *
|
|
|
- * @param userIds 其他玩家id集合
|
|
|
- * @param message 消息体
|
|
|
- */
|
|
|
- public void sendMessageAllOther(List<String> userIds, String message) {
|
|
|
- clients.values().forEach(webSocket -> {
|
|
|
- if (!Objects.equals(webSocket.userId, userId) && userIds.contains(webSocket.userId)) {
|
|
|
- log.info(String.format("服务器给所有当前区域内在线用户发送消息,当前在线人员为[%S]。消息:[%S]", webSocket.userId.toString(), message));
|
|
|
- try {
|
|
|
- webSocket.session.getBasicRemote().sendText(message);
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("sendMessageAllOther error", e);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
+ if (!clients.containsKey(toUserId)) {
|
|
|
+ throw new BusinessException("session信息不存在");
|
|
|
+ }
|
|
|
+ log.info(String.format("给指定的在线用户发送消息,当前在线人员为[%S]。消息:[%S]", toUserId, message));
|
|
|
+ try {
|
|
|
+ clients.get(toUserId).getBasicRemote().sendText(message);
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 分发消息给所有玩家
|
|
|
+ * 构建玩家登陆信息
|
|
|
*
|
|
|
- * @param message 消息体
|
|
|
+ * @param jsonObject 玩家位置等信息json对象
|
|
|
+ * @param cityId 城市id
|
|
|
+ * @param regionId 区域id
|
|
|
+ * @return 玩家位置信息
|
|
|
*/
|
|
|
- public void sendMessageAll(String message) {
|
|
|
- clients.values().forEach(webSocket -> {
|
|
|
- log.info(String.format("服务器给所有当前区域内在线用户发送消息,当前在线人员为[%S]。消息:[%S]", webSocket.userId.toString(), message));
|
|
|
- try {
|
|
|
- webSocket.session.getBasicRemote().sendText(message);
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("sendMessageAll error", e);
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- private MetaMMOLoginInfo buildMetaMMOLoginInfo(JSONObject jsonObject, Long cityId, Long regionId) {
|
|
|
- // 拿到自己进入地图市时的信息通知给其他人,获取当前区域内其他玩家信息
|
|
|
- String role = jsonObject.getString("role");
|
|
|
+ private MetaMMOLoginInfo buildMetaMMOLoginInfo(JSONObject jsonObject, Long cityId, Long regionId, String nickName, String userId) {
|
|
|
// 获取到进入地图时自己的信息
|
|
|
MetaMMOLoginInfo metaMMOLoginInfo = new MetaMMOLoginInfo();
|
|
|
- buildMetaMMOLoginInfo(metaMMOLoginInfo, jsonObject);
|
|
|
- metaMMOLoginInfo.setUserId(Long.parseLong(userId));
|
|
|
+ buildCommonProperty(metaMMOLoginInfo, jsonObject);
|
|
|
metaMMOLoginInfo.setCityId(cityId);
|
|
|
metaMMOLoginInfo.setRegionId(regionId);
|
|
|
- if (StringUtils.isNotBlank(role)) {
|
|
|
- metaMMOLoginInfo.setRole(role);
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
- private void buildMetaMMOLoginInfo(MetaMMOLoginInfo metaMMOLoginInfo, JSONObject jsonObject) {
|
|
|
+ /**
|
|
|
+ * 根据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")));
|
|
|
}
|
|
|
@@ -441,8 +343,58 @@ public class WebSocket {
|
|
|
if (Objects.nonNull(jsonObject.getString("eulerZ"))) {
|
|
|
metaMMOLoginInfo.setEulerZ(Float.parseFloat(jsonObject.getString("eulerZ")));
|
|
|
}
|
|
|
- if (Objects.nonNull(jsonObject.getString("nickName"))) {
|
|
|
- metaMMOLoginInfo.setNickname(jsonObject.getString("nickName"));
|
|
|
+ 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("anim"))) {
|
|
|
+ metaMMOLoginInfo.setAnim(Integer.parseInt(jsonObject.getString("anim")));
|
|
|
+ }
|
|
|
+ if (Objects.nonNull(jsonObject.getString("emoji"))) {
|
|
|
+ metaMMOLoginInfo.setEmoji(Integer.parseInt(jsonObject.getString("emoji")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验参数
|
|
|
+ *
|
|
|
+ * @param jsonObject 参数
|
|
|
+ * @return 校验结果
|
|
|
+ */
|
|
|
+ private MetaServiceResult checkParams(JSONObject jsonObject) {
|
|
|
+ if (Objects.isNull(jsonObject)) {
|
|
|
+ return MetaServiceResult.returnError("Illegal parameter : jsonObject can not be null");
|
|
|
+ }
|
|
|
+ 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");
|
|
|
+ }
|
|
|
+ if (Objects.isNull(jsonObject.getString("id"))) {
|
|
|
+ return MetaServiceResult.returnError("Illegal parameter : id can not be null");
|
|
|
+ }
|
|
|
+ return MetaServiceResult.returnSuccess("check success");
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<String> remove(String key, String userId) {
|
|
|
+ List<String> userIds = redisTemplate.opsForList().range(REDIS_PREFIX.concat(key), 0, -1);
|
|
|
+ // 去除当前玩家id
|
|
|
+ List<String> otherUserIds = new ArrayList<>();
|
|
|
+ if (CollectionUtils.isNotEmpty(userIds)) {
|
|
|
+ otherUserIds = userIds.stream().filter(id -> !Objects.equals(id, REDIS_PREFIX.concat(userId))).collect(Collectors.toList());
|
|
|
}
|
|
|
+ return otherUserIds;
|
|
|
}
|
|
|
}
|