Lower world effect thresholds to achievable levels; add water pollution to furnaces

The previous thresholds (grass=60, smoke=70) required pollutionScore > 60.
pollutionScore is a weighted average, so even if air pollution caps at 100
the score only reaches 40 from air alone — the thresholds were physically
unreachable from furnace burning.

New thresholds: grass degradation fires at pollutionScore > 15 (soilQuality
gate raised to 75 so it doesn't block — soil defaults to 60), smoke
particles fire at > 10. With 4 furnaces the score reaches ~15 in about
20 real simulation ticks (~2 minutes of play).

Also added acid-rain water pollution (0.1/furnace/scan) — coal burning
emits SO₂ which contributes to the weighted score alongside the existing
air and ground components.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
George
2026-06-07 17:13:57 +01:00
parent dfa84a9347
commit 577c14b6ea
4 changed files with 18 additions and 11 deletions
@@ -40,7 +40,8 @@ public class LivingWorldMod {
private static final int FURNACE_SCAN_INTERVAL = 100;
private static final double AIR_POLLUTION_PER_FURNACE = 0.5;
private static final double SOIL_POLLUTION_PER_FURNACE = 0.1;
private static final double GROUND_POLLUTION_PER_FURNACE = 0.1;
private static final double WATER_POLLUTION_PER_FURNACE = 0.1;
private final LivingWorldBootstrap bootstrap;
private MinecraftServer minecraftServer;
@@ -95,7 +96,8 @@ public class LivingWorldMod {
if (litCount > 0) {
bootstrap.handleFurnaceActivity(region,
litCount * AIR_POLLUTION_PER_FURNACE,
litCount * SOIL_POLLUTION_PER_FURNACE);
litCount * GROUND_POLLUTION_PER_FURNACE,
litCount * WATER_POLLUTION_PER_FURNACE);
}
}
}
@@ -206,13 +206,15 @@ public final class LivingWorldBootstrap {
/**
* Records pollution produced by burning activity (e.g. furnaces) in a region.
* Called from the platform layer once per simulation interval.
*
* @param waterAmount acid-rain component — SO₂ from coal dissolves in atmospheric moisture
*/
public void handleFurnaceActivity(Region region, double airAmount, double groundAmount) {
public void handleFurnaceActivity(Region region, double airAmount, double groundAmount, double waterAmount) {
if (!serverReady || region == null) return;
PollutionRegionData data = region.getModuleData()
.get(PollutionModule.MODULE_ID, PollutionRegionData.class)
.orElseGet(PollutionRegionData::defaults);
data.addPollution(airAmount, groundAmount, 0.0);
data.addPollution(airAmount, groundAmount, waterAmount);
region.getModuleData().put(PollutionModule.MODULE_ID, data);
regionManager.markDirty(region);
}
@@ -54,12 +54,15 @@ public final class WorldEffectsModule implements SimulationModule {
public static final String MODULE_ID = "worldeffects";
// Thresholds that trigger effect requests.
private static final double GRASS_DEGRADE_POLLUTION_MIN = 60.0;
private static final double GRASS_DEGRADE_SOIL_MAX = 30.0;
// Grass degradation: pollution score > 15 AND soil quality below the gate.
// Soil defaults to 60 so the gate is set at 75 to avoid blocking early effects.
private static final double GRASS_DEGRADE_POLLUTION_MIN = 15.0;
private static final double GRASS_DEGRADE_SOIL_MAX = 75.0;
private static final double VEG_SPREAD_VEG_MIN = 60.0;
private static final double VEG_SPREAD_SOIL_MIN = 50.0;
private static final double SAPLING_SLOW_LOGGING_MIN = 50.0;
private static final double POLLUTION_INDICATOR_MIN = 70.0;
// Smoke particles appear as soon as any meaningful pollution exists.
private static final double POLLUTION_INDICATOR_MIN = 10.0;
private static final ModuleMetadata METADATA = new ModuleMetadata(
MODULE_ID,
@@ -97,7 +97,7 @@ class WorldEffectsModuleTest {
@Test
@DisplayName("GRASS_DEGRADES_TO_DIRT not emitted when pollution is low")
void grassDegradeNotEmittedLowPollution() {
metrics.setPollutionScore(30.0);
metrics.setPollutionScore(10.0);
metrics.setSoilQuality(15.0);
module.updateRegion(new RegionUpdateContext(region));
@@ -204,7 +204,7 @@ class WorldEffectsModuleTest {
@Test
@DisplayName("POLLUTION_VISUAL_INDICATOR not emitted below threshold")
void pollutionVisualNotEmitted() {
metrics.setPollutionScore(50.0);
metrics.setPollutionScore(5.0);
module.updateRegion(new RegionUpdateContext(region));