Add WorldGuard auto-region creation and split ConfigLoader
- Add WorldGuardConfig with template-based naming ({mine_name}_{random_4}, etc.)
- Add WorldGuardRegionService for creating/updating/deleting WG regions
- Add WorldGuardConfigLoader for parsing WG config from YAML
- Add configurable flags, owners, members for WG regions
- Update MineConfig to include worldGuard section
- Update Mines.java to create/delete WG regions on mine create/delete
- Update MineFileManager to load WG defaults from defaults.yml
- Split ConfigLoader into specialized loaders:
- BlockConfigLoader, RegionConfigLoader, ResetConfigLoader
- RewardConfigLoader, TeleportConfigLoader, UIConfigLoader
- Reduce ConfigLoader from 427 lines to 151 lines
- Update defaults.yml with WorldGuard configuration section
This commit is contained in:
parent
75d785147d
commit
3ba6f303f8
15 changed files with 1126 additions and 318 deletions
|
|
@ -6,6 +6,7 @@ import dev.loki.lomines.core.service.MineFileManager;
|
|||
import dev.loki.lomines.core.service.MineRepository;
|
||||
import dev.loki.lomines.data.config.ConfigLoader;
|
||||
import dev.loki.lomines.data.config.MineConfig;
|
||||
import dev.loki.lomines.integration.worldguard.WorldGuardRegionService;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -26,6 +27,7 @@ public final class Mines {
|
|||
private final MineFileManager fileManager;
|
||||
private final MineRepository repository;
|
||||
private final MaskScanService maskScanService;
|
||||
private final WorldGuardRegionService worldGuardService;
|
||||
|
||||
public Mines(LoMinesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
|
@ -33,6 +35,7 @@ public final class Mines {
|
|||
this.fileManager = new MineFileManager(minesFolder);
|
||||
this.repository = new MineRepository(plugin, fileManager);
|
||||
this.maskScanService = new MaskScanService(repository, fileManager);
|
||||
this.worldGuardService = new WorldGuardRegionService(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,6 +80,7 @@ public final class Mines {
|
|||
|
||||
/**
|
||||
* Creates a new mine; optional corners define {@code selection.1} and {@code selection.2} (same world required).
|
||||
* If WorldGuard integration is enabled, creates a region for the mine.
|
||||
*/
|
||||
public void create(String name, Location corner1, Location corner2) throws IOException {
|
||||
if (repository.exists(name)) {
|
||||
|
|
@ -96,12 +100,19 @@ public final class Mines {
|
|||
throw new IOException("Failed to parse created mine configuration: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// Create WorldGuard region if enabled
|
||||
String regionName = worldGuardService.createRegion(name, config);
|
||||
if (regionName != null) {
|
||||
plugin.loLogger().info("Created WorldGuard region '" + regionName + "' for mine: " + name);
|
||||
}
|
||||
|
||||
repository.createAndStart(name, config);
|
||||
plugin.loLogger().info("Created mine: " + name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a mine by name.
|
||||
* Also deletes the associated WorldGuard region if it exists.
|
||||
*/
|
||||
public void delete(String name) throws IOException {
|
||||
Mine mine = repository.remove(name);
|
||||
|
|
@ -111,6 +122,14 @@ public final class Mines {
|
|||
}
|
||||
|
||||
mine.stop();
|
||||
|
||||
// Delete WorldGuard region if exists
|
||||
MineConfig config = mine.getConfig();
|
||||
boolean wgDeleted = worldGuardService.deleteRegion(name, config);
|
||||
if (wgDeleted) {
|
||||
plugin.loLogger().info("Deleted WorldGuard region for mine: " + name);
|
||||
}
|
||||
|
||||
fileManager.deleteConfig(name);
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +175,27 @@ public final class Mines {
|
|||
|
||||
/**
|
||||
* Reloads one mine from disk (stop, replace instance, start tasks).
|
||||
* Updates WorldGuard region if mine regions changed.
|
||||
*/
|
||||
public void reloadMine(String name) throws IOException, ConfigLoader.ConfigLoadException {
|
||||
// Get old config before reload
|
||||
Mine oldMine = repository.find(name).orElse(null);
|
||||
|
||||
repository.reload(name);
|
||||
|
||||
// Update WorldGuard region if mine exists
|
||||
if (oldMine != null) {
|
||||
Mine newMine = repository.find(name).orElse(null);
|
||||
if (newMine != null) {
|
||||
worldGuardService.updateRegion(name, newMine.getConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the WorldGuard region service for direct access.
|
||||
*/
|
||||
public WorldGuardRegionService getWorldGuardService() {
|
||||
return worldGuardService;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import dev.loki.lomines.data.config.reset.ResetConfig;
|
|||
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||
import dev.loki.lomines.util.location.Cuboid;
|
||||
import dev.loki.lomines.util.location.LocationParser;
|
||||
import org.bukkit.Location;
|
||||
|
|
@ -44,6 +45,7 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
|||
|
||||
/**
|
||||
* Creates a default mine configuration with new format.
|
||||
* WorldGuard region settings are loaded from defaults.yml.
|
||||
*/
|
||||
public void createDefaultConfig(String name, Location corner1, Location corner2) throws IOException {
|
||||
ensureFolderExists();
|
||||
|
|
@ -62,6 +64,9 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
|||
weights.put(new BlockKey.Vanilla(Material.STONE), 1.0);
|
||||
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
|
||||
|
||||
// Load WorldGuard defaults from _defaults.yml
|
||||
WorldGuardConfig wgConfig = loadWorldGuardDefaults();
|
||||
|
||||
// Build mine config with defaults
|
||||
MineConfig config = MineConfig.builder(name)
|
||||
.region(region)
|
||||
|
|
@ -70,12 +75,51 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
|||
.rewards(RewardConfig.empty())
|
||||
.teleport(TeleportConfig.disabled())
|
||||
.ui(UIConfig.defaults())
|
||||
.worldGuard(wgConfig)
|
||||
.build();
|
||||
|
||||
// Save using new loader
|
||||
configLoader.save(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads WorldGuard configuration from defaults.yml.
|
||||
*/
|
||||
private WorldGuardConfig loadWorldGuardDefaults() {
|
||||
Path defaultsPath = minesFolder.resolve("_defaults.yml");
|
||||
if (!Files.exists(defaultsPath)) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
|
||||
try {
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(defaultsPath.toFile());
|
||||
ConfigurationSection wgSection = yaml.getConfigurationSection("worldguard");
|
||||
|
||||
if (wgSection == null) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
|
||||
boolean enabled = wgSection.getBoolean("enabled", false);
|
||||
if (!enabled) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
|
||||
String template = wgSection.getString("region-template", "{mine_name}_{random_4}");
|
||||
|
||||
return WorldGuardConfig.builder()
|
||||
.enabled(true)
|
||||
.template(template)
|
||||
.owners(wgSection.getStringList("owners"))
|
||||
.members(wgSection.getStringList("members"))
|
||||
.flags(wgSection.getStringList("flags"))
|
||||
.protectOnCreate(wgSection.getBoolean("protect-on-create", true))
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
}
|
||||
|
||||
public MineConfig loadConfig(String name) throws IOException, ConfigLoader.ConfigLoadException {
|
||||
return configLoader.load(name);
|
||||
}
|
||||
|
|
@ -115,6 +159,7 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
|||
.rewards(config.rewards())
|
||||
.teleport(config.teleport())
|
||||
.ui(config.ui())
|
||||
.worldGuard(config.worldGuard())
|
||||
.build();
|
||||
|
||||
configLoader.save(updated);
|
||||
|
|
|
|||
|
|
@ -1,47 +1,38 @@
|
|||
package dev.loki.lomines.data.config;
|
||||
|
||||
import dev.loki.lomines.data.config.block.BlockConfig;
|
||||
import dev.loki.lomines.data.config.block.BlockKey;
|
||||
import dev.loki.lomines.data.config.block.FillMode;
|
||||
import dev.loki.lomines.data.config.region.RegionConfig;
|
||||
import dev.loki.lomines.data.config.reset.ResetConfig;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig.RewardEntry;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig.RewardEntry.ItemReward;
|
||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||
import dev.loki.lomines.util.location.Cuboid;
|
||||
import dev.loki.lomines.util.location.LocationParser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import dev.loki.lomines.data.config.loader.*;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Clean config loader for section-based configuration.
|
||||
* Supports YAML inheritance from defaults.
|
||||
* Delegates to specialized loaders for each section.
|
||||
*/
|
||||
public final class ConfigLoader {
|
||||
|
||||
private final Path dataFolder;
|
||||
private YamlConfiguration defaults;
|
||||
|
||||
// Section loaders
|
||||
private RegionConfigLoader regionLoader;
|
||||
private BlockConfigLoader blockLoader;
|
||||
private ResetConfigLoader resetLoader;
|
||||
private RewardConfigLoader rewardLoader;
|
||||
private TeleportConfigLoader teleportLoader;
|
||||
private UIConfigLoader uiLoader;
|
||||
private WorldGuardConfigLoader worldGuardLoader;
|
||||
|
||||
public ConfigLoader(Path dataFolder) {
|
||||
this.dataFolder = dataFolder;
|
||||
loadDefaults();
|
||||
initLoaders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load or create defaults.yml.
|
||||
*/
|
||||
private void loadDefaults() {
|
||||
Path defaultsPath = dataFolder.resolve("mines").resolve("_defaults.yml");
|
||||
defaults = new YamlConfiguration();
|
||||
|
|
@ -49,7 +40,6 @@ public final class ConfigLoader {
|
|||
if (Files.exists(defaultsPath)) {
|
||||
defaults = YamlConfiguration.loadConfiguration(defaultsPath.toFile());
|
||||
} else {
|
||||
// Create defaults with sensible values
|
||||
setDefaults(defaults);
|
||||
try {
|
||||
Files.createDirectories(defaultsPath.getParent());
|
||||
|
|
@ -73,8 +63,19 @@ public final class ConfigLoader {
|
|||
yaml.set("ui.timer-format", "mm:ss");
|
||||
|
||||
yaml.set("teleport.enabled", false);
|
||||
|
||||
yaml.set("rewards", List.of());
|
||||
|
||||
worldGuardLoader.setDefaults(yaml);
|
||||
}
|
||||
|
||||
private void initLoaders() {
|
||||
regionLoader = new RegionConfigLoader();
|
||||
blockLoader = new BlockConfigLoader();
|
||||
resetLoader = new ResetConfigLoader(defaults);
|
||||
rewardLoader = new RewardConfigLoader();
|
||||
teleportLoader = new TeleportConfigLoader();
|
||||
uiLoader = new UIConfigLoader(defaults);
|
||||
worldGuardLoader = new WorldGuardConfigLoader(defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -88,18 +89,17 @@ public final class ConfigLoader {
|
|||
}
|
||||
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(configPath.toFile());
|
||||
|
||||
// Merge with defaults (YAML inheritance)
|
||||
mergeDefaults(yaml);
|
||||
|
||||
try {
|
||||
return MineConfig.builder(mineName)
|
||||
.region(parseRegion(yaml))
|
||||
.blocks(parseBlocks(yaml))
|
||||
.reset(parseReset(yaml))
|
||||
.rewards(parseRewards(yaml))
|
||||
.teleport(parseTeleport(yaml))
|
||||
.ui(parseUI(yaml))
|
||||
.region(regionLoader.parse(yaml))
|
||||
.blocks(blockLoader.parse(yaml))
|
||||
.reset(resetLoader.parse(yaml))
|
||||
.rewards(rewardLoader.parse(yaml))
|
||||
.teleport(teleportLoader.parse(yaml))
|
||||
.ui(uiLoader.parse(yaml))
|
||||
.worldGuard(worldGuardLoader.parse(yaml))
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
throw new ConfigLoadException("Failed to load mine '" + mineName + "': " + e.getMessage(), e);
|
||||
|
|
@ -111,26 +111,15 @@ public final class ConfigLoader {
|
|||
*/
|
||||
public void save(MineConfig config) throws ConfigLoadException {
|
||||
Path configPath = dataFolder.resolve("mines").resolve(config.name() + ".yml");
|
||||
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
|
||||
// Save regions
|
||||
saveRegion(yaml, config.region());
|
||||
|
||||
// Save blocks
|
||||
saveBlocks(yaml, config.blocks());
|
||||
|
||||
// Save reset
|
||||
saveReset(yaml, config.reset());
|
||||
|
||||
// Save rewards
|
||||
saveRewards(yaml, config.rewards());
|
||||
|
||||
// Save teleport
|
||||
saveTeleport(yaml, config.teleport());
|
||||
|
||||
// Save UI
|
||||
saveUI(yaml, config.ui());
|
||||
regionLoader.save(yaml, config.region());
|
||||
blockLoader.save(yaml, config.blocks());
|
||||
resetLoader.save(yaml, config.reset());
|
||||
rewardLoader.save(yaml, config.rewards());
|
||||
teleportLoader.save(yaml, config.teleport());
|
||||
uiLoader.save(yaml, config.ui());
|
||||
worldGuardLoader.save(yaml, config.worldGuard());
|
||||
|
||||
try {
|
||||
Files.createDirectories(configPath.getParent());
|
||||
|
|
@ -140,272 +129,7 @@ public final class ConfigLoader {
|
|||
}
|
||||
}
|
||||
|
||||
// --- Parsers ---
|
||||
|
||||
private RegionConfig parseRegion(YamlConfiguration yaml) {
|
||||
List<Location> selections = new ArrayList<>();
|
||||
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
String key = "region.selection." + i;
|
||||
if (yaml.contains(key)) {
|
||||
String locStr = yaml.getString(key);
|
||||
if (locStr != null && !locStr.isBlank()) {
|
||||
selections.add(parseLocation(locStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selections.isEmpty()) {
|
||||
// Legacy fallback
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
String key = "selection." + i;
|
||||
if (yaml.contains(key)) {
|
||||
String locStr = yaml.getString(key);
|
||||
if (locStr != null && !locStr.isBlank()) {
|
||||
selections.add(parseLocation(locStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selections.size() < 2) {
|
||||
throw new IllegalArgumentException("Mine must have at least 2 selection points (1 region)");
|
||||
}
|
||||
|
||||
return RegionConfig.fromSelections(selections);
|
||||
}
|
||||
|
||||
private BlockConfig parseBlocks(YamlConfiguration yaml) {
|
||||
ConfigurationSection contents = yaml.getConfigurationSection("blocks.contents");
|
||||
if (contents == null) {
|
||||
contents = yaml.getConfigurationSection("contents"); // Legacy fallback
|
||||
}
|
||||
|
||||
if (contents == null) {
|
||||
throw new IllegalArgumentException("Missing 'blocks.contents' section");
|
||||
}
|
||||
|
||||
Map<BlockKey, Double> weights = new HashMap<>();
|
||||
for (String key : contents.getKeys(false)) {
|
||||
double weight = contents.getDouble(key);
|
||||
if (weight <= 0) continue;
|
||||
weights.put(BlockKey.deserialize(key), weight);
|
||||
}
|
||||
|
||||
FillMode fillMode = FillMode.valueOf(
|
||||
yaml.getString("blocks.fill-mode", "CUBOID").toUpperCase()
|
||||
);
|
||||
|
||||
// Parse mask config if applicable
|
||||
BlockConfig.MaskConfig mask = null;
|
||||
if (fillMode == FillMode.MASK) {
|
||||
String markerStr = yaml.getString("blocks.mask.marker", "pink_concrete");
|
||||
BlockKey marker = BlockKey.deserialize(markerStr);
|
||||
|
||||
Map<String, Boolean> positions = new HashMap<>();
|
||||
List<String> posList = yaml.getStringList("blocks.mask.positions");
|
||||
for (String pos : posList) {
|
||||
positions.put(pos, true);
|
||||
}
|
||||
|
||||
mask = new BlockConfig.MaskConfig(marker, positions);
|
||||
}
|
||||
|
||||
return new BlockConfig(weights, fillMode, mask);
|
||||
}
|
||||
|
||||
private ResetConfig parseReset(YamlConfiguration yaml) {
|
||||
String intervalStr = yaml.getString("reset.interval", defaults.getString("reset.interval", "5m"));
|
||||
|
||||
return ResetConfig.builder()
|
||||
.interval(intervalStr)
|
||||
.percentTrigger(yaml.getDouble("reset.percent-trigger", defaults.getDouble("reset.percent-trigger", 10.0)))
|
||||
.percentEnabled(yaml.getBoolean("reset.percent-enabled", defaults.getBoolean("reset.percent-enabled", false)))
|
||||
.commands(yaml.getStringList("reset.commands"))
|
||||
.broadcastMessage(yaml.getString("reset.broadcast", ""))
|
||||
.build();
|
||||
}
|
||||
|
||||
private RewardConfig parseRewards(YamlConfiguration yaml) {
|
||||
List<RewardEntry> entries = new ArrayList<>();
|
||||
List<Map<?, ?>> rewardList = yaml.getMapList("rewards");
|
||||
|
||||
if (rewardList.isEmpty()) {
|
||||
rewardList = yaml.getMapList("random-rewards"); // Legacy fallback
|
||||
}
|
||||
|
||||
for (Map<?, ?> map : rewardList) {
|
||||
entries.add(parseRewardEntry(map));
|
||||
}
|
||||
|
||||
return new RewardConfig(entries);
|
||||
}
|
||||
|
||||
private RewardEntry parseRewardEntry(Map<?, ?> map) {
|
||||
double chance = ((Number) map.getOrDefault("chance", 0)).doubleValue();
|
||||
|
||||
List<BlockKey> blocks = new ArrayList<>();
|
||||
List<?> blockList = (List<?>) map.get("blocks");
|
||||
if (blockList != null) {
|
||||
for (Object b : blockList) {
|
||||
blocks.add(BlockKey.deserialize(b.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemReward> items = new ArrayList<>();
|
||||
List<?> itemList = (List<?>) map.get("items");
|
||||
if (itemList != null) {
|
||||
for (Object i : itemList) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> itemMap = (Map<String, Object>) i;
|
||||
items.add(parseItemReward(itemMap));
|
||||
}
|
||||
}
|
||||
|
||||
List<String> commands = (List<String>) map.getOrDefault("commands", List.of());
|
||||
boolean preventDrops = (Boolean) map.getOrDefault("prevent-drops", false);
|
||||
|
||||
return new RewardEntry(blocks, chance, items, commands, preventDrops);
|
||||
}
|
||||
|
||||
private ItemReward parseItemReward(Map<String, Object> map) {
|
||||
String typeStr = (String) map.get("type");
|
||||
Material material = Material.matchMaterial(typeStr);
|
||||
if (material == null) {
|
||||
material = Material.STONE;
|
||||
}
|
||||
|
||||
int amount = ((Number) map.getOrDefault("amount", 1)).intValue();
|
||||
String name = (String) map.get("name");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> lore = (List<String>) map.getOrDefault("lore", List.of());
|
||||
|
||||
return new ItemReward(material, amount, name, lore);
|
||||
}
|
||||
|
||||
private TeleportConfig parseTeleport(YamlConfiguration yaml) {
|
||||
boolean enabled = yaml.getBoolean("teleport.enabled", false);
|
||||
if (!enabled) {
|
||||
return TeleportConfig.disabled();
|
||||
}
|
||||
|
||||
String locStr = yaml.getString("teleport.location");
|
||||
if (locStr == null) {
|
||||
return TeleportConfig.disabled();
|
||||
}
|
||||
|
||||
return TeleportConfig.at(parseLocation(locStr));
|
||||
}
|
||||
|
||||
private UIConfig parseUI(YamlConfiguration yaml) {
|
||||
boolean actionBarEnabled = yaml.getBoolean("ui.actionbar.enabled",
|
||||
defaults.getBoolean("ui.actionbar.enabled", true));
|
||||
|
||||
return new UIConfig(
|
||||
actionBarEnabled,
|
||||
yaml.getString("ui.actionbar.format", UIConfig.DEFAULT_ACTIONBAR_FORMAT),
|
||||
yaml.getDouble("ui.actionbar.range", 50.0),
|
||||
yaml.getString("ui.timer-format", UIConfig.DEFAULT_TIMER_FORMAT)
|
||||
);
|
||||
}
|
||||
|
||||
// --- Savers ---
|
||||
|
||||
private void saveRegion(YamlConfiguration yaml, RegionConfig region) {
|
||||
int i = 1;
|
||||
for (Cuboid cuboid : region.regions()) {
|
||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMin()));
|
||||
i++;
|
||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMax()));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBlocks(YamlConfiguration yaml, BlockConfig blocks) {
|
||||
for (var entry : blocks.weights().entrySet()) {
|
||||
yaml.set("blocks.contents." + entry.getKey().serialize(), entry.getValue());
|
||||
}
|
||||
yaml.set("blocks.fill-mode", blocks.fillMode().name().toLowerCase());
|
||||
|
||||
if (blocks.fillMode() == FillMode.MASK && blocks.mask() != null) {
|
||||
yaml.set("blocks.mask.marker", blocks.mask().marker().serialize());
|
||||
yaml.set("blocks.mask.positions", new ArrayList<>(blocks.mask().positions().keySet()));
|
||||
}
|
||||
}
|
||||
|
||||
private void saveReset(YamlConfiguration yaml, ResetConfig reset) {
|
||||
yaml.set("reset.interval", reset.intervalDisplay());
|
||||
yaml.set("reset.percent-trigger", reset.percentTrigger());
|
||||
yaml.set("reset.percent-enabled", reset.percentEnabled());
|
||||
yaml.set("reset.commands", reset.commands());
|
||||
yaml.set("reset.broadcast", reset.broadcastMessage());
|
||||
}
|
||||
|
||||
private void saveRewards(YamlConfiguration yaml, RewardConfig rewards) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (RewardEntry entry : rewards.entries()) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("chance", entry.chance());
|
||||
map.put("blocks", entry.blocks().stream().map(BlockKey::serialize).toList());
|
||||
|
||||
List<Map<String, Object>> items = new ArrayList<>();
|
||||
for (ItemReward item : entry.items()) {
|
||||
Map<String, Object> itemMap = new LinkedHashMap<>();
|
||||
itemMap.put("type", item.material().name().toLowerCase());
|
||||
itemMap.put("amount", item.amount());
|
||||
if (item.displayName() != null) {
|
||||
itemMap.put("name", item.displayName());
|
||||
}
|
||||
if (!item.lore().isEmpty()) {
|
||||
itemMap.put("lore", item.lore());
|
||||
}
|
||||
items.add(itemMap);
|
||||
}
|
||||
map.put("items", items);
|
||||
map.put("commands", entry.commands());
|
||||
map.put("prevent-drops", entry.preventVanillaDrops());
|
||||
list.add(map);
|
||||
}
|
||||
yaml.set("rewards", list);
|
||||
}
|
||||
|
||||
private void saveTeleport(YamlConfiguration yaml, TeleportConfig teleport) {
|
||||
yaml.set("teleport.enabled", teleport.enabled());
|
||||
teleport.getLocation().ifPresent(loc ->
|
||||
yaml.set("teleport.location", LocationParser.format(loc)));
|
||||
}
|
||||
|
||||
private void saveUI(YamlConfiguration yaml, UIConfig ui) {
|
||||
yaml.set("ui.actionbar.enabled", ui.actionBarEnabled());
|
||||
yaml.set("ui.actionbar.format", ui.actionBarFormat());
|
||||
yaml.set("ui.actionbar.range", ui.actionBarRange());
|
||||
yaml.set("ui.timer-format", ui.timerFormat());
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
private Location parseLocation(String str) {
|
||||
String[] parts = str.split(";");
|
||||
if (parts.length < 4) {
|
||||
throw new IllegalArgumentException("Invalid location format: " + str);
|
||||
}
|
||||
|
||||
World world = Bukkit.getWorld(parts[0]);
|
||||
if (world == null) {
|
||||
throw new IllegalArgumentException("Unknown world: " + parts[0]);
|
||||
}
|
||||
|
||||
double x = Double.parseDouble(parts[1]);
|
||||
double y = Double.parseDouble(parts[2]);
|
||||
double z = Double.parseDouble(parts[3]);
|
||||
float yaw = parts.length > 4 ? Float.parseFloat(parts[4]) : 0;
|
||||
float pitch = parts.length > 5 ? Float.parseFloat(parts[5]) : 0;
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
|
||||
private void mergeDefaults(YamlConfiguration yaml) {
|
||||
// Simple shallow merge - could be enhanced for deep merging
|
||||
for (String key : defaults.getKeys(true)) {
|
||||
if (!yaml.contains(key)) {
|
||||
yaml.set(key, defaults.get(key));
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import dev.loki.lomines.data.config.reset.ResetConfig;
|
|||
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
|
@ -20,7 +21,8 @@ public record MineConfig(
|
|||
ResetConfig reset,
|
||||
RewardConfig rewards,
|
||||
TeleportConfig teleport,
|
||||
UIConfig ui
|
||||
UIConfig ui,
|
||||
WorldGuardConfig worldGuard
|
||||
) {
|
||||
|
||||
public MineConfig {
|
||||
|
|
@ -36,6 +38,7 @@ public record MineConfig(
|
|||
Objects.requireNonNull(rewards, "Reward config cannot be null");
|
||||
Objects.requireNonNull(teleport, "Teleport config cannot be null");
|
||||
Objects.requireNonNull(ui, "UI config cannot be null");
|
||||
// worldGuard can be null (disabled by default)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,7 +73,8 @@ public record MineConfig(
|
|||
ResetConfig.defaults(),
|
||||
RewardConfig.empty(),
|
||||
TeleportConfig.disabled(),
|
||||
UIConfig.defaults()
|
||||
UIConfig.defaults(),
|
||||
WorldGuardConfig.disabled()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +88,7 @@ public record MineConfig(
|
|||
private RewardConfig rewards = RewardConfig.empty();
|
||||
private TeleportConfig teleport = TeleportConfig.disabled();
|
||||
private UIConfig ui = UIConfig.defaults();
|
||||
private WorldGuardConfig worldGuard = WorldGuardConfig.disabled();
|
||||
|
||||
private Builder(String name) {
|
||||
this.name = name;
|
||||
|
|
@ -119,8 +124,13 @@ public record MineConfig(
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder worldGuard(WorldGuardConfig worldGuard) {
|
||||
this.worldGuard = worldGuard;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MineConfig build() {
|
||||
return new MineConfig(name, region, blocks, reset, rewards, teleport, ui);
|
||||
return new MineConfig(name, region, blocks, reset, rewards, teleport, ui, worldGuard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.block.BlockConfig;
|
||||
import dev.loki.lomines.data.config.block.BlockKey;
|
||||
import dev.loki.lomines.data.config.block.FillMode;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Loader for blocks configuration section.
|
||||
*/
|
||||
public final class BlockConfigLoader {
|
||||
|
||||
/**
|
||||
* Parses block configuration from YAML.
|
||||
*/
|
||||
public BlockConfig parse(YamlConfiguration yaml) {
|
||||
ConfigurationSection contents = yaml.getConfigurationSection("blocks.contents");
|
||||
if (contents == null) {
|
||||
contents = yaml.getConfigurationSection("contents"); // Legacy fallback
|
||||
}
|
||||
|
||||
if (contents == null) {
|
||||
throw new IllegalArgumentException("Missing 'blocks.contents' section");
|
||||
}
|
||||
|
||||
Map<BlockKey, Double> weights = new HashMap<>();
|
||||
for (String key : contents.getKeys(false)) {
|
||||
double weight = contents.getDouble(key);
|
||||
if (weight <= 0) continue;
|
||||
weights.put(BlockKey.deserialize(key), weight);
|
||||
}
|
||||
|
||||
FillMode fillMode = FillMode.valueOf(
|
||||
yaml.getString("blocks.fill-mode", "CUBOID").toUpperCase()
|
||||
);
|
||||
|
||||
// Parse mask config if applicable
|
||||
BlockConfig.MaskConfig mask = null;
|
||||
if (fillMode == FillMode.MASK) {
|
||||
String markerStr = yaml.getString("blocks.mask.marker", "pink_concrete");
|
||||
BlockKey marker = BlockKey.deserialize(markerStr);
|
||||
|
||||
Map<String, Boolean> positions = new HashMap<>();
|
||||
List<String> posList = yaml.getStringList("blocks.mask.positions");
|
||||
for (String pos : posList) {
|
||||
positions.put(pos, true);
|
||||
}
|
||||
|
||||
mask = new BlockConfig.MaskConfig(marker, positions);
|
||||
}
|
||||
|
||||
return new BlockConfig(weights, fillMode, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves block configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, BlockConfig blocks) {
|
||||
for (var entry : blocks.weights().entrySet()) {
|
||||
yaml.set("blocks.contents." + entry.getKey().serialize(), entry.getValue());
|
||||
}
|
||||
yaml.set("blocks.fill-mode", blocks.fillMode().name().toLowerCase());
|
||||
|
||||
if (blocks.fillMode() == FillMode.MASK && blocks.mask() != null) {
|
||||
yaml.set("blocks.mask.marker", blocks.mask().marker().serialize());
|
||||
yaml.set("blocks.mask.positions", new ArrayList<>(blocks.mask().positions().keySet()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.region.RegionConfig;
|
||||
import dev.loki.lomines.util.location.LocationParser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loader for region configuration section.
|
||||
*/
|
||||
public final class RegionConfigLoader {
|
||||
|
||||
/**
|
||||
* Parses region configuration from YAML.
|
||||
*/
|
||||
public RegionConfig parse(YamlConfiguration yaml) {
|
||||
List<Location> selections = new ArrayList<>();
|
||||
|
||||
// Try new format first
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
String key = "region.selection." + i;
|
||||
if (yaml.contains(key)) {
|
||||
String locStr = yaml.getString(key);
|
||||
if (locStr != null && !locStr.isBlank()) {
|
||||
selections.add(parseLocation(locStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy fallback
|
||||
if (selections.isEmpty()) {
|
||||
for (int i = 1; i <= 10; i++) {
|
||||
String key = "selection." + i;
|
||||
if (yaml.contains(key)) {
|
||||
String locStr = yaml.getString(key);
|
||||
if (locStr != null && !locStr.isBlank()) {
|
||||
selections.add(parseLocation(locStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selections.size() < 2) {
|
||||
throw new IllegalArgumentException("Mine must have at least 2 selection points (1 region)");
|
||||
}
|
||||
|
||||
return RegionConfig.fromSelections(selections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves region configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, RegionConfig region) {
|
||||
int i = 1;
|
||||
for (var cuboid : region.regions()) {
|
||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMin()));
|
||||
i++;
|
||||
yaml.set("region.selection." + i, LocationParser.format(cuboid.getMax()));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private Location parseLocation(String str) {
|
||||
String[] parts = str.split(";");
|
||||
if (parts.length < 4) {
|
||||
throw new IllegalArgumentException("Invalid location format: " + str);
|
||||
}
|
||||
|
||||
World world = Bukkit.getWorld(parts[0]);
|
||||
if (world == null) {
|
||||
throw new IllegalArgumentException("Unknown world: " + parts[0]);
|
||||
}
|
||||
|
||||
double x = Double.parseDouble(parts[1]);
|
||||
double y = Double.parseDouble(parts[2]);
|
||||
double z = Double.parseDouble(parts[3]);
|
||||
float yaw = parts.length > 4 ? Float.parseFloat(parts[4]) : 0;
|
||||
float pitch = parts.length > 5 ? Float.parseFloat(parts[5]) : 0;
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.reset.ResetConfig;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Loader for reset configuration section.
|
||||
*/
|
||||
public final class ResetConfigLoader {
|
||||
|
||||
private final YamlConfiguration defaults;
|
||||
|
||||
public ResetConfigLoader(YamlConfiguration defaults) {
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses reset configuration from YAML.
|
||||
*/
|
||||
public ResetConfig parse(YamlConfiguration yaml) {
|
||||
String intervalStr = yaml.getString("reset.interval",
|
||||
defaults.getString("reset.interval", "5m"));
|
||||
|
||||
return ResetConfig.builder()
|
||||
.interval(intervalStr)
|
||||
.percentTrigger(yaml.getDouble("reset.percent-trigger",
|
||||
defaults.getDouble("reset.percent-trigger", 10.0)))
|
||||
.percentEnabled(yaml.getBoolean("reset.percent-enabled",
|
||||
defaults.getBoolean("reset.percent-enabled", false)))
|
||||
.commands(yaml.getStringList("reset.commands"))
|
||||
.broadcastMessage(yaml.getString("reset.broadcast", ""))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves reset configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, ResetConfig reset) {
|
||||
yaml.set("reset.interval", reset.intervalDisplay());
|
||||
yaml.set("reset.percent-trigger", reset.percentTrigger());
|
||||
yaml.set("reset.percent-enabled", reset.percentEnabled());
|
||||
yaml.set("reset.commands", reset.commands());
|
||||
yaml.set("reset.broadcast", reset.broadcastMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.block.BlockKey;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig.RewardEntry;
|
||||
import dev.loki.lomines.data.config.reward.RewardConfig.RewardEntry.ItemReward;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Loader for rewards configuration section.
|
||||
*/
|
||||
public final class RewardConfigLoader {
|
||||
|
||||
/**
|
||||
* Parses rewards from YAML configuration.
|
||||
*/
|
||||
public RewardConfig parse(YamlConfiguration yaml) {
|
||||
List<RewardEntry> entries = new ArrayList<>();
|
||||
List<Map<?, ?>> rewardList = yaml.getMapList("rewards");
|
||||
|
||||
if (rewardList.isEmpty()) {
|
||||
rewardList = yaml.getMapList("random-rewards"); // Legacy fallback
|
||||
}
|
||||
|
||||
for (Map<?, ?> map : rewardList) {
|
||||
entries.add(parseRewardEntry(map));
|
||||
}
|
||||
|
||||
return new RewardConfig(entries);
|
||||
}
|
||||
|
||||
private RewardEntry parseRewardEntry(Map<?, ?> map) {
|
||||
double chance = ((Number) map.getOrDefault("chance", 0)).doubleValue();
|
||||
|
||||
List<BlockKey> blocks = new ArrayList<>();
|
||||
List<?> blockList = (List<?>) map.get("blocks");
|
||||
if (blockList != null) {
|
||||
for (Object b : blockList) {
|
||||
blocks.add(BlockKey.deserialize(b.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemReward> items = new ArrayList<>();
|
||||
List<?> itemList = (List<?>) map.get("items");
|
||||
if (itemList != null) {
|
||||
for (Object i : itemList) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> itemMap = (Map<String, Object>) i;
|
||||
items.add(parseItemReward(itemMap));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> commands = (List<String>) map.getOrDefault("commands", List.of());
|
||||
boolean preventDrops = (Boolean) map.getOrDefault("prevent-drops", false);
|
||||
|
||||
return new RewardEntry(blocks, chance, items, commands, preventDrops);
|
||||
}
|
||||
|
||||
private ItemReward parseItemReward(Map<String, Object> map) {
|
||||
String typeStr = (String) map.get("type");
|
||||
Material material = Material.matchMaterial(typeStr);
|
||||
if (material == null) {
|
||||
material = Material.STONE;
|
||||
}
|
||||
|
||||
int amount = ((Number) map.getOrDefault("amount", 1)).intValue();
|
||||
String name = (String) map.get("name");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> lore = (List<String>) map.getOrDefault("lore", List.of());
|
||||
|
||||
return new ItemReward(material, amount, name, lore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves rewards to YAML configuration.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, RewardConfig rewards) {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (RewardEntry entry : rewards.entries()) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("chance", entry.chance());
|
||||
map.put("blocks", entry.blocks().stream().map(BlockKey::serialize).toList());
|
||||
|
||||
List<Map<String, Object>> items = new ArrayList<>();
|
||||
for (ItemReward item : entry.items()) {
|
||||
Map<String, Object> itemMap = new LinkedHashMap<>();
|
||||
itemMap.put("type", item.material().name().toLowerCase());
|
||||
itemMap.put("amount", item.amount());
|
||||
if (item.displayName() != null) {
|
||||
itemMap.put("name", item.displayName());
|
||||
}
|
||||
if (!item.lore().isEmpty()) {
|
||||
itemMap.put("lore", item.lore());
|
||||
}
|
||||
items.add(itemMap);
|
||||
}
|
||||
map.put("items", items);
|
||||
map.put("commands", entry.commands());
|
||||
map.put("prevent-drops", entry.preventVanillaDrops());
|
||||
list.add(map);
|
||||
}
|
||||
yaml.set("rewards", list);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||
import dev.loki.lomines.util.location.LocationParser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
/**
|
||||
* Loader for teleport configuration section.
|
||||
*/
|
||||
public final class TeleportConfigLoader {
|
||||
|
||||
/**
|
||||
* Parses teleport configuration from YAML.
|
||||
*/
|
||||
public TeleportConfig parse(YamlConfiguration yaml) {
|
||||
boolean enabled = yaml.getBoolean("teleport.enabled", false);
|
||||
if (!enabled) {
|
||||
return TeleportConfig.disabled();
|
||||
}
|
||||
|
||||
String locStr = yaml.getString("teleport.location");
|
||||
if (locStr == null || locStr.isBlank()) {
|
||||
return TeleportConfig.disabled();
|
||||
}
|
||||
|
||||
return TeleportConfig.at(parseLocation(locStr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves teleport configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, TeleportConfig teleport) {
|
||||
yaml.set("teleport.enabled", teleport.enabled());
|
||||
teleport.getLocation().ifPresent(loc ->
|
||||
yaml.set("teleport.location", LocationParser.format(loc)));
|
||||
}
|
||||
|
||||
private Location parseLocation(String str) {
|
||||
String[] parts = str.split(";");
|
||||
if (parts.length < 4) {
|
||||
throw new IllegalArgumentException("Invalid location format: " + str);
|
||||
}
|
||||
|
||||
World world = Bukkit.getWorld(parts[0]);
|
||||
if (world == null) {
|
||||
throw new IllegalArgumentException("Unknown world: " + parts[0]);
|
||||
}
|
||||
|
||||
double x = Double.parseDouble(parts[1]);
|
||||
double y = Double.parseDouble(parts[2]);
|
||||
double z = Double.parseDouble(parts[3]);
|
||||
float yaw = parts.length > 4 ? Float.parseFloat(parts[4]) : 0;
|
||||
float pitch = parts.length > 5 ? Float.parseFloat(parts[5]) : 0;
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
/**
|
||||
* Loader for UI configuration section.
|
||||
*/
|
||||
public final class UIConfigLoader {
|
||||
|
||||
private final YamlConfiguration defaults;
|
||||
|
||||
public UIConfigLoader(YamlConfiguration defaults) {
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses UI configuration from YAML.
|
||||
*/
|
||||
public UIConfig parse(YamlConfiguration yaml) {
|
||||
boolean actionBarEnabled = yaml.getBoolean("ui.actionbar.enabled",
|
||||
defaults.getBoolean("ui.actionbar.enabled", true));
|
||||
|
||||
return new UIConfig(
|
||||
actionBarEnabled,
|
||||
yaml.getString("ui.actionbar.format", UIConfig.DEFAULT_ACTIONBAR_FORMAT),
|
||||
yaml.getDouble("ui.actionbar.range", 50.0),
|
||||
yaml.getString("ui.timer-format", UIConfig.DEFAULT_TIMER_FORMAT)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves UI configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, UIConfig ui) {
|
||||
yaml.set("ui.actionbar.enabled", ui.actionBarEnabled());
|
||||
yaml.set("ui.actionbar.format", ui.actionBarFormat());
|
||||
yaml.set("ui.actionbar.range", ui.actionBarRange());
|
||||
yaml.set("ui.timer-format", ui.timerFormat());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.ConfigLoader;
|
||||
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Loader for WorldGuard configuration section.
|
||||
*/
|
||||
public final class WorldGuardConfigLoader {
|
||||
|
||||
private final YamlConfiguration defaults;
|
||||
|
||||
public WorldGuardConfigLoader(YamlConfiguration defaults) {
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses WorldGuard configuration from YAML.
|
||||
*/
|
||||
public WorldGuardConfig parse(YamlConfiguration yaml) {
|
||||
ConfigurationSection wgSection = yaml.getConfigurationSection("worldguard");
|
||||
if (wgSection == null) {
|
||||
// Check defaults
|
||||
boolean defaultEnabled = defaults.getBoolean("worldguard.enabled", false);
|
||||
if (!defaultEnabled) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
}
|
||||
|
||||
boolean enabled = yaml.getBoolean("worldguard.enabled",
|
||||
defaults.getBoolean("worldguard.enabled", false));
|
||||
|
||||
if (!enabled) {
|
||||
return WorldGuardConfig.disabled();
|
||||
}
|
||||
|
||||
String template = yaml.getString("worldguard.region-template",
|
||||
defaults.getString("worldguard.region-template", "{mine_name}_{random_4}"));
|
||||
|
||||
List<String> owners = yaml.getStringList("worldguard.owners");
|
||||
if (owners.isEmpty()) {
|
||||
owners = defaults.getStringList("worldguard.owners");
|
||||
}
|
||||
|
||||
List<String> members = yaml.getStringList("worldguard.members");
|
||||
if (members.isEmpty()) {
|
||||
members = defaults.getStringList("worldguard.members");
|
||||
}
|
||||
|
||||
List<String> flags = yaml.getStringList("worldguard.flags");
|
||||
if (flags.isEmpty()) {
|
||||
flags = defaults.getStringList("worldguard.flags");
|
||||
}
|
||||
if (flags.isEmpty()) {
|
||||
flags = List.of("passthrough=deny", "build=allow");
|
||||
}
|
||||
|
||||
boolean protect = yaml.getBoolean("worldguard.protect-on-create",
|
||||
defaults.getBoolean("worldguard.protect-on-create", true));
|
||||
|
||||
return WorldGuardConfig.builder()
|
||||
.enabled(true)
|
||||
.template(template)
|
||||
.owners(owners)
|
||||
.members(members)
|
||||
.flags(flags)
|
||||
.protectOnCreate(protect)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves WorldGuard configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, WorldGuardConfig config) {
|
||||
yaml.set("worldguard.enabled", config.enabled());
|
||||
|
||||
if (config.enabled()) {
|
||||
yaml.set("worldguard.region-template", config.regionNameTemplate());
|
||||
yaml.set("worldguard.owners", config.owners());
|
||||
yaml.set("worldguard.members", config.members());
|
||||
yaml.set("worldguard.flags", config.flags());
|
||||
yaml.set("worldguard.protect-on-create", config.protectOnCreate());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default values for WorldGuard configuration.
|
||||
*/
|
||||
public void setDefaults(YamlConfiguration yaml) {
|
||||
yaml.set("worldguard.enabled", false);
|
||||
yaml.set("worldguard.region-template", "{mine_name}_{random_4}");
|
||||
yaml.set("worldguard.owners", List.of());
|
||||
yaml.set("worldguard.members", List.of());
|
||||
yaml.set("worldguard.flags", List.of("passthrough=deny", "build=allow"));
|
||||
yaml.set("worldguard.protect-on-create", true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package dev.loki.lomines.integration.worldguard;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Configuration for WorldGuard auto-region creation.
|
||||
*/
|
||||
public record WorldGuardConfig(
|
||||
boolean enabled,
|
||||
String regionNameTemplate,
|
||||
List<String> owners,
|
||||
List<String> members,
|
||||
List<String> flags,
|
||||
boolean protectOnCreate
|
||||
) {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
private static final String DEFAULT_TEMPLATE = "{mine_name}_{random_4}";
|
||||
|
||||
public WorldGuardConfig {
|
||||
enabled = enabled;
|
||||
regionNameTemplate = regionNameTemplate != null && !regionNameTemplate.isBlank()
|
||||
? regionNameTemplate
|
||||
: DEFAULT_TEMPLATE;
|
||||
owners = owners != null ? List.copyOf(owners) : List.of();
|
||||
members = members != null ? List.copyOf(members) : List.of();
|
||||
flags = flags != null ? List.copyOf(flags) : List.of(
|
||||
"passthrough=deny",
|
||||
"build=allow"
|
||||
);
|
||||
protectOnCreate = protectOnCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a region name from the template.
|
||||
*
|
||||
* @param mineName the name of the mine
|
||||
* @return the generated region name
|
||||
*/
|
||||
public String generateRegionName(String mineName) {
|
||||
String result = regionNameTemplate;
|
||||
|
||||
// Replace {mine_name}
|
||||
result = result.replace("{mine_name}", mineName);
|
||||
|
||||
// Replace {random_4} with 4 random digits
|
||||
if (result.contains("{random_4}")) {
|
||||
int randomNum = RANDOM.nextInt(10000);
|
||||
result = result.replace("{random_4}", String.format("%04d", randomNum));
|
||||
}
|
||||
|
||||
// Replace {random_3} with 3 random digits
|
||||
if (result.contains("{random_3}")) {
|
||||
int randomNum = RANDOM.nextInt(1000);
|
||||
result = result.replace("{random_3}", String.format("%03d", randomNum));
|
||||
}
|
||||
|
||||
// Replace {random_6} with 6 random alphanumeric
|
||||
if (result.contains("{random_6}")) {
|
||||
result = result.replace("{random_6}", generateRandomString(6));
|
||||
}
|
||||
|
||||
// Sanitize for WorldGuard (only alphanumeric, underscore, hyphen)
|
||||
return result.replaceAll("[^a-zA-Z0-9_-]", "_").toLowerCase();
|
||||
}
|
||||
|
||||
private String generateRandomString(int length) {
|
||||
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(chars.charAt(RANDOM.nextInt(chars.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default configuration with auto-region enabled.
|
||||
*/
|
||||
public static WorldGuardConfig defaults() {
|
||||
return new WorldGuardConfig(
|
||||
true,
|
||||
DEFAULT_TEMPLATE,
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of("passthrough=deny", "build=allow"),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled configuration.
|
||||
*/
|
||||
public static WorldGuardConfig disabled() {
|
||||
return new WorldGuardConfig(
|
||||
false,
|
||||
DEFAULT_TEMPLATE,
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for fluent construction.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private boolean enabled = true;
|
||||
private String template = DEFAULT_TEMPLATE;
|
||||
private List<String> owners = List.of();
|
||||
private List<String> members = List.of();
|
||||
private List<String> flags = List.of("passthrough=deny", "build=allow");
|
||||
private boolean protectOnCreate = true;
|
||||
|
||||
public Builder enabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder template(String template) {
|
||||
this.template = template;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder owners(List<String> owners) {
|
||||
this.owners = owners;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder members(List<String> members) {
|
||||
this.members = members;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder flags(List<String> flags) {
|
||||
this.flags = flags;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder protectOnCreate(boolean protect) {
|
||||
this.protectOnCreate = protect;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorldGuardConfig build() {
|
||||
return new WorldGuardConfig(enabled, template, owners, members, flags, protectOnCreate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package dev.loki.lomines.integration.worldguard;
|
||||
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
|
||||
/**
|
||||
* Parses and applies WorldGuard flags from string entries.
|
||||
*/
|
||||
public final class WorldGuardFlagParser {
|
||||
|
||||
private final LoMinesPlugin plugin;
|
||||
|
||||
public WorldGuardFlagParser(LoMinesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and sets a flag from a "key=value" string entry.
|
||||
*
|
||||
* @param region the region to set the flag on
|
||||
* @param flagEntry the flag entry in format "flag=value"
|
||||
*/
|
||||
public void parseAndSetFlag(ProtectedRegion region, String flagEntry) {
|
||||
String[] parts = flagEntry.split("=", 2);
|
||||
if (parts.length != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
String flagName = parts[0].trim().toLowerCase();
|
||||
String value = parts[1].trim();
|
||||
|
||||
try {
|
||||
switch (flagName) {
|
||||
case "passthrough" -> setStateFlag(region, Flags.PASSTHROUGH, value);
|
||||
case "build" -> setStateFlag(region, Flags.BUILD, value);
|
||||
case "pvp" -> setStateFlag(region, Flags.PVP, value);
|
||||
case "tnt" -> setStateFlag(region, Flags.TNT, value);
|
||||
case "creeper-explosion" -> setStateFlag(region, Flags.CREEPER_EXPLOSION, value);
|
||||
case "greeting" -> region.setFlag(Flags.GREET_MESSAGE, value);
|
||||
case "farewell" -> region.setFlag(Flags.FAREWELL_MESSAGE, value);
|
||||
default -> plugin.loLogger().warn("Unknown WorldGuard flag: " + flagName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.loLogger().warn("Failed to set flag " + flagName + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void setStateFlag(ProtectedRegion region, StateFlag flag, String value) {
|
||||
region.setFlag(flag, "allow".equalsIgnoreCase(value)
|
||||
? StateFlag.State.ALLOW
|
||||
: StateFlag.State.DENY);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
package dev.loki.lomines.integration.worldguard;
|
||||
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.data.config.MineConfig;
|
||||
import dev.loki.lomines.util.location.Cuboid;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Service for managing WorldGuard regions for mines.
|
||||
* Creates, updates, and deletes WorldGuard regions when mines are managed.
|
||||
*/
|
||||
public final class WorldGuardRegionService {
|
||||
|
||||
private final LoMinesPlugin plugin;
|
||||
private final WorldGuardFlagParser flagParser;
|
||||
private boolean worldGuardEnabled;
|
||||
|
||||
public WorldGuardRegionService(LoMinesPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.flagParser = new WorldGuardFlagParser(plugin);
|
||||
checkWorldGuard();
|
||||
}
|
||||
|
||||
private void checkWorldGuard() {
|
||||
this.worldGuardEnabled = Bukkit.getPluginManager().getPlugin("WorldGuard") != null
|
||||
&& Bukkit.getPluginManager().isPluginEnabled("WorldGuard");
|
||||
|
||||
if (worldGuardEnabled) {
|
||||
plugin.loLogger().info("WorldGuard integration enabled - auto-region creation active");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WorldGuard region for a mine if enabled in config.
|
||||
*/
|
||||
public String createRegion(String mineName, MineConfig config) {
|
||||
if (!worldGuardEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
WorldGuardConfig wgConfig = config.worldGuard();
|
||||
if (wgConfig == null || !wgConfig.enabled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String regionName = wgConfig.generateRegionName(mineName);
|
||||
|
||||
try {
|
||||
RegionManager regionManager = getRegionManager(config.worldName());
|
||||
if (regionManager == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (regionManager.hasRegion(regionName)) {
|
||||
plugin.loLogger().info("WorldGuard region already exists: " + regionName);
|
||||
return regionName;
|
||||
}
|
||||
|
||||
ProtectedCuboidRegion region = createRegionFromCuboids(regionName, config);
|
||||
if (region == null) {
|
||||
plugin.loLogger().warn("Failed to create region for mine " + mineName + ": no valid regions");
|
||||
return null;
|
||||
}
|
||||
|
||||
applyOwnersAndMembers(region, wgConfig);
|
||||
applyFlags(region, wgConfig.flags());
|
||||
|
||||
regionManager.addRegion(region);
|
||||
plugin.loLogger().info("Created WorldGuard region '" + regionName + "' for mine " + mineName);
|
||||
return regionName;
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.loLogger().error("Failed to create WorldGuard region for mine " + mineName + ": " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an existing WorldGuard region when mine regions change.
|
||||
*/
|
||||
public boolean updateRegion(String mineName, MineConfig config) {
|
||||
if (!worldGuardEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldGuardConfig wgConfig = config.worldGuard();
|
||||
if (wgConfig == null || !wgConfig.enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String regionName = wgConfig.generateRegionName(mineName);
|
||||
|
||||
try {
|
||||
RegionManager regionManager = getRegionManager(config.worldName());
|
||||
if (regionManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (regionManager.hasRegion(regionName)) {
|
||||
regionManager.removeRegion(regionName);
|
||||
}
|
||||
|
||||
return createRegion(mineName, config) != null;
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.loLogger().error("Failed to update WorldGuard region: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a WorldGuard region for a mine.
|
||||
*/
|
||||
public boolean deleteRegion(String mineName, MineConfig config) {
|
||||
if (!worldGuardEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldGuardConfig wgConfig = config.worldGuard();
|
||||
if (wgConfig == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String regionName = wgConfig.generateRegionName(mineName);
|
||||
|
||||
try {
|
||||
RegionManager regionManager = getRegionManager(config.worldName());
|
||||
if (regionManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (regionManager.hasRegion(regionName)) {
|
||||
regionManager.removeRegion(regionName);
|
||||
plugin.loLogger().info("Deleted WorldGuard region: " + regionName);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
plugin.loLogger().error("Failed to delete WorldGuard region: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private RegionManager getRegionManager(String worldName) {
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return WorldGuard.getInstance()
|
||||
.getPlatform()
|
||||
.getRegionContainer()
|
||||
.get(com.sk89q.worldedit.bukkit.BukkitAdapter.adapt(world));
|
||||
}
|
||||
|
||||
private ProtectedCuboidRegion createRegionFromCuboids(String regionName, MineConfig config) {
|
||||
List<Cuboid> regions = config.region().regions();
|
||||
if (regions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Cuboid first = regions.get(0);
|
||||
BlockVector3 min = BlockVector3.at(first.getMinX(), first.getMinY(), first.getMinZ());
|
||||
BlockVector3 max = BlockVector3.at(first.getMaxX(), first.getMaxY(), first.getMaxZ());
|
||||
|
||||
ProtectedCuboidRegion mainRegion = new ProtectedCuboidRegion(regionName, min, max);
|
||||
|
||||
if (regions.size() > 1) {
|
||||
plugin.loLogger().warn("Mine " + regionName + " has multiple regions - " +
|
||||
"only the first region is fully protected by WorldGuard");
|
||||
}
|
||||
|
||||
return mainRegion;
|
||||
}
|
||||
|
||||
private void applyOwnersAndMembers(ProtectedCuboidRegion region, WorldGuardConfig wgConfig) {
|
||||
// Set owners
|
||||
for (String owner : wgConfig.owners()) {
|
||||
if (owner.startsWith("uuid:")) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(owner.substring(5));
|
||||
region.getOwners().addPlayer(uuid);
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.loLogger().warn("Invalid owner UUID: " + owner);
|
||||
}
|
||||
} else {
|
||||
region.getOwners().addPlayer(owner);
|
||||
}
|
||||
}
|
||||
|
||||
// Set members
|
||||
for (String member : wgConfig.members()) {
|
||||
if (member.startsWith("uuid:")) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(member.substring(5));
|
||||
region.getMembers().addPlayer(uuid);
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.loLogger().warn("Invalid member UUID: " + member);
|
||||
}
|
||||
} else {
|
||||
region.getMembers().addPlayer(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyFlags(ProtectedCuboidRegion region, List<String> flags) {
|
||||
for (String flagEntry : flags) {
|
||||
flagParser.parseAndSetFlag(region, flagEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWorldGuardEnabled() {
|
||||
return worldGuardEnabled;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue