Add map templates, multi-config system, &#rrggbb colors

- MapTemplate: Save/load structures via Bukkit Structure API (.nbt files)
- TemplateManager: Manage templates and presets
- MapBuilder: Build/clear map with generators, hooks, pallets, etc.
- SetupCommand: /dbdsetup wand/save/load/set/build for map editing
- MessagesConfig: All messages with &#rrggbb color support via MiniMessage
- SkillCheckConfig: Skill check colors, zones, rotation settings
- Update GameConfig with color codes
- ConfigManager: Load/save all 4 config files
- Update plugin.yml with dbdsetup command
- Add methods to Generator for template integration
This commit is contained in:
loki5512344 2026-05-31 21:05:25 +02:00
parent 362b791774
commit 2a2b9f4b5b
10 changed files with 951 additions and 1 deletions

View file

@ -15,6 +15,8 @@ public class ConfigManager {
private LocationsConfig locationsConfig;
private GameConfig gameConfig;
private MessagesConfig messagesConfig;
private SkillCheckConfig skillCheckConfig;
public ConfigManager(mdbd plugin) {
this.plugin = plugin;
@ -27,9 +29,18 @@ public class ConfigManager {
public void loadConfigs() {
this.locationsConfig = new LocationsConfig(loadConfig("locations.yml"));
this.gameConfig = new GameConfig(loadConfig("game.yml"));
this.messagesConfig = new MessagesConfig(loadConfig("messages.yml"));
this.skillCheckConfig = new SkillCheckConfig(loadConfig("skillcheck.yml"));
plugin.getLogger().info("Configs loaded successfully");
}
public void saveAllConfigs() {
saveConfig("locations.yml", locationsConfig.getConfig());
saveConfig("game.yml", gameConfig.getConfig());
saveConfig("messages.yml", messagesConfig.getConfig());
saveConfig("skillcheck.yml", skillCheckConfig.getConfig());
}
private FileConfiguration loadConfig(String fileName) {
File file = new File(dataFolder, fileName);
if (!file.exists()) {
@ -65,4 +76,12 @@ public class ConfigManager {
public GameConfig getGame() {
return gameConfig;
}
public MessagesConfig getMessages() {
return messagesConfig;
}
public SkillCheckConfig getSkillCheck() {
return skillCheckConfig;
}
}

View file

@ -25,12 +25,21 @@ public class GameConfig {
setDefault("generators.kick-regression-rate", 2.5);
setDefault("generators.kick-duration-seconds", 30);
// Skill check settings
// Skill check settings (legacy - moved to skillcheck.yml)
setDefault("skillcheck.zone-size", 0.15);
setDefault("skillcheck.rotation-speed", 3.0);
setDefault("skillcheck.success-bonus", 5.0);
setDefault("skillcheck.fail-penalty", 10.0);
// Colors for UI (&#rrggbb format support)
setDefault("colors.progress-bar-complete", "&#00FF00");
setDefault("colors.progress-bar-incomplete", "&#FF0000");
setDefault("colors.progress-bar-background", "&#333333");
setDefault("colors.hp-healthy", "&#00FF00");
setDefault("colors.hp-injured", "&#FFA500");
setDefault("colors.hp-downed", "&#FF0000");
setDefault("colors.hp-dead", "&#8B0000");
// Hook settings
setDefault("hooks.stage1-seconds", 60);
setDefault("hooks.stage2-seconds", 60);

View file

@ -0,0 +1,126 @@
package dev.loki.config;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.configuration.file.FileConfiguration;
public class MessagesConfig {
private final FileConfiguration config;
private final MiniMessage miniMessage;
public MessagesConfig(FileConfiguration config) {
this.config = config;
this.miniMessage = MiniMessage.miniMessage();
setDefaults();
}
private void setDefaults() {
// Prefix (orange)
setDefault("prefix", "&#FF6B00&l[DBD]&r ");
// Game messages
setDefault("game.start", "&#00FF00Игра началась! Бегите от Киллера!");
setDefault("game.end.victory-escape", "&#FFD700Выжившие сбежали!");
setDefault("game.end.victory-killer", "&#DC143CКиллер победил!");
setDefault("game.waiting", "&#FFFF00Ожидание игроков... (%s/%s)");
setDefault("game.countdown", "&#FFA500До начала: %s сек");
// Generator messages
setDefault("generator.repair.start", "&#00CED1Вы начали чинить генератор...");
setDefault("generator.repair.stop", "&#87CEEBВы остановились.");
setDefault("generator.repair.complete", "&#00FF00✓ Генератор активирован!");
setDefault("generator.skillcheck.success", "&#00FF00Отлично!");
setDefault("generator.skillcheck.fail", "&#FF0000✗ Провал!");
setDefault("generator.explosion", "&#FF4500⚠ Взрыв генератора!");
setDefault("generator.regression", "&#FF6347Генератор откатывается...");
setDefault("generator.progress", "&#FFD700Генераторы: %s/%s");
// Killer messages
setDefault("killer.terror-near", "&#8B0000Сердце колотится...");
setDefault("killer.chase.start", "&#FF0000⚠ Киллер преследует вас!");
setDefault("killer.chase.stop", "&#00FF00Вы ушли от погони.");
setDefault("killer.hit", "&#DC143CВы ранены!");
setDefault("killer.down", "&#8B0000Вы в нокдауне!");
setDefault("killer.pickup", "&#800080Киллер поднял вас...");
setDefault("killer.hook", "&#4B0082Вас повесили на крюк!");
// Survivor messages
setDefault("survivor.heal.start", "&#00FA9AВы лечите...");
setDefault("survivor.heal.complete", "&#00FF00Вылечено!");
setDefault("survivor.heal.interrupt", "&#FFD700Лечение прервано!");
setDefault("survivor.sprint.exhausted", "&#FF8C00Вы устали...");
setDefault("survivor.pallet.drop", "&#DEB887Вы бросили паллет!");
setDefault("survivor.pallet.stun", "&#FFD700Киллер оглушен!");
setDefault("survivor.vault.fast", "&#00CED1Быстрый прыжок!");
setDefault("survivor.vault.slow", "&#87CEEBМедленный прыжок...");
// Hook messages
setDefault("hook.stage1", "&#FFFF00Крюк: Фаза 1");
setDefault("hook.stage2", "&#FFA500Крюк: Фаза 2 — БОРИТЕСЬ!");
setDefault("hook.struggle.success", "&#00FF00Успех!");
setDefault("hook.struggle.fail", "&#FF0000Провал!");
setDefault("hook.rescue.start", "&#00CED1Спасение...");
setDefault("hook.rescue.complete", "&#00FF00Спасены!");
setDefault("hook.sacrifice", "&#8B0000☠ Вы жертвованы...");
// Item messages
setDefault("item.found", "&#FFD700Найдено: %s");
setDefault("item.medkit.use", "&#00FA9AИспользуете аптечку...");
setDefault("item.flashlight.blind", "&#FFFF00Ослепили киллера!");
setDefault("item.key.hatch", "&#00CED1Ключ открывает люк!");
setDefault("item.map.reveal", "&#87CEEBОбъекты показаны на карте");
// Endgame
setDefault("endgame.gates.powered", "&#00FF00Ворота запитаны!");
setDefault("endgame.gates.opening", "&#FFD700Открываете ворота...");
setDefault("endgame.hatch.open", "&#4B0082Люк открыт!");
setDefault("endgame.collapse.warning", "&#FF0000⚠ КОЛЛАПС ЧЕРЕЗ %s СЕК!");
setDefault("endgame.collapse.start", "&#8B0000КОЛЛАПС НАЧАЛСЯ!");
setDefault("endgame.escape", "&#00FF00✓ ПОБЕГ!");
// Error messages
setDefault("error.no-permission", "&#FF0000Нет прав!");
setDefault("error.not-in-game", "&#FF6347Вы не в игре!");
setDefault("error.already-in-game", "&#FF6347Вы уже в игре!");
setDefault("error.game-full", "&#FF6347Игра заполнена!");
setDefault("error.no-game", "&#FF6347Нет активной игры!");
}
private void setDefault(String path, String value) {
if (!config.contains(path)) {
config.set(path, value);
}
}
public Component get(String path, Object... args) {
String raw = config.getString(path, "&cMissing: " + path);
String withPrefix = config.getString("prefix", "") + raw;
// Replace &#RRGGBB with MiniMessage <#RRGGBB>
String mini = withPrefix.replaceAll("&#([0-9A-Fa-f]{6})", "<#$1>");
// Replace %s with arguments
if (args.length > 0) {
for (Object arg : args) {
mini = mini.replaceFirst("%s", String.valueOf(arg));
}
}
return miniMessage.deserialize(mini);
}
public Component getRaw(String path, Object... args) {
String raw = config.getString(path, "&cMissing: " + path);
String mini = raw.replaceAll("&#([0-9A-Fa-f]{6})", "<#$1>");
if (args.length > 0) {
for (Object arg : args) {
mini = mini.replaceFirst("%s", String.valueOf(arg));
}
}
return miniMessage.deserialize(mini);
}
public FileConfiguration getConfig() {
return config;
}
}

View file

@ -0,0 +1,91 @@
package dev.loki.config;
import org.bukkit.configuration.file.FileConfiguration;
public class SkillCheckConfig {
private final FileConfiguration config;
public SkillCheckConfig(FileConfiguration config) {
this.config = config;
setDefaults();
}
private void setDefaults() {
// Colors (&#rrggbb format)
setDefault("colors.zone-success", "&#00FF00"); // Green zone
setDefault("colors.zone-super", "&#FFD700"); // Gold zone (great skill check)
setDefault("colors.arrow", "&#FFFFFF"); // White arrow
setDefault("colors.background", "&#333333"); // Dark gray track
setDefault("colors.text-title", "&#FFFF00"); // Yellow title
setDefault("colors.text-subtitle", "&#FFFFFF"); // White subtitle
// Zone sizes (degrees)
setDefault("zones.success-size", 15); // ±15°
setDefault("zones.super-size", 5); // ±5° (smaller, bonus)
// Rotation
setDefault("rotation.speed", 3.0); // rotations per second
setDefault("rotation.direction", "CLOCKWISE"); // or COUNTER_CLOCKWISE
setDefault("rotation.variation", true); // randomize direction
// Timing
setDefault("timing.min-interval", 80); // ticks between skill checks (4s min)
setDefault("timing.max-interval", 200); // ticks between skill checks (10s max)
setDefault("timing.reaction-window", 20); // ticks to press (1s)
// Rewards/Penalties
setDefault("rewards.success-bonus", 5.0); // +5% progress
setDefault("rewards.super-bonus", 10.0); // +10% progress
setDefault("penalties.fail-penalty", 10.0); // -10% progress
setDefault("penalties.fail-alert-range", 16); // blocks
setDefault("penalties.fail-explosion", true); // visual explosion
// Visual
setDefault("visual.show-track", true);
setDefault("visual.show-arrow", true);
setDefault("visual.use-boss-bar", false); // alternative display
setDefault("visual.screenshake-on-fail", true);
}
private void setDefault(String path, Object value) {
if (!config.contains(path)) {
config.set(path, value);
}
}
// Getters with defaults
public String getZoneSuccessColor() { return config.getString("colors.zone-success", "&#00FF00"); }
public String getZoneSuperColor() { return config.getString("colors.zone-super", "&#FFD700"); }
public String getArrowColor() { return config.getString("colors.arrow", "&#FFFFFF"); }
public String getBackgroundColor() { return config.getString("colors.background", "&#333333"); }
public String getTextTitleColor() { return config.getString("colors.text-title", "&#FFFF00"); }
public String getTextSubtitleColor() { return config.getString("colors.text-subtitle", "&#FFFFFF"); }
public double getSuccessZoneSize() { return config.getDouble("zones.success-size", 15); }
public double getSuperZoneSize() { return config.getDouble("zones.super-size", 5); }
public double getRotationSpeed() { return config.getDouble("rotation.speed", 3.0); }
public boolean isClockwise() {
return config.getString("rotation.direction", "CLOCKWISE").equals("CLOCKWISE");
}
public boolean hasVariation() { return config.getBoolean("rotation.variation", true); }
public int getMinInterval() { return config.getInt("timing.min-interval", 80); }
public int getMaxInterval() { return config.getInt("timing.max-interval", 200); }
public int getReactionWindow() { return config.getInt("timing.reaction-window", 20); }
public double getSuccessBonus() { return config.getDouble("rewards.success-bonus", 5.0); }
public double getSuperBonus() { return config.getDouble("rewards.super-bonus", 10.0); }
public double getFailPenalty() { return config.getDouble("penalties.fail-penalty", 10.0); }
public int getFailAlertRange() { return config.getInt("penalties.fail-alert-range", 16); }
public boolean hasFailExplosion() { return config.getBoolean("penalties.fail-explosion", true); }
public boolean showTrack() { return config.getBoolean("visual.show-track", true); }
public boolean showArrow() { return config.getBoolean("visual.show-arrow", true); }
public boolean useBossBar() { return config.getBoolean("visual.use-boss-bar", false); }
public boolean hasScreenshake() { return config.getBoolean("visual.screenshake-on-fail", true); }
public FileConfiguration getConfig() {
return config;
}
}