diff --git a/src/main/java/dev/loki/loparkour/generator/core/coordinator/GeneratorProfileManager.java b/src/main/java/dev/loki/loparkour/generator/core/coordinator/GeneratorProfileManager.java index ec189fa..e2dfd9f 100644 --- a/src/main/java/dev/loki/loparkour/generator/core/coordinator/GeneratorProfileManager.java +++ b/src/main/java/dev/loki/loparkour/generator/core/coordinator/GeneratorProfileManager.java @@ -130,7 +130,12 @@ public class GeneratorProfileManager { String materialName = Config.GENERATION.getString(materialPath); int chance = Config.GENERATION.getInt(chancePath, 1); - BlockData blockData = org.bukkit.Bukkit.createBlockData(materialName); + BlockData blockData; + try { + blockData = org.bukkit.Bukkit.createBlockData(materialName); + } catch (IllegalArgumentException e) { + continue; // skip invalid material names + } generator.state.specialChances.put(blockData, (double) chance); } diff --git a/src/main/java/dev/loki/loparkour/generator/core/model/GeneratorState.java b/src/main/java/dev/loki/loparkour/generator/core/model/GeneratorState.java index 33c3cee..4e45f59 100644 --- a/src/main/java/dev/loki/loparkour/generator/core/model/GeneratorState.java +++ b/src/main/java/dev/loki/loparkour/generator/core/model/GeneratorState.java @@ -31,8 +31,9 @@ public class GeneratorState { // Time state public Instant start; - // Block history (sync list: all mutations occur on the main thread; avoids accidental CME if extended later) - public final List history = Collections.synchronizedList(new LinkedList<>()); + // Block history — all access is main-thread-only (Bukkit scheduler runTimer), so no sync wrapper needed. + // Iteration is safe without external synchronization as all mutations happen on the same thread. + public final List history = new ArrayList<>(); public int lastPositionIndexPlayer = -1; // Schematic state diff --git a/src/main/java/dev/loki/loparkour/generator/core/model/Profile.java b/src/main/java/dev/loki/loparkour/generator/core/model/Profile.java index 4629f94..c1e21b6 100644 --- a/src/main/java/dev/loki/loparkour/generator/core/model/Profile.java +++ b/src/main/java/dev/loki/loparkour/generator/core/model/Profile.java @@ -45,16 +45,18 @@ public class Profile { } /** - * @return The value as a double. + * @return The value as a double. Returns 0.0 if the value is empty. */ public double asDouble() { + if (value.isEmpty()) return 0.0; return Double.parseDouble(value); } /** - * @return The value as an int. + * @return The value as an int. Returns 0 if the value is empty. */ public int asInt() { + if (value.isEmpty()) return 0; return Integer.parseInt(value); } } diff --git a/src/main/java/dev/loki/loparkour/generator/jump/placement/BlockSelector.java b/src/main/java/dev/loki/loparkour/generator/jump/placement/BlockSelector.java index af09e0c..2d2c65f 100644 --- a/src/main/java/dev/loki/loparkour/generator/jump/placement/BlockSelector.java +++ b/src/main/java/dev/loki/loparkour/generator/jump/placement/BlockSelector.java @@ -9,6 +9,8 @@ import org.bukkit.block.data.BlockData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * Handles selection of block types and materials for parkour generation. */ @@ -29,7 +31,11 @@ public class BlockSelector { public BlockData selectBlockData() { Style style = Registry.getStyle(generator.profile.get("style").value()); if (style == null) { - generator.profile.set("style", Registry.getStyles().stream().findFirst().orElseThrow().getName()); + List