Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/main/java/world/bentobox/caveblock/CaveBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ public void onEnable()

// Register listeners
this.registerListener(new CustomHeightLimitations(this));
this.registerListener(new StructureGenerationListener(this));
// StructureGenerationListener is registered earlier, in createWorlds(), so it is
// active before the first chunks (including the spawn area) are generated.
}


Expand Down Expand Up @@ -138,6 +139,11 @@ public void allLoaded() {
@Override
public void createWorlds()
{
// Register the structure listener before any world is created. createWorlds() runs
// before onEnable(), and generating a world also generates its spawn-area chunks, so a
// listener registered in onEnable() would miss those first structures (issue #116).
this.registerListener(new StructureGenerationListener(this));

String worldName = this.settings.getWorldName().toLowerCase();

if (this.getServer().getWorld(worldName) == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ public StructureGenerationListener(CaveBlock addon) {
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onStructureSpawn(AsyncStructureSpawnEvent event) {
World world = event.getWorld();
// Only the CaveBlock overworld uses vanilla structures; nether/end do not.
if (world.getEnvironment() != World.Environment.NORMAL || !addon.inWorld(world)) {
if (!isCaveOverworld(event.getWorld())) {
return;
}
String structureKey = event.getStructure().getKey().getKey();
Expand All @@ -81,7 +80,7 @@ public void onStructureSpawn(AsyncStructureSpawnEvent event) {
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onStructuresLocate(StructuresLocateEvent event) {
if (!addon.inWorld(event.getWorld())) {
if (!isCaveOverworld(event.getWorld())) {
return;
}
List<Structure> targets = event.getStructures();
Expand All @@ -100,6 +99,24 @@ public void onStructuresLocate(StructuresLocateEvent event) {
}
}

/**
* @param world a world
* @return {@code true} if {@code world} is the CaveBlock overworld.
*
* <p>Matches on the configured world name rather than {@link CaveBlock#inWorld(World)}
* because structures in the spawn area are generated during {@code createWorlds()},
* before the addon's island-world reference is assigned. At that point
* {@code inWorld()} would compare against a null world and fail, so the first
* structures would slip through (issue #116).</p>
*/
private boolean isCaveOverworld(World world) {
if (world.getEnvironment() != World.Environment.NORMAL) {
return false;
}
String configuredName = addon.getSettings().getWorldName();
return configuredName != null && world.getName().equalsIgnoreCase(configuredName);
}

/**
* @param structureKey the vanilla structure key path, e.g. {@code ancient_city}
* @return {@code true} if the config explicitly disables this structure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public void setUp() {
lenient().when(addon.getSettings()).thenReturn(settings);
lenient().when(settings.getGenerateStructures())
.thenReturn(Map.of("ancient_city", false, "trial_chambers", false, "mineshaft", true));
lenient().when(addon.inWorld(world)).thenReturn(true);
lenient().when(settings.getWorldName()).thenReturn("caveblock_world");
lenient().when(world.getName()).thenReturn("caveblock_world");
lenient().when(world.getEnvironment()).thenReturn(World.Environment.NORMAL);
listener = new StructureGenerationListener(addon);
}
Expand Down Expand Up @@ -92,7 +93,7 @@ void testUnlistedStructureGeneratesNormally() {

@Test
void testStructureOutsideCaveBlockWorldIsIgnored() {
when(addon.inWorld(world)).thenReturn(false);
when(world.getName()).thenReturn("some_other_world");
AsyncStructureSpawnEvent e = event("ancient_city");
listener.onStructureSpawn(e);
verify(e, never()).setCancelled(true);
Expand Down Expand Up @@ -156,7 +157,7 @@ void testLocateAllEnabledIsUntouched() {

@Test
void testLocateOutsideCaveBlockWorldIsIgnored() {
when(addon.inWorld(world)).thenReturn(false);
when(world.getName()).thenReturn("some_other_world");
StructuresLocateEvent e = locateEvent("trial_chambers");
listener.onStructuresLocate(e);
verify(e, never()).setCancelled(true);
Expand Down
Loading