Complete phase 8 underground systems

This commit is contained in:
George
2026-06-11 18:27:33 +01:00
parent eaf5db723b
commit 48643b6ef6
3 changed files with 126 additions and 0 deletions
@@ -164,6 +164,7 @@ public final class LivingWorldBootstrap {
private final Set<RegionCoordinate> farmlandRegions = new HashSet<>();
private final Set<RegionCoordinate> exhaustedFarmlandRegions = new HashSet<>();
private final Map<RegionCoordinate, Integer> farmingInactiveCycles = new HashMap<>();
private int undergroundCycleTick = 0;
private PlatformAdapter platformAdapter;
private Path worldSaveDirectory;
@@ -360,6 +361,7 @@ public final class LivingWorldBootstrap {
farmlandRegions.clear();
exhaustedFarmlandRegions.clear();
farmingInactiveCycles.clear();
undergroundCycleTick = 0;
simSpeedMultiplier = 1;
serverReady = false;
LivingWorldLogger.info(
@@ -533,6 +535,31 @@ public final class LivingWorldBootstrap {
applyEcologyExpansion();
applyLongCycleEffects();
applyPlayerFeedbackLoops();
applyUndergroundSystems();
}
private void applyUndergroundSystems() {
if (worldEffectsModule == null) return;
undergroundCycleTick++;
for (Region region : regionManager.getActiveRegions()) {
RegionCoordinate coord = region.getCoordinate();
double groundwater = groundwaterLevel.getOrDefault(coord, 0.0);
if (groundwater > 80.0 && windRandom.nextDouble() < 0.01) {
worldEffectsModule.queueEffect(new WorldEffectRequest(
WorldEffectType.CAVE_FLOODS, coord,
Math.min(1.0, groundwater / 100.0)));
}
if (volcanoPhase.get(coord) == VolcanoPhase.FERTILE
&& windRandom.nextDouble() < 0.01) {
worldEffectsModule.queueEffect(new WorldEffectRequest(
WorldEffectType.VEIN_SHIFTS, coord, 0.7));
}
if (geothermalRegions.contains(coord) && groundwater > 60.0
&& undergroundCycleTick % 100 == 0) {
worldEffectsModule.queueEffect(new WorldEffectRequest(
WorldEffectType.STALACTITE_GROWS, coord, 0.6));
}
}
}
private void applyLongCycleEffects() {
@@ -211,4 +211,13 @@ public enum WorldEffectType {
/** Exhausted farmland fails into coarse dirt and loses its crop. */
CROPLAND_EXHAUSTS,
/** Saturated groundwater enters a natural cave opening. */
CAVE_FLOODS,
/** Volcanic mineralisation buries old ore and exposes a new shallow vein. */
VEIN_SHIFTS,
/** Wet dripstone cave ceilings grow a pointed stalactite segment. */
STALACTITE_GROWS,
}
@@ -25,6 +25,7 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.tags.FluidTags;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.levelgen.Heightmap;
/**
@@ -176,6 +177,12 @@ public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer {
siltRiver(level, baseX, baseZ, request.intensity());
case CROPLAND_EXHAUSTS ->
exhaustCropland(level, baseX, baseZ, request.intensity());
case CAVE_FLOODS ->
floodCave(level, baseX, baseZ, request.intensity());
case VEIN_SHIFTS ->
shiftMineralVein(level, baseX, baseZ, request.intensity());
case STALACTITE_GROWS ->
growStalactite(level, baseX, baseZ, request.intensity());
}
}
@@ -1034,6 +1041,17 @@ public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer {
|| state.is(Blocks.BASALT);
}
private boolean isOre(net.minecraft.world.level.block.state.BlockState state) {
return state.is(Blocks.COAL_ORE) || state.is(Blocks.DEEPSLATE_COAL_ORE)
|| state.is(Blocks.IRON_ORE) || state.is(Blocks.DEEPSLATE_IRON_ORE)
|| state.is(Blocks.COPPER_ORE) || state.is(Blocks.DEEPSLATE_COPPER_ORE)
|| state.is(Blocks.GOLD_ORE) || state.is(Blocks.DEEPSLATE_GOLD_ORE)
|| state.is(Blocks.REDSTONE_ORE) || state.is(Blocks.DEEPSLATE_REDSTONE_ORE)
|| state.is(Blocks.LAPIS_ORE) || state.is(Blocks.DEEPSLATE_LAPIS_ORE)
|| state.is(Blocks.DIAMOND_ORE) || state.is(Blocks.DEEPSLATE_DIAMOND_ORE)
|| state.is(Blocks.EMERALD_ORE) || state.is(Blocks.DEEPSLATE_EMERALD_ORE);
}
private void cleanExpiredFloodWater(ServerLevel level, ResourceKey<Level> dimensionKey) {
List<TimedWater> entries = floodWater.get(dimensionKey);
if (entries == null) return;
@@ -1307,6 +1325,78 @@ public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer {
}
}
private void floodCave(ServerLevel level, int baseX, int baseZ, double intensity) {
for (int attempt = 0; attempt < 10; attempt++) {
int x = baseX + random.nextInt(REGION_BLOCKS);
int z = baseZ + random.nextInt(REGION_BLOCKS);
int surfaceY = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
for (int depth = 2; depth <= 10; depth++) {
BlockPos cave = new BlockPos(x, surfaceY - depth, z);
if (!level.isLoaded(cave) || !level.getBlockState(cave).isAir()) continue;
if (level.getBlockState(cave.above()).isSolid()) {
level.setBlock(cave, Blocks.WATER.defaultBlockState(), Block.UPDATE_ALL);
return;
}
}
}
}
private void shiftMineralVein(ServerLevel level, int baseX, int baseZ, double intensity) {
int writes = 0;
for (int attempt = 0; attempt < 10 && writes < 10; attempt++) {
int x = baseX + random.nextInt(REGION_BLOCKS);
int z = baseZ + random.nextInt(REGION_BLOCKS);
int surfaceY = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
for (int depth = 5; depth <= 20 && writes < 10; depth++) {
BlockPos pos = new BlockPos(x, surfaceY - depth, z);
if (!level.isLoaded(pos)) continue;
var state = level.getBlockState(pos);
if (isOre(state)) {
for (Direction direction : Direction.values()) {
BlockPos adjacent = pos.relative(direction);
if (writes >= 6) break;
if (level.getBlockState(adjacent).is(Blocks.STONE)) {
level.setBlock(adjacent, random.nextBoolean()
? Blocks.TUFF.defaultBlockState()
: Blocks.BASALT.defaultBlockState(), Block.UPDATE_ALL);
writes++;
}
}
break;
}
}
int shallowDepth = 5 + random.nextInt(6);
BlockPos exposure = new BlockPos(x, surfaceY - shallowDepth, z);
if (writes < 10 && level.isLoaded(exposure)
&& level.getBlockState(exposure).is(Blocks.STONE)) {
level.setBlock(exposure, random.nextInt(4) == 0
? Blocks.RAW_GOLD_BLOCK.defaultBlockState()
: Blocks.COPPER_ORE.defaultBlockState(), Block.UPDATE_ALL);
writes++;
}
}
}
private void growStalactite(ServerLevel level, int baseX, int baseZ, double intensity) {
for (int attempt = 0; attempt < 10; attempt++) {
int x = baseX + random.nextInt(REGION_BLOCKS);
int z = baseZ + random.nextInt(REGION_BLOCKS);
int surfaceY = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
for (int depth = 5; depth <= 30; depth++) {
BlockPos air = new BlockPos(x, surfaceY - depth, z);
if (!level.isLoaded(air) || !level.getBlockState(air).isAir()) continue;
BlockPos ceiling = air.above();
if (level.getBlockState(ceiling).is(Blocks.DRIPSTONE_BLOCK)
|| level.getBlockState(ceiling).is(Blocks.STONE)) {
var dripstone = Blocks.POINTED_DRIPSTONE.defaultBlockState()
.setValue(BlockStateProperties.VERTICAL_DIRECTION, Direction.DOWN);
level.setBlock(air, dripstone, Block.UPDATE_ALL);
return;
}
}
}
}
private BlockPos surfaceAt(ServerLevel level, int x, int z) {
int y = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
if (y < level.getMinBuildHeight()) {