Skip to content

Commit

Permalink
Revert waterfall generator generation at initial fluid rendering, fix…
Browse files Browse the repository at this point in the history
… concurrent modification crashes
  • Loading branch information
doctor4t committed Dec 25, 2021
1 parent e85f203 commit af087a7
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 96 deletions.
2 changes: 1 addition & 1 deletion src/main/java/ladysnake/effective/client/Effective.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void onInitializeClient() {

// ticking generators
ClientTickEvents.END_WORLD_TICK.register(world -> {
WaterfallCloudGenerators.tick();
if (Config.enableWaterfallParticles) WaterfallCloudGenerators.tick();
});

// sound events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<WaterfallCloudGenerator> 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));
}
Expand All @@ -32,29 +31,27 @@ 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;
}

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 {
Expand All @@ -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
Expand All @@ -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);
}
}
}
33 changes: 33 additions & 0 deletions src/main/java/ladysnake/effective/mixin/BlockMixin.java
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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<Boolean> callbackInfoReturnable) {
WaterfallCloudGenerators.tryAddGenerator(world, pos);
}
}
70 changes: 70 additions & 0 deletions src/main/java/ladysnake/effective/mixin/CompatMixinPlugin.java
Original file line number Diff line number Diff line change
@@ -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<String> myTargets, Set<String> otherTargets) {

}

@Override
public List<String> 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
}
}
39 changes: 0 additions & 39 deletions src/main/java/ladysnake/effective/mixin/WaterFluidMixin.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<Boolean> cir) {
WaterfallCloudGenerators.tryAddGenerator(world, pos);
}
}
8 changes: 6 additions & 2 deletions src/main/resources/effective.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit af087a7

Please sign in to comment.