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
This commit is contained in:
parent
0b6409397b
commit
ba421dc211
6 changed files with 24 additions and 9 deletions
|
|
@ -130,7 +130,12 @@ public class GeneratorProfileManager {
|
||||||
String materialName = Config.GENERATION.getString(materialPath);
|
String materialName = Config.GENERATION.getString(materialPath);
|
||||||
int chance = Config.GENERATION.getInt(chancePath, 1);
|
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);
|
generator.state.specialChances.put(blockData, (double) chance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ public class GeneratorState {
|
||||||
// Time state
|
// Time state
|
||||||
public Instant start;
|
public Instant start;
|
||||||
|
|
||||||
// Block history (sync list: all mutations occur on the main thread; avoids accidental CME if extended later)
|
// Block history — all access is main-thread-only (Bukkit scheduler runTimer), so no sync wrapper needed.
|
||||||
public final List<Block> history = Collections.synchronizedList(new LinkedList<>());
|
// Iteration is safe without external synchronization as all mutations happen on the same thread.
|
||||||
|
public final List<Block> history = new ArrayList<>();
|
||||||
public int lastPositionIndexPlayer = -1;
|
public int lastPositionIndexPlayer = -1;
|
||||||
|
|
||||||
// Schematic state
|
// Schematic state
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
public double asDouble() {
|
||||||
|
if (value.isEmpty()) return 0.0;
|
||||||
return Double.parseDouble(value);
|
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() {
|
public int asInt() {
|
||||||
|
if (value.isEmpty()) return 0;
|
||||||
return Integer.parseInt(value);
|
return Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import org.bukkit.block.data.BlockData;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles selection of block types and materials for parkour generation.
|
* Handles selection of block types and materials for parkour generation.
|
||||||
*/
|
*/
|
||||||
|
|
@ -29,7 +31,11 @@ public class BlockSelector {
|
||||||
public BlockData selectBlockData() {
|
public BlockData selectBlockData() {
|
||||||
Style style = Registry.getStyle(generator.profile.get("style").value());
|
Style style = Registry.getStyle(generator.profile.get("style").value());
|
||||||
if (style == null) {
|
if (style == null) {
|
||||||
generator.profile.set("style", Registry.getStyles().stream().findFirst().orElseThrow().getName());
|
List<Style> styles = Registry.getStyles();
|
||||||
|
if (styles.isEmpty()) {
|
||||||
|
return Material.STONE.createBlockData();
|
||||||
|
}
|
||||||
|
generator.profile.set("style", styles.stream().findFirst().orElseThrow().getName());
|
||||||
return selectBlockData();
|
return selectBlockData();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < MAX_STYLE_PICKS; i++) {
|
for (int i = 0; i < MAX_STYLE_PICKS; i++) {
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,8 @@ public class LifecycleTickManager {
|
||||||
|
|
||||||
if (currentBlocks < targetBlocks) {
|
if (currentBlocks < targetBlocks) {
|
||||||
int needed = targetBlocks - currentBlocks;
|
int needed = targetBlocks - currentBlocks;
|
||||||
generator.generate(needed);
|
// Cap generation per tick to prevent runaway generation in multiplayer
|
||||||
|
generator.generate(Math.min(needed, 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ public class PlayerInteractionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate more blocks after scoring
|
// Block generation is handled by LifecycleTickManager.maintainBlockLead()
|
||||||
generator.generate(1);
|
// to avoid runaway generation in multiplayer (N players = N generates per tick otherwise).
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue