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:
parent
362b791774
commit
2a2b9f4b5b
10 changed files with 951 additions and 1 deletions
221
src/main/java/dev/loki/command/SetupCommand.java
Normal file
221
src/main/java/dev/loki/command/SetupCommand.java
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
package dev.loki.command;
|
||||||
|
|
||||||
|
import dev.loki.mdbd;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.BlockVector;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SetupCommand implements TabExecutor {
|
||||||
|
private final mdbd plugin;
|
||||||
|
private final java.util.Map<String, Location> selectionCorners;
|
||||||
|
|
||||||
|
public SetupCommand(mdbd plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.selectionCorners = new java.util.HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
|
@NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("mdbd.admin")) {
|
||||||
|
sender.sendMessage(Component.text("Нет прав!", NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sender instanceof Player player)) {
|
||||||
|
sender.sendMessage(Component.text("Только игроки!", NamedTextColor.RED));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
sendUsage(sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sub = args[0].toLowerCase();
|
||||||
|
return switch (sub) {
|
||||||
|
case "wand" -> giveWand(player);
|
||||||
|
case "pos1" -> setPos(player, 1);
|
||||||
|
case "pos2" -> setPos(player, 2);
|
||||||
|
case "save" -> saveTemplate(player, args);
|
||||||
|
case "load" -> loadTemplate(player, args);
|
||||||
|
case "list" -> listTemplates(sender);
|
||||||
|
case "set" -> setObject(player, args);
|
||||||
|
case "build" -> buildMap(player);
|
||||||
|
case "clear" -> clearMap(player);
|
||||||
|
case "lobby" -> setLobby(player);
|
||||||
|
default -> {
|
||||||
|
sendUsage(sender);
|
||||||
|
yield true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean giveWand(Player player) {
|
||||||
|
var wand = new org.bukkit.inventory.ItemStack(org.bukkit.Material.STICK);
|
||||||
|
wand.editMeta(meta -> {
|
||||||
|
meta.displayName(Component.text("&#FF6B00DBD Wand").append(Component.text(" (Выделение)")));
|
||||||
|
meta.lore(List.of(
|
||||||
|
Component.text("&#FFD700ЛКМ — Первая точка"),
|
||||||
|
Component.text("&#FFD700ПКМ — Вторая точка")
|
||||||
|
));
|
||||||
|
});
|
||||||
|
player.getInventory().addItem(wand);
|
||||||
|
player.sendMessage(Component.text("�FF00Получена палочка выделения!", NamedTextColor.GREEN));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setPos(Player player, int num) {
|
||||||
|
String key = player.getUniqueId().toString();
|
||||||
|
Location loc = player.getLocation().getBlock().getLocation();
|
||||||
|
selectionCorners.put(key + "_pos" + num, loc);
|
||||||
|
player.sendMessage(Component.text("�FF00Установлена точка " + num + ": " + formatLoc(loc)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean saveTemplate(Player player, String[] args) {
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup save <name>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String key = player.getUniqueId().toString();
|
||||||
|
Location pos1 = selectionCorners.get(key + "_pos1");
|
||||||
|
Location pos2 = selectionCorners.get(key + "_pos2");
|
||||||
|
|
||||||
|
if (pos1 == null || pos2 == null) {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Сначала установите обе точки!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getTemplateManager().saveTemplate(args[1], pos1, pos2);
|
||||||
|
player.sendMessage(Component.text("�FF00Шаблон '" + args[1] + "' сохранен!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean loadTemplate(Player player, String[] args) {
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup load <name>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var template = plugin.getTemplateManager().getTemplate(args[1]);
|
||||||
|
if (template == null) {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Шаблон не найден!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template.place(player.getLocation(), false);
|
||||||
|
player.sendMessage(Component.text("�FF00Шаблон '" + args[1] + "' загружен!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean listTemplates(CommandSender sender) {
|
||||||
|
var templates = plugin.getTemplateManager().getAllTemplates();
|
||||||
|
sender.sendMessage(Component.text("&#FFD700=== Шаблоны ==="));
|
||||||
|
if (templates.isEmpty()) {
|
||||||
|
sender.sendMessage(Component.text("󅒐Нет шаблонов"));
|
||||||
|
} else {
|
||||||
|
templates.keySet().forEach(name ->
|
||||||
|
sender.sendMessage(Component.text("�CED1- " + name))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setObject(Player player, String[] args) {
|
||||||
|
if (args.length < 2) {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Использование: /dbdsetup set <generator|hook|pallet|chest|totem|gate|lobby>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Location loc = player.getLocation().getBlock().getLocation();
|
||||||
|
String type = args[1].toLowerCase();
|
||||||
|
var locations = plugin.getConfigManager().getLocations();
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "generator" -> locations.addLocation("generators", loc);
|
||||||
|
case "hook" -> locations.addLocation("hooks", loc);
|
||||||
|
case "pallet" -> locations.addLocation("pallets", loc);
|
||||||
|
case "chest" -> locations.addLocation("chests", loc);
|
||||||
|
case "totem" -> locations.addLocation("totems", loc);
|
||||||
|
case "gate" -> locations.addLocation("exitgates", loc);
|
||||||
|
case "lobby" -> locations.setLobby(loc);
|
||||||
|
default -> {
|
||||||
|
player.sendMessage(Component.text("&#FF0000Неизвестный тип: " + type));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig());
|
||||||
|
player.sendMessage(Component.text("�FF00Установлен: " + type + " на " + formatLoc(loc)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean buildMap(Player player) {
|
||||||
|
player.sendMessage(Component.text("&#FFD700Строительство карты..."));
|
||||||
|
plugin.getMapBuilder().buildMap(plugin.getConfigManager().getLocations());
|
||||||
|
player.sendMessage(Component.text("�FF00Карта построена!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean clearMap(Player player) {
|
||||||
|
player.sendMessage(Component.text("&#FFA500Очистка карты..."));
|
||||||
|
plugin.getMapBuilder().clearMap(plugin.getConfigManager().getLocations());
|
||||||
|
player.sendMessage(Component.text("�FF00Карта очищена!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setLobby(Player player) {
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
plugin.getConfigManager().getLocations().setLobby(loc);
|
||||||
|
plugin.getConfigManager().saveConfig("locations.yml",
|
||||||
|
plugin.getConfigManager().getLocations().getConfig());
|
||||||
|
player.sendMessage(Component.text("�FF00Лобби установлено на " + formatLoc(loc)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendUsage(CommandSender sender) {
|
||||||
|
sender.sendMessage(Component.text("&#FF6B00=== DBD Setup ==="));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup wand — Получить палочку"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup pos1/pos2 — Установить точки"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup save <name> — Сохранить шаблон"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup load <name> — Загрузить шаблон"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup list — Список шаблонов"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup set <type> — Установить объект"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup build — Построить карту"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup clear — Очистить карту"));
|
||||||
|
sender.sendMessage(Component.text("&#FFD700/dbdsetup lobby — Установить лобби"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatLoc(Location loc) {
|
||||||
|
return String.format("[%s, %.0f, %.0f, %.0f]",
|
||||||
|
loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
|
@NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("mdbd.admin")) return List.of();
|
||||||
|
|
||||||
|
if (args.length == 1) {
|
||||||
|
return Arrays.asList("wand", "pos1", "pos2", "save", "load", "list",
|
||||||
|
"set", "build", "clear", "lobby").stream()
|
||||||
|
.filter(s -> s.startsWith(args[0].toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
if (args.length == 2 && args[0].equalsIgnoreCase("set")) {
|
||||||
|
return Arrays.asList("generator", "hook", "pallet", "chest", "totem", "gate", "lobby")
|
||||||
|
.stream()
|
||||||
|
.filter(s -> s.startsWith(args[1].toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,6 +15,8 @@ public class ConfigManager {
|
||||||
|
|
||||||
private LocationsConfig locationsConfig;
|
private LocationsConfig locationsConfig;
|
||||||
private GameConfig gameConfig;
|
private GameConfig gameConfig;
|
||||||
|
private MessagesConfig messagesConfig;
|
||||||
|
private SkillCheckConfig skillCheckConfig;
|
||||||
|
|
||||||
public ConfigManager(mdbd plugin) {
|
public ConfigManager(mdbd plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -27,9 +29,18 @@ public class ConfigManager {
|
||||||
public void loadConfigs() {
|
public void loadConfigs() {
|
||||||
this.locationsConfig = new LocationsConfig(loadConfig("locations.yml"));
|
this.locationsConfig = new LocationsConfig(loadConfig("locations.yml"));
|
||||||
this.gameConfig = new GameConfig(loadConfig("game.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");
|
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) {
|
private FileConfiguration loadConfig(String fileName) {
|
||||||
File file = new File(dataFolder, fileName);
|
File file = new File(dataFolder, fileName);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
|
|
@ -65,4 +76,12 @@ public class ConfigManager {
|
||||||
public GameConfig getGame() {
|
public GameConfig getGame() {
|
||||||
return gameConfig;
|
return gameConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MessagesConfig getMessages() {
|
||||||
|
return messagesConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkillCheckConfig getSkillCheck() {
|
||||||
|
return skillCheckConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,21 @@ public class GameConfig {
|
||||||
setDefault("generators.kick-regression-rate", 2.5);
|
setDefault("generators.kick-regression-rate", 2.5);
|
||||||
setDefault("generators.kick-duration-seconds", 30);
|
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.zone-size", 0.15);
|
||||||
setDefault("skillcheck.rotation-speed", 3.0);
|
setDefault("skillcheck.rotation-speed", 3.0);
|
||||||
setDefault("skillcheck.success-bonus", 5.0);
|
setDefault("skillcheck.success-bonus", 5.0);
|
||||||
setDefault("skillcheck.fail-penalty", 10.0);
|
setDefault("skillcheck.fail-penalty", 10.0);
|
||||||
|
|
||||||
|
// Colors for UI (&#rrggbb format support)
|
||||||
|
setDefault("colors.progress-bar-complete", "�FF00");
|
||||||
|
setDefault("colors.progress-bar-incomplete", "&#FF0000");
|
||||||
|
setDefault("colors.progress-bar-background", "񑘕");
|
||||||
|
setDefault("colors.hp-healthy", "�FF00");
|
||||||
|
setDefault("colors.hp-injured", "&#FFA500");
|
||||||
|
setDefault("colors.hp-downed", "&#FF0000");
|
||||||
|
setDefault("colors.hp-dead", "B0000");
|
||||||
|
|
||||||
// Hook settings
|
// Hook settings
|
||||||
setDefault("hooks.stage1-seconds", 60);
|
setDefault("hooks.stage1-seconds", 60);
|
||||||
setDefault("hooks.stage2-seconds", 60);
|
setDefault("hooks.stage2-seconds", 60);
|
||||||
|
|
|
||||||
126
src/main/java/dev/loki/config/MessagesConfig.java
Normal file
126
src/main/java/dev/loki/config/MessagesConfig.java
Normal 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", "�FF00Игра началась! Бегите от Киллера!");
|
||||||
|
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", "�CED1Вы начали чинить генератор...");
|
||||||
|
setDefault("generator.repair.stop", "WCEEBВы остановились.");
|
||||||
|
setDefault("generator.repair.complete", "�FF00✓ Генератор активирован!");
|
||||||
|
setDefault("generator.skillcheck.success", "�FF00Отлично!");
|
||||||
|
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", "B0000Сердце колотится...");
|
||||||
|
setDefault("killer.chase.start", "&#FF0000⚠ Киллер преследует вас!");
|
||||||
|
setDefault("killer.chase.stop", "�FF00Вы ушли от погони.");
|
||||||
|
setDefault("killer.hit", "&#DC143CВы ранены!");
|
||||||
|
setDefault("killer.down", "B0000Вы в нокдауне!");
|
||||||
|
setDefault("killer.pickup", "󃕐Киллер поднял вас...");
|
||||||
|
setDefault("killer.hook", "B0082Вас повесили на крюк!");
|
||||||
|
|
||||||
|
// Survivor messages
|
||||||
|
setDefault("survivor.heal.start", "�FA9AВы лечите...");
|
||||||
|
setDefault("survivor.heal.complete", "�FF00Вылечено!");
|
||||||
|
setDefault("survivor.heal.interrupt", "&#FFD700Лечение прервано!");
|
||||||
|
setDefault("survivor.sprint.exhausted", "&#FF8C00Вы устали...");
|
||||||
|
setDefault("survivor.pallet.drop", "&#DEB887Вы бросили паллет!");
|
||||||
|
setDefault("survivor.pallet.stun", "&#FFD700Киллер оглушен!");
|
||||||
|
setDefault("survivor.vault.fast", "�CED1Быстрый прыжок!");
|
||||||
|
setDefault("survivor.vault.slow", "WCEEBМедленный прыжок...");
|
||||||
|
|
||||||
|
// Hook messages
|
||||||
|
setDefault("hook.stage1", "&#FFFF00Крюк: Фаза 1");
|
||||||
|
setDefault("hook.stage2", "&#FFA500Крюк: Фаза 2 — БОРИТЕСЬ!");
|
||||||
|
setDefault("hook.struggle.success", "�FF00Успех!");
|
||||||
|
setDefault("hook.struggle.fail", "&#FF0000Провал!");
|
||||||
|
setDefault("hook.rescue.start", "�CED1Спасение...");
|
||||||
|
setDefault("hook.rescue.complete", "�FF00Спасены!");
|
||||||
|
setDefault("hook.sacrifice", "B0000☠ Вы жертвованы...");
|
||||||
|
|
||||||
|
// Item messages
|
||||||
|
setDefault("item.found", "&#FFD700Найдено: %s");
|
||||||
|
setDefault("item.medkit.use", "�FA9AИспользуете аптечку...");
|
||||||
|
setDefault("item.flashlight.blind", "&#FFFF00Ослепили киллера!");
|
||||||
|
setDefault("item.key.hatch", "�CED1Ключ открывает люк!");
|
||||||
|
setDefault("item.map.reveal", "WCEEBОбъекты показаны на карте");
|
||||||
|
|
||||||
|
// Endgame
|
||||||
|
setDefault("endgame.gates.powered", "�FF00Ворота запитаны!");
|
||||||
|
setDefault("endgame.gates.opening", "&#FFD700Открываете ворота...");
|
||||||
|
setDefault("endgame.hatch.open", "B0082Люк открыт!");
|
||||||
|
setDefault("endgame.collapse.warning", "&#FF0000⚠ КОЛЛАПС ЧЕРЕЗ %s СЕК!");
|
||||||
|
setDefault("endgame.collapse.start", "B0000КОЛЛАПС НАЧАЛСЯ!");
|
||||||
|
setDefault("endgame.escape", "�FF00✓ ПОБЕГ!");
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
91
src/main/java/dev/loki/config/SkillCheckConfig.java
Normal file
91
src/main/java/dev/loki/config/SkillCheckConfig.java
Normal 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", "�FF00"); // Green zone
|
||||||
|
setDefault("colors.zone-super", "&#FFD700"); // Gold zone (great skill check)
|
||||||
|
setDefault("colors.arrow", "&#FFFFFF"); // White arrow
|
||||||
|
setDefault("colors.background", "񑘕"); // 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", "�FF00"); }
|
||||||
|
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", "񑘕"); }
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
220
src/main/java/dev/loki/map/MapBuilder.java
Normal file
220
src/main/java/dev/loki/map/MapBuilder.java
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
package dev.loki.map;
|
||||||
|
|
||||||
|
import dev.loki.mdbd;
|
||||||
|
import dev.loki.config.LocationsConfig;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.structure.StructureRotation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MapBuilder {
|
||||||
|
private final mdbd plugin;
|
||||||
|
private final TemplateManager templateManager;
|
||||||
|
|
||||||
|
public MapBuilder(mdbd plugin, TemplateManager templateManager) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.templateManager = templateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildMap(LocationsConfig config) {
|
||||||
|
World world = Bukkit.getWorlds().get(0);
|
||||||
|
if (world == null) return;
|
||||||
|
|
||||||
|
// Place generators
|
||||||
|
List<Location> generators = config.getGenerators();
|
||||||
|
for (int i = 0; i < generators.size(); i++) {
|
||||||
|
Location loc = generators.get(i);
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placeGenerator(loc, i, StructureRotation.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place hooks
|
||||||
|
List<Location> hooks = config.getHooks();
|
||||||
|
for (int i = 0; i < hooks.size(); i++) {
|
||||||
|
Location loc = hooks.get(i);
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placeHook(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place pallets
|
||||||
|
List<Location> pallets = config.getPallets();
|
||||||
|
for (Location loc : pallets) {
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placePallet(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place chests
|
||||||
|
List<Location> chests = config.getChests();
|
||||||
|
for (Location loc : chests) {
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placeChest(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place totems
|
||||||
|
List<Location> totems = config.getTotems();
|
||||||
|
for (Location loc : totems) {
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placeTotem(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place exit gates
|
||||||
|
List<Location> gates = config.getExitGates();
|
||||||
|
for (int i = 0; i < gates.size(); i++) {
|
||||||
|
Location loc = gates.get(i);
|
||||||
|
if (loc == null) continue;
|
||||||
|
loc.setWorld(world);
|
||||||
|
placeExitGate(loc, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getLogger().info("Map built successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearMap(LocationsConfig config) {
|
||||||
|
// Clear all objects (set to air)
|
||||||
|
clearLocations(config.getGenerators());
|
||||||
|
clearLocations(config.getHooks());
|
||||||
|
clearLocations(config.getPallets());
|
||||||
|
clearLocations(config.getChests());
|
||||||
|
clearLocations(config.getTotems());
|
||||||
|
clearLocations(config.getExitGates());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearLocations(List<Location> locations) {
|
||||||
|
for (Location loc : locations) {
|
||||||
|
if (loc == null || loc.getWorld() == null) continue;
|
||||||
|
// Clear 3x3x3 area around each object
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
for (int y = 0; y <= 2; y++) {
|
||||||
|
for (int z = -1; z <= 1; z++) {
|
||||||
|
Location clearLoc = loc.clone().add(x, y, z);
|
||||||
|
clearLoc.getBlock().setType(org.bukkit.Material.AIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean placeGenerator(Location location, int id, StructureRotation rotation) {
|
||||||
|
// Try custom template first
|
||||||
|
if (templateManager.hasTemplate("generator")) {
|
||||||
|
return templateManager.placeObject("generator", location, rotation);
|
||||||
|
}
|
||||||
|
// Default: build generator structure
|
||||||
|
buildDefaultGenerator(location, id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeHook(Location location) {
|
||||||
|
if (templateManager.hasTemplate("hook")) {
|
||||||
|
templateManager.placeObject("hook", location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildDefaultHook(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placePallet(Location location) {
|
||||||
|
if (templateManager.hasTemplate("pallet")) {
|
||||||
|
templateManager.placeObject("pallet", location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildDefaultPallet(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeChest(Location location) {
|
||||||
|
if (templateManager.hasTemplate("chest")) {
|
||||||
|
templateManager.placeObject("chest", location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
location.getBlock().setType(org.bukkit.Material.CHEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeTotem(Location location) {
|
||||||
|
if (templateManager.hasTemplate("totem")) {
|
||||||
|
templateManager.placeObject("totem", location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildDefaultTotem(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeExitGate(Location location, int id) {
|
||||||
|
if (templateManager.hasTemplate("exitgate")) {
|
||||||
|
templateManager.placeObject("exitgate", location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buildDefaultExitGate(location, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultGenerator(Location loc, int id) {
|
||||||
|
World world = loc.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
|
||||||
|
// Base: Iron blocks 3x3
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
for (int z = -1; z <= 1; z++) {
|
||||||
|
world.getBlockAt(loc.clone().add(x, 0, z)).setType(org.bukkit.Material.IRON_BLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Engine: Pistons in center
|
||||||
|
world.getBlockAt(loc.clone().add(0, 1, 0)).setType(org.bukkit.Material.PISTON);
|
||||||
|
// Lights: Redstone lamps around
|
||||||
|
world.getBlockAt(loc.clone().add(1, 1, 0)).setType(org.bukkit.Material.REDSTONE_LAMP);
|
||||||
|
world.getBlockAt(loc.clone().add(-1, 1, 0)).setType(org.bukkit.Material.REDSTONE_LAMP);
|
||||||
|
world.getBlockAt(loc.clone().add(0, 1, 1)).setType(org.bukkit.Material.REDSTONE_LAMP);
|
||||||
|
world.getBlockAt(loc.clone().add(0, 1, -1)).setType(org.bukkit.Material.REDSTONE_LAMP);
|
||||||
|
// Control panel: Lever
|
||||||
|
world.getBlockAt(loc.clone().add(1, 0, 1)).setType(org.bukkit Material.OAK_PLANKS);
|
||||||
|
world.getBlockAt(loc.clone().add(1, 1, 1)).setType(org.bukkit Material.LEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultHook(Location loc) {
|
||||||
|
World world = loc.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
// Pole: 3 blocks high
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
world.getBlockAt(loc.clone().add(0, y, 0)).setType(org.bukkit.Material.IRON_BARS);
|
||||||
|
}
|
||||||
|
// Hook at top: Tripwire hook
|
||||||
|
world.getBlockAt(loc.clone().add(0, 3, 0)).setType(org.bukkit Material.TRIPWIRE_HOOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultPallet(Location loc) {
|
||||||
|
World world = loc.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
// Horizontal pallet: 3 oak planks
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
world.getBlockAt(loc.clone().add(x, 1, 0)).setType(org.bukkit.Material.OAK_PLANKS);
|
||||||
|
}
|
||||||
|
// Supports: Fences
|
||||||
|
world.getBlockAt(loc.clone().add(-1, 0, 0)).setType(org.bukkit.Material.OAK_FENCE);
|
||||||
|
world.getBlockAt(loc.clone().add(1, 0, 0)).setType(org.bukkit.Material.OAK_FENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultTotem(Location loc) {
|
||||||
|
World world = loc.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
// Base: Mossy stone
|
||||||
|
world.getBlockAt(loc).setType(org.bukkit.Material.MOSSY_COBBLESTONE);
|
||||||
|
// Skull on top
|
||||||
|
world.getBlockAt(loc.clone().add(0, 1, 0)).setType(org.bukkit.Material.PLAYER_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildDefaultExitGate(Location loc, int id) {
|
||||||
|
World world = loc.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
// Door frame: Iron bars
|
||||||
|
for (int x = -1; x <= 1; x++) {
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
world.getBlockAt(loc.clone().add(x, y, 0)).setType(org.bukkit.Material.IRON_BARS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Switch: Button
|
||||||
|
world.getBlockAt(loc.clone().add(1, 1, 1)).setType(org.bukkit.Material.STONE_BUTTON);
|
||||||
|
}
|
||||||
|
}
|
||||||
116
src/main/java/dev/loki/map/MapTemplate.java
Normal file
116
src/main/java/dev/loki/map/MapTemplate.java
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
package dev.loki.map;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.structure.Mirror;
|
||||||
|
import org.bukkit.block.structure.StructureRotation;
|
||||||
|
import org.bukkit.structure.Structure;
|
||||||
|
import org.bukkit.structure.StructureManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class MapTemplate {
|
||||||
|
private final String name;
|
||||||
|
private final StructureManager structureManager;
|
||||||
|
private Structure structure;
|
||||||
|
|
||||||
|
public MapTemplate(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.structureManager = Bukkit.getStructureManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean loadFromFile(File file) {
|
||||||
|
try {
|
||||||
|
this.structure = structureManager.loadStructure(file.toPath());
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "Failed to load template: " + name, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveToFile(File file) {
|
||||||
|
if (structure == null) return;
|
||||||
|
try {
|
||||||
|
if (!file.getParentFile().exists()) {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
}
|
||||||
|
structureManager.saveStructure(file.toPath(), structure);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "Failed to save template: " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveArea(Location corner1, Location corner2) {
|
||||||
|
World world = corner1.getWorld();
|
||||||
|
if (world == null || !world.equals(corner2.getWorld())) return;
|
||||||
|
|
||||||
|
int minX = Math.min(corner1.getBlockX(), corner2.getBlockX());
|
||||||
|
int minY = Math.min(corner1.getBlockY(), corner2.getBlockY());
|
||||||
|
int minZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
|
||||||
|
int maxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
|
||||||
|
int maxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
|
||||||
|
int maxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());
|
||||||
|
|
||||||
|
Location origin = new Location(world, minX, minY, minZ);
|
||||||
|
int sizeX = maxX - minX + 1;
|
||||||
|
int sizeY = maxY - minY + 1;
|
||||||
|
int sizeZ = maxZ - minZ + 1;
|
||||||
|
|
||||||
|
this.structure = structureManager.createStructure();
|
||||||
|
structure.fill(origin, sizeX, sizeY, sizeZ, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void place(Location location, boolean includeEntities) {
|
||||||
|
if (structure == null) return;
|
||||||
|
structure.place(location, true, StructureRotation.NONE, Mirror.NONE,
|
||||||
|
0, 1.0f, includeEntities ? 1.0f : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeWithRotation(Location location, StructureRotation rotation, Mirror mirror) {
|
||||||
|
if (structure == null) return;
|
||||||
|
structure.place(location, true, rotation, mirror, 0, 1.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Location location) {
|
||||||
|
if (structure == null) return;
|
||||||
|
World world = location.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
|
||||||
|
Location rel = structure.getRelativePosition();
|
||||||
|
for (int x = 0; x < structure.getSize().getBlockX(); x++) {
|
||||||
|
for (int y = 0; y < structure.getSize().getBlockY(); y++) {
|
||||||
|
for (int z = 0; z < structure.getSize().getBlockZ(); z++) {
|
||||||
|
Location blockLoc = location.clone().add(
|
||||||
|
x - rel.getBlockX(),
|
||||||
|
y - rel.getBlockY(),
|
||||||
|
z - rel.getBlockZ()
|
||||||
|
);
|
||||||
|
world.getBlockAt(blockLoc).setType(org.bukkit.Material.AIR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return structure != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public org.bukkit.util.Vector getSize() {
|
||||||
|
return structure != null ? structure.getSize() : new org.bukkit.util.Vector(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NamespacedKey getKey(String name) {
|
||||||
|
return new NamespacedKey("mdbd", name.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
119
src/main/java/dev/loki/map/TemplateManager.java
Normal file
119
src/main/java/dev/loki/map/TemplateManager.java
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
package dev.loki.map;
|
||||||
|
|
||||||
|
import dev.loki.mdbd;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class TemplateManager {
|
||||||
|
private final mdbd plugin;
|
||||||
|
private final File templatesFolder;
|
||||||
|
private final Map<String, MapTemplate> templates;
|
||||||
|
private final Map<String, PresetMap> presets;
|
||||||
|
|
||||||
|
public TemplateManager(mdbd plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.templatesFolder = new File(plugin.getDataFolder(), "templates");
|
||||||
|
this.templates = new HashMap<>();
|
||||||
|
this.presets = new HashMap<>();
|
||||||
|
if (!templatesFolder.exists()) {
|
||||||
|
templatesFolder.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadAllTemplates() {
|
||||||
|
templates.clear();
|
||||||
|
File[] files = templatesFolder.listFiles((dir, name) -> name.endsWith(".nbt"));
|
||||||
|
if (files == null) return;
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
String name = file.getName().replace(".nbt", "");
|
||||||
|
MapTemplate template = new MapTemplate(name);
|
||||||
|
if (template.loadFromFile(file)) {
|
||||||
|
templates.put(name, template);
|
||||||
|
plugin.getLogger().info("Loaded template: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapTemplate getTemplate(String name) {
|
||||||
|
return templates.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasTemplate(String name) {
|
||||||
|
return templates.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveTemplate(String name, Location corner1, Location corner2) {
|
||||||
|
MapTemplate template = new MapTemplate(name);
|
||||||
|
template.saveArea(corner1, corner2);
|
||||||
|
File file = new File(templatesFolder, name + ".nbt");
|
||||||
|
template.saveToFile(file);
|
||||||
|
templates.put(name, template);
|
||||||
|
plugin.getLogger().info("Saved template: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, MapTemplate> getAllTemplates() {
|
||||||
|
return new HashMap<>(templates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerPreset(String name, PresetMap preset) {
|
||||||
|
presets.put(name, preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PresetMap getPreset(String name) {
|
||||||
|
return presets.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadDefaultPresets() {
|
||||||
|
// Generator presets (3x3x3 structure)
|
||||||
|
presets.put("generator_default", new PresetMap("generator_default",
|
||||||
|
"generator", new Location(null, 1, 0, 1)));
|
||||||
|
|
||||||
|
// Hook preset (2x3x2)
|
||||||
|
presets.put("hook_default", new PresetMap("hook_default",
|
||||||
|
"hook", new Location(null, 1, 0, 1)));
|
||||||
|
|
||||||
|
// Pallet preset (3x2x1)
|
||||||
|
presets.put("pallet_default", new PresetMap("pallet_default",
|
||||||
|
"pallet", new Location(null, 1, 0, 0)));
|
||||||
|
|
||||||
|
// Chest preset (1x1x1)
|
||||||
|
presets.put("chest_default", new PresetMap("chest_default",
|
||||||
|
"chest", new Location(null, 0, 0, 0)));
|
||||||
|
|
||||||
|
// Totem preset (1x2x1)
|
||||||
|
presets.put("totem_default", new PresetMap("totem_default",
|
||||||
|
"totem", new Location(null, 0, 0, 0)));
|
||||||
|
|
||||||
|
// Hatch preset (2x1x2)
|
||||||
|
presets.put("hatch_default", new PresetMap("hatch_default",
|
||||||
|
"hatch", new Location(null, 1, 0, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean placeObject(String templateName, Location location) {
|
||||||
|
MapTemplate template = templates.get(templateName);
|
||||||
|
if (template == null || !template.isLoaded()) return false;
|
||||||
|
|
||||||
|
template.place(location, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean placeObject(String templateName, Location location,
|
||||||
|
org.bukkit.block.structure.StructureRotation rotation) {
|
||||||
|
MapTemplate template = templates.get(templateName);
|
||||||
|
if (template == null || !template.isLoaded()) return false;
|
||||||
|
|
||||||
|
template.placeWithRotation(location, rotation,
|
||||||
|
org.bukkit.block.structure.Mirror.NONE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record PresetMap(String name, String templateName, Location offset) {}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
package dev.loki;
|
package dev.loki;
|
||||||
|
|
||||||
import dev.loki.command.DBDCommand;
|
import dev.loki.command.DBDCommand;
|
||||||
|
import dev.loki.command.SetupCommand;
|
||||||
import dev.loki.config.ConfigManager;
|
import dev.loki.config.ConfigManager;
|
||||||
import dev.loki.core.GameManager;
|
import dev.loki.core.GameManager;
|
||||||
|
import dev.loki.map.MapBuilder;
|
||||||
|
import dev.loki.map.TemplateManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public final class mdbd extends JavaPlugin {
|
public final class mdbd extends JavaPlugin {
|
||||||
private static mdbd instance;
|
private static mdbd instance;
|
||||||
private ConfigManager configManager;
|
private ConfigManager configManager;
|
||||||
private GameManager gameManager;
|
private GameManager gameManager;
|
||||||
|
private TemplateManager templateManager;
|
||||||
|
private MapBuilder mapBuilder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
|
@ -18,12 +23,21 @@ public final class mdbd extends JavaPlugin {
|
||||||
this.configManager = new ConfigManager(this);
|
this.configManager = new ConfigManager(this);
|
||||||
this.configManager.loadConfigs();
|
this.configManager.loadConfigs();
|
||||||
|
|
||||||
|
this.templateManager = new TemplateManager(this);
|
||||||
|
this.templateManager.loadAllTemplates();
|
||||||
|
this.templateManager.loadDefaultPresets();
|
||||||
|
|
||||||
|
this.mapBuilder = new MapBuilder(this, templateManager);
|
||||||
|
|
||||||
this.gameManager = new GameManager(this);
|
this.gameManager = new GameManager(this);
|
||||||
|
|
||||||
getCommand("dbd").setExecutor(new DBDCommand(this, gameManager));
|
getCommand("dbd").setExecutor(new DBDCommand(this, gameManager));
|
||||||
getCommand("dbd").setTabCompleter(new DBDCommand(this, gameManager));
|
getCommand("dbd").setTabCompleter(new DBDCommand(this, gameManager));
|
||||||
|
getCommand("dbdsetup").setExecutor(new SetupCommand(this));
|
||||||
|
getCommand("dbdsetup").setTabCompleter(new SetupCommand(this));
|
||||||
|
|
||||||
getLogger().info("Mdbd Plugin enabled successfully!");
|
getLogger().info("Mdbd Plugin enabled successfully!");
|
||||||
|
getLogger().info("Loaded " + templateManager.getAllTemplates().size() + " templates");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -32,6 +46,9 @@ public final class mdbd extends JavaPlugin {
|
||||||
if (gameManager != null) {
|
if (gameManager != null) {
|
||||||
gameManager.endGame();
|
gameManager.endGame();
|
||||||
}
|
}
|
||||||
|
if (configManager != null) {
|
||||||
|
configManager.saveAllConfigs();
|
||||||
|
}
|
||||||
instance = null;
|
instance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,4 +63,12 @@ public final class mdbd extends JavaPlugin {
|
||||||
public GameManager getGameManager() {
|
public GameManager getGameManager() {
|
||||||
return gameManager;
|
return gameManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TemplateManager getTemplateManager() {
|
||||||
|
return templateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapBuilder getMapBuilder() {
|
||||||
|
return mapBuilder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ commands:
|
||||||
description: "Главная команда DBD плагина"
|
description: "Главная команда DBD плагина"
|
||||||
usage: "/dbd <join|leave|create|forcestart|stop>"
|
usage: "/dbd <join|leave|create|forcestart|stop>"
|
||||||
permission: mdbd.player
|
permission: mdbd.player
|
||||||
|
dbdsetup:
|
||||||
|
description: "Команды настройки карты и объектов"
|
||||||
|
usage: "/dbdsetup <wand|pos1|pos2|save|load|set|build|clear|lobby>"
|
||||||
|
permission: mdbd.admin
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
mdbd.admin:
|
mdbd.admin:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue