房间系统
概述
房间系统是灾难玩法的核心框架,负责管理游戏房间的创建、玩家加入/退出、游戏流程控制等。每个房间是一个独立的游戏实例,拥有自己的世界、玩家集合和游戏状态。
核心类
RoomManager(房间管理器)
路径:cn.enderrealm.disaster.room.RoomManager
房间管理器是全局单例,负责管理所有房间实例。
java
public class RoomManager {
private final disaster plugin;
private final Map<String, Room> rooms; // 房间ID -> 房间实例
private final Map<Room, GameManager> gameManagers; // 房间 -> 游戏管理器
private String roomPrefix; // 房间世界前缀
private int nextRoomId; // 下一个房间ID
}主要职责
房间生命周期管理
- 创建新房间(复制地图模板)
- 查找可用房间
- 清理空房间
- 卸载和删除房间世界
地图模板管理
- 从
plugins/disaster/worlds/目录加载地图模板 - 随机选择地图
- 复制世界文件
- 从
游戏管理器关联
- 注册房间与游戏管理器的关联
- 获取房间的游戏管理器
核心方法
java
// 创建新房间
public Room createRoom() {
// 1. 从 worlds 目录获取地图模板
File worldsFolder = new File(plugin.getDataFolder(), "worlds");
File[] mapFolders = worldsFolder.listFiles(File::isDirectory);
// 2. 随机选择一个地图模板
File mapFolder = mapFolders[(int) (Math.random() * mapFolders.length)];
// 3. 创建新的世界名称
String worldName = roomPrefix + nextRoomId++;
// 4. 复制地图文件并加载世界
copyWorldFiles(mapFolder, serverWorldFolder);
World world = new WorldCreator(worldName).createWorld();
// 5. 创建房间实例
return new Room(plugin, world, waitingLocation, mapFolder);
}
// 查找可用房间
public Room getAvailableRoom() {
for (Room room : rooms.values()) {
if (!room.isFull() && room.isWaiting() && !room.isStarted()) {
return room;
}
}
return null;
}
// 加入房间
public void joinRoom(Player player) {
Room room = getAvailableRoom();
if (room == null) {
room = createRoom();
}
if (room != null) {
room.addPlayer(player);
}
}Room(房间类)
路径:cn.enderrealm.disaster.room.Room
房间类代表一个游戏房间实例,管理房间内的玩家和游戏状态。
java
public class Room {
private final World world; // 房间世界
private final Set<Player> players; // 房间内玩家
private Location waitingLocation; // 等待位置
private final disaster plugin; // 插件实例
private boolean isWait; // 是否等待中
private boolean isStart; // 是否已开始
private int minPlayers; // 最小玩家数
private int maxPlayers; // 最大玩家数
private int countdownTime; // 倒计时时间
private BukkitTask countdownTask; // 倒计时任务
private String mapName; // 地图名称
private File mapFolder; // 地图文件夹
}房间状态
| 状态 | 描述 |
|---|---|
isWait = true, isStart = false | 等待玩家加入 |
isWait = false, isStart = true | 游戏进行中 |
isWait = false, isStart = false | 游戏已结束 |
玩家管理
java
// 玩家加入房间
public void addPlayer(Player player) {
players.add(player);
player.teleport(waitingLocation);
// 清空玩家背包
player.getInventory().clear();
// 添加恢复效果
player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 30, 2, false, false));
// 添加退出物品(粘液球)
ItemStack quitItem = new ItemStack(Material.SLIME_BALL);
player.getInventory().setItem(8, quitItem);
// 显示房间信息
showRoomInfo(player);
// 广播加入消息
for (Player p : players) {
p.sendMessage(plugin.getLanguageManager().getText("player-join-message", p,
player.getName(), String.valueOf(players.size()), String.valueOf(maxPlayers)));
}
// 检查是否达到最小玩家数
checkAndStartCountdown();
}
// 玩家离开房间
public void removePlayer(Player player) {
players.remove(player);
// 广播离开消息
for (Player p : players) {
p.sendMessage(plugin.getLanguageManager().getText("player-leave-message", p,
player.getName(), String.valueOf(players.size()), String.valueOf(maxPlayers)));
}
}倒计时系统
java
private void startCountdown() {
final int[] timeLeft = {countdownTime};
countdownTask = new BukkitRunnable() {
@Override
public void run() {
// 检查玩家数量是否足够
if (players.size() < minPlayers) {
cancel();
countdownTask = null;
for (Player p : players) {
p.sendMessage(plugin.getLanguageManager().getText("countdown-cancelled", p));
}
return;
}
// 倒计时结束,开始游戏
if (timeLeft[0] <= 0) {
cancel();
countdownTask = null;
startGame();
return;
}
// 显示倒计时
for (Player p : players) {
p.sendTitle("", plugin.getLanguageManager().getText("countdown-subtitle", p,
String.valueOf(timeLeft[0])), 0, 20, 10);
// 最后5秒显示主标题并播放音效
if (timeLeft[0] <= 5) {
String titleColor = timeLeft[0] <= 3 ? "§c" : "§a";
p.sendTitle(titleColor + timeLeft[0], "", 0, 20, 10);
p.playSound(p.getLocation(), "ui.button.click", 1.0f, 1.0f);
}
}
timeLeft[0]--;
}
}.runTaskTimer(plugin, 20L, 20L); // 每秒执行一次
}游戏开始
java
private void startGame() {
isWait = false;
isStart = true;
// 取消 ActionBar 任务
if (roomInfoTask != null) {
roomInfoTask.cancel();
roomInfoTask = null;
}
// 清空玩家背包
for (Player p : players) {
p.getInventory().clear();
p.sendMessage(plugin.getLanguageManager().getText("game-started", p));
}
// 创建游戏管理器并开始游戏
GameManager gameManager = new GameManager(plugin, world, players, mapName, mapFolder);
plugin.getRoomManager().registerGameManager(this, gameManager);
gameManager.startGame();
}地图配置
地图文件结构
plugins/disaster/worlds/
├── map_name_1/
│ ├── config.yml # 地图配置
│ ├── region/ # 地图区域文件
│ └── ... # 其他世界文件
├── map_name_2/
│ ├── config.yml
│ └── ...配置文件格式
yaml
# 地图名称
name: "Map Name"
# 等待大厅位置
waiting-lobby:
x: 0.0
y: 65.0
z: 0.0
yaw: 0.0
pitch: 0.0
# 出生点列表
spawn-points:
- x: 10.0
y: 65.0
z: 10.0
yaw: 0.0
pitch: 0.0
- x: -10.0
y: 65.0
z: -10.0
yaw: 180.0
pitch: 0.0
# 地图范围(用于灾难生成)
map-scope:
point1:
x: -50.0
y: 0.0
z: -50.0
point2:
x: 50.0
y: 255.0
z: 50.0ActionBar 显示
房间系统使用 ActionBar 显示房间信息,每秒更新一次:
java
private void showRoomInfo(Player player) {
String mapInfo = plugin.getLanguageManager().getText("room-info", player,
mapName, String.valueOf(players.size()), String.valueOf(maxPlayers));
if (isWait) {
// 常驻显示 ActionBar
roomInfoTask = new BukkitRunnable() {
@Override
public void run() {
for (Player p : players) {
p.spigot().sendMessage(net.md_5.bungee.api.ChatMessageType.ACTION_BAR,
net.md_5.bungee.api.chat.TextComponent.fromLegacyText(
plugin.getLanguageManager().getText("room-info", p,
mapName, String.valueOf(players.size()), String.valueOf(maxPlayers))));
}
}
}.runTaskTimer(plugin, 0L, 20L);
}
}