diff --git a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java index 1ad3f0a1..4e2a8ac4 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java +++ b/src/main/java/com/minelittlepony/unicopia/client/UnicopiaClient.java @@ -21,7 +21,6 @@ import com.minelittlepony.unicopia.container.*; import com.minelittlepony.unicopia.entity.player.PlayerCamera; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.network.handler.ClientNetworkHandlerImpl; -import com.minelittlepony.unicopia.server.world.WeatherConditions; import com.minelittlepony.unicopia.server.world.ZapAppleStageStore; import com.minelittlepony.unicopia.util.Lerp; @@ -38,7 +37,6 @@ import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.resource.ResourceType; import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -55,9 +53,8 @@ public class UnicopiaClient implements ClientModInitializer { return Pony.of(MinecraftClient.getInstance().player); } - @Nullable - private Float originalRainGradient; private final Lerp rainGradient = new Lerp(0); + private final Lerp thunderGradient = new Lerp(0); public final Lerp tangentalSkyAngle = new Lerp(0, true); public final Lerp skyAngle = new Lerp(0, true); @@ -157,38 +154,22 @@ public class UnicopiaClient implements ClientModInitializer { } private void onWorldTick(ClientWorld world) { - BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos(); + /*BlockPos pos = MinecraftClient.getInstance().getCameraEntity().getBlockPos(); float tickDelta = MinecraftClient.getInstance().getTickDelta(); - Float targetRainGradient = getTargetRainGradient(world, pos, tickDelta); + Float targetRainGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : ((WeatherAccess)world).isBelowCloudLayer(pos) ? null : (Float)0F; + Float targetThunderGradient = ((WeatherAccess)world).isInRangeOfStorm(pos) ? (Float)1F : null; - if (targetRainGradient != null) { - rainGradient.update(targetRainGradient, 2000); - } + ((WeatherAccess)world).setWeatherOverride(null, null); + rainGradient.update(targetRainGradient == null ? world.getRainGradient(tickDelta) : targetRainGradient, 2000); - float gradient = rainGradient.getValue(); - if (!rainGradient.isFinished()) { - world.setRainGradient(gradient); - world.setThunderGradient(gradient); - } - } + ((WeatherAccess)world).setWeatherOverride(1F, null); + thunderGradient.update(targetThunderGradient == null ? world.getThunderGradient(tickDelta) : targetThunderGradient, 2000); - private Float getTargetRainGradient(ClientWorld world, BlockPos pos, float tickDelta) { - if (WeatherConditions.get(world).isInRangeOfStorm(pos)) { - if (originalRainGradient == null) { - originalRainGradient = world.getRainGradient(tickDelta); - } - - return 1F; - } - - if (originalRainGradient != null) { - Float f = originalRainGradient; - originalRainGradient = null; - return f; - } - - return null; + ((WeatherAccess)world).setWeatherOverride( + rainGradient.isFinished() ? targetRainGradient : (Float)rainGradient.getValue(), + thunderGradient.isFinished() ? targetThunderGradient : (Float)thunderGradient.getValue() + );*/ } private void onScreenInit(Screen screen, ButtonList buttons) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index fba23373..d245382e 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -691,7 +691,7 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (entity.getWorld().hasRain(entity.getBlockPos())) { applyTurbulance(velocity); } else { - float targetUpdraft = (float)WeatherConditions.getUpdraft(new BlockPos.Mutable().set(entity.getBlockPos()), entity.getWorld()) / 3F; + float targetUpdraft = WeatherConditions.THERMAL_FIELD.getValue(entity.getWorld(), new BlockPos.Mutable().set(entity.getBlockPos())) / 3F; targetUpdraft *= 1 + motion; if (isGravityNegative()) { targetUpdraft *= -1; diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java index 99ca9150..f0377bb4 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinWorld.java @@ -1,21 +1,32 @@ package com.minelittlepony.unicopia.mixin; import java.util.function.Supplier; + +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + import com.minelittlepony.unicopia.entity.duck.RotatedView; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; +import com.minelittlepony.unicopia.server.world.WeatherAccess; + import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; @Mixin(World.class) -abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView { - +abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source, RotatedView, WeatherAccess { private final Supplier destructions = BlockDestructionManager.create((World)(Object)this); + @Nullable + private Float rainGradientOverride; + @Nullable + private Float thunderGradientOverride; + private boolean mirrorEntityStatuses; @Override @@ -28,11 +39,36 @@ abstract class MixinWorld implements WorldAccess, BlockDestructionManager.Source return destructions.get(); } + @Override + public void setWeatherOverride(Float rain, Float thunder) { + rainGradientOverride = rain; + thunderGradientOverride = thunder; + } + @Inject(method = "sendEntityStatus(Lnet/minecraft/entity/Entity;B)V", at = @At("HEAD")) private void onSendEntityStatus(Entity entity, byte status, CallbackInfo info) { if (mirrorEntityStatuses) { entity.handleStatus(status); } } + + @Inject(method = "getThunderGradient", at = @At("HEAD"), cancellable = true) + private void onGetThunderGradient(float delta, CallbackInfoReturnable info) { + if (thunderGradientOverride != null) { + info.setReturnValue(thunderGradientOverride * ((World)(Object)this).getRainGradient(delta)); + } + } + + @Inject(method = "getRainGradient", at = @At("HEAD"), cancellable = true) + private void onGetRainGradient(float delta, CallbackInfoReturnable info) { + if (rainGradientOverride != null) { + info.setReturnValue(rainGradientOverride); + } + } + + @Inject(method = "hasRain", at = @At("RETURN"), cancellable = true) + private void onHasRain(BlockPos pos, CallbackInfoReturnable info) { + info.setReturnValue((info.getReturnValue() && isBelowCloudLayer(pos)) || isInRangeOfStorm(pos)); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java index edcc852d..4dcaf112 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinWorldRenderer.java @@ -15,6 +15,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.minelittlepony.unicopia.client.ClientBlockDestructionManager; import com.minelittlepony.unicopia.client.UnicopiaClient; +import com.minelittlepony.unicopia.server.world.WeatherAccess; + import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import net.minecraft.client.render.BlockBreakingInfo; import net.minecraft.client.render.Camera; @@ -22,7 +24,10 @@ import net.minecraft.client.render.WorldRenderer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; import net.minecraft.resource.SynchronousResourceReloader; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RotationAxis; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biome.Precipitation; @Mixin(value = WorldRenderer.class, priority = 1001) abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCloseable, ClientBlockDestructionManager.Source { @@ -80,4 +85,13 @@ abstract class MixinWorldRenderer implements SynchronousResourceReloader, AutoCl matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(UnicopiaClient.getInstance().getSkyAngleDelta(tickDelta))); matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(UnicopiaClient.getInstance().tangentalSkyAngle.getValue())); } + + @Redirect(method = "renderWeather", at = @At(value = "INVOKE", target = "net/minecraft/world/biome/Biome.getPrecipitation(Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/world/biome/Biome$Precipitation;")) + private Biome.Precipitation modifyPrecipitation(Biome biome, BlockPos pos) { + Biome.Precipitation precipitation = biome.getPrecipitation(pos); + if (!((WeatherAccess)world).isBelowClientCloudLayer(pos)) { + return Precipitation.NONE; + } + return precipitation; + } } diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java new file mode 100644 index 00000000..59f62cd5 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherAccess.java @@ -0,0 +1,89 @@ +package com.minelittlepony.unicopia.server.world; + +import com.minelittlepony.unicopia.block.cloud.CloudLike; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.ChunkSectionPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +public interface WeatherAccess { + void setWeatherOverride(Float rain, Float thunder); + + default boolean isInRangeOfStorm(BlockPos pos) { + return WeatherConditions.get((World)this).isInRangeOfStorm(pos); + } + + @Environment(EnvType.CLIENT) + default boolean isBelowClientCloudLayer(BlockPos pos) { + + int range = MinecraftClient.isFancyGraphicsOrBetter() ? 10 : 5; + + if (pos.getY() < 230 - range) { + return true; + } + + Chunk chunk = ((World)this).getChunk(pos); + int topSection = chunk.getHighestNonEmptySection(); + + if (topSection > -1) { + int sectionBottomY = ChunkSectionPos.getBlockCoord(topSection); + if (sectionBottomY >= pos.getY() - 16) { + BlockPos.Mutable mutable = pos.mutableCopy(); + BlockPos.Mutable probeMutable = pos.mutableCopy(); + int maxDistance = 16; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (!((World)this).isAir(probeMutable.setY(mutable.getY() + range))) { + + mutable.set(pos); + maxDistance = 16; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (((World)this).getBlockState(probeMutable.setY(mutable.getY())).getBlock() instanceof CloudLike) { + return false; + } + mutable.move(Direction.DOWN); + } + + return true; + } + mutable.move(Direction.UP); + } + } + } + return false; + } + + default boolean isBelowCloudLayer(BlockPos pos) { + if (pos.getY() < 230) { + return true; + } + + Chunk chunk = ((World)this).getChunk(pos); + int topSection = chunk.getHighestNonEmptySection(); + + if (topSection > -1) { + int sectionBottomY = ChunkSectionPos.getBlockCoord(topSection); + if (sectionBottomY >= pos.getY() - 16) { + BlockPos.Mutable mutable = pos.mutableCopy(); + int maxDistance = 32; + + while (((World)this).isInBuildLimit(mutable)) { + if (--maxDistance <= 0) break; + if (!((World)this).isAir(mutable)) { + return true; + } + mutable.move(Direction.UP); + } + } + } + return false; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java index ac2d4e84..cc77d9ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java +++ b/src/main/java/com/minelittlepony/unicopia/server/world/WeatherConditions.java @@ -23,8 +23,21 @@ import net.minecraft.world.PersistentState; import net.minecraft.world.World; public class WeatherConditions extends PersistentState implements Tickable { + public static final double FIRE_UPDRAFT = 0.13; + public static final double SAND_UPDRAFT = 0.03; + public static final double SOUL_SAND_UPDRAFT = -0.03; + public static final double ICE_UPDRAFT = 0; + public static final double VOID_UPDRAFT = -0.23; + + public static final float MAX_UPDRAFT_HEIGHT = 20; + public static final float MAX_TERRAIN_HEIGHT = 50; + public static final float MAX_WIND_HEIGHT = 70; + public static final Plane HEIGHT_MAP_FIELD = (world, pos) -> world.getTopY(Heightmap.Type.WORLD_SURFACE_WG, pos.getX(), pos.getZ()); - public static final Plane THERMAL_FIELD = (world, pos) -> (float)getUpdraft(pos, world); + public static final Plane THERMAL_FIELD = (world, pos) -> { + double factor = 1 - getScaledDistanceFromTerrain(pos, world, MAX_UPDRAFT_HEIGHT); + return (float)(factor * getMaterialSurfaceTemperature(pos, world)); + }; public static final Plane LOCAL_ALTITUDE_FIELD = (world, pos) -> { if (!world.isAir(pos)) { return 0; @@ -36,16 +49,6 @@ public class WeatherConditions extends PersistentState implements Tickable { return y - pos.getY(); }; - public static final double FIRE_UPDRAFT = 0.13; - public static final double SAND_UPDRAFT = 0.03; - public static final double SOUL_SAND_UPDRAFT = -0.03; - public static final double ICE_UPDRAFT = 0; - public static final double VOID_UPDRAFT = -0.23; - - public static final float MAX_UPDRAFT_HEIGHT = 20; - public static final float MAX_TERRAIN_HEIGHT = 50; - public static final float MAX_WIND_HEIGHT = 70; - private static final Identifier ID = Unicopia.id("weather_conditions"); public static WeatherConditions get(World world) { @@ -176,11 +179,6 @@ public class WeatherConditions extends PersistentState implements Tickable { .multiply(windFactor); } - public static double getUpdraft(BlockPos.Mutable pos, World world) { - double factor = 1 - getScaledDistanceFromTerrain(pos, world, MAX_UPDRAFT_HEIGHT); - return factor * getMaterialSurfaceTemperature(pos, world); - } - private static float getScaledDistanceFromTerrain(BlockPos.Mutable pos, World world, float maxDistance) { return Math.min(maxDistance, LOCAL_ALTITUDE_FIELD.getValue(world, pos)) / maxDistance; }