diff --git a/ambiance/build.gradle b/ambiance/build.gradle index 5c4a53b..74f2cd8 100644 --- a/ambiance/build.gradle +++ b/ambiance/build.gradle @@ -265,6 +265,8 @@ tasks.register("verifyAmbiance") { 'class AmbianceEnvironmentController', 'enum AmbianceDailyWeather', 'enum AmbianceCloudCover', 'enum AmbianceLunarNight', 'id("environment_sync")', 'setRainLevel(weather.rainIntensity())', + 'ClientboundGameEventPacket.RAIN_LEVEL_CHANGE', + 'WEATHER_FADE_EPSILON', 'Math.multiplyExact(worldDay, MINECRAFT_DAY_TICKS)', 'class AmbianceEffects', 'class AmbianceBiomeTints', 'AmbianceShaderCompatibility.isShaderPackActive()', 'case LIGHT_RAIN -> 0.72F', diff --git a/ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/environment/AmbianceEnvironmentController.java b/ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/environment/AmbianceEnvironmentController.java index 50ceff3..be8b886 100644 --- a/ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/environment/AmbianceEnvironmentController.java +++ b/ambiance/src/main/java/fr/koka99cab/sanctuary26/ambiance/environment/AmbianceEnvironmentController.java @@ -10,8 +10,10 @@ import java.util.IdentityHashMap; import java.util.Map; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.network.protocol.game.ClientboundGameEventPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.players.PlayerList; import net.minecraft.util.RandomSource; import net.minecraft.world.level.saveddata.WeatherData; @@ -22,6 +24,8 @@ import net.minecraft.world.level.saveddata.WeatherData; */ public final class AmbianceEnvironmentController { private static final int UPDATE_INTERVAL_TICKS = 20; + /** Vanilla fades rain and thunder by 0.01 per tick; stay above that so we do not snap. */ + private static final float WEATHER_FADE_EPSILON = 0.012F; private static final Map TIMED_WEATHER = new IdentityHashMap<>(); private static final Map LUNAR_OVERRIDES = new IdentityHashMap<>(); private static final Map LAST_BROADCAST_WEATHER = new IdentityHashMap<>(); @@ -44,6 +48,8 @@ public final class AmbianceEnvironmentController { ServerTickEvents.END_SERVER_TICK.register(server -> { if (server.getTickCount() % UPDATE_INTERVAL_TICKS == 0) { refresh(server); + } else { + applyWeather(server, effectiveWeather(server, AmbianceData.get(server))); } }); } @@ -210,6 +216,9 @@ public final class AmbianceEnvironmentController { } private static void applyWeather(MinecraftServer server, AmbianceDailyWeather weather) { + float targetRain = weather.rainIntensity(); + float targetThunder = weather.thunder() ? 1.0F : 0.0F; + PlayerList players = server.getPlayerList(); for (ServerLevel level : server.getAllLevels()) { if (!level.canHaveWeather()) { continue; @@ -217,11 +226,37 @@ public final class AmbianceEnvironmentController { WeatherData data = level.getWeatherData(); data.setClearWeatherTime(weather.raining() ? 0 : 2400); data.setRainTime(weather.raining() ? 2400 : 0); - data.setRaining(weather.raining()); data.setThunderTime(weather.thunder() ? 2400 : 0); - data.setThundering(weather.thunder()); - level.setRainLevel(weather.rainIntensity()); - level.setThunderLevel(weather.thunder() ? 1.0F : 0.0F); + float currentRain = level.getRainLevel(1.0F); + float currentThunder = level.getThunderLevel(1.0F); + if (currentRain > targetRain + WEATHER_FADE_EPSILON) { + data.setRaining(false); + } else if (currentRain < targetRain - WEATHER_FADE_EPSILON) { + data.setRaining(true); + } else { + data.setRaining(weather.raining()); + if (currentRain != targetRain) { + level.setRainLevel(weather.rainIntensity()); + players.broadcastAll( + new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, targetRain), + level.dimension() + ); + } + } + if (currentThunder > targetThunder + WEATHER_FADE_EPSILON) { + data.setThundering(false); + } else if (currentThunder < targetThunder - WEATHER_FADE_EPSILON) { + data.setThundering(true); + } else { + data.setThundering(weather.thunder()); + if (currentThunder != targetThunder) { + level.setThunderLevel(targetThunder); + players.broadcastAll( + new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, targetThunder), + level.dimension() + ); + } + } } } diff --git a/build.gradle b/build.gradle index 5fe28f4..73f6113 100644 --- a/build.gradle +++ b/build.gradle @@ -3592,6 +3592,7 @@ project(":anotherworld") { project(":ouch") { dependencies { implementation project(":anotherworld") + implementation project(":ambiance") implementation project(":sanctuary") } } diff --git a/ouch/build.gradle b/ouch/build.gradle index 5e073e6..805c8b2 100644 --- a/ouch/build.gradle +++ b/ouch/build.gradle @@ -23,6 +23,8 @@ tasks.register("verifyOuch") { def itemRegistry = file("src/main/java/fr/koka99cab/sanctuary26/ouch/registry/OuchItems.java").text def creativeTab = file("src/main/java/fr/koka99cab/sanctuary26/ouch/registry/OuchCreativeTab.java").text def weatherRegistry = file("src/main/java/fr/koka99cab/sanctuary26/ouch/registry/OuchWeatherTnt.java").text + def weatherEntity = file("src/main/java/fr/koka99cab/sanctuary26/ouch/entity/WeatherTntEntity.java").text + def manifest = new JsonSlurper().parse(file("src/main/resources/fabric.mod.json")) if (!itemRegistry.contains("MIGRATED_WEAPONS = List.of(CREEPERLOCK, MITRAILLETTE, EXPULSEUR, ASPIRATEUR)") || !itemRegistry.contains("WEAPONS = List.of(CREEPERLOCK, MITRAILLETTE, EXPULSEUR, ASPIRATEUR, MINING_RIFLE, BETA_BOW)") || !creativeTab.contains('OuchMod.id("arsenal")') @@ -35,11 +37,16 @@ tasks.register("verifyOuch") { || !weatherRegistry.contains('OuchMod.id("weather_tnt")') || !weatherRegistry.contains('Identifier.fromNamespaceAndPath("redstoner", "weather_tnt")') || !weatherRegistry.contains('Identifier.fromNamespaceAndPath("weather_tnt", "weather_tnt")') + || !weatherEntity.contains("AmbianceEnvironmentController.setWeatherForDuration") + || !weatherEntity.contains("AmbianceDailyWeather.CLEAR") + || !weatherEntity.contains("CLEAR_WEATHER_TICKS = 864_000") + || weatherEntity.contains("setWeatherParameters") + || manifest.depends?.ambiance != "*" || !file("src/main/resources/assets/ouch/blockstates/weather_tnt.json").isFile() || !file("src/main/resources/assets/ouch/items/weather_tnt.json").isFile() || !file("src/main/resources/data/ouch/loot_table/blocks/weather_tnt.json").isFile() || !file("src/main/resources/data/ouch/recipe/weather_tnt.json").isFile()) { - throw new GradleException("Ouch must own Weather TNT and preserve both historical aliases") + throw new GradleException("Ouch must own Weather TNT, clear Ambiance rain for twelve hours, and preserve both historical aliases") } if (!itemRegistry.contains('register("mining_rifle", properties -> new MiningRifleItem(properties.durability(640).enchantable(14)))')) { diff --git a/ouch/src/main/java/fr/koka99cab/sanctuary26/ouch/entity/WeatherTntEntity.java b/ouch/src/main/java/fr/koka99cab/sanctuary26/ouch/entity/WeatherTntEntity.java index bd2aba6..0e13267 100644 --- a/ouch/src/main/java/fr/koka99cab/sanctuary26/ouch/entity/WeatherTntEntity.java +++ b/ouch/src/main/java/fr/koka99cab/sanctuary26/ouch/entity/WeatherTntEntity.java @@ -1,5 +1,7 @@ package fr.koka99cab.sanctuary26.ouch.entity; +import fr.koka99cab.sanctuary26.ambiance.environment.AmbianceDailyWeather; +import fr.koka99cab.sanctuary26.ambiance.environment.AmbianceEnvironmentController; import fr.koka99cab.sanctuary26.ouch.registry.OuchWeatherTnt; import net.minecraft.core.particles.DustParticleOptions; import net.minecraft.core.particles.ParticleTypes; @@ -16,7 +18,7 @@ import net.minecraft.world.phys.Vec3; public class WeatherTntEntity extends PrimedTnt { public static final int DEFAULT_FUSE_TICKS = 60; - private static final int CLEAR_WEATHER_TICKS = 72_000; + private static final int CLEAR_WEATHER_TICKS = 864_000; private static final double LAUNCH_SPEED = 0.56D; private static final DustParticleOptions BLUE_DUST = new DustParticleOptions(0x44A6FF, 1.35F); @@ -82,7 +84,11 @@ public class WeatherTntEntity extends PrimedTnt { private void detonate(ServerLevel level) { MinecraftServer server = level.getServer(); if (server != null) { - server.setWeatherParameters(CLEAR_WEATHER_TICKS, 0, false, false); + AmbianceEnvironmentController.setWeatherForDuration( + server, + AmbianceDailyWeather.CLEAR, + CLEAR_WEATHER_TICKS + ); } level.setSkyFlashTime(2); diff --git a/ouch/src/main/resources/fabric.mod.json b/ouch/src/main/resources/fabric.mod.json index 82b5730..7e07d36 100644 --- a/ouch/src/main/resources/fabric.mod.json +++ b/ouch/src/main/resources/fabric.mod.json @@ -24,6 +24,7 @@ "java": ">=25", "fabric-api": ">=0.154.2+26.2", "anotherworld": ">=0.0.0-alpha.46", + "ambiance": "*", "sanctuary": ">=0.0.0-alpha.110" }, "custom": {