完善联机框架
This commit is contained in:
parent
6cd918d669
commit
87cd436846
|
@ -1,6 +1,8 @@
|
||||||
package com.example.catchTheLetters.entity;
|
package com.example.catchTheLetters.entity;
|
||||||
|
|
||||||
import com.example.catchTheLetters.enums.MessageType;
|
import com.example.catchTheLetters.enums.MessageType;
|
||||||
|
import com.example.catchTheLetters.utils.GameMessageDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -8,11 +10,12 @@ import java.io.Serializable;
|
||||||
/**
|
/**
|
||||||
* 游戏消息
|
* 游戏消息
|
||||||
*
|
*
|
||||||
* @auther spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@JsonDeserialize(using = GameMessageDeserializer.class)
|
||||||
public class GameMessage<T> implements Serializable {
|
public class GameMessage<T> implements Serializable {
|
||||||
private String roomId;
|
private long roomId;
|
||||||
private MessageType type;
|
private MessageType type;
|
||||||
private T data;
|
private T data;
|
||||||
|
|
||||||
|
@ -21,9 +24,12 @@ public class GameMessage<T> implements Serializable {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameMessage(String roomId, MessageType type, T data) {
|
public GameMessage(long roomId, MessageType type, T data) {
|
||||||
this.roomId = roomId;
|
this.roomId = roomId;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameMessage() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.example.catchTheLetters.entity;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.enums.HealthActionType;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 血量操作
|
||||||
|
*
|
||||||
|
* @auther spyn
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class HealthAction implements Serializable {
|
||||||
|
private HealthActionType type;
|
||||||
|
private int health;
|
||||||
|
private String userId;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.example.catchTheLetters.entity;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.enums.LetterActionType;
|
||||||
|
import com.example.catchTheLetters.model.vo.Letter;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字母操作
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class LetterAction implements Serializable {
|
||||||
|
private LetterActionType type;
|
||||||
|
private Letter letter;
|
||||||
|
private String userId;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import java.io.Serializable;
|
||||||
/**
|
/**
|
||||||
* 游戏中的玩家
|
* 游戏中的玩家
|
||||||
*
|
*
|
||||||
* @auther spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class PlayerInGame implements Serializable {
|
public class PlayerInGame implements Serializable {
|
||||||
|
|
|
@ -15,4 +15,7 @@ public class PlayerInput implements Serializable {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlayerInput() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.catchTheLetters.entity;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.enums.RoomActionType;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class RoomAction implements Serializable {
|
||||||
|
private RoomActionType type;
|
||||||
|
// 创建或加入房间时的token
|
||||||
|
private String token;
|
||||||
|
// 房主踢出玩家时或被邀请的玩家ID
|
||||||
|
private String userID;
|
||||||
|
private long roomID;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.example.catchTheLetters.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分数操作
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ScoreAction implements Serializable {
|
||||||
|
private String userId;
|
||||||
|
private int score;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.example.catchTheLetters.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 血量操作类型
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
public enum HealthActionType {
|
||||||
|
CHANGE,
|
||||||
|
DEAD
|
||||||
|
}
|
|
@ -1,21 +1,13 @@
|
||||||
package com.example.catchTheLetters.enums;
|
package com.example.catchTheLetters.enums;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入类型
|
* 输入类型
|
||||||
*
|
*
|
||||||
* @author spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
@Getter
|
|
||||||
public enum InputKeyType {
|
public enum InputKeyType {
|
||||||
LEFT("left"),
|
LEFT,
|
||||||
RIGHT("right"),
|
RIGHT,
|
||||||
SHIFT("shift");
|
SHIFT,
|
||||||
|
SPACE
|
||||||
private final String key;
|
|
||||||
|
|
||||||
InputKeyType(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,11 @@
|
||||||
package com.example.catchTheLetters.enums;
|
package com.example.catchTheLetters.enums;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输入状态
|
* 输入状态
|
||||||
*
|
*
|
||||||
* @author spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
@Getter
|
|
||||||
public enum InputState {
|
public enum InputState {
|
||||||
PRESS("press"),
|
PRESS,
|
||||||
RELEASE("release");
|
RELEASE
|
||||||
|
|
||||||
private final String state;
|
|
||||||
|
|
||||||
InputState(String state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.example.catchTheLetters.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字母操作类型
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
public enum LetterActionType {
|
||||||
|
CREATE,
|
||||||
|
GET
|
||||||
|
}
|
|
@ -3,18 +3,13 @@ package com.example.catchTheLetters.enums;
|
||||||
/**
|
/**
|
||||||
* WebSocket 消息类型
|
* WebSocket 消息类型
|
||||||
*
|
*
|
||||||
* @auther spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
public enum MessageType {
|
public enum MessageType {
|
||||||
INPUT("input"),
|
INPUT,
|
||||||
ROOM("room"),
|
ROOM,
|
||||||
LETTER("letter"),
|
LETTER,
|
||||||
SCORE("score"),
|
SCORE,
|
||||||
HEALTH("health");
|
HEALTH,
|
||||||
|
ERROR
|
||||||
private final String type;
|
|
||||||
|
|
||||||
MessageType(String type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.example.catchTheLetters.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 房间操作
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
public enum RoomActionType {
|
||||||
|
CREATE,
|
||||||
|
JOIN,
|
||||||
|
KICK,
|
||||||
|
LEAVE,
|
||||||
|
START,
|
||||||
|
INVITE
|
||||||
|
}
|
|
@ -6,12 +6,6 @@ package com.example.catchTheLetters.enums;
|
||||||
* @author spyn
|
* @author spyn
|
||||||
*/
|
*/
|
||||||
public enum RoomStatus {
|
public enum RoomStatus {
|
||||||
WAITING("waiting"),
|
WAITING,
|
||||||
PLAYING("playing");
|
PLAYING
|
||||||
|
|
||||||
private final String status;
|
|
||||||
|
|
||||||
RoomStatus(String status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
package com.example.catchTheLetters.handler;
|
package com.example.catchTheLetters.handler;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.entity.GameMessage;
|
||||||
|
import com.example.catchTheLetters.entity.PlayerInput;
|
||||||
|
import com.example.catchTheLetters.enums.MessageType;
|
||||||
|
import com.example.catchTheLetters.service.RoomService;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.socket.TextMessage;
|
import org.springframework.web.socket.TextMessage;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebSocket 处理器
|
* WebSocket 处理器
|
||||||
*
|
*
|
||||||
|
@ -13,8 +23,41 @@ import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
@Controller
|
@Controller
|
||||||
public class WebSocketHandler extends TextWebSocketHandler {
|
public class WebSocketHandler extends TextWebSocketHandler {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RoomService roomService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTextMessage(WebSocketSession session, TextMessage message) {
|
public void handleTextMessage(@NotNull WebSocketSession session, TextMessage message) {
|
||||||
// 处理接收到的消息
|
// 处理接收到的消息
|
||||||
|
GameMessage<?> gameMessage;
|
||||||
|
try {
|
||||||
|
gameMessage = objectMapper.readValue(message.getPayload(), GameMessage.class);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
roomService.sendMessage(session, new GameMessage<>(MessageType.ERROR, "消息解析失败"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (gameMessage.getType()) {
|
||||||
|
case INPUT:
|
||||||
|
// 处理输入消息
|
||||||
|
roomService.handleInput(gameMessage.getRoomId(), session, (PlayerInput) gameMessage.getData());
|
||||||
|
break;
|
||||||
|
case ROOM:
|
||||||
|
// 处理房间消息
|
||||||
|
break;
|
||||||
|
case LETTER:
|
||||||
|
// 处理字母消息
|
||||||
|
break;
|
||||||
|
case SCORE:
|
||||||
|
// 处理分数消息
|
||||||
|
break;
|
||||||
|
case HEALTH:
|
||||||
|
// 处理生命值消息
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
roomService.sendMessage(session, new GameMessage<>(MessageType.ERROR, "未知的消息类型"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,14 @@ public interface RoomService {
|
||||||
*/
|
*/
|
||||||
void removePlayer(long roomId, WebSocketSession session);
|
void removePlayer(long roomId, WebSocketSession session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 踢出玩家
|
||||||
|
* @param roomId 房间号
|
||||||
|
* @param session 房主的 WebSocket 会话
|
||||||
|
* @param playerID 要踢出的玩家 ID
|
||||||
|
*/
|
||||||
|
void kickPlayer(long roomId, WebSocketSession session, String playerID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始游戏
|
* 开始游戏
|
||||||
* @param roomId 房间号
|
* @param roomId 房间号
|
||||||
|
@ -64,4 +72,33 @@ public interface RoomService {
|
||||||
* @param roomId 房间号
|
* @param roomId 房间号
|
||||||
*/
|
*/
|
||||||
void removeRoom(long roomId);
|
void removeRoom(long roomId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邀请玩家
|
||||||
|
* @param roomId 房间号
|
||||||
|
* @param session WebSocket 会话
|
||||||
|
* @param playerID 被邀请的玩家ID
|
||||||
|
*/
|
||||||
|
void invitePlayer(long roomId, WebSocketSession session, String playerID);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接ws
|
||||||
|
* @param session WebSocket 会话
|
||||||
|
* @param token 玩家 token
|
||||||
|
*/
|
||||||
|
void connect(WebSocketSession session, String token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开ws
|
||||||
|
* @param token 玩家 token
|
||||||
|
*/
|
||||||
|
void disconnect(String token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
* @param session WebSocket 会话
|
||||||
|
* @param message 消息
|
||||||
|
* @param <T> 消息类型
|
||||||
|
*/
|
||||||
|
<T> void sendMessage(WebSocketSession session, T message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.example.catchTheLetters.service.impl;
|
||||||
|
|
||||||
import com.example.catchTheLetters.entity.*;
|
import com.example.catchTheLetters.entity.*;
|
||||||
import com.example.catchTheLetters.enums.MessageType;
|
import com.example.catchTheLetters.enums.MessageType;
|
||||||
|
import com.example.catchTheLetters.enums.RoomActionType;
|
||||||
import com.example.catchTheLetters.enums.RoomStatus;
|
import com.example.catchTheLetters.enums.RoomStatus;
|
||||||
import com.example.catchTheLetters.model.vo.Letter;
|
import com.example.catchTheLetters.model.vo.Letter;
|
||||||
import com.example.catchTheLetters.service.AuthService;
|
import com.example.catchTheLetters.service.AuthService;
|
||||||
|
@ -18,12 +19,20 @@ import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 房间服务实现类
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class RoomServiceImpl implements RoomService {
|
public class RoomServiceImpl implements RoomService {
|
||||||
|
|
||||||
// 房间列表
|
// 房间列表
|
||||||
private final ConcurrentHashMap<Long, GameRoom> rooms = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<Long, GameRoom> rooms = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// 玩家列表
|
||||||
|
private final ConcurrentHashMap<String, WebSocketSession> playerInGame = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
@ -70,6 +79,24 @@ public class RoomServiceImpl implements RoomService {
|
||||||
// TODO 发送消息通知其他玩家有人退出了
|
// TODO 发送消息通知其他玩家有人退出了
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void kickPlayer(long roomId, WebSocketSession session, String playerID) {
|
||||||
|
var room = rooms.get(roomId);
|
||||||
|
// 如果不是房主,返回错误信息
|
||||||
|
if (session != room.getHost()) {
|
||||||
|
sendMessage(session, new GameMessage<>(MessageType.ERROR, "你不是房主"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var players = room.getPlayers();
|
||||||
|
for (var player : players.entrySet()) {
|
||||||
|
if (player.getValue().getUserId().equals(playerID)) {
|
||||||
|
players.remove(player.getKey());
|
||||||
|
// TODO 发送消息通知有玩家被踢出了
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startGame(long roomId, WebSocketSession session) {
|
public void startGame(long roomId, WebSocketSession session) {
|
||||||
var room = rooms.get(roomId);
|
var room = rooms.get(roomId);
|
||||||
|
@ -129,6 +156,53 @@ public class RoomServiceImpl implements RoomService {
|
||||||
rooms.remove(roomId);
|
rooms.remove(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invitePlayer(long roomId, WebSocketSession session, String playerID) {
|
||||||
|
var roomAction = new RoomAction();
|
||||||
|
roomAction.setType(RoomActionType.INVITE);
|
||||||
|
roomAction.setRoomID(roomId);
|
||||||
|
roomAction.setUserID(playerID);
|
||||||
|
var aimSession = playerInGame.get(playerID);
|
||||||
|
|
||||||
|
// 如果玩家在线,发送邀请消息
|
||||||
|
if (aimSession != null) sendMessage(session, new GameMessage<>(MessageType.ROOM, roomAction));
|
||||||
|
else sendMessage(session, new GameMessage<>(MessageType.ERROR, "玩家不在线"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(WebSocketSession session, String token) {
|
||||||
|
var player = authService.verify(token);
|
||||||
|
playerInGame.put(player.getId(), session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(String token) {
|
||||||
|
var player = authService.verify(token);
|
||||||
|
var session = playerInGame.remove(player.getId());
|
||||||
|
try {
|
||||||
|
session.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("关闭WebSocket会话失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void sendMessage(WebSocketSession session, T message) {
|
||||||
|
String json;
|
||||||
|
if (!(message instanceof String)) {
|
||||||
|
try {
|
||||||
|
json = objectMapper.writeValueAsString(message);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("消息转为JSON字符串操作失败", e);
|
||||||
|
}
|
||||||
|
} else json = (String) message;
|
||||||
|
try {
|
||||||
|
session.sendMessage(new TextMessage(json));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("发送消息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void generateLetter(GameRoom room) {
|
private void generateLetter(GameRoom room) {
|
||||||
var players = room.getPlayers();
|
var players = room.getPlayers();
|
||||||
var words = room.getWords();
|
var words = room.getWords();
|
||||||
|
@ -156,22 +230,6 @@ public class RoomServiceImpl implements RoomService {
|
||||||
sendMessage(player, new GameMessage<>(MessageType.LETTER, letter));
|
sendMessage(player, new GameMessage<>(MessageType.LETTER, letter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void sendMessage(WebSocketSession session, T message) {
|
|
||||||
String json;
|
|
||||||
if (!(message instanceof String)) {
|
|
||||||
try {
|
|
||||||
json = objectMapper.writeValueAsString(message);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("消息转为JSON字符串操作失败", e);
|
|
||||||
}
|
|
||||||
} else json = (String) message;
|
|
||||||
try {
|
|
||||||
session.sendMessage(new TextMessage(json));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("发送消息失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getWords(Map<String, Integer> words) {
|
private void getWords(Map<String, Integer> words) {
|
||||||
// TODO 从数据库中获取一批随机单词,然后放入words中,并把单词数组推送给所有玩家
|
// TODO 从数据库中获取一批随机单词,然后放入words中,并把单词数组推送给所有玩家
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.example.catchTheLetters.utils;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.entity.*;
|
||||||
|
import com.example.catchTheLetters.enums.MessageType;
|
||||||
|
import com.fasterxml.jackson.core.JacksonException;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 游戏消息反序列化
|
||||||
|
*
|
||||||
|
* @author spyn
|
||||||
|
*/
|
||||||
|
public class GameMessageDeserializer extends JsonDeserializer<GameMessage<?>> {
|
||||||
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameMessage<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
|
||||||
|
var node = jsonParser.getCodec().readTree(jsonParser);
|
||||||
|
var type = objectMapper.convertValue(node.get("type"), JsonNode.class);
|
||||||
|
var data = objectMapper.convertValue(node.get("data"), JsonNode.class);
|
||||||
|
return switch (type.asText()) {
|
||||||
|
case "INPUT" -> new GameMessage<>(MessageType.INPUT, objectMapper.treeToValue(data, PlayerInput.class));
|
||||||
|
case "ROOM" -> new GameMessage<>(MessageType.ROOM, objectMapper.treeToValue(data, RoomAction.class));
|
||||||
|
case "LETTER" -> new GameMessage<>(MessageType.LETTER, objectMapper.treeToValue(data, LetterAction.class));
|
||||||
|
case "SCORE" -> new GameMessage<>(MessageType.SCORE, objectMapper.treeToValue(data, ScoreAction.class));
|
||||||
|
case "HEALTH" -> new GameMessage<>(MessageType.HEALTH, objectMapper.treeToValue(data, HealthAction.class));
|
||||||
|
default -> throw new IllegalArgumentException("未知的消息类型");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
package com.example.catchTheLetters;
|
package com.example.catchTheLetters;
|
||||||
|
|
||||||
|
import com.example.catchTheLetters.entity.GameMessage;
|
||||||
import com.example.catchTheLetters.entity.PlayerInput;
|
import com.example.catchTheLetters.entity.PlayerInput;
|
||||||
import com.example.catchTheLetters.enums.InputKeyType;
|
import com.example.catchTheLetters.enums.InputKeyType;
|
||||||
import com.example.catchTheLetters.enums.InputState;
|
import com.example.catchTheLetters.enums.InputState;
|
||||||
|
import com.example.catchTheLetters.enums.MessageType;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -13,8 +15,17 @@ class JSONTest {
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contextLoads() throws JsonProcessingException {
|
void enumToJSON() throws JsonProcessingException {
|
||||||
var input = new PlayerInput(InputKeyType.LEFT, InputState.PRESS);
|
var input = new PlayerInput(InputKeyType.LEFT, InputState.PRESS);
|
||||||
System.out.println(objectMapper.writeValueAsString(input));
|
System.out.println(objectMapper.writeValueAsString(new GameMessage<>(MessageType.INPUT, input)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void jsonToEnum() throws JsonProcessingException {
|
||||||
|
var json = "{\"type\":\"INPUT\",\"data\":{\"key\":\"LEFT\",\"state\":\"PRESS\"}}";
|
||||||
|
var message = objectMapper.readValue(json, GameMessage.class);
|
||||||
|
System.out.println(message);
|
||||||
|
System.out.println(message.getType() == MessageType.INPUT);
|
||||||
|
System.out.println(message.getData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue