CatchTheLettersBackend/src/main/java/com/example/catchTheLetters/service/impl/RoomServiceImpl.java

242 lines
8.7 KiB
Java
Raw Normal View History

2024-06-14 10:51:41 +00:00
package com.example.catchTheLetters.service.impl;
import com.example.catchTheLetters.entity.*;
import com.example.catchTheLetters.enums.MessageType;
2024-06-14 15:58:52 +00:00
import com.example.catchTheLetters.enums.RoomActionType;
2024-06-14 10:51:41 +00:00
import com.example.catchTheLetters.enums.RoomStatus;
import com.example.catchTheLetters.model.vo.Letter;
import com.example.catchTheLetters.service.AuthService;
import com.example.catchTheLetters.service.RoomService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
2024-06-14 15:58:52 +00:00
/**
* 房间服务实现类
*
* @author spyn
*/
2024-06-14 10:51:41 +00:00
@Service
public class RoomServiceImpl implements RoomService {
// 房间列表
private final ConcurrentHashMap<Long, GameRoom> rooms = new ConcurrentHashMap<>();
2024-06-14 15:58:52 +00:00
// 玩家列表
private final ConcurrentHashMap<String, WebSocketSession> playerInGame = new ConcurrentHashMap<>();
2024-06-14 10:51:41 +00:00
private final ObjectMapper objectMapper = new ObjectMapper();
private final Random random = new Random();
@Resource
private MongoTemplate mongoTemplate;
@Resource
private AuthService authService;
@Override
public void addPlayer(long roomId, WebSocketSession session, String token) {
var room = rooms.get(roomId);
var players = room.getPlayers();
var user = authService.verify(token);
var player = new PlayerInGame(user.getId(), user);
// 如果玩家已经在房间中更新他们的WebSocketSession
for (var entry : players.entrySet()) {
if (entry.getValue().getUserId().equals(user.getId())) {
player = entry.getValue();
players.remove(entry.getKey());
break;
}
}
players.put(session, player);
// TODO 发送消息通知其他玩家有人加入了
}
@Override
public void removePlayer(long roomId, WebSocketSession session) {
var room = rooms.get(roomId);
var players = room.getPlayers();
players.remove(session);
// 如果是房主退出,更换房主,否则关闭房间
if (session == room.getHost()) {
if (!players.isEmpty()) {
room.setHost(players.keySet().iterator().next());
} else {
rooms.remove(roomId);
}
}
// TODO 发送消息通知其他玩家有人退出了
}
2024-06-14 15:58:52 +00:00
@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;
}
}
}
2024-06-14 10:51:41 +00:00
@Override
public void startGame(long roomId, WebSocketSession session) {
var room = rooms.get(roomId);
var players = room.getPlayers();
var readyPlayers = room.getReadyPlayers();
readyPlayers.add(session);
// TODO 发送消息通知其他玩家有人准备好了
// 如果所有玩家都准备好了,开始游戏
if (readyPlayers.size() == room.getPlayers().size()) {
// TODO 发送消息通知所有玩家游戏开始
readyPlayers.clear();
room.setStatus(RoomStatus.PLAYING);
gameLogic(room);
}
}
@Override
public void cancelStartGame(long roomId, WebSocketSession session) {
var room = rooms.get(roomId);
var readyPlayers = room.getReadyPlayers();
readyPlayers.remove(session);
// TODO 发送消息通知其他玩家有人取消准备
}
@Override
public void endGame(long roomId) {
var room = rooms.get(roomId);
room.setStatus(RoomStatus.WAITING);
// TODO 发送消息通知所有玩家游戏结束
}
@Override
public void handleInput(long roomId, WebSocketSession session, PlayerInput input) {
var message = new GameMessage<>(MessageType.INPUT, input);
var room = rooms.get(roomId);
var players = room.getPlayers();
for (var player : players.keySet())
if (player != session) sendMessage(player, message);
}
@Override
public void createRoom(WebSocketSession session, String token) {
var user = authService.verify(token);
var player = new PlayerInGame(user.getId(), user);
var room = new GameRoom(session, player);
rooms.put(room.getRoomId(), room);
}
@Override
public void removeRoom(long roomId) {
// 如果房间内还有玩家,全部移除
var room = rooms.get(roomId);
var players = room.getPlayers();
for (var player : players.keySet()) {
// TODO 发送消息通知所有玩家房间已解散
}
rooms.remove(roomId);
}
2024-06-14 15:58:52 +00:00
@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);
}
}
2024-06-14 10:51:41 +00:00
private void generateLetter(GameRoom room) {
var players = room.getPlayers();
var words = room.getWords();
// 如果words长度<=5从数据库中再获取一批随机单词
if (words.size() <= 5) getWords(words);
Letter letter;
var val = random.nextInt(100);
// 在80%概率当前单词的字母中随机选择一个19%随机生成一个字母1%是回血爱心。选定后随机赋值2f到6f的下落速度
if (val == 0)
// 回血爱心
letter = new Letter("10", random.nextFloat(1), random.nextFloat(2, 6));
2024-06-14 10:52:39 +00:00
else if (val <= 81)
2024-06-14 10:51:41 +00:00
// 从当前单词中随机选择一个字母
letter = new Letter(words.keySet().toArray()[random.nextInt(words.size())].toString(), random.nextFloat(1), random.nextFloat(2, 6));
else
// 随机生成一个字母
letter = new Letter(String.valueOf((char) (random.nextInt(26) + 'a')), random.nextFloat(1), random.nextFloat(2, 6));
// 给所有玩家发送字母
for (var player : players.keySet())
sendMessage(player, new GameMessage<>(MessageType.LETTER, letter));
}
private void getWords(Map<String, Integer> words) {
// TODO 从数据库中获取一批随机单词然后放入words中并把单词数组推送给所有玩家
}
private void gameLogic(GameRoom room) {
getWords(room.getWords());
// TODO 从300秒开始倒计时每秒调用一次generateLetter方法如果时间到了调用endGame方法如果当前单词被某玩家拼完Map对应单词的value++如果value>=玩家数(有可能中途有人退出),目前单词出队列,继续下一个单词
}
}