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.core.service.MineRepository;
|
||||||
import dev.loki.lomines.data.config.ConfigLoader;
|
import dev.loki.lomines.data.config.ConfigLoader;
|
||||||
import dev.loki.lomines.data.config.MineConfig;
|
import dev.loki.lomines.data.config.MineConfig;
|
||||||
|
import dev.loki.lomines.integration.worldguard.WorldGuardRegionService;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -26,6 +27,7 @@ public final class Mines {
|
||||||
private final MineFileManager fileManager;
|
private final MineFileManager fileManager;
|
||||||
private final MineRepository repository;
|
private final MineRepository repository;
|
||||||
private final MaskScanService maskScanService;
|
private final MaskScanService maskScanService;
|
||||||
|
private final WorldGuardRegionService worldGuardService;
|
||||||
|
|
||||||
public Mines(LoMinesPlugin plugin) {
|
public Mines(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
|
@ -33,6 +35,7 @@ public final class Mines {
|
||||||
this.fileManager = new MineFileManager(minesFolder);
|
this.fileManager = new MineFileManager(minesFolder);
|
||||||
this.repository = new MineRepository(plugin, fileManager);
|
this.repository = new MineRepository(plugin, fileManager);
|
||||||
this.maskScanService = new MaskScanService(repository, 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).
|
* 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 {
|
public void create(String name, Location corner1, Location corner2) throws IOException {
|
||||||
if (repository.exists(name)) {
|
if (repository.exists(name)) {
|
||||||
|
|
@ -96,12 +100,19 @@ public final class Mines {
|
||||||
throw new IOException("Failed to parse created mine configuration: " + e.getMessage(), e);
|
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);
|
repository.createAndStart(name, config);
|
||||||
plugin.loLogger().info("Created mine: " + name);
|
plugin.loLogger().info("Created mine: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a mine by name.
|
* Deletes a mine by name.
|
||||||
|
* Also deletes the associated WorldGuard region if it exists.
|
||||||
*/
|
*/
|
||||||
public void delete(String name) throws IOException {
|
public void delete(String name) throws IOException {
|
||||||
Mine mine = repository.remove(name);
|
Mine mine = repository.remove(name);
|
||||||
|
|
@ -111,6 +122,14 @@ public final class Mines {
|
||||||
}
|
}
|
||||||
|
|
||||||
mine.stop();
|
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);
|
fileManager.deleteConfig(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,8 +175,27 @@ public final class Mines {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reloads one mine from disk (stop, replace instance, start tasks).
|
* 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 {
|
public void reloadMine(String name) throws IOException, ConfigLoader.ConfigLoadException {
|
||||||
|
// Get old config before reload
|
||||||
|
Mine oldMine = repository.find(name).orElse(null);
|
||||||
|
|
||||||
repository.reload(name);
|
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.reward.RewardConfig;
|
||||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
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.Cuboid;
|
||||||
import dev.loki.lomines.util.location.LocationParser;
|
import dev.loki.lomines.util.location.LocationParser;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
|
@ -44,6 +45,7 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a default mine configuration with new format.
|
* 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 {
|
public void createDefaultConfig(String name, Location corner1, Location corner2) throws IOException {
|
||||||
ensureFolderExists();
|
ensureFolderExists();
|
||||||
|
|
@ -62,6 +64,9 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
weights.put(new BlockKey.Vanilla(Material.STONE), 1.0);
|
weights.put(new BlockKey.Vanilla(Material.STONE), 1.0);
|
||||||
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
|
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
|
||||||
|
|
||||||
|
// Load WorldGuard defaults from _defaults.yml
|
||||||
|
WorldGuardConfig wgConfig = loadWorldGuardDefaults();
|
||||||
|
|
||||||
// Build mine config with defaults
|
// Build mine config with defaults
|
||||||
MineConfig config = MineConfig.builder(name)
|
MineConfig config = MineConfig.builder(name)
|
||||||
.region(region)
|
.region(region)
|
||||||
|
|
@ -70,12 +75,51 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
.rewards(RewardConfig.empty())
|
.rewards(RewardConfig.empty())
|
||||||
.teleport(TeleportConfig.disabled())
|
.teleport(TeleportConfig.disabled())
|
||||||
.ui(UIConfig.defaults())
|
.ui(UIConfig.defaults())
|
||||||
|
.worldGuard(wgConfig)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Save using new loader
|
// Save using new loader
|
||||||
configLoader.save(config);
|
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 {
|
public MineConfig loadConfig(String name) throws IOException, ConfigLoader.ConfigLoadException {
|
||||||
return configLoader.load(name);
|
return configLoader.load(name);
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +159,7 @@ public record MineFileManager(Path minesFolder, ConfigLoader configLoader) {
|
||||||
.rewards(config.rewards())
|
.rewards(config.rewards())
|
||||||
.teleport(config.teleport())
|
.teleport(config.teleport())
|
||||||
.ui(config.ui())
|
.ui(config.ui())
|
||||||
|
.worldGuard(config.worldGuard())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
configLoader.save(updated);
|
configLoader.save(updated);
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,38 @@
|
||||||
package dev.loki.lomines.data.config;
|
package dev.loki.lomines.data.config;
|
||||||
|
|
||||||
import dev.loki.lomines.data.config.block.BlockConfig;
|
import dev.loki.lomines.data.config.loader.*;
|
||||||
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 org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.time.Duration;
|
import java.util.List;
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean config loader for section-based configuration.
|
* Clean config loader for section-based configuration.
|
||||||
* Supports YAML inheritance from defaults.
|
* Supports YAML inheritance from defaults.
|
||||||
|
* Delegates to specialized loaders for each section.
|
||||||
*/
|
*/
|
||||||
public final class ConfigLoader {
|
public final class ConfigLoader {
|
||||||
|
|
||||||
private final Path dataFolder;
|
private final Path dataFolder;
|
||||||
private YamlConfiguration defaults;
|
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) {
|
public ConfigLoader(Path dataFolder) {
|
||||||
this.dataFolder = dataFolder;
|
this.dataFolder = dataFolder;
|
||||||
loadDefaults();
|
loadDefaults();
|
||||||
|
initLoaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load or create defaults.yml.
|
|
||||||
*/
|
|
||||||
private void loadDefaults() {
|
private void loadDefaults() {
|
||||||
Path defaultsPath = dataFolder.resolve("mines").resolve("_defaults.yml");
|
Path defaultsPath = dataFolder.resolve("mines").resolve("_defaults.yml");
|
||||||
defaults = new YamlConfiguration();
|
defaults = new YamlConfiguration();
|
||||||
|
|
@ -49,7 +40,6 @@ public final class ConfigLoader {
|
||||||
if (Files.exists(defaultsPath)) {
|
if (Files.exists(defaultsPath)) {
|
||||||
defaults = YamlConfiguration.loadConfiguration(defaultsPath.toFile());
|
defaults = YamlConfiguration.loadConfiguration(defaultsPath.toFile());
|
||||||
} else {
|
} else {
|
||||||
// Create defaults with sensible values
|
|
||||||
setDefaults(defaults);
|
setDefaults(defaults);
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(defaultsPath.getParent());
|
Files.createDirectories(defaultsPath.getParent());
|
||||||
|
|
@ -73,8 +63,19 @@ public final class ConfigLoader {
|
||||||
yaml.set("ui.timer-format", "mm:ss");
|
yaml.set("ui.timer-format", "mm:ss");
|
||||||
|
|
||||||
yaml.set("teleport.enabled", false);
|
yaml.set("teleport.enabled", false);
|
||||||
|
|
||||||
yaml.set("rewards", List.of());
|
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());
|
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(configPath.toFile());
|
||||||
|
|
||||||
// Merge with defaults (YAML inheritance)
|
|
||||||
mergeDefaults(yaml);
|
mergeDefaults(yaml);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return MineConfig.builder(mineName)
|
return MineConfig.builder(mineName)
|
||||||
.region(parseRegion(yaml))
|
.region(regionLoader.parse(yaml))
|
||||||
.blocks(parseBlocks(yaml))
|
.blocks(blockLoader.parse(yaml))
|
||||||
.reset(parseReset(yaml))
|
.reset(resetLoader.parse(yaml))
|
||||||
.rewards(parseRewards(yaml))
|
.rewards(rewardLoader.parse(yaml))
|
||||||
.teleport(parseTeleport(yaml))
|
.teleport(teleportLoader.parse(yaml))
|
||||||
.ui(parseUI(yaml))
|
.ui(uiLoader.parse(yaml))
|
||||||
|
.worldGuard(worldGuardLoader.parse(yaml))
|
||||||
.build();
|
.build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ConfigLoadException("Failed to load mine '" + mineName + "': " + e.getMessage(), 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 {
|
public void save(MineConfig config) throws ConfigLoadException {
|
||||||
Path configPath = dataFolder.resolve("mines").resolve(config.name() + ".yml");
|
Path configPath = dataFolder.resolve("mines").resolve(config.name() + ".yml");
|
||||||
|
|
||||||
YamlConfiguration yaml = new YamlConfiguration();
|
YamlConfiguration yaml = new YamlConfiguration();
|
||||||
|
|
||||||
// Save regions
|
regionLoader.save(yaml, config.region());
|
||||||
saveRegion(yaml, config.region());
|
blockLoader.save(yaml, config.blocks());
|
||||||
|
resetLoader.save(yaml, config.reset());
|
||||||
// Save blocks
|
rewardLoader.save(yaml, config.rewards());
|
||||||
saveBlocks(yaml, config.blocks());
|
teleportLoader.save(yaml, config.teleport());
|
||||||
|
uiLoader.save(yaml, config.ui());
|
||||||
// Save reset
|
worldGuardLoader.save(yaml, config.worldGuard());
|
||||||
saveReset(yaml, config.reset());
|
|
||||||
|
|
||||||
// Save rewards
|
|
||||||
saveRewards(yaml, config.rewards());
|
|
||||||
|
|
||||||
// Save teleport
|
|
||||||
saveTeleport(yaml, config.teleport());
|
|
||||||
|
|
||||||
// Save UI
|
|
||||||
saveUI(yaml, config.ui());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(configPath.getParent());
|
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) {
|
private void mergeDefaults(YamlConfiguration yaml) {
|
||||||
// Simple shallow merge - could be enhanced for deep merging
|
|
||||||
for (String key : defaults.getKeys(true)) {
|
for (String key : defaults.getKeys(true)) {
|
||||||
if (!yaml.contains(key)) {
|
if (!yaml.contains(key)) {
|
||||||
yaml.set(key, defaults.get(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.reward.RewardConfig;
|
||||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||||
|
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
@ -20,7 +21,8 @@ public record MineConfig(
|
||||||
ResetConfig reset,
|
ResetConfig reset,
|
||||||
RewardConfig rewards,
|
RewardConfig rewards,
|
||||||
TeleportConfig teleport,
|
TeleportConfig teleport,
|
||||||
UIConfig ui
|
UIConfig ui,
|
||||||
|
WorldGuardConfig worldGuard
|
||||||
) {
|
) {
|
||||||
|
|
||||||
public MineConfig {
|
public MineConfig {
|
||||||
|
|
@ -36,6 +38,7 @@ public record MineConfig(
|
||||||
Objects.requireNonNull(rewards, "Reward config cannot be null");
|
Objects.requireNonNull(rewards, "Reward config cannot be null");
|
||||||
Objects.requireNonNull(teleport, "Teleport config cannot be null");
|
Objects.requireNonNull(teleport, "Teleport config cannot be null");
|
||||||
Objects.requireNonNull(ui, "UI 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(),
|
ResetConfig.defaults(),
|
||||||
RewardConfig.empty(),
|
RewardConfig.empty(),
|
||||||
TeleportConfig.disabled(),
|
TeleportConfig.disabled(),
|
||||||
UIConfig.defaults()
|
UIConfig.defaults(),
|
||||||
|
WorldGuardConfig.disabled()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +88,7 @@ public record MineConfig(
|
||||||
private RewardConfig rewards = RewardConfig.empty();
|
private RewardConfig rewards = RewardConfig.empty();
|
||||||
private TeleportConfig teleport = TeleportConfig.disabled();
|
private TeleportConfig teleport = TeleportConfig.disabled();
|
||||||
private UIConfig ui = UIConfig.defaults();
|
private UIConfig ui = UIConfig.defaults();
|
||||||
|
private WorldGuardConfig worldGuard = WorldGuardConfig.disabled();
|
||||||
|
|
||||||
private Builder(String name) {
|
private Builder(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
@ -119,8 +124,13 @@ public record MineConfig(
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder worldGuard(WorldGuardConfig worldGuard) {
|
||||||
|
this.worldGuard = worldGuard;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public MineConfig build() {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -62,3 +62,34 @@ rewards: []
|
||||||
teleport:
|
teleport:
|
||||||
enabled: false
|
enabled: false
|
||||||
location: ""
|
location: ""
|
||||||
|
|
||||||
|
# WorldGuard integration
|
||||||
|
worldguard:
|
||||||
|
# Enable automatic region creation when mines are created
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Region name template. Available placeholders:
|
||||||
|
# {mine_name} - name of the mine
|
||||||
|
# {random_4} - 4 random digits (0000-9999)
|
||||||
|
# {random_3} - 3 random digits (000-999)
|
||||||
|
# {random_6} - 6 random alphanumeric characters
|
||||||
|
region-template: "{mine_name}_{random_4}"
|
||||||
|
|
||||||
|
# Region owners (player names or "uuid:<uuid>")
|
||||||
|
owners: []
|
||||||
|
# - "player_name"
|
||||||
|
# - "uuid:12345678-1234-1234-1234-123456789012"
|
||||||
|
|
||||||
|
# Region members (player names or "uuid:<uuid>")
|
||||||
|
members: []
|
||||||
|
|
||||||
|
# WorldGuard flags to set
|
||||||
|
flags:
|
||||||
|
- "passthrough=deny"
|
||||||
|
- "build=allow"
|
||||||
|
- "pvp=deny"
|
||||||
|
- "tnt=deny"
|
||||||
|
- "creeper-explosion=deny"
|
||||||
|
|
||||||
|
# Automatically protect the region on creation
|
||||||
|
protect-on-create: true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue