Fix atmospheric event fidelity from final audit

This commit is contained in:
George
2026-06-11 18:33:40 +01:00
parent d7f8e3ea36
commit 0799d4d4c9
2 changed files with 46 additions and 5 deletions
@@ -136,6 +136,7 @@ public class LivingWorldMod {
private boolean migrationCompanionSpawn;
/** Stores playerCheckTick when a region last played an ambient sound (per-region throttle). */
private final Map<RegionCoordinate, Integer> regionSoundLastTick = new HashMap<>();
private final Map<RegionCoordinate, Integer> lightningLastTick = new HashMap<>();
public LivingWorldMod(IEventBus eventBus, ModContainer modContainer) {
LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "Living World mod starting...");
@@ -253,6 +254,7 @@ public class LivingWorldMod {
waterBodyLastScan.clear();
elevationInitialized.clear();
regionSoundLastTick.clear();
lightningLastTick.clear();
trackedPassiveMobs.clear();
tideTick = 0;
lastTideLevel = 0.0;
@@ -621,6 +623,18 @@ public class LivingWorldMod {
movement.y, movement.z + Math.sin(angle) * 0.025);
player.addEffect(new MobEffectInstance(
MobEffects.MOVEMENT_SLOWDOWN, 60, 0, true, false));
for (var mob : ambLevel.getEntitiesOfClass(
net.minecraft.world.entity.LivingEntity.class,
player.getBoundingBox().inflate(32),
entity -> !(entity instanceof ServerPlayer))) {
var mobMovement = mob.getDeltaMovement();
mob.setDeltaMovement(
mobMovement.x + Math.cos(angle) * 0.018,
mobMovement.y,
mobMovement.z + Math.sin(angle) * 0.018);
mob.addEffect(new MobEffectInstance(
MobEffects.MOVEMENT_SLOWDOWN, 40, 0, true, false));
}
}
if (bootstrap.isClimateEventActive(
coord, com.livingworld.climate.ClimateEventType.EARTHQUAKE)) {
@@ -634,6 +648,14 @@ public class LivingWorldMod {
playAmbientSound(player, Holder.direct(SoundEvents.WEATHER_RAIN),
0.08f, 0.75f);
}
if (bootstrap.isClimateEventActive(
coord, com.livingworld.climate.ClimateEventType.LIGHTNING_STORM)) {
Integer lastStrike = lightningLastTick.get(coord);
if (lastStrike == null || playerCheckTick - lastStrike >= 8) {
triggerDryLightning(ambLevel, coord);
lightningLastTick.put(coord, playerCheckTick);
}
}
}
}
}
@@ -997,6 +1019,30 @@ public class LivingWorldMod {
return false;
}
private void triggerDryLightning(ServerLevel level, RegionCoordinate coord) {
int baseX = coord.x() * REGION_BLOCKS;
int baseZ = coord.z() * REGION_BLOCKS;
int strikes = 1 + random.nextInt(3);
for (int strike = 0; strike < strikes; strike++) {
for (int attempt = 0; attempt < 20; attempt++) {
int x = baseX + random.nextInt(REGION_BLOCKS);
int z = baseZ + random.nextInt(REGION_BLOCKS);
int y = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
BlockPos surface = new BlockPos(x, y, z);
BlockPos fire = surface.above();
if (!level.isLoaded(fire) || !level.getBlockState(fire).isAir()) continue;
var state = level.getBlockState(surface);
if (state.is(BlockTags.LOGS) || state.is(BlockTags.LEAVES)
|| state.is(net.minecraft.world.level.block.Blocks.GRASS_BLOCK)) {
level.setBlock(fire,
net.minecraft.world.level.block.Blocks.FIRE.defaultBlockState(),
net.minecraft.world.level.block.Block.UPDATE_ALL);
break;
}
}
}
}
/** Step 6: Samples the dominant biome at the region centre and returns a succession ceiling. */
private SuccessionStage deriveBiomeCap(ServerLevel level, RegionCoordinate coord) {
int cx = coord.x() * LivingWorldConstants.DEFAULT_REGION_SIZE_CHUNKS * 16 + 64;
@@ -2419,11 +2419,6 @@ public final class LivingWorldBootstrap {
.get(AtmosphereModule.MODULE_ID, AtmosphereRegionData.class).orElse(null);
if (atm == null || atm.getThunderLevel() < 0.25) {
shouldResolve = true;
break;
}
if (worldEffectsModule != null && windRandom.nextDouble() < 0.45) {
worldEffectsModule.queueEffect(new WorldEffectRequest(
WorldEffectType.WILDFIRE, coord, 0.25));
}
}
case EARTHQUAKE -> {