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:
loki5512344 2026-05-31 20:43:40 +02:00
parent 53f3f6e9da
commit 82ed455cd2
20 changed files with 884 additions and 8 deletions

View 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;
}
}