diff --git a/docs/PORTING.md b/docs/PORTING.md index f22ecb0..a1b06ad 100644 --- a/docs/PORTING.md +++ b/docs/PORTING.md @@ -276,6 +276,11 @@ dimension skylight while retaining local block light. The latter is the closest server-safe modern equivalent to Legacy's removed per-dimension light-table scaling hook. +Version 0.2.18.1 prevents Cave Ages from choosing a spawn on their upper roof. +Their grounded arrival search now begins with the floor below player Y=64 and +works downward. If it finds no suitable footing, the existing floor-Y=63 +platform fallback places the player at Y=64. + Version 0.2.14.0 restores the legacy Linking and Descriptive Book artwork for inventory items and gives each book its matching open-book texture when placed on a Book Stand. Return Linking Books created inside another Age also retain and diff --git a/gradle.properties b/gradle.properties index ff3c396..344eaa2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,7 +35,7 @@ mod_name=Rivencraft # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0-or-later # The mod version. Rivencraft uses the x.y.z.b policy documented in README.md. -mod_version=0.2.18.0 +mod_version=0.2.18.1 immersive_portals_version=6.0.7 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. diff --git a/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java b/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java index 00427d5..b45db4a 100644 --- a/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java +++ b/src/main/java/net/dnorberg/rivencraft/book/AgeDimensionService.java @@ -37,6 +37,7 @@ public final class AgeDimensionService { private static final int PLATFORM_RADIUS = 2; private static final int SURFACE_SEARCH_RADIUS = 16; private static final int FALLBACK_PLATFORM_Y = 63; + private static final int CAVE_SPAWN_SEARCH_Y = 64; private AgeDimensionService() { } @@ -64,7 +65,7 @@ public final class AgeDimensionService { BlockPos spawn = definition.spawn(); if (spawn == null) { - spawn = createSafeSpawn(level); + spawn = createSafeSpawn(level, definition); definition = AgeRegistrySavedData.get(level).setSpawn(definition.id(), spawn); } return Optional.of(new LinkTarget( @@ -105,10 +106,19 @@ public final class AgeDimensionService { return ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, definition.dimensionId()); } - private static BlockPos createSafeSpawn(ServerLevel level) { - BlockPos floorCenter = isNetherStyle(level) - ? netherSpawnFloor(level) - : highestFootedSurface(level).orElseGet(() -> fallbackSpawnFloor(level)); + private static BlockPos createSafeSpawn(ServerLevel level, AgeDefinition age) { + BlockPos floorCenter; + if (age.generationProfile().equals(AgeGenerationProfiles.CAVE)) { + // Cave Ages are enclosed. Searching from the world ceiling would + // select or expose their roof, so begin with the floor beneath a + // player standing at Y=64 and search downward from there. + floorCenter = highestFootedSurface(level, CAVE_SPAWN_SEARCH_Y - 1) + .orElseGet(() -> fallbackSpawnFloor(level)); + } else if (isNetherStyle(level)) { + floorCenter = netherSpawnFloor(level); + } else { + floorCenter = highestFootedSurface(level).orElseGet(() -> fallbackSpawnFloor(level)); + } for (int x = -PLATFORM_RADIUS; x <= PLATFORM_RADIUS; x++) { for (int z = -PLATFORM_RADIUS; z <= PLATFORM_RADIUS; z++) { @@ -138,8 +148,13 @@ public final class AgeDimensionService { /** Selects the highest nearby terrain column that can naturally support a player. */ private static Optional highestFootedSurface(ServerLevel level) { + return highestFootedSurface(level, level.getMaxBuildHeight() - 5); + } + + private static Optional highestFootedSurface(ServerLevel level, int requestedMaximumFloorY) { BlockPos best = null; - int maximumFloorY = level.getMaxBuildHeight() - 5; + int maximumFloorY = Math.clamp(requestedMaximumFloorY, + level.getMinBuildHeight(), level.getMaxBuildHeight() - 5); for (int x = -SURFACE_SEARCH_RADIUS; x <= SURFACE_SEARCH_RADIUS; x++) { for (int z = -SURFACE_SEARCH_RADIUS; z <= SURFACE_SEARCH_RADIUS; z++) {