Fix locale bug and parkour spawn position
- Fix locale 'true' bug with sanitization at all levels: * ConfigAccessor.getString() - force String.valueOf() * Option.java - sanitize LANG defaults from config * PlayerSettingsManager - sanitize on settings load * SQLDataMapper - sanitize on SQL load * StorageDisk - sanitize on JSON load * SQLMigrationManager - SQL migration to fix DB - Fix parkour first block position: * Island.java - spawn 6 blocks forward + 1 up from center * GeneratorCleanup.java - same position after fall/reset - Add spawn-location config option at top of config.yml
This commit is contained in:
parent
b0c03cd484
commit
3546d7f9e3
10 changed files with 154 additions and 272 deletions
|
|
@ -85,11 +85,17 @@ public class ConfigAccessor {
|
|||
|
||||
/**
|
||||
* Get string value at path.
|
||||
* Forces conversion to String even if YAML parsed as Boolean/Number.
|
||||
*/
|
||||
@NotNull
|
||||
public String getString(@NotNull String path) {
|
||||
warnIfMissing(path);
|
||||
return config.getString(path, "");
|
||||
Object value = config.get(path);
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
// Force toString() to handle Boolean/Number values
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -266,6 +266,12 @@ public class Option {
|
|||
// Always read as String to avoid Boolean parsing issues
|
||||
String value = Config.CONFIG.getString(defaultPath);
|
||||
|
||||
// Sanitize legacy Boolean values for LANG option
|
||||
if (option == ParkourOption.LANG && ("true".equals(value) || "false".equals(value) || "1".equals(value) || "0".equals(value))) {
|
||||
value = "en";
|
||||
LoParkour.getPlugin().getLogger().warning("LANG option had invalid Boolean value, reset to 'en'");
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
if (option == ParkourOption.LANG) {
|
||||
LoParkour.getPlugin().getLogger().info("LANG option: path=" + defaultPath + ", value=" + value);
|
||||
|
|
|
|||
|
|
@ -72,11 +72,12 @@ public final class Island {
|
|||
}
|
||||
}
|
||||
|
||||
// Player stand 2 blocks "behind" center along heading; course line continues +4 then first jump +4 more (old island logic)
|
||||
int px = cx - 2 * hx;
|
||||
int pz = cz - 2 * hz;
|
||||
int qx = px + 4 * hx;
|
||||
int qz = pz + 4 * hz;
|
||||
// Player spawns at center, first parkour block 6 blocks forward and 1 block up
|
||||
int px = cx;
|
||||
int pz = cz;
|
||||
int qx = cx + 6 * hx;
|
||||
int qz = cz + 6 * hz;
|
||||
int qy = cy + 1;
|
||||
|
||||
Block playerFoot = world.getBlockAt(px, cy, pz);
|
||||
|
||||
|
|
@ -84,10 +85,7 @@ public final class Island {
|
|||
ps.setYaw((float) Config.GENERATION.getInt("advanced.island.spawn.yaw"));
|
||||
ps.setPitch((float) Config.GENERATION.getInt("advanced.island.spawn.pitch"));
|
||||
|
||||
Location parkourStart = world.getBlockAt(qx, cy, qz).getLocation().add(
|
||||
h.getX() * 4,
|
||||
0,
|
||||
h.getZ() * 4);
|
||||
Location parkourStart = world.getBlockAt(qx, qy, qz).getLocation();
|
||||
|
||||
session.generator.generateFirst(ps, parkourStart);
|
||||
session.generator.startTick();
|
||||
|
|
|
|||
|
|
@ -111,15 +111,15 @@ public class GeneratorCleanup {
|
|||
// Regenerate first block
|
||||
Location spawn = generator.state.playerSpawn;
|
||||
if (spawn != null) {
|
||||
// Place first block ahead of spawn based on heading direction
|
||||
Location blockSpawn = spawn.clone().add(0, -1, 0);
|
||||
// Place first block 6 blocks forward and 1 block up from spawn
|
||||
Location blockSpawn = spawn.clone();
|
||||
|
||||
// Move block forward based on heading
|
||||
// Move block forward based on heading (6 blocks forward, 1 up)
|
||||
switch (dev.loki.loparkour.config.Option.HEADING) {
|
||||
case NORTH -> blockSpawn.add(0, 0, -3);
|
||||
case SOUTH -> blockSpawn.add(0, 0, 3);
|
||||
case WEST -> blockSpawn.add(-3, 0, 0);
|
||||
case EAST -> blockSpawn.add(3, 0, 0);
|
||||
case NORTH -> blockSpawn.add(0, 1, -6);
|
||||
case SOUTH -> blockSpawn.add(0, 1, 6);
|
||||
case WEST -> blockSpawn.add(-6, 1, 0);
|
||||
case EAST -> blockSpawn.add(6, 1, 0);
|
||||
}
|
||||
|
||||
generator.generateFirst(spawn, blockSpawn);
|
||||
|
|
|
|||
|
|
@ -35,8 +35,13 @@ public class PlayerSettingsManager {
|
|||
p.selectedTime = parseIntSafe(v, defaultSelectedTime())));
|
||||
COLUMN_MAPPINGS.put("collectedRewards", new OptionContainer(null, PlayerSettingsManager::applyCollectedRewards));
|
||||
COLUMN_MAPPINGS.put("locale", new OptionContainer(ParkourOption.LANG, (p, v) -> {
|
||||
p._locale = v;
|
||||
p.locale = v;
|
||||
// Sanitize legacy Boolean values from old config parsing
|
||||
String sanitized = v;
|
||||
if ("true".equals(v) || "false".equals(v)) {
|
||||
sanitized = Option.OPTIONS_DEFAULTS.getOrDefault(ParkourOption.LANG, "en");
|
||||
}
|
||||
p._locale = sanitized;
|
||||
p.locale = sanitized;
|
||||
}));
|
||||
COLUMN_MAPPINGS.put("schematicDifficulty", new OptionContainer(ParkourOption.SCHEMATICS, (p, v) ->
|
||||
p.schematicDifficulty = parseDoubleSafe(v, defaultSchematicDifficulty())));
|
||||
|
|
|
|||
|
|
@ -85,9 +85,14 @@ public class SQLDataMapper {
|
|||
* Apply player data to ParkourPlayer object.
|
||||
*/
|
||||
public static void applyPlayerData(@NotNull ParkourPlayer player, @NotNull PlayerData data) {
|
||||
player.locale = data.locale();
|
||||
// Sanitize legacy Boolean locale values
|
||||
String locale = data.locale();
|
||||
if (locale == null || "true".equals(locale) || "false".equals(locale) || "1".equals(locale) || "0".equals(locale)) {
|
||||
locale = "en";
|
||||
}
|
||||
player.locale = locale;
|
||||
player.style = data.styleName();
|
||||
|
||||
|
||||
// Apply settings if available
|
||||
if (data.settings() != null && !data.settings().isEmpty()) {
|
||||
deserializeSettings(player, data.settings());
|
||||
|
|
|
|||
|
|
@ -46,5 +46,9 @@ class SQLMigrationManager {
|
|||
queryExecutor.executeStaticUpdateSuppressed("ALTER TABLE `%soptions` ADD `sound` BOOLEAN;".formatted(prefix));
|
||||
queryExecutor.executeStaticUpdateSuppressed("ALTER TABLE `%soptions` DROP COLUMN `useDifficulty`;".formatted(prefix));
|
||||
queryExecutor.executeStaticUpdateSuppressed("ALTER TABLE `%soptions` DROP COLUMN `useStructure`;".formatted(prefix));
|
||||
|
||||
// Fix legacy Boolean locale values (true/false) to proper locale codes
|
||||
queryExecutor.executeStaticUpdateSuppressed(
|
||||
"UPDATE `%soptions` SET `locale` = 'en' WHERE `locale` IN ('true', 'false', '1', '0');".formatted(prefix));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,13 @@ class StorageDisk {
|
|||
settings.put("showScoreboard", from.showScoreboard);
|
||||
settings.put("selectedTime", from.selectedTime);
|
||||
settings.put("collectedRewards", from.collectedRewards);
|
||||
settings.put("locale", from._locale);
|
||||
|
||||
// Sanitize legacy Boolean locale values
|
||||
String locale = from._locale;
|
||||
if (locale == null || "true".equals(locale) || "false".equals(locale) || "1".equals(locale) || "0".equals(locale)) {
|
||||
locale = "en";
|
||||
}
|
||||
settings.put("locale", locale);
|
||||
settings.put("schematicDifficulty", from.schematicDifficulty);
|
||||
settings.put("sound", from.sound);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue