From ba421dc2118d7792aa834365492f504bd0e9fffd Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Mon, 8 Jun 2026 14:34:03 +0200 Subject: [PATCH] fix(generator): fix 6 code safety bugs - Fix ProfileValue NFE - add isEmpty guards in asInt/asDouble - Fix GeneratorProfileManager - catch IllegalArgumentException on createBlockData - Fix GeneratorState - replace synchronized LinkedList with ArrayList - Fix BlockSelector - guard against empty styles list - Fix multiplayer runaway generation - cap blocks/tick, remove redundant generate - Fix subList.clear() on LinkedList - resolved by ArrayList conversion --- .../core/coordinator/GeneratorProfileManager.java | 7 ++++++- .../loparkour/generator/core/model/GeneratorState.java | 5 +++-- .../dev/loki/loparkour/generator/core/model/Profile.java | 6 ++++-- .../loparkour/generator/jump/placement/BlockSelector.java | 8 +++++++- .../generator/lifecycle/loop/LifecycleTickManager.java | 3 ++- .../lifecycle/player/PlayerInteractionHandler.java | 4 ++-- 6 files changed, 24 insertions(+), 9 deletions(-) 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