Complete Stage 1: Core Game Loop
- Add GameState enum (LOBBY, ROLE_ASSIGN, IN_GAME, ENDING) - Add Phase interface with enter/tick/exit/isComplete - Add GameSession with tick-based phase machine - Add GameEventBus for internal events - Add GameManager for session lifecycle - Add all phases: LobbyPhase, RoleAssignPhase, GameplayPhase, EndgamePhase - Add role assignment: RoleAssigner, RoleQueue, SpawnPosition - Add BasePlayer, Survivor, Killer, PlayerState - Add DBDCommand with /dbd join/leave/create/forcestart/stop - Update mdbd.java with GameManager and command registration - Add command definition to paper-plugin.yml - Mark Stage 1 complete in PLAN.md
This commit is contained in:
parent
53f3f6e9da
commit
82ed455cd2
20 changed files with 884 additions and 8 deletions
148
src/main/java/dev/loki/command/DBDCommand.java
Normal file
148
src/main/java/dev/loki/command/DBDCommand.java
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
package dev.loki.command;
|
||||
|
||||
import dev.loki.core.GameManager;
|
||||
import dev.loki.mdbd;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class DBDCommand implements TabExecutor {
|
||||
private final mdbd plugin;
|
||||
private final GameManager gameManager;
|
||||
|
||||
public DBDCommand(mdbd plugin, GameManager gameManager) {
|
||||
this.plugin = plugin;
|
||||
this.gameManager = gameManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 0) {
|
||||
sendUsage(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
String sub = args[0].toLowerCase();
|
||||
return switch (sub) {
|
||||
case "join" -> handleJoin(sender);
|
||||
case "leave" -> handleLeave(sender);
|
||||
case "forcestart" -> handleForceStart(sender);
|
||||
case "create" -> handleCreate(sender);
|
||||
case "stop" -> handleStop(sender);
|
||||
default -> {
|
||||
sendUsage(sender);
|
||||
yield true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean handleJoin(CommandSender sender) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(Component.text("Только игроки!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
if (gameManager.joinGame(player)) {
|
||||
player.sendMessage(Component.text("[DBD] Вы присоединились к игре!", NamedTextColor.GREEN));
|
||||
} else {
|
||||
player.sendMessage(Component.text("[DBD] Не удалось присоединиться", NamedTextColor.RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleLeave(CommandSender sender) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage(Component.text("Только игроки!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
if (gameManager.leaveGame(player)) {
|
||||
player.sendMessage(Component.text("[DBD] Вы покинули игру", NamedTextColor.YELLOW));
|
||||
} else {
|
||||
player.sendMessage(Component.text("[DBD] Вы не в игре", NamedTextColor.RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleForceStart(CommandSender sender) {
|
||||
if (!sender.hasPermission("mdbd.admin")) {
|
||||
sender.sendMessage(Component.text("Нет прав!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
var session = gameManager.getCurrentSession();
|
||||
if (session == null) {
|
||||
sender.sendMessage(Component.text("Нет активной игры!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
var phase = session.getCurrentPhase();
|
||||
if (phase instanceof dev.loki.phase.LobbyPhase lobby) {
|
||||
lobby.forceStart();
|
||||
sender.sendMessage(Component.text("[DBD] Игра форсирована!", NamedTextColor.GREEN));
|
||||
} else {
|
||||
sender.sendMessage(Component.text("Нельзя форсировать сейчас", NamedTextColor.RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleCreate(CommandSender sender) {
|
||||
if (!sender.hasPermission("mdbd.admin")) {
|
||||
sender.sendMessage(Component.text("Нет прав!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
if (gameManager.createGame()) {
|
||||
sender.sendMessage(Component.text("[DBD] Игра создана!", NamedTextColor.GREEN));
|
||||
} else {
|
||||
sender.sendMessage(Component.text("[DBD] Игра уже существует", NamedTextColor.RED));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean handleStop(CommandSender sender) {
|
||||
if (!sender.hasPermission("mdbd.admin")) {
|
||||
sender.sendMessage(Component.text("Нет прав!", NamedTextColor.RED));
|
||||
return true;
|
||||
}
|
||||
gameManager.endGame();
|
||||
sender.sendMessage(Component.text("[DBD] Игра остановлена", NamedTextColor.YELLOW));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendUsage(CommandSender sender) {
|
||||
sender.sendMessage(Component.text("=== DBD Commands ===", NamedTextColor.GOLD));
|
||||
sender.sendMessage(Component.text("/dbd join - присоединиться", NamedTextColor.GRAY));
|
||||
sender.sendMessage(Component.text("/dbd leave - покинуть", NamedTextColor.GRAY));
|
||||
if (sender.hasPermission("mdbd.admin")) {
|
||||
sender.sendMessage(Component.text("/dbd create - создать игру", NamedTextColor.GRAY));
|
||||
sender.sendMessage(Component.text("/dbd forcestart - форс старт", NamedTextColor.GRAY));
|
||||
sender.sendMessage(Component.text("/dbd stop - остановить", NamedTextColor.GRAY));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||
@NotNull String label, @NotNull String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> completions = new ArrayList<>(Arrays.asList("join", "leave"));
|
||||
if (sender.hasPermission("mdbd.admin")) {
|
||||
completions.addAll(Arrays.asList("create", "forcestart", "stop"));
|
||||
}
|
||||
return completions.stream()
|
||||
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
private Object getCurrentPhase() {
|
||||
var session = gameManager.getCurrentSession();
|
||||
return session != null ? session.getState() : null;
|
||||
}
|
||||
}
|
||||
30
src/main/java/dev/loki/core/GameEventBus.java
Normal file
30
src/main/java/dev/loki/core/GameEventBus.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package dev.loki.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class GameEventBus {
|
||||
private final Map<Class<?>, List<Consumer<Object>>> listeners = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> void on(Class<T> eventClass, Consumer<T> listener) {
|
||||
listeners.computeIfAbsent(eventClass, k -> new ArrayList<>())
|
||||
.add((Consumer<Object>) listener);
|
||||
}
|
||||
|
||||
public void emit(Object event) {
|
||||
List<Consumer<Object>> eventListeners = listeners.get(event.getClass());
|
||||
if (eventListeners != null) {
|
||||
for (Consumer<Object> listener : eventListeners) {
|
||||
listener.accept(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
listeners.clear();
|
||||
}
|
||||
}
|
||||
68
src/main/java/dev/loki/core/GameManager.java
Normal file
68
src/main/java/dev/loki/core/GameManager.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package dev.loki.core;
|
||||
|
||||
import dev.loki.mdbd;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GameManager {
|
||||
private final mdbd plugin;
|
||||
private final Map<UUID, GameSession> playerSessions;
|
||||
private GameSession currentSession;
|
||||
|
||||
public GameManager(mdbd plugin) {
|
||||
this.plugin = plugin;
|
||||
this.playerSessions = new HashMap<>();
|
||||
}
|
||||
|
||||
public boolean createGame() {
|
||||
if (currentSession != null) {
|
||||
return false;
|
||||
}
|
||||
currentSession = new GameSession(plugin);
|
||||
currentSession.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean joinGame(Player player) {
|
||||
if (currentSession == null) {
|
||||
return false;
|
||||
}
|
||||
if (playerSessions.containsKey(player.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
playerSessions.put(player.getUniqueId(), currentSession);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean leaveGame(Player player) {
|
||||
GameSession session = playerSessions.remove(player.getUniqueId());
|
||||
if (session != null) {
|
||||
session.removePlayer(player.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void endGame() {
|
||||
if (currentSession != null) {
|
||||
currentSession.stop();
|
||||
currentSession = null;
|
||||
playerSessions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public GameSession getCurrentSession() {
|
||||
return currentSession;
|
||||
}
|
||||
|
||||
public boolean isInGame(UUID uuid) {
|
||||
return playerSessions.containsKey(uuid);
|
||||
}
|
||||
|
||||
public GameSession getPlayerSession(UUID uuid) {
|
||||
return playerSessions.get(uuid);
|
||||
}
|
||||
}
|
||||
128
src/main/java/dev/loki/core/GameSession.java
Normal file
128
src/main/java/dev/loki/core/GameSession.java
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package dev.loki.core;
|
||||
|
||||
import dev.loki.config.GameConfig;
|
||||
import dev.loki.mdbd;
|
||||
import dev.loki.phase.LobbyPhase;
|
||||
import dev.loki.phase.Phase;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class GameSession {
|
||||
private final mdbd plugin;
|
||||
private final GameEventBus eventBus;
|
||||
private final Map<UUID, BasePlayer> players;
|
||||
private Phase currentPhase;
|
||||
private BukkitTask tickTask;
|
||||
private int ticksElapsed;
|
||||
|
||||
public GameSession(mdbd plugin) {
|
||||
this.plugin = plugin;
|
||||
this.eventBus = new GameEventBus();
|
||||
this.players = new HashMap<>();
|
||||
this.ticksElapsed = 0;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
switchPhase(new LobbyPhase(plugin.getConfigManager().getGame()));
|
||||
this.tickTask = Bukkit.getScheduler().runTaskTimer(plugin, this::tick, 1L, 1L);
|
||||
plugin.getLogger().info("Game session started");
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (tickTask != null) {
|
||||
tickTask.cancel();
|
||||
tickTask = null;
|
||||
}
|
||||
if (currentPhase != null) {
|
||||
currentPhase.exit(this);
|
||||
}
|
||||
players.clear();
|
||||
eventBus.clear();
|
||||
plugin.getLogger().info("Game session stopped");
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
ticksElapsed++;
|
||||
if (currentPhase != null) {
|
||||
currentPhase.tick(this);
|
||||
if (currentPhase.isComplete()) {
|
||||
transitionToNextPhase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void transitionToNextPhase() {
|
||||
currentPhase.exit(this);
|
||||
Phase nextPhase = determineNextPhase();
|
||||
if (nextPhase != null) {
|
||||
switchPhase(nextPhase);
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
private Phase determineNextPhase() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void switchPhase(Phase newPhase) {
|
||||
if (currentPhase != null) {
|
||||
currentPhase.exit(this);
|
||||
}
|
||||
currentPhase = newPhase;
|
||||
currentPhase.enter(this);
|
||||
}
|
||||
|
||||
public void addPlayer(BasePlayer player) {
|
||||
players.put(player.getUuid(), player);
|
||||
eventBus.emit(new PlayerJoinEvent(player));
|
||||
}
|
||||
|
||||
public void removePlayer(UUID uuid) {
|
||||
BasePlayer removed = players.remove(uuid);
|
||||
if (removed != null) {
|
||||
eventBus.emit(new PlayerLeaveEvent(removed));
|
||||
}
|
||||
}
|
||||
|
||||
public BasePlayer getPlayer(UUID uuid) {
|
||||
return players.get(uuid);
|
||||
}
|
||||
|
||||
public Map<UUID, BasePlayer> getPlayers() {
|
||||
return new HashMap<>(players);
|
||||
}
|
||||
|
||||
public int getPlayerCount() {
|
||||
return players.size();
|
||||
}
|
||||
|
||||
public GameState getState() {
|
||||
if (currentPhase instanceof LobbyPhase) return GameState.LOBBY;
|
||||
return GameState.IN_GAME;
|
||||
}
|
||||
|
||||
public mdbd getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public GameConfig getConfig() {
|
||||
return plugin.getConfigManager().getGame();
|
||||
}
|
||||
|
||||
public int getTicksElapsed() {
|
||||
return ticksElapsed;
|
||||
}
|
||||
|
||||
public GameEventBus getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
public record PlayerJoinEvent(BasePlayer player) {}
|
||||
public record PlayerLeaveEvent(BasePlayer player) {}
|
||||
}
|
||||
18
src/main/java/dev/loki/core/GameState.java
Normal file
18
src/main/java/dev/loki/core/GameState.java
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package dev.loki.core;
|
||||
|
||||
public enum GameState {
|
||||
LOBBY("Ожидание игроков"),
|
||||
ROLE_ASSIGN("Назначение ролей"),
|
||||
IN_GAME("Игра идет"),
|
||||
ENDING("Завершение");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
GameState(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
package dev.loki;
|
||||
|
||||
import dev.loki.command.DBDCommand;
|
||||
import dev.loki.config.ConfigManager;
|
||||
import dev.loki.core.GameManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class mdbd extends JavaPlugin {
|
||||
private static mdbd instance;
|
||||
private ConfigManager configManager;
|
||||
private GameManager gameManager;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
|
@ -15,12 +18,20 @@ public final class mdbd extends JavaPlugin {
|
|||
this.configManager = new ConfigManager(this);
|
||||
this.configManager.loadConfigs();
|
||||
|
||||
this.gameManager = new GameManager(this);
|
||||
|
||||
getCommand("dbd").setExecutor(new DBDCommand(this, gameManager));
|
||||
getCommand("dbd").setTabCompleter(new DBDCommand(this, gameManager));
|
||||
|
||||
getLogger().info("Mdbd Plugin enabled successfully!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
getLogger().info("Mdbd Plugin disabling...");
|
||||
if (gameManager != null) {
|
||||
gameManager.endGame();
|
||||
}
|
||||
instance = null;
|
||||
}
|
||||
|
||||
|
|
@ -31,4 +42,8 @@ public final class mdbd extends JavaPlugin {
|
|||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public GameManager getGameManager() {
|
||||
return gameManager;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
src/main/java/dev/loki/phase/EndgamePhase.java
Normal file
31
src/main/java/dev/loki/phase/EndgamePhase.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package dev.loki.phase;
|
||||
|
||||
import dev.loki.core.GameSession;
|
||||
|
||||
public class EndgamePhase implements Phase {
|
||||
private int collapseTicks;
|
||||
private boolean complete;
|
||||
|
||||
@Override
|
||||
public void enter(GameSession session) {
|
||||
collapseTicks = session.getConfig().getGame().getInt("endgame.collapse-seconds", 120) * 20;
|
||||
complete = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(GameSession session) {
|
||||
collapseTicks--;
|
||||
if (collapseTicks <= 0) {
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(GameSession session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
}
|
||||
36
src/main/java/dev/loki/phase/GameplayPhase.java
Normal file
36
src/main/java/dev/loki/phase/GameplayPhase.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package dev.loki.phase;
|
||||
|
||||
import dev.loki.core.GameSession;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class GameplayPhase implements Phase {
|
||||
private int gameTicks;
|
||||
private boolean shouldEnd;
|
||||
|
||||
@Override
|
||||
public void enter(GameSession session) {
|
||||
Bukkit.broadcastMessage("[DBD] Игра началась! Выжившие, чините генераторы!");
|
||||
gameTicks = 0;
|
||||
shouldEnd = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(GameSession session) {
|
||||
gameTicks++;
|
||||
// TODO: Check endgame conditions
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(GameSession session) {
|
||||
Bukkit.broadcastMessage("[DBD] Игра завершена!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return shouldEnd;
|
||||
}
|
||||
|
||||
public void forceEnd() {
|
||||
shouldEnd = true;
|
||||
}
|
||||
}
|
||||
74
src/main/java/dev/loki/phase/LobbyPhase.java
Normal file
74
src/main/java/dev/loki/phase/LobbyPhase.java
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
package dev.loki.phase;
|
||||
|
||||
import dev.loki.config.GameConfig;
|
||||
import dev.loki.core.GameSession;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class LobbyPhase implements Phase {
|
||||
private final GameConfig config;
|
||||
private int countdown;
|
||||
private int secondsLeft;
|
||||
private boolean started;
|
||||
|
||||
public LobbyPhase(GameConfig config) {
|
||||
this.config = config;
|
||||
this.secondsLeft = config.getLobbyCountdown();
|
||||
this.countdown = 0;
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(GameSession session) {
|
||||
Bukkit.broadcast(Component.text("[DBD] Лобби открыто! Используйте /dbd join", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(GameSession session) {
|
||||
int playerCount = session.getPlayerCount();
|
||||
int minPlayers = config.getMinPlayers();
|
||||
|
||||
if (playerCount < minPlayers) {
|
||||
secondsLeft = config.getLobbyCountdown();
|
||||
countdown = 0;
|
||||
started = false;
|
||||
return;
|
||||
}
|
||||
|
||||
countdown++;
|
||||
if (countdown >= 20) {
|
||||
countdown = 0;
|
||||
secondsLeft--;
|
||||
|
||||
if (secondsLeft <= 5 || secondsLeft % 10 == 0) {
|
||||
Bukkit.broadcast(Component.text(
|
||||
"[DBD] До начала: " + secondsLeft + " сек. (" + playerCount + "/" + minPlayers + ")",
|
||||
NamedTextColor.YELLOW));
|
||||
}
|
||||
}
|
||||
|
||||
if (secondsLeft <= 0) {
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(GameSession session) {
|
||||
Bukkit.broadcast(Component.text("[DBD] Игра начинается!", NamedTextColor.GREEN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return started;
|
||||
}
|
||||
|
||||
public void forceStart() {
|
||||
secondsLeft = 0;
|
||||
started = true;
|
||||
}
|
||||
|
||||
public int getSecondsLeft() {
|
||||
return secondsLeft;
|
||||
}
|
||||
}
|
||||
10
src/main/java/dev/loki/phase/Phase.java
Normal file
10
src/main/java/dev/loki/phase/Phase.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package dev.loki.phase;
|
||||
|
||||
import dev.loki.core.GameSession;
|
||||
|
||||
public interface Phase {
|
||||
void enter(GameSession session);
|
||||
void tick(GameSession session);
|
||||
void exit(GameSession session);
|
||||
boolean isComplete();
|
||||
}
|
||||
40
src/main/java/dev/loki/phase/RoleAssignPhase.java
Normal file
40
src/main/java/dev/loki/phase/RoleAssignPhase.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package dev.loki.phase;
|
||||
|
||||
import dev.loki.core.GameSession;
|
||||
import dev.loki.role.RoleAssigner;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class RoleAssignPhase implements Phase {
|
||||
private final RoleAssigner assigner;
|
||||
private int ticksLeft;
|
||||
private boolean complete;
|
||||
|
||||
public RoleAssignPhase(RoleAssigner assigner) {
|
||||
this.assigner = assigner;
|
||||
this.complete = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(GameSession session) {
|
||||
ticksLeft = session.getConfig().getRoleAssignDelay() * 20;
|
||||
assigner.assignRoles(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(GameSession session) {
|
||||
ticksLeft--;
|
||||
if (ticksLeft <= 0) {
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exit(GameSession session) {
|
||||
Bukkit.broadcastMessage("[DBD] Роли назначены!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
}
|
||||
49
src/main/java/dev/loki/player/BasePlayer.java
Normal file
49
src/main/java/dev/loki/player/BasePlayer.java
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package dev.loki.player;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class BasePlayer {
|
||||
protected final UUID uuid;
|
||||
protected PlayerState state;
|
||||
protected Location spawnLocation;
|
||||
|
||||
public BasePlayer(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
this.state = PlayerState.HEALTHY;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return Bukkit.getPlayer(uuid);
|
||||
}
|
||||
|
||||
public PlayerState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(PlayerState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public Location getSpawnLocation() {
|
||||
return spawnLocation;
|
||||
}
|
||||
|
||||
public void setSpawnLocation(Location location) {
|
||||
this.spawnLocation = location;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
Player player = getPlayer();
|
||||
return player != null && player.isOnline();
|
||||
}
|
||||
|
||||
public abstract boolean isKiller();
|
||||
}
|
||||
25
src/main/java/dev/loki/player/Killer.java
Normal file
25
src/main/java/dev/loki/player/Killer.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package dev.loki.player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Killer extends BasePlayer {
|
||||
private boolean carrying;
|
||||
|
||||
public Killer(UUID uuid) {
|
||||
super(uuid);
|
||||
this.carrying = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKiller() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isCarrying() {
|
||||
return carrying;
|
||||
}
|
||||
|
||||
public void setCarrying(boolean carrying) {
|
||||
this.carrying = carrying;
|
||||
}
|
||||
}
|
||||
21
src/main/java/dev/loki/player/PlayerState.java
Normal file
21
src/main/java/dev/loki/player/PlayerState.java
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package dev.loki.player;
|
||||
|
||||
public enum PlayerState {
|
||||
HEALTHY("Здоров"),
|
||||
INJURED("Ранен"),
|
||||
DOWNED("В нокдауне"),
|
||||
HOOKED("На крюке"),
|
||||
CARRIED("Унесен"),
|
||||
DEAD("Мертв"),
|
||||
ESCAPED("Сбежал");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
PlayerState(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
25
src/main/java/dev/loki/player/Survivor.java
Normal file
25
src/main/java/dev/loki/player/Survivor.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package dev.loki.player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Survivor extends BasePlayer {
|
||||
private int hooksTaken;
|
||||
|
||||
public Survivor(UUID uuid) {
|
||||
super(uuid);
|
||||
this.hooksTaken = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isKiller() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getHooksTaken() {
|
||||
return hooksTaken;
|
||||
}
|
||||
|
||||
public void incrementHooks() {
|
||||
hooksTaken++;
|
||||
}
|
||||
}
|
||||
65
src/main/java/dev/loki/role/RoleAssigner.java
Normal file
65
src/main/java/dev/loki/role/RoleAssigner.java
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package dev.loki.role;
|
||||
|
||||
import dev.loki.config.LocationsConfig;
|
||||
import dev.loki.core.GameSession;
|
||||
import dev.loki.player.BasePlayer;
|
||||
import dev.loki.player.Killer;
|
||||
import dev.loki.player.Survivor;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class RoleAssigner {
|
||||
private final RoleQueue queue;
|
||||
private final LocationsConfig locations;
|
||||
|
||||
public RoleAssigner(LocationsConfig locations) {
|
||||
this.queue = new RoleQueue();
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public void registerPlayer(UUID uuid) {
|
||||
queue.addPlayer(uuid);
|
||||
}
|
||||
|
||||
public void unregisterPlayer(UUID uuid) {
|
||||
queue.removePlayer(uuid);
|
||||
}
|
||||
|
||||
public void assignRoles(GameSession session) {
|
||||
Map<UUID, BasePlayer> players = session.getPlayers();
|
||||
if (players.isEmpty()) return;
|
||||
|
||||
List<UUID> uuids = new ArrayList<>(players.keySet());
|
||||
|
||||
UUID killerUuid = selectKiller(uuids);
|
||||
|
||||
for (UUID uuid : uuids) {
|
||||
BasePlayer player;
|
||||
if (uuid.equals(killerUuid)) {
|
||||
player = new Killer(uuid);
|
||||
Location spawn = locations.getKillerSpawn();
|
||||
player.setSpawnLocation(spawn);
|
||||
} else {
|
||||
player = new Survivor(uuid);
|
||||
}
|
||||
session.getEventBus().emit(new RoleAssignedEvent(uuid, player));
|
||||
}
|
||||
|
||||
queue.rotate();
|
||||
}
|
||||
|
||||
private UUID selectKiller(List<UUID> uuids) {
|
||||
UUID queuedKiller = queue.nextKiller();
|
||||
if (queuedKiller != null && uuids.contains(queuedKiller)) {
|
||||
return queuedKiller;
|
||||
}
|
||||
return uuids.get(new Random().nextInt(uuids.size()));
|
||||
}
|
||||
|
||||
public void resetQueue() {
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
public record RoleAssignedEvent(UUID uuid, BasePlayer player) {}
|
||||
}
|
||||
59
src/main/java/dev/loki/role/RoleQueue.java
Normal file
59
src/main/java/dev/loki/role/RoleQueue.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package dev.loki.role;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class RoleQueue {
|
||||
private final Map<UUID, Integer> queuePosition;
|
||||
private final List<UUID> queue;
|
||||
|
||||
public RoleQueue() {
|
||||
this.queuePosition = new HashMap<>();
|
||||
this.queue = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addPlayer(UUID uuid) {
|
||||
if (!queuePosition.containsKey(uuid)) {
|
||||
queue.add(uuid);
|
||||
updatePositions();
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayer(UUID uuid) {
|
||||
queue.remove(uuid);
|
||||
queuePosition.remove(uuid);
|
||||
updatePositions();
|
||||
}
|
||||
|
||||
public UUID nextKiller() {
|
||||
if (queue.isEmpty()) return null;
|
||||
return queue.get(0);
|
||||
}
|
||||
|
||||
public void rotate() {
|
||||
if (!queue.isEmpty()) {
|
||||
UUID first = queue.remove(0);
|
||||
queue.add(first);
|
||||
updatePositions();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePositions() {
|
||||
queuePosition.clear();
|
||||
for (int i = 0; i < queue.size(); i++) {
|
||||
queuePosition.put(queue.get(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
public int getPosition(UUID uuid) {
|
||||
return queuePosition.getOrDefault(uuid, -1);
|
||||
}
|
||||
|
||||
public boolean isInQueue(UUID uuid) {
|
||||
return queuePosition.containsKey(uuid);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
queue.clear();
|
||||
queuePosition.clear();
|
||||
}
|
||||
}
|
||||
28
src/main/java/dev/loki/role/SpawnPosition.java
Normal file
28
src/main/java/dev/loki/role/SpawnPosition.java
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package dev.loki.role;
|
||||
|
||||
import dev.loki.config.LocationsConfig;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class SpawnPosition {
|
||||
private final LocationsConfig config;
|
||||
private final Random random;
|
||||
|
||||
public SpawnPosition(LocationsConfig config) {
|
||||
this.config = config;
|
||||
this.random = new Random();
|
||||
}
|
||||
|
||||
public Location getRandomSurvivorSpawn() {
|
||||
List<Location> spawns = config.getSurvivorSpawns();
|
||||
if (spawns.isEmpty()) return config.getLobby();
|
||||
return spawns.get(random.nextInt(spawns.size()));
|
||||
}
|
||||
|
||||
public Location getKillerSpawn() {
|
||||
Location spawn = config.getKillerSpawn();
|
||||
return spawn != null ? spawn : config.getLobby();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue