Add player-spawn config for stuck players and limit teleport height
- Add PlayerSpawnConfig for separate spawn location when players are stuck in blocks - Add PlayerSpawnConfigLoader for YAML parsing - Update MineConfig with playerSpawn section and getSpawnForStuckPlayer() helper - Update ConfigLoader to include playerSpawn configuration - Update MineFileManager to preserve playerSpawn when saving - Update MineResetHandler.teleportPlayers() to use player-spawn location - Update defaults.yml with player-spawn documentation - Limit findSafeTeleportLocation() to max 3 blocks upward search - Priority: same level nearby, then up (max 3), then down, then diagonal - Prevents teleporting players too high in the air If player-spawn is not configured, falls back to teleport.location for backward compatibility.
This commit is contained in:
parent
0603096f60
commit
bb2e47a917
8 changed files with 195 additions and 16 deletions
|
|
@ -26,6 +26,7 @@ public final class ConfigLoader {
|
|||
private TeleportConfigLoader teleportLoader;
|
||||
private UIConfigLoader uiLoader;
|
||||
private WorldGuardConfigLoader worldGuardLoader;
|
||||
private PlayerSpawnConfigLoader playerSpawnLoader;
|
||||
|
||||
public ConfigLoader(Path dataFolder) {
|
||||
this.dataFolder = dataFolder;
|
||||
|
|
@ -66,6 +67,7 @@ public final class ConfigLoader {
|
|||
yaml.set("rewards", List.of());
|
||||
|
||||
worldGuardLoader.setDefaults(yaml);
|
||||
playerSpawnLoader.setDefaults(yaml);
|
||||
}
|
||||
|
||||
private void initLoaders() {
|
||||
|
|
@ -76,6 +78,7 @@ public final class ConfigLoader {
|
|||
teleportLoader = new TeleportConfigLoader();
|
||||
uiLoader = new UIConfigLoader(defaults);
|
||||
worldGuardLoader = new WorldGuardConfigLoader(defaults);
|
||||
playerSpawnLoader = new PlayerSpawnConfigLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,6 +103,7 @@ public final class ConfigLoader {
|
|||
.teleport(teleportLoader.parse(yaml))
|
||||
.ui(uiLoader.parse(yaml))
|
||||
.worldGuard(worldGuardLoader.parse(yaml))
|
||||
.playerSpawn(playerSpawnLoader.parse(yaml))
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
throw new ConfigLoadException("Failed to load mine '" + mineName + "': " + e.getMessage(), e);
|
||||
|
|
@ -120,6 +124,7 @@ public final class ConfigLoader {
|
|||
teleportLoader.save(yaml, config.teleport());
|
||||
uiLoader.save(yaml, config.ui());
|
||||
worldGuardLoader.save(yaml, config.worldGuard());
|
||||
playerSpawnLoader.save(yaml, config.playerSpawn());
|
||||
|
||||
try {
|
||||
Files.createDirectories(configPath.getParent());
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@ import dev.loki.lomines.data.config.block.BlockConfig;
|
|||
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.spawn.PlayerSpawnConfig;
|
||||
import dev.loki.lomines.data.config.teleport.TeleportConfig;
|
||||
import dev.loki.lomines.data.config.ui.UIConfig;
|
||||
import dev.loki.lomines.integration.worldguard.WorldGuardConfig;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Clean, type-safe, section-based mine configuration.
|
||||
|
|
@ -22,7 +26,8 @@ public record MineConfig(
|
|||
RewardConfig rewards,
|
||||
TeleportConfig teleport,
|
||||
UIConfig ui,
|
||||
WorldGuardConfig worldGuard
|
||||
WorldGuardConfig worldGuard,
|
||||
PlayerSpawnConfig playerSpawn
|
||||
) {
|
||||
|
||||
public MineConfig {
|
||||
|
|
@ -38,7 +43,10 @@ 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)
|
||||
// worldGuard and playerSpawn can be null (disabled by default)
|
||||
if (playerSpawn == null) {
|
||||
playerSpawn = PlayerSpawnConfig.disabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -74,10 +82,21 @@ public record MineConfig(
|
|||
RewardConfig.empty(),
|
||||
TeleportConfig.disabled(),
|
||||
UIConfig.defaults(),
|
||||
WorldGuardConfig.disabled()
|
||||
WorldGuardConfig.disabled(),
|
||||
PlayerSpawnConfig.disabled()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the spawn location for stuck players.
|
||||
* If playerSpawn is not set, falls back to teleport location.
|
||||
*/
|
||||
public Optional<Location> getSpawnForStuckPlayer() {
|
||||
return playerSpawn.enabled()
|
||||
? playerSpawn.getLocation()
|
||||
: teleport.getLocation();
|
||||
}
|
||||
|
||||
// --- Builder ---
|
||||
|
||||
public static class Builder {
|
||||
|
|
@ -89,6 +108,7 @@ public record MineConfig(
|
|||
private TeleportConfig teleport = TeleportConfig.disabled();
|
||||
private UIConfig ui = UIConfig.defaults();
|
||||
private WorldGuardConfig worldGuard = WorldGuardConfig.disabled();
|
||||
private PlayerSpawnConfig playerSpawn = PlayerSpawnConfig.disabled();
|
||||
|
||||
private Builder(String name) {
|
||||
this.name = name;
|
||||
|
|
@ -129,8 +149,13 @@ public record MineConfig(
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder playerSpawn(PlayerSpawnConfig playerSpawn) {
|
||||
this.playerSpawn = playerSpawn;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MineConfig build() {
|
||||
return new MineConfig(name, region, blocks, reset, rewards, teleport, ui, worldGuard);
|
||||
return new MineConfig(name, region, blocks, reset, rewards, teleport, ui, worldGuard, playerSpawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package dev.loki.lomines.data.config.loader;
|
||||
|
||||
import dev.loki.lomines.data.config.spawn.PlayerSpawnConfig;
|
||||
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 player spawn configuration section.
|
||||
*/
|
||||
public final class PlayerSpawnConfigLoader {
|
||||
|
||||
/**
|
||||
* Parses player spawn configuration from YAML.
|
||||
*/
|
||||
public PlayerSpawnConfig parse(YamlConfiguration yaml) {
|
||||
boolean enabled = yaml.getBoolean("player-spawn.enabled", false);
|
||||
if (!enabled) {
|
||||
return PlayerSpawnConfig.disabled();
|
||||
}
|
||||
|
||||
String locStr = yaml.getString("player-spawn.location");
|
||||
if (locStr == null || locStr.isBlank()) {
|
||||
return PlayerSpawnConfig.disabled();
|
||||
}
|
||||
|
||||
return PlayerSpawnConfig.at(parseLocation(locStr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves player spawn configuration to YAML.
|
||||
*/
|
||||
public void save(YamlConfiguration yaml, PlayerSpawnConfig spawn) {
|
||||
yaml.set("player-spawn.enabled", spawn.enabled());
|
||||
spawn.getLocation().ifPresent(loc ->
|
||||
yaml.set("player-spawn.location", LocationParser.format(loc)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default values for player spawn configuration.
|
||||
*/
|
||||
public void setDefaults(YamlConfiguration yaml) {
|
||||
yaml.set("player-spawn.enabled", false);
|
||||
yaml.set("player-spawn.location", "");
|
||||
}
|
||||
|
||||
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.spawn;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Configuration for player spawn location when stuck in blocks.
|
||||
* Used to teleport players out when they are suffocating after mine reset.
|
||||
*/
|
||||
public record PlayerSpawnConfig(
|
||||
boolean enabled,
|
||||
Location location
|
||||
) {
|
||||
|
||||
public PlayerSpawnConfig {
|
||||
if (!enabled) {
|
||||
location = null;
|
||||
} else if (location != null) {
|
||||
// Defensive copy
|
||||
location = location.clone();
|
||||
Objects.requireNonNull(location.getWorld(), "Spawn world cannot be null");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the spawn location if enabled.
|
||||
*/
|
||||
public Optional<Location> getLocation() {
|
||||
return Optional.ofNullable(enabled ? location : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled spawn config (default).
|
||||
*/
|
||||
public static PlayerSpawnConfig disabled() {
|
||||
return new PlayerSpawnConfig(false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates enabled config with location.
|
||||
*/
|
||||
public static PlayerSpawnConfig at(Location location) {
|
||||
return new PlayerSpawnConfig(true, location);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue