From af087a7837b49ab6976708caf5ea760dde7caeab Mon Sep 17 00:00:00 2001 From: doctor4t <25477005+doctor4t@users.noreply.github.com> Date: Sat, 25 Dec 2021 19:20:24 +0100 Subject: [PATCH] Revert waterfall generator generation at initial fluid rendering, fix concurrent modification crashes --- .../ladysnake/effective/client/Effective.java | 2 +- .../world/WaterfallCloudGenerators.java | 93 ++++++++----------- .../ladysnake/effective/mixin/BlockMixin.java | 33 +++++++ .../mixin/BlockRenderManagerMixin.java | 20 ++++ .../effective/mixin/CompatMixinPlugin.java | 70 ++++++++++++++ .../effective/mixin/WaterFluidMixin.java | 39 -------- .../CanvasTerrainRenderContextMixin.java | 20 ++++ .../compat/SodiumFluidRendererMixin.java | 20 ++++ src/main/resources/effective.mixins.json | 8 +- 9 files changed, 209 insertions(+), 96 deletions(-) create mode 100644 src/main/java/ladysnake/effective/mixin/BlockMixin.java create mode 100644 src/main/java/ladysnake/effective/mixin/BlockRenderManagerMixin.java create mode 100644 src/main/java/ladysnake/effective/mixin/CompatMixinPlugin.java delete mode 100644 src/main/java/ladysnake/effective/mixin/WaterFluidMixin.java create mode 100644 src/main/java/ladysnake/effective/mixin/compat/CanvasTerrainRenderContextMixin.java create mode 100644 src/main/java/ladysnake/effective/mixin/compat/SodiumFluidRendererMixin.java diff --git a/src/main/java/ladysnake/effective/client/Effective.java b/src/main/java/ladysnake/effective/client/Effective.java index 258dcaba..cb664c3b 100644 --- a/src/main/java/ladysnake/effective/client/Effective.java +++ b/src/main/java/ladysnake/effective/client/Effective.java @@ -118,7 +118,7 @@ public void onInitializeClient() { // ticking generators ClientTickEvents.END_WORLD_TICK.register(world -> { - WaterfallCloudGenerators.tick(); + if (Config.enableWaterfallParticles) WaterfallCloudGenerators.tick(); }); // sound events diff --git a/src/main/java/ladysnake/effective/client/world/WaterfallCloudGenerators.java b/src/main/java/ladysnake/effective/client/world/WaterfallCloudGenerators.java index 334fd37d..f9ab2dd1 100644 --- a/src/main/java/ladysnake/effective/client/world/WaterfallCloudGenerators.java +++ b/src/main/java/ladysnake/effective/client/world/WaterfallCloudGenerators.java @@ -6,22 +6,21 @@ import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; import net.minecraft.fluid.FlowableFluid; -import net.minecraft.fluid.FluidState; import net.minecraft.sound.SoundCategory; -import net.minecraft.tag.FluidTags; import net.minecraft.util.math.BlockPos; import net.minecraft.world.BlockRenderView; import net.minecraft.world.World; +import org.spongepowered.include.com.google.common.base.Objects; import java.util.HashSet; import java.util.Set; -import org.spongepowered.include.com.google.common.base.Objects; - public class WaterfallCloudGenerators { public static final Set generators = new HashSet<>(); - public static void tryAddGenerator(BlockPos pos, BlockRenderView world) { + public static void tryAddGenerator(BlockRenderView world, BlockPos pos) { + if (!Config.enableWaterfallParticles) return; + if (isInRange(pos) && isPositionValid(world, pos)) { generators.add(new WaterfallCloudGenerator(MinecraftClient.getInstance().world, pos)); } @@ -32,11 +31,15 @@ public static void removeGenerator(World world, BlockPos blockPos) { } public static void tick() { - generators.removeIf(WaterfallCloudGenerator::tick); + for (WaterfallCloudGenerator generator : generators) { + generator.tick(); + } + + generators.removeIf(waterfallCloudGenerator -> waterfallCloudGenerator.isOutofRange() || !isPositionValid(waterfallCloudGenerator.world, waterfallCloudGenerator.blockPos)); } private static boolean isInRange(BlockPos pos) { - MinecraftClient client = MinecraftClient.getInstance(); + MinecraftClient client = MinecraftClient.getInstance(); return client.player != null && Math.sqrt(pos.getSquaredDistance(client.player.getBlockPos())) < client.options.viewDistance * 16f; } @@ -44,17 +47,11 @@ private static boolean isPositionValid(BlockRenderView world, BlockPos pos) { BlockState state = world.getBlockState(pos); BlockState above = world.getBlockState(pos.up()); - return state.isOf(Blocks.WATER) - && state.getFluidState().isStill() - && isFlowingAndFalling(above.getFluidState()); - } - - public static boolean isFlowingAndFalling(FluidState state) { - return state.isIn(FluidTags.WATER) - && !state.isStill() - && state.getHeight() >= 0.77f - && state.contains(FlowableFluid.FALLING) - && state.get(FlowableFluid.FALLING); + return state.isOf(Blocks.WATER) && state.getFluidState().isStill() + && above.isOf(Blocks.WATER) && !above.getFluidState().isStill() + && above.getFluidState().contains(FlowableFluid.FALLING) + && above.getFluidState().get(FlowableFluid.FALLING) + && above.getFluidState().getHeight() >= 0.77f; } public static final class WaterfallCloudGenerator { @@ -70,41 +67,29 @@ public boolean isOutofRange() { return !isInRange(blockPos) || world != MinecraftClient.getInstance().player.world; } - public boolean tick() { - if (!Config.enableWaterfallParticles) { - return true; + public void tick() { + if (world.isPlayerInRange(blockPos.getX(), blockPos.getY(), blockPos.getZ(), 100f)) { + if (world.getTime() % 11 == 0) { + world.playSound(blockPos.getX(), blockPos.getY(), blockPos.getZ(), + Effective.AMBIENCE_WATERFALL, SoundCategory.AMBIENT, + 2.5f, + 1f + world.random.nextFloat() / 10f, false); + } + + for (int i = 0; i < 1; i++) { + double offsetX = world.random.nextGaussian() / 5f; + double offsetZ = world.random.nextGaussian() / 5f; + + world.addParticle(Effective.WATERFALL_CLOUD, + blockPos.getX() + .5 + offsetX, + blockPos.getY() + 1 + world.random.nextFloat(), + blockPos.getZ() + .5 + offsetZ, + world.random.nextFloat() / 5f * Math.signum(offsetX), + world.random.nextFloat() / 5f, + world.random.nextFloat() / 5f * Math.signum(offsetZ) + ); + } } - - if (isOutofRange() || !isPositionValid(world, blockPos)) { - return true; - } - - if (world.random.nextInt(1) != 0) { - return false; - } - - if (world.getTime() % 11 == 0) { - world.playSound(blockPos.getX(), blockPos.getY(), blockPos.getZ(), - Effective.AMBIENCE_WATERFALL, SoundCategory.AMBIENT, - 1.8f, - 1f + world.random.nextFloat() / 10f, true); - } - - for (int i = 0; i < 5; i++) { - double offsetX = world.random.nextGaussian() / 5f; - double offsetZ = world.random.nextGaussian() / 5f; - - world.addParticle(Effective.WATERFALL_CLOUD, - blockPos.getX() + .5 + offsetX, - blockPos.getY() + 1 + world.random.nextFloat(), - blockPos.getZ() + .5 + offsetZ, - world.random.nextFloat() / 5f * Math.signum(offsetX), - world.random.nextFloat() / 5f, - world.random.nextFloat() / 5f * Math.signum(offsetZ) - ); - } - - return false; } @Override @@ -115,8 +100,8 @@ public int hashCode() { @Override public boolean equals(Object other) { return other instanceof WaterfallCloudGenerator - && Objects.equal(((WaterfallCloudGenerator)other).blockPos, blockPos) - && Objects.equal(((WaterfallCloudGenerator)other).world, world); + && Objects.equal(((WaterfallCloudGenerator) other).blockPos, blockPos) + && Objects.equal(((WaterfallCloudGenerator) other).world, world); } } } diff --git a/src/main/java/ladysnake/effective/mixin/BlockMixin.java b/src/main/java/ladysnake/effective/mixin/BlockMixin.java new file mode 100644 index 00000000..142dc892 --- /dev/null +++ b/src/main/java/ladysnake/effective/mixin/BlockMixin.java @@ -0,0 +1,33 @@ +package ladysnake.effective.mixin; + +import ladysnake.effective.client.Config; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Random; + +@Mixin(Block.class) +public abstract class BlockMixin { + @Shadow + public abstract BlockState getDefaultState(); + + @Inject(method = "randomDisplayTick", at = @At("RETURN")) + protected void illuminations$randomDisplayTick(BlockState state, World world, BlockPos pos, Random random, CallbackInfo ci) { + if (Config.enableWaterfallParticles && state.getBlock() == Blocks.WATER && !world.getBlockState(pos.add(0, 1, 0)).getFluidState().isStill() && world.getBlockState(pos.add(0, 1, 0)).getBlock() == Blocks.WATER && !world.getBlockState(pos.add(0, 1, 0)).getFluidState().isStill() && world.getBlockState(pos.add(0, 1, 0)).getFluidState().getHeight() >= 0.77f) { + Vec3d vec3d = state.getFluidState().getVelocity(world, pos); + for (int i = 0; i < random.nextInt(50); i++) { + world.addParticle(ParticleTypes.SPLASH, pos.getX() + .5 + random.nextGaussian() / 2f, pos.getY() + 1 + random.nextFloat(), pos.getZ() + .5 + random.nextGaussian() / 2f, vec3d.getX() * random.nextFloat(), random.nextFloat() / 10f, vec3d.getZ() * random.nextFloat()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ladysnake/effective/mixin/BlockRenderManagerMixin.java b/src/main/java/ladysnake/effective/mixin/BlockRenderManagerMixin.java new file mode 100644 index 00000000..c3bca7cc --- /dev/null +++ b/src/main/java/ladysnake/effective/mixin/BlockRenderManagerMixin.java @@ -0,0 +1,20 @@ +package ladysnake.effective.mixin; + +import ladysnake.effective.client.world.WaterfallCloudGenerators; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +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.CallbackInfoReturnable; + +@Mixin(BlockRenderManager.class) +public class BlockRenderManagerMixin { + @Inject(method = "renderFluid", at = @At("TAIL")) + public void renderFluid(BlockPos pos, BlockRenderView world, VertexConsumer vertexConsumer, FluidState state, CallbackInfoReturnable callbackInfoReturnable) { + WaterfallCloudGenerators.tryAddGenerator(world, pos); + } +} \ No newline at end of file diff --git a/src/main/java/ladysnake/effective/mixin/CompatMixinPlugin.java b/src/main/java/ladysnake/effective/mixin/CompatMixinPlugin.java new file mode 100644 index 00000000..d90ca870 --- /dev/null +++ b/src/main/java/ladysnake/effective/mixin/CompatMixinPlugin.java @@ -0,0 +1,70 @@ +package ladysnake.effective.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class CompatMixinPlugin implements IMixinConfigPlugin { + private static final Logger logger = LogManager.getLogger("Effective"); + + @Override + public void onLoad(String mixinPackage) { + // NOOP + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + if (mixinClassName.equals("ladysnake.effective.mixin.compat.CanvasTerrainRenderContextMixin")) { + final boolean canvasIsLoaded = FabricLoader.getInstance().isModLoaded("canvas"); + + if (canvasIsLoaded) { + logger.info("Canvas found. Applying compatibility mixin..."); + } + + return canvasIsLoaded; + } + + if (mixinClassName.equals("ladysnake.effective.mixin.compat.SodiumFluidRendererMixin")) { + final boolean sodiumIsLoaded = FabricLoader.getInstance().isModLoaded("sodium"); + + if (sodiumIsLoaded) { + logger.info("Sodium found. Applying compatibility mixin..."); + } + + return sodiumIsLoaded; + } + + return true; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // NOOP + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // NOOP + } +} diff --git a/src/main/java/ladysnake/effective/mixin/WaterFluidMixin.java b/src/main/java/ladysnake/effective/mixin/WaterFluidMixin.java deleted file mode 100644 index 172abd8e..00000000 --- a/src/main/java/ladysnake/effective/mixin/WaterFluidMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -package ladysnake.effective.mixin; - -import ladysnake.effective.client.Config; -import net.minecraft.fluid.FluidState; -import net.minecraft.fluid.WaterFluid; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -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 ladysnake.effective.client.world.WaterfallCloudGenerators; - -import java.util.Random; - -@Mixin(WaterFluid.class) -abstract class WaterFluidMixin { - @Inject(method = "randomDisplayTick", at = @At("RETURN")) - private void illuminations$randomDisplayTick(World world, BlockPos pos, FluidState state, Random random, CallbackInfo ci) { - if (!Config.enableWaterfallParticles) return; - - if (!state.isStill() && WaterfallCloudGenerators.isFlowingAndFalling(world.getBlockState(pos.up()).getFluidState())) { - Vec3d vec3d = state.getVelocity(world, pos); - for (int i = 0; i < random.nextInt(50); i++) { - world.addParticle(ParticleTypes.SPLASH, - pos.getX() + 0.5 + random.nextGaussian() / 2f, - pos.getY() + 1 + random.nextFloat(), - pos.getZ() + 0.5 + random.nextGaussian() / 2f, - vec3d.getX() * random.nextFloat(), random.nextFloat() / 10f, - vec3d.getZ() * random.nextFloat() - ); - } - } - WaterfallCloudGenerators.tryAddGenerator(pos, world); - } -} \ No newline at end of file diff --git a/src/main/java/ladysnake/effective/mixin/compat/CanvasTerrainRenderContextMixin.java b/src/main/java/ladysnake/effective/mixin/compat/CanvasTerrainRenderContextMixin.java new file mode 100644 index 00000000..1c63f1f0 --- /dev/null +++ b/src/main/java/ladysnake/effective/mixin/compat/CanvasTerrainRenderContextMixin.java @@ -0,0 +1,20 @@ +package ladysnake.effective.mixin.compat; + +import grondag.canvas.apiimpl.rendercontext.CanvasTerrainRenderContext; +import io.vram.frex.api.model.BlockModel; +import ladysnake.effective.client.world.WaterfallCloudGenerators; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.math.BlockPos; +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; + +@Mixin(CanvasTerrainRenderContext.class) +public class CanvasTerrainRenderContextMixin { + @Inject(method = "renderFluid", at = @At("TAIL")) + public void renderFluid(BlockState blockState, BlockPos blockPos, boolean defaultAo, BlockModel model, CallbackInfo ci) { + WaterfallCloudGenerators.tryAddGenerator(MinecraftClient.getInstance().world, blockPos); + } +} diff --git a/src/main/java/ladysnake/effective/mixin/compat/SodiumFluidRendererMixin.java b/src/main/java/ladysnake/effective/mixin/compat/SodiumFluidRendererMixin.java new file mode 100644 index 00000000..04ff12ad --- /dev/null +++ b/src/main/java/ladysnake/effective/mixin/compat/SodiumFluidRendererMixin.java @@ -0,0 +1,20 @@ +package ladysnake.effective.mixin.compat; + +import ladysnake.effective.client.world.WaterfallCloudGenerators; +import me.jellysquid.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder; +import me.jellysquid.mods.sodium.client.render.pipeline.FluidRenderer; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockRenderView; +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.CallbackInfoReturnable; + +@Mixin(FluidRenderer.class) +public class SodiumFluidRendererMixin { + @Inject(method = "render", at = @At("HEAD")) + public void renderFluid(BlockRenderView world, FluidState fluidState, BlockPos pos, BlockPos offset, ChunkModelBuilder buffers, CallbackInfoReturnable cir) { + WaterfallCloudGenerators.tryAddGenerator(world, pos); + } +} diff --git a/src/main/resources/effective.mixins.json b/src/main/resources/effective.mixins.json index 04bb9b5d..42be41d9 100644 --- a/src/main/resources/effective.mixins.json +++ b/src/main/resources/effective.mixins.json @@ -2,10 +2,14 @@ "required": true, "package": "ladysnake.effective.mixin", "compatibilityLevel": "JAVA_8", + "plugin": "ladysnake.effective.mixin.CompatMixinPlugin", "client": [ - "WaterFluidMixin", + "BlockMixin", "EntityMixin", - "RenderLayerAccessor" + "RenderLayerAccessor", + "BlockRenderManagerMixin", + "compat.CanvasTerrainRenderContextMixin", + "compat.SodiumFluidRendererMixin" ], "injectors": { "defaultRequire": 1