Complete phase 2 atmospheric events
This commit is contained in:
@@ -216,6 +216,13 @@ public class LivingWorldMod {
|
|||||||
if (biome.is(BiomeTags.IS_OCEAN) || biome.is(BiomeTags.IS_DEEP_OCEAN)) {
|
if (biome.is(BiomeTags.IS_OCEAN) || biome.is(BiomeTags.IS_DEEP_OCEAN)) {
|
||||||
bootstrap.markOceanicRegion(coord);
|
bootstrap.markOceanicRegion(coord);
|
||||||
}
|
}
|
||||||
|
if (biome.is(BiomeTags.IS_BADLANDS) || temp >= 2.0f) {
|
||||||
|
bootstrap.markDesertRegion(coord);
|
||||||
|
}
|
||||||
|
if (biome.is(BiomeTags.IS_BEACH) || biome.is(BiomeTags.IS_OCEAN)
|
||||||
|
|| biome.is(BiomeTags.IS_DEEP_OCEAN) || downfall > 0.8f) {
|
||||||
|
bootstrap.markCoastalOrWetlandRegion(coord);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
NeoForge.EVENT_BUS.addListener(ServerStoppingEvent.class, event -> {
|
NeoForge.EVENT_BUS.addListener(ServerStoppingEvent.class, event -> {
|
||||||
@@ -488,6 +495,36 @@ public class LivingWorldMod {
|
|||||||
player.getX(), player.getY() + 1.0, player.getZ(),
|
player.getX(), player.getY() + 1.0, player.getZ(),
|
||||||
4, 5.0, 2.0, 5.0, 0.01);
|
4, 5.0, 2.0, 5.0, 0.01);
|
||||||
}
|
}
|
||||||
|
double humidity = bootstrap.getRegionHumidity(coord);
|
||||||
|
double temperature = bootstrap.getRegionTemperature(coord);
|
||||||
|
double pollution = metricsOpt.map(RegionMetrics::getPollutionScore).orElse(100.0);
|
||||||
|
long localTime = ambLevel.getDayTime() % 24000L;
|
||||||
|
if (bootstrap.isCoastalOrWetlandRegion(coord) && humidity > 0.70
|
||||||
|
&& (atm == null || atm.getThunderLevel() < 0.15)) {
|
||||||
|
ambLevel.sendParticles(player, ParticleTypes.CLOUD, false,
|
||||||
|
player.getX(), player.getY() + 0.5, player.getZ(),
|
||||||
|
5, 10.0, 1.5, 10.0, 0.005);
|
||||||
|
}
|
||||||
|
if ((bootstrap.isDesertRegion(coord) || pollution > 60.0)
|
||||||
|
&& localTime < 12000L) {
|
||||||
|
ambLevel.sendParticles(player, ParticleTypes.FLAME, false,
|
||||||
|
player.getX(), player.getY() + 0.2, player.getZ(),
|
||||||
|
2, 5.0, 0.1, 5.0, 0.01);
|
||||||
|
}
|
||||||
|
if (temperature < 0.15 && localTime > 13000L
|
||||||
|
&& pollution < 10.0 && (atm == null || atm.getRainLevel() < 0.1)) {
|
||||||
|
ambLevel.sendParticles(player, ParticleTypes.END_ROD, false,
|
||||||
|
player.getX(), Math.min(220.0, Math.max(180.0, player.getY() + 100.0)),
|
||||||
|
player.getZ(), 5, 24.0, 4.0, 24.0, 0.01);
|
||||||
|
}
|
||||||
|
if (bootstrap.isClimateEventActive(coord, com.livingworld.climate.ClimateEventType.BLIZZARD)) {
|
||||||
|
double angle = bootstrap.getWindAngle();
|
||||||
|
var movement = player.getDeltaMovement();
|
||||||
|
player.setDeltaMovement(movement.x + Math.cos(angle) * 0.025,
|
||||||
|
movement.y, movement.z + Math.sin(angle) * 0.025);
|
||||||
|
player.addEffect(new MobEffectInstance(
|
||||||
|
MobEffects.MOVEMENT_SLOWDOWN, 60, 0, true, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,6 +774,16 @@ public class LivingWorldMod {
|
|||||||
float temp = biome.value().getBaseTemperature();
|
float temp = biome.value().getBaseTemperature();
|
||||||
float downfall = biome.value().getModifiedClimateSettings().downfall();
|
float downfall = biome.value().getModifiedClimateSettings().downfall();
|
||||||
bootstrap.initializeRegionBiomeValues(coord, temp, downfall);
|
bootstrap.initializeRegionBiomeValues(coord, temp, downfall);
|
||||||
|
if (biome.is(BiomeTags.IS_OCEAN) || biome.is(BiomeTags.IS_DEEP_OCEAN)) {
|
||||||
|
bootstrap.markOceanicRegion(coord);
|
||||||
|
}
|
||||||
|
if (biome.is(BiomeTags.IS_BADLANDS) || temp >= 2.0f) {
|
||||||
|
bootstrap.markDesertRegion(coord);
|
||||||
|
}
|
||||||
|
if (biome.is(BiomeTags.IS_BEACH) || biome.is(BiomeTags.IS_OCEAN)
|
||||||
|
|| biome.is(BiomeTags.IS_DEEP_OCEAN) || downfall > 0.8f) {
|
||||||
|
bootstrap.markCoastalOrWetlandRegion(coord);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int REGION_BLOCKS =
|
private static final int REGION_BLOCKS =
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ public final class LivingWorldBootstrap {
|
|||||||
/** Ocean-floor regions; can develop submarine volcanoes regardless of surface elevation. */
|
/** Ocean-floor regions; can develop submarine volcanoes regardless of surface elevation. */
|
||||||
private final Set<RegionCoordinate> oceanicRegions = new HashSet<>();
|
private final Set<RegionCoordinate> oceanicRegions = new HashSet<>();
|
||||||
private final Map<RegionCoordinate, Float> regionTemperatures = new HashMap<>();
|
private final Map<RegionCoordinate, Float> regionTemperatures = new HashMap<>();
|
||||||
|
private final Map<RegionCoordinate, Float> regionDownfall = new HashMap<>();
|
||||||
|
private final Set<RegionCoordinate> desertRegions = new HashSet<>();
|
||||||
|
private final Set<RegionCoordinate> coastalWetlandRegions = new HashSet<>();
|
||||||
private final Map<RegionCoordinate, Integer> oceanPollutionCycles = new HashMap<>();
|
private final Map<RegionCoordinate, Integer> oceanPollutionCycles = new HashMap<>();
|
||||||
private final Set<RegionCoordinate> deadZoneRegions = new HashSet<>();
|
private final Set<RegionCoordinate> deadZoneRegions = new HashSet<>();
|
||||||
private final Set<RegionCoordinate> ventedRegions = new HashSet<>();
|
private final Set<RegionCoordinate> ventedRegions = new HashSet<>();
|
||||||
@@ -291,6 +294,9 @@ public final class LivingWorldBootstrap {
|
|||||||
volcanicRegions.clear();
|
volcanicRegions.clear();
|
||||||
oceanicRegions.clear();
|
oceanicRegions.clear();
|
||||||
regionTemperatures.clear();
|
regionTemperatures.clear();
|
||||||
|
regionDownfall.clear();
|
||||||
|
desertRegions.clear();
|
||||||
|
coastalWetlandRegions.clear();
|
||||||
oceanPollutionCycles.clear();
|
oceanPollutionCycles.clear();
|
||||||
deadZoneRegions.clear();
|
deadZoneRegions.clear();
|
||||||
ventedRegions.clear();
|
ventedRegions.clear();
|
||||||
@@ -886,6 +892,38 @@ public final class LivingWorldBootstrap {
|
|||||||
return coord != null && oceanicRegions.contains(coord);
|
return coord != null && oceanicRegions.contains(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markDesertRegion(RegionCoordinate coord) {
|
||||||
|
if (coord != null) desertRegions.add(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markCoastalOrWetlandRegion(RegionCoordinate coord) {
|
||||||
|
if (coord != null) coastalWetlandRegions.add(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDesertRegion(RegionCoordinate coord) {
|
||||||
|
return coord != null && desertRegions.contains(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCoastalOrWetlandRegion(RegionCoordinate coord) {
|
||||||
|
return coord != null && coastalWetlandRegions.contains(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRegionTemperature(RegionCoordinate coord) {
|
||||||
|
return regionTemperatures.getOrDefault(coord, 0.8f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRegionHumidity(RegionCoordinate coord) {
|
||||||
|
return regionDownfall.getOrDefault(coord, 0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClimateEventActive(RegionCoordinate coord, ClimateEventType type) {
|
||||||
|
if (coord == null || type == null) return false;
|
||||||
|
for (ClimateEvent event : activeClimateEvents) {
|
||||||
|
if (event.getType() == type && event.getAffectedRegions().contains(coord)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Advances reefs, kelp forests, blooms and dead zones. All physical work is queued
|
* Advances reefs, kelp forests, blooms and dead zones. All physical work is queued
|
||||||
* through the bounded world-effect executor.
|
* through the bounded world-effect executor.
|
||||||
@@ -1374,6 +1412,8 @@ public final class LivingWorldBootstrap {
|
|||||||
RecoveryRegionData recovery = region.getModuleData().get(RecoveryModule.MODULE_ID, RecoveryRegionData.class).orElse(null);
|
RecoveryRegionData recovery = region.getModuleData().get(RecoveryModule.MODULE_ID, RecoveryRegionData.class).orElse(null);
|
||||||
PollutionRegionData poll = region.getModuleData().get(PollutionModule.MODULE_ID, PollutionRegionData.class).orElse(null);
|
PollutionRegionData poll = region.getModuleData().get(PollutionModule.MODULE_ID, PollutionRegionData.class).orElse(null);
|
||||||
if (water == null || atm == null || recovery == null) continue;
|
if (water == null || atm == null || recovery == null) continue;
|
||||||
|
float temperature = regionTemperatures.getOrDefault(coord, 0.8f);
|
||||||
|
float humidity = regionDownfall.getOrDefault(coord, 0.4f);
|
||||||
|
|
||||||
// --- DROUGHT trigger ---
|
// --- DROUGHT trigger ---
|
||||||
if (water.getWaterAvailability() < 20 && water.getDroughtRisk() > 65) {
|
if (water.getWaterAvailability() < 20 && water.getDroughtRisk() > 65) {
|
||||||
@@ -1426,6 +1466,52 @@ public final class LivingWorldBootstrap {
|
|||||||
+ coord.x() + "," + coord.z() + ") overflowing into lowlands.");
|
+ coord.x() + "," + coord.z() + ") overflowing into lowlands.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (poll != null && poll.getAirPollution() > 70.0 && atm.getRainLevel() > 0.25) {
|
||||||
|
ClimateEvent acidRain = new ClimateEvent(
|
||||||
|
ClimateEventType.ACID_RAIN, coord, simTick,
|
||||||
|
Math.min(1.0, poll.getAirPollution() / 100.0));
|
||||||
|
activeClimateEvents.add(acidRain);
|
||||||
|
coveredByEvent.add(coord);
|
||||||
|
pendingEventMessages.add("[LW] Acid rain falling at region ("
|
||||||
|
+ coord.x() + "," + coord.z() + ").");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (temperature < 0.15f && humidity > 0.6f
|
||||||
|
&& atm.getRainLevel() > 0.45 && atm.getThunderLevel() > 0.25) {
|
||||||
|
ClimateEvent blizzard = new ClimateEvent(
|
||||||
|
ClimateEventType.BLIZZARD, coord, simTick,
|
||||||
|
Math.min(1.0, 0.4 + atm.getThunderLevel()));
|
||||||
|
activeClimateEvents.add(blizzard);
|
||||||
|
coveredByEvent.add(coord);
|
||||||
|
pendingEventMessages.add("[LW] Blizzard conditions at region ("
|
||||||
|
+ coord.x() + "," + coord.z() + ").");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desertRegions.contains(coord) && humidity < 0.25f
|
||||||
|
&& atm.getThunderLevel() > 0.25) {
|
||||||
|
ClimateEvent sandstorm = new ClimateEvent(
|
||||||
|
ClimateEventType.SANDSTORM, coord, simTick,
|
||||||
|
Math.min(1.0, 0.35 + atm.getThunderLevel()));
|
||||||
|
activeClimateEvents.add(sandstorm);
|
||||||
|
coveredByEvent.add(coord);
|
||||||
|
pendingEventMessages.add("[LW] Sandstorm crossing region ("
|
||||||
|
+ coord.x() + "," + coord.z() + ").");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humidity < 0.30f && atm.getThunderLevel() > 0.55
|
||||||
|
&& windRandom.nextDouble() < 0.20) {
|
||||||
|
ClimateEvent lightning = new ClimateEvent(
|
||||||
|
ClimateEventType.LIGHTNING_STORM, coord, simTick,
|
||||||
|
Math.min(1.0, atm.getThunderLevel()));
|
||||||
|
activeClimateEvents.add(lightning);
|
||||||
|
coveredByEvent.add(coord);
|
||||||
|
pendingEventMessages.add("[LW] Dry lightning storm at region ("
|
||||||
|
+ coord.x() + "," + coord.z() + ").");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1517,6 +1603,78 @@ public final class LivingWorldBootstrap {
|
|||||||
WorldEffectType.ALGAE_BLOOM, coord, ev.getSeverity()));
|
WorldEffectType.ALGAE_BLOOM, coord, ev.getSeverity()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case ACID_RAIN -> {
|
||||||
|
AtmosphereRegionData atm = region.getModuleData()
|
||||||
|
.get(AtmosphereModule.MODULE_ID, AtmosphereRegionData.class).orElse(null);
|
||||||
|
PollutionRegionData pollution = region.getModuleData()
|
||||||
|
.get(PollutionModule.MODULE_ID, PollutionRegionData.class).orElse(null);
|
||||||
|
SoilRegionData soil = region.getModuleData()
|
||||||
|
.get(SoilModule.MODULE_ID, SoilRegionData.class).orElse(null);
|
||||||
|
if (atm == null || pollution == null
|
||||||
|
|| atm.getRainLevel() < 0.1 || pollution.getAirPollution() < 70.0) {
|
||||||
|
shouldResolve = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (soil != null) {
|
||||||
|
soil.setContamination(Math.min(100, soil.getContamination() + 5.0));
|
||||||
|
region.getModuleData().put(SoilModule.MODULE_ID, soil);
|
||||||
|
}
|
||||||
|
if (worldEffectsModule != null) {
|
||||||
|
worldEffectsModule.queueEffect(new WorldEffectRequest(
|
||||||
|
WorldEffectType.ACID_RAIN_DAMAGE, coord, ev.getSeverity()));
|
||||||
|
}
|
||||||
|
regionManager.markDirty(region);
|
||||||
|
}
|
||||||
|
case BLIZZARD -> {
|
||||||
|
AtmosphereRegionData atm = region.getModuleData()
|
||||||
|
.get(AtmosphereModule.MODULE_ID, AtmosphereRegionData.class).orElse(null);
|
||||||
|
float temperature = regionTemperatures.getOrDefault(coord, 0.8f);
|
||||||
|
if (temperature > 0.15f || atm == null || atm.getRainLevel() < 0.2) {
|
||||||
|
shouldResolve = true;
|
||||||
|
if (temperature > 0.0f && worldEffectsModule != null) {
|
||||||
|
worldEffectsModule.queueEffect(new WorldEffectRequest(
|
||||||
|
WorldEffectType.SNOW_MELTS, coord, 0.7));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (worldEffectsModule != null) {
|
||||||
|
worldEffectsModule.queueEffect(new WorldEffectRequest(
|
||||||
|
WorldEffectType.SNOW_ACCUMULATION, coord, ev.getSeverity()));
|
||||||
|
worldEffectsModule.queueEffect(new WorldEffectRequest(
|
||||||
|
WorldEffectType.WATER_FREEZES, coord, ev.getSeverity()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case SANDSTORM -> {
|
||||||
|
AtmosphereRegionData atm = region.getModuleData()
|
||||||
|
.get(AtmosphereModule.MODULE_ID, AtmosphereRegionData.class).orElse(null);
|
||||||
|
if (!desertRegions.contains(coord) || atm == null || atm.getThunderLevel() < 0.15) {
|
||||||
|
shouldResolve = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (worldEffectsModule != null) {
|
||||||
|
worldEffectsModule.queueEffect(new WorldEffectRequest(
|
||||||
|
WorldEffectType.SAND_DEPOSIT, coord, ev.getSeverity()));
|
||||||
|
}
|
||||||
|
SoilRegionData soil = region.getModuleData()
|
||||||
|
.get(SoilModule.MODULE_ID, SoilRegionData.class).orElse(null);
|
||||||
|
if (soil != null) {
|
||||||
|
soil.setContamination(Math.min(100, soil.getContamination() + 0.1));
|
||||||
|
region.getModuleData().put(SoilModule.MODULE_ID, soil);
|
||||||
|
regionManager.markDirty(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case LIGHTNING_STORM -> {
|
||||||
|
AtmosphereRegionData atm = region.getModuleData()
|
||||||
|
.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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1568,6 +1726,7 @@ public final class LivingWorldBootstrap {
|
|||||||
public void initializeRegionBiomeValues(RegionCoordinate coord, float temp, float downfall) {
|
public void initializeRegionBiomeValues(RegionCoordinate coord, float temp, float downfall) {
|
||||||
if (!serverReady || coord == null) return;
|
if (!serverReady || coord == null) return;
|
||||||
regionTemperatures.put(coord, temp);
|
regionTemperatures.put(coord, temp);
|
||||||
|
regionDownfall.put(coord, downfall);
|
||||||
regionManager.resolve(coord).ifPresent(region -> {
|
regionManager.resolve(coord).ifPresent(region -> {
|
||||||
SoilRegionData soil = region.getModuleData()
|
SoilRegionData soil = region.getModuleData()
|
||||||
.get(SoilModule.MODULE_ID, SoilRegionData.class).orElse(null);
|
.get(SoilModule.MODULE_ID, SoilRegionData.class).orElse(null);
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ public enum ClimateEventType {
|
|||||||
WILDFIRE("Wildfire", "Fire spreading through drought-stressed forest regions"),
|
WILDFIRE("Wildfire", "Fire spreading through drought-stressed forest regions"),
|
||||||
FLOOD("Flood", "Heavy rainfall overwhelming low-lying terrain"),
|
FLOOD("Flood", "Heavy rainfall overwhelming low-lying terrain"),
|
||||||
VOLCANIC_ERUPTION("Volcanic Eruption", "Lava flows and ash clouds from an active volcano"),
|
VOLCANIC_ERUPTION("Volcanic Eruption", "Lava flows and ash clouds from an active volcano"),
|
||||||
ALGAE_BLOOM("Algae Bloom", "Nutrient pollution causing a bloom and aquatic dead zone");
|
ALGAE_BLOOM("Algae Bloom", "Nutrient pollution causing a bloom and aquatic dead zone"),
|
||||||
|
ACID_RAIN("Acid Rain", "Polluted rainfall damaging soil, stone and vegetation"),
|
||||||
|
BLIZZARD("Blizzard", "Wind-driven snow accumulation and freezing water"),
|
||||||
|
SANDSTORM("Sandstorm", "Dry high winds stripping plants and depositing sand"),
|
||||||
|
LIGHTNING_STORM("Lightning Storm", "Dry thunderstorm producing isolated ignition strikes");
|
||||||
|
|
||||||
private final String displayName;
|
private final String displayName;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
|||||||
@@ -130,4 +130,19 @@ public enum WorldEffectType {
|
|||||||
|
|
||||||
/** Volcanic seafloor activity creates a permanent bubbling vent field. */
|
/** Volcanic seafloor activity creates a permanent bubbling vent field. */
|
||||||
HYDROTHERMAL_VENT,
|
HYDROTHERMAL_VENT,
|
||||||
|
|
||||||
|
/** Polluted rainfall weathers exposed rock and kills surface vegetation. */
|
||||||
|
ACID_RAIN_DAMAGE,
|
||||||
|
|
||||||
|
/** Blizzard snowfall builds bounded snow layers on exposed terrain. */
|
||||||
|
SNOW_ACCUMULATION,
|
||||||
|
|
||||||
|
/** Blizzard conditions freeze exposed standing water. */
|
||||||
|
WATER_FREEZES,
|
||||||
|
|
||||||
|
/** Warm conditions remove accumulated seasonal snow one layer at a time. */
|
||||||
|
SNOW_MELTS,
|
||||||
|
|
||||||
|
/** Dry high winds deposit sand and strip fragile surface plants. */
|
||||||
|
SAND_DEPOSIT,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,16 @@ public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer {
|
|||||||
deadZone(level, baseX, baseZ, request.intensity());
|
deadZone(level, baseX, baseZ, request.intensity());
|
||||||
case HYDROTHERMAL_VENT ->
|
case HYDROTHERMAL_VENT ->
|
||||||
hydrothermalVent(level, baseX, baseZ, request.intensity());
|
hydrothermalVent(level, baseX, baseZ, request.intensity());
|
||||||
|
case ACID_RAIN_DAMAGE ->
|
||||||
|
acidRainDamage(level, baseX, baseZ, request.intensity());
|
||||||
|
case SNOW_ACCUMULATION ->
|
||||||
|
accumulateSnow(level, baseX, baseZ, request.intensity());
|
||||||
|
case WATER_FREEZES ->
|
||||||
|
freezeWater(level, baseX, baseZ, request.intensity());
|
||||||
|
case SNOW_MELTS ->
|
||||||
|
meltSnow(level, baseX, baseZ, request.intensity());
|
||||||
|
case SAND_DEPOSIT ->
|
||||||
|
depositSand(level, baseX, baseZ, request.intensity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,6 +721,96 @@ public final class NeoForgeWorldEffectExecutor implements WorldEffectConsumer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void acidRainDamage(ServerLevel level, int baseX, int baseZ, double intensity) {
|
||||||
|
if (random.nextDouble() > 0.25) return;
|
||||||
|
for (int i = 0; i < Math.max(2, (int) (intensity * 8)); i++) {
|
||||||
|
BlockPos pos = surfaceAt(level, baseX + random.nextInt(REGION_BLOCKS),
|
||||||
|
baseZ + random.nextInt(REGION_BLOCKS));
|
||||||
|
if (pos == null || !level.canSeeSky(pos.above())) continue;
|
||||||
|
var state = level.getBlockState(pos);
|
||||||
|
if (state.is(Blocks.STONE) || state.is(Blocks.COBBLESTONE)) {
|
||||||
|
level.setBlock(pos, Blocks.GRAVEL.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
} else if (state.is(Blocks.GRASS_BLOCK)) {
|
||||||
|
level.setBlock(pos, Blocks.DIRT.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
BlockPos above = pos.above();
|
||||||
|
if (level.getBlockState(above).is(BlockTags.FLOWERS)
|
||||||
|
|| level.getBlockState(above).is(Blocks.SHORT_GRASS)
|
||||||
|
|| level.getBlockState(above).is(BlockTags.SAPLINGS)) {
|
||||||
|
level.setBlock(above, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void accumulateSnow(ServerLevel level, int baseX, int baseZ, double intensity) {
|
||||||
|
if (random.nextDouble() > 0.35) return;
|
||||||
|
for (int i = 0; i < Math.max(2, (int) (intensity * 8)); i++) {
|
||||||
|
BlockPos surface = surfaceAt(level, baseX + random.nextInt(REGION_BLOCKS),
|
||||||
|
baseZ + random.nextInt(REGION_BLOCKS));
|
||||||
|
if (surface == null) continue;
|
||||||
|
BlockPos above = surface.above();
|
||||||
|
if (!level.canSeeSky(above)) continue;
|
||||||
|
var state = level.getBlockState(above);
|
||||||
|
if (state.isAir()) {
|
||||||
|
level.setBlock(above, Blocks.SNOW.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
} else if (state.is(Blocks.SNOW)
|
||||||
|
&& state.getValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS) < 4) {
|
||||||
|
level.setBlock(above, state.setValue(
|
||||||
|
net.minecraft.world.level.block.SnowLayerBlock.LAYERS,
|
||||||
|
state.getValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS) + 1),
|
||||||
|
Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void freezeWater(ServerLevel level, int baseX, int baseZ, double intensity) {
|
||||||
|
if (random.nextDouble() > 0.25) return;
|
||||||
|
for (int i = 0; i < Math.max(1, (int) (intensity * 6)); i++) {
|
||||||
|
int x = baseX + random.nextInt(REGION_BLOCKS);
|
||||||
|
int z = baseZ + random.nextInt(REGION_BLOCKS);
|
||||||
|
int y = level.getHeight(Heightmap.Types.WORLD_SURFACE, x, z) - 1;
|
||||||
|
BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
if (level.isLoaded(pos) && level.getBlockState(pos).is(Blocks.WATER)
|
||||||
|
&& level.getFluidState(pos).isSource() && level.canSeeSky(pos.above())) {
|
||||||
|
level.setBlock(pos, Blocks.ICE.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void meltSnow(ServerLevel level, int baseX, int baseZ, double intensity) {
|
||||||
|
for (int i = 0; i < Math.max(2, (int) (intensity * 8)); i++) {
|
||||||
|
BlockPos pos = surfaceAt(level, baseX + random.nextInt(REGION_BLOCKS),
|
||||||
|
baseZ + random.nextInt(REGION_BLOCKS));
|
||||||
|
if (pos == null || !level.getBlockState(pos).is(Blocks.SNOW)) continue;
|
||||||
|
var state = level.getBlockState(pos);
|
||||||
|
int layers = state.getValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS);
|
||||||
|
level.setBlock(pos, layers > 1
|
||||||
|
? state.setValue(net.minecraft.world.level.block.SnowLayerBlock.LAYERS, layers - 1)
|
||||||
|
: Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void depositSand(ServerLevel level, int baseX, int baseZ, double intensity) {
|
||||||
|
if (random.nextDouble() > 0.30) return;
|
||||||
|
for (int i = 0; i < Math.max(2, (int) (intensity * 8)); i++) {
|
||||||
|
BlockPos surface = surfaceAt(level, baseX + random.nextInt(REGION_BLOCKS),
|
||||||
|
baseZ + random.nextInt(REGION_BLOCKS));
|
||||||
|
if (surface == null) continue;
|
||||||
|
BlockPos above = surface.above();
|
||||||
|
var aboveState = level.getBlockState(above);
|
||||||
|
if (aboveState.is(BlockTags.FLOWERS) || aboveState.is(Blocks.SHORT_GRASS)
|
||||||
|
|| aboveState.is(Blocks.DEAD_BUSH)) {
|
||||||
|
level.setBlock(above, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
} else if (aboveState.isAir() && level.canSeeSky(above)
|
||||||
|
&& (level.getBlockState(surface).is(Blocks.SAND)
|
||||||
|
|| level.getBlockState(surface).is(Blocks.RED_SAND)
|
||||||
|
|| level.getBlockState(surface).is(Blocks.SANDSTONE)
|
||||||
|
|| level.getBlockState(surface).is(Blocks.TERRACOTTA))) {
|
||||||
|
level.setBlock(above, Blocks.SAND.defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BlockPos surfaceAt(ServerLevel level, int x, int z) {
|
private BlockPos surfaceAt(ServerLevel level, int x, int z) {
|
||||||
int y = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
|
int y = level.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, x, z) - 1;
|
||||||
if (y < level.getMinBuildHeight()) {
|
if (y < level.getMinBuildHeight()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user