diff --git a/PLAN.md b/PLAN.md index a5a3c1b..678e247 100644 --- a/PLAN.md +++ b/PLAN.md @@ -167,12 +167,12 @@ src/main/java/com/dbd/plugin/ ## TODO (по порядку) ### Этап 0: Скелет проекта -- [ ] Создать `build.gradle` (Paper 1.20.6, Java 17, ProtocolLib) -- [ ] `plugin.yml` с пермишнами -- [ ] `DBDPlugin.java` — onEnable/onDisable -- [ ] `ConfigManager` — загрузка yaml без перезаписи -- [ ] `LocationsConfig` — структура для всех координат -- [ ] `GameConfig` — балансные цифры +- [x] Создать `build.gradle` (Paper 1.20.6, Java 21, ProtocolLib) +- [x] `plugin.yml` с пермишнами +- [x] `DBDPlugin.java` — onEnable/onDisable +- [x] `ConfigManager` — загрузка yaml без перезаписи +- [x] `LocationsConfig` — структура для всех координат +- [x] `GameConfig` — балансные цифры ### Этап 1: Core Game Loop - [ ] `GameState` enum diff --git a/build.gradle.kts b/build.gradle.kts index 68ba464..0a72c12 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,22 +6,21 @@ plugins { repositories { mavenCentral() maven("https://repo.papermc.io/repository/maven-public/") + maven("https://repo.dmulloy2.net/repository/public/") } dependencies { - compileOnly("io.papermc.paper:paper-api:26.1.2.build.+") + compileOnly("io.papermc.paper:paper-api:1.20.6-R0.1-SNAPSHOT") + compileOnly("com.comphenix.protocol:ProtocolLib:5.3.0") } java { - toolchain.languageVersion = JavaLanguageVersion.of(25) + toolchain.languageVersion = JavaLanguageVersion.of(21) } tasks { runServer { - // Configure the Minecraft version for our task. - // This is the only required configuration besides applying the plugin. - // Your plugin's jar (or shadowJar if present) will be used automatically. - minecraftVersion("26.1.2") + minecraftVersion("1.20.6") jvmArgs("-Xms2G", "-Xmx2G") } diff --git a/src/main/java/dev/loki/config/ConfigManager.java b/src/main/java/dev/loki/config/ConfigManager.java new file mode 100644 index 0000000..996541f --- /dev/null +++ b/src/main/java/dev/loki/config/ConfigManager.java @@ -0,0 +1,68 @@ +package dev.loki.config; + +import dev.loki.mdbd; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +public class ConfigManager { + private final mdbd plugin; + private final File dataFolder; + + private LocationsConfig locationsConfig; + private GameConfig gameConfig; + + public ConfigManager(mdbd plugin) { + this.plugin = plugin; + this.dataFolder = plugin.getDataFolder(); + if (!dataFolder.exists()) { + dataFolder.mkdirs(); + } + } + + public void loadConfigs() { + this.locationsConfig = new LocationsConfig(loadConfig("locations.yml")); + this.gameConfig = new GameConfig(loadConfig("game.yml")); + plugin.getLogger().info("Configs loaded successfully"); + } + + private FileConfiguration loadConfig(String fileName) { + File file = new File(dataFolder, fileName); + if (!file.exists()) { + createDefaultConfig(fileName, file); + } + return YamlConfiguration.loadConfiguration(file); + } + + private void createDefaultConfig(String resourceName, File targetFile) { + try (InputStream is = plugin.getResource(resourceName)) { + if (is != null) { + Files.copy(is, targetFile.toPath()); + } else { + targetFile.createNewFile(); + } + } catch (IOException e) { + plugin.getLogger().warning("Could not create config: " + resourceName); + } + } + + public void saveConfig(String fileName, FileConfiguration config) { + try { + config.save(new File(dataFolder, fileName)); + } catch (IOException e) { + plugin.getLogger().warning("Could not save config: " + fileName); + } + } + + public LocationsConfig getLocations() { + return locationsConfig; + } + + public GameConfig getGame() { + return gameConfig; + } +} diff --git a/src/main/java/dev/loki/config/GameConfig.java b/src/main/java/dev/loki/config/GameConfig.java new file mode 100644 index 0000000..ac2fe0a --- /dev/null +++ b/src/main/java/dev/loki/config/GameConfig.java @@ -0,0 +1,176 @@ +package dev.loki.config; + +import org.bukkit.configuration.file.FileConfiguration; + +public class GameConfig { + private final FileConfiguration config; + + public GameConfig(FileConfiguration config) { + this.config = config; + setDefaults(); + } + + private void setDefaults() { + // Lobby settings + setDefault("lobby.min-players", 5); + setDefault("lobby.max-players", 5); + setDefault("lobby.countdown-seconds", 60); + setDefault("lobby.role-assign-delay", 5); + + // Generator settings + setDefault("generators.total-count", 7); + setDefault("generators.required-count", 5); + setDefault("generators.repair-seconds", 80); + setDefault("generators.regression-rate", 0.25); + setDefault("generators.kick-regression-rate", 2.5); + setDefault("generators.kick-duration-seconds", 30); + + // Skill check settings + setDefault("skillcheck.zone-size", 0.15); + setDefault("skillcheck.rotation-speed", 3.0); + setDefault("skillcheck.success-bonus", 5.0); + setDefault("skillcheck.fail-penalty", 10.0); + + // Hook settings + setDefault("hooks.stage1-seconds", 60); + setDefault("hooks.stage2-seconds", 60); + setDefault("hooks.struggle-interval", 2); + setDefault("hooks.max-hooks", 3); + + // Movement speeds (% of normal) + setDefault("movement.killer", 115); + setDefault("movement.killer-carry", 92); + setDefault("movement.survivor-walk", 100); + setDefault("movement.survivor-sprint", 150); + setDefault("movement.survivor-crawl", 30); + setDefault("movement.exhaustion-duration", 3); + setDefault("movement.exhaustion-cooldown", 5); + + // Healing settings + setDefault("healing.self-heal-seconds", 30); + setDefault("healing.other-heal-seconds", 16); + setDefault("healing.medkit-bonus", 0.5); + + // Killer settings + setDefault("killer.attack-cooldown", 2.5); + setDefault("killer.attack-range", 3.0); + setDefault("killer.pallet-stun-seconds", 2.5); + setDefault("killer.pallet-break-seconds", 3.0); + setDefault("killer.terror-radius", 32); + + // Window vault + setDefault("window.vault-survivor-fast", 1.0); + setDefault("window.vault-survivor-slow", 1.5); + setDefault("window.vault-killer", 1.5); + + // Endgame + setDefault("endgame.gate-open-seconds", 20); + setDefault("endgame.collapse-seconds", 120); + setDefault("endgame.chest-open-seconds", 3); + + // Hatch + setDefault("hatch.min-survivors-for-open", 1); + } + + private void setDefault(String path, Object value) { + if (!config.contains(path)) { + config.set(path, value); + } + } + + public int getMinPlayers() { + return config.getInt("lobby.min-players", 5); + } + + public int getMaxPlayers() { + return config.getInt("lobby.max-players", 5); + } + + public int getLobbyCountdown() { + return config.getInt("lobby.countdown-seconds", 60); + } + + public int getRoleAssignDelay() { + return config.getInt("lobby.role-assign-delay", 5); + } + + public int getGeneratorTotal() { + return config.getInt("generators.total-count", 7); + } + + public int getGeneratorRequired() { + return config.getInt("generators.required-count", 5); + } + + public int getGeneratorRepairSeconds() { + return config.getInt("generators.repair-seconds", 80); + } + + public double getRegressionRate() { + return config.getDouble("generators.regression-rate", 0.25); + } + + public double getKickRegressionRate() { + return config.getDouble("generators.kick-regression-rate", 2.5); + } + + public int getKickDuration() { + return config.getInt("generators.kick-duration-seconds", 30); + } + + public int getStage1Seconds() { + return config.getInt("hooks.stage1-seconds", 60); + } + + public int getStage2Seconds() { + return config.getInt("hooks.stage2-seconds", 60); + } + + public int getMaxHooks() { + return config.getInt("hooks.max-hooks", 3); + } + + public double getKillerSpeed() { + return config.getDouble("movement.killer", 115) / 100.0; + } + + public double getKillerCarrySpeed() { + return config.getDouble("movement.killer-carry", 92) / 100.0; + } + + public double getSurvivorWalkSpeed() { + return config.getDouble("movement.survivor-walk", 100) / 100.0; + } + + public double getSurvivorSprintSpeed() { + return config.getDouble("movement.survivor-sprint", 150) / 100.0; + } + + public double getSurvivorCrawlSpeed() { + return config.getDouble("movement.survivor-crawl", 30) / 100.0; + } + + public int getAttackCooldown() { + return (int) (config.getDouble("killer.attack-cooldown", 2.5) * 20); + } + + public double getAttackRange() { + return config.getDouble("killer.attack-range", 3.0); + } + + public int getPalletStunTicks() { + return (int) (config.getDouble("killer.pallet-stun-seconds", 2.5) * 20); + } + + public int getPalletBreakTicks() { + return (int) (config.getDouble("killer.pallet-break-seconds", 3.0) * 20); + } + + public int getTerrorRadius() { + return config.getInt("killer.terror-radius", 32); + } + + public FileConfiguration getConfig() { + return config; + } +} diff --git a/src/main/java/dev/loki/config/LocationsConfig.java b/src/main/java/dev/loki/config/LocationsConfig.java new file mode 100644 index 0000000..d499ecc --- /dev/null +++ b/src/main/java/dev/loki/config/LocationsConfig.java @@ -0,0 +1,159 @@ +package dev.loki.config; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; + +import java.util.ArrayList; +import java.util.List; + +public class LocationsConfig { + private final FileConfiguration config; + + public LocationsConfig(FileConfiguration config) { + this.config = config; + setDefaults(); + } + + private void setDefaults() { + if (!config.contains("lobby")) { + config.set("lobby.world", "world"); + config.set("lobby.x", 0.0); + config.set("lobby.y", 100.0); + config.set("lobby.z", 0.0); + config.set("lobby.yaw", 0.0); + config.set("lobby.pitch", 0.0); + } + if (!config.contains("generators")) { + config.set("generators", new ArrayList<>()); + } + if (!config.contains("hooks")) { + config.set("hooks", new ArrayList<>()); + } + if (!config.contains("pallets")) { + config.set("pallets", new ArrayList<>()); + } + if (!config.contains("windows")) { + config.set("windows", new ArrayList<>()); + } + if (!config.contains("chests")) { + config.set("chests", new ArrayList<>()); + } + if (!config.contains("totems")) { + config.set("totems", new ArrayList<>()); + } + if (!config.contains("exitgates")) { + config.set("exitgates", new ArrayList<>()); + } + if (!config.contains("killer-spawn")) { + config.set("killer-spawn", new ArrayList<>()); + } + if (!config.contains("survivor-spawns")) { + config.set("survivor-spawns", new ArrayList<>()); + } + } + + public Location getLobby() { + World world = Bukkit.getWorld(config.getString("lobby.world", "world")); + if (world == null) return null; + return new Location( + world, + config.getDouble("lobby.x", 0.0), + config.getDouble("lobby.y", 100.0), + config.getDouble("lobby.z", 0.0), + (float) config.getDouble("lobby.yaw", 0.0), + (float) config.getDouble("lobby.pitch", 0.0) + ); + } + + public void setLobby(Location loc) { + config.set("lobby.world", loc.getWorld().getName()); + config.set("lobby.x", loc.getX()); + config.set("lobby.y", loc.getY()); + config.set("lobby.z", loc.getZ()); + config.set("lobby.yaw", loc.getYaw()); + config.set("lobby.pitch", loc.getPitch()); + } + + public List getGenerators() { + return loadLocationList("generators"); + } + + public List getHooks() { + return loadLocationList("hooks"); + } + + public List getPallets() { + return loadLocationList("pallets"); + } + + public List getWindows() { + return loadLocationList("windows"); + } + + public List getChests() { + return loadLocationList("chests"); + } + + public List getTotems() { + return loadLocationList("totems"); + } + + public List getExitGates() { + return loadLocationList("exitgates"); + } + + public Location getKillerSpawn() { + List spawns = loadLocationList("killer-spawn"); + return spawns.isEmpty() ? null : spawns.get(0); + } + + public List getSurvivorSpawns() { + return loadLocationList("survivor-spawns"); + } + + private List loadLocationList(String path) { + List locations = new ArrayList<>(); + List list = config.getList(path); + if (list == null) return locations; + + for (Object obj : list) { + if (obj instanceof String) { + Location loc = parseLocation((String) obj); + if (loc != null) locations.add(loc); + } + } + return locations; + } + + private Location parseLocation(String str) { + String[] parts = str.split(","); + if (parts.length < 4) return null; + World world = Bukkit.getWorld(parts[0].trim()); + if (world == null) return null; + try { + double x = Double.parseDouble(parts[1].trim()); + double y = Double.parseDouble(parts[2].trim()); + double z = Double.parseDouble(parts[3].trim()); + float yaw = parts.length > 4 ? Float.parseFloat(parts[4].trim()) : 0f; + float pitch = parts.length > 5 ? Float.parseFloat(parts[5].trim()) : 0f; + return new Location(world, x, y, z, yaw, pitch); + } catch (NumberFormatException e) { + return null; + } + } + + public void addLocation(String path, Location loc) { + List list = config.getStringList(path); + list.add(String.format("%s,%.2f,%.2f,%.2f,%.1f,%.1f", + loc.getWorld().getName(), + loc.getX(), loc.getY(), loc.getZ(), + loc.getYaw(), loc.getPitch())); + config.set(path, list); + } + + public FileConfiguration getConfig() { + return config; + } +} diff --git a/src/main/java/dev/loki/mdbd.java b/src/main/java/dev/loki/mdbd.java index 43905f3..888bc8b 100644 --- a/src/main/java/dev/loki/mdbd.java +++ b/src/main/java/dev/loki/mdbd.java @@ -1,16 +1,34 @@ package dev.loki; +import dev.loki.config.ConfigManager; import org.bukkit.plugin.java.JavaPlugin; public final class mdbd extends JavaPlugin { + private static mdbd instance; + private ConfigManager configManager; @Override public void onEnable() { - // Plugin startup logic + instance = this; + getLogger().info("Mdbd Plugin enabling..."); + + this.configManager = new ConfigManager(this); + this.configManager.loadConfigs(); + + getLogger().info("Mdbd Plugin enabled successfully!"); } @Override public void onDisable() { - // Plugin shutdown logic + getLogger().info("Mdbd Plugin disabling..."); + instance = null; + } + + public static mdbd getInstance() { + return instance; + } + + public ConfigManager getConfigManager() { + return configManager; } } diff --git a/src/main/resources/paper-plugin.yml b/src/main/resources/paper-plugin.yml index 2e32ed9..3ab1d6b 100644 --- a/src/main/resources/paper-plugin.yml +++ b/src/main/resources/paper-plugin.yml @@ -4,7 +4,15 @@ version: '${version}' main: dev.loki.mdbd bootstrapper: dev.loki.mdbdBootstrap loader: dev.loki.mdbdLoader -api-version: '26.1.2' +api-version: '1.20.6' load: POSTWORLD authors: [ loki ] + +permissions: + mdbd.admin: + description: "Полный доступ к админ-командам плагина" + default: op + mdbd.player: + description: "Базовые команды для игроков" + default: true