From 2daf7d0c3a022b3c08d51d39a40035944d4f4ceb Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 18 Feb 2017 23:23:38 +0100 Subject: [PATCH 1/2] R2.1 -BIG optimizations(block breaking/placing, rendering,...) -changed rendering method -changed the way brigthness affects particles -enabled back face culling (makes the particle look better when they're transparent) -fixed bug where particles were twitching while fading away -more stuff I couldn't remember... --- build.gradle | 2 +- .../com/TominoCZ/FBP/math/FBPMathHelper.java | 33 +++++--- .../FBP/particle/FBPParticleDigging.java | 84 +++++++++---------- .../FBP/particle/FBPParticleEmitter.java | 43 +++++----- src/main/resources/mcmod.info | 2 +- 5 files changed, 89 insertions(+), 75 deletions(-) diff --git a/build.gradle b/build.gradle index f985c73..975d5bf 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ apply plugin: 'net.minecraftforge.gradle.forge' group= "com.TominoCZ.FBP" // http://maven.apache.org/guides/mini/guide-naming-conventions.html -version = "1.10.2" +version = "1.10.2-2.1" archivesBaseName = "FancyBlockParticles" sourceCompatibility = targetCompatibility = "1.8" // Need this here so eclipse task generates correctly. diff --git a/src/main/java/com/TominoCZ/FBP/math/FBPMathHelper.java b/src/main/java/com/TominoCZ/FBP/math/FBPMathHelper.java index bc7e1ff..88cdb66 100644 --- a/src/main/java/com/TominoCZ/FBP/math/FBPMathHelper.java +++ b/src/main/java/com/TominoCZ/FBP/math/FBPMathHelper.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import net.minecraft.util.math.MathHelper; +import scala.actors.threadpool.Arrays; public class FBPMathHelper { static ArrayList newVec = new ArrayList(); @@ -21,16 +22,26 @@ public class FBPMathHelper { static float radsY; static float radsZ; - public static ArrayList rotateCubeXYZ(double AngleX, double AngleY, double AngleZ, double size) { - double center = (size / 2); - - cube = new double[] { center, -center, center, center, center, center, -center, center, center, -center, - -center, center, -center, -center, -center, -center, center, -center, center, center, -center, center, - -center, -center, -center, -center, center, -center, center, center, -center, center, -center, -center, - -center, -center, center, -center, -center, center, center, -center, center, center, center, center, - -center, center, -center, center, -center, -center, center, center, center, center, center, center, - center, -center, -center, -center, center, -center, -center, -center, center, -center, -center, center, - -center, center }; + public static ArrayList rotateCubeXYZ(double AngleX, double AngleY, double AngleZ, double halfSize) { + // cube = new double[] { center, -center, center, center, center, + // center, -center, center, center, -center,-center, center, -center, + // -center, -center, -center, center, -center, center, center, -center, + // center,-center, -center, -center, -center, center, -center, center, + // center, -center, center, -center, -center,-center, -center, center, + // -center, -center, center, center, -center, center, center, center, + // center,-center, center, -center, center, -center, -center, center, + // center, center, center, center, center,center, -center, -center, + // -center, center, -center, -center, -center, center, -center, -center, + // center,-center, center }; + + cube = new double[] { -halfSize, -halfSize, halfSize, -halfSize, halfSize, halfSize, halfSize, halfSize, + halfSize, halfSize, -halfSize, halfSize, halfSize, -halfSize, -halfSize, halfSize, halfSize, -halfSize, + -halfSize, halfSize, -halfSize, -halfSize, -halfSize, -halfSize, -halfSize, -halfSize, -halfSize, + -halfSize, halfSize, -halfSize, -halfSize, halfSize, halfSize, -halfSize, -halfSize, halfSize, halfSize, + -halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, -halfSize, halfSize, -halfSize, + -halfSize, halfSize, halfSize, -halfSize, halfSize, halfSize, halfSize, -halfSize, halfSize, halfSize, + -halfSize, halfSize, -halfSize, -halfSize, -halfSize, -halfSize, -halfSize, -halfSize, halfSize, + halfSize, -halfSize, halfSize, halfSize, -halfSize, -halfSize }; radsX = (float) Math.toRadians(AngleX); radsY = (float) Math.toRadians(AngleY); @@ -51,7 +62,7 @@ public static ArrayList rotateCubeXYZ(double AngleX, double AngleY, do cube[i + 1] * sinAngleX + cube[i + 2] * cosAngleX }; d = new double[] { d[0] * cosAngleY + d[2] * sinAngleY, d[1], d[0] * sinAngleY - d[2] * cosAngleY }; d = new double[] { d[0] * cosAngleZ - d[1] * sinAngleZ, d[0] * sinAngleZ + d[1] * cosAngleZ, d[2] }; - + newVec.add(d); } diff --git a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleDigging.java b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleDigging.java index c2f6290..45c1b81 100644 --- a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleDigging.java +++ b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleDigging.java @@ -11,6 +11,7 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.VertexBuffer; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.entity.Entity; @@ -22,7 +23,7 @@ public class FBPParticleDigging extends Particle { private final IBlockState sourceState; - int j2, k2, vecIndex; + int vecIndex;// , j2, k2; double endScale, scaleAlpha, prevParticleScale, prevParticleAlpha, prevMotionX, prevMotionZ; @@ -39,29 +40,34 @@ public class FBPParticleDigging extends Particle { double[] legacySpeed; - public FBPParticleDigging(World worldIn, double xCoordIn, double yCoordIn, double zCoordIn, double xSpeedIn, + float brightness = 1; + + public FBPParticleDigging(World worldObjIn, double xCoordIn, double yCoordIn, double zCoordIn, double xSpeedIn, double ySpeedIn, double zSpeedIn, IBlockState state) { - super(worldIn, xCoordIn, yCoordIn, zCoordIn, xSpeedIn, ySpeedIn, zSpeedIn); + super(worldObjIn, xCoordIn, yCoordIn, zCoordIn, xSpeedIn, ySpeedIn, zSpeedIn); sourceState = state; particleGravity = (float) (state.getBlock().blockParticleGravity * FBP.gravityMult); particleScale = (float) FBP.random.nextDouble(FBP.minScale + 0.399D, FBP.maxScale + 0.4D); particleMaxAge = (int) FBP.random.nextDouble(FBP.minAge, FBP.maxAge + 0.5); - endScale = particleScale / 3; - scaleAlpha = particleScale / 1.65; + this.particleRed = this.particleGreen = this.particleBlue = 0.75F + + (0.2F * Minecraft.getMinecraft().gameSettings.gammaSetting); + + endScale = particleScale / 3.25; + scaleAlpha = particleScale / 1.5; // 1.65 // GET THE TOP TEXTURE OF THE BLOCK if (FBP.inheritBlockTopTexture && posY - ((int) posY) <= 0.105 && posY - ((int) posY) >= 0) { List quads = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes() .getModelForState(state).getQuads(state, EnumFacing.UP, rand.nextLong()); - if (!quads.isEmpty()) { + if (quads != null && !quads.isEmpty()) { this.particleTexture = quads.get(0).getSprite(); multiplyColor(new BlockPos(xCoordIn, yCoordIn, zCoordIn)); } } - if (((particleTexture == null) ? true : (particleTexture.getIconName() == "missingno"))) + if (particleTexture == null || particleTexture.getIconName() == "missingno") particleTexture = Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelShapes() .getTexture(state); @@ -70,7 +76,7 @@ public FBPParticleDigging(World worldIn, double xCoordIn, double yCoordIn, doubl double blockHeight; - if ((blockHeight = state.getBlock().getBoundingBox(state, worldIn, + if ((blockHeight = state.getBlock().getBoundingBox(state, worldObjIn, new BlockPos(posX, posY, posZ)).maxY) != 1) { if (posY - ((int) posY) - 0.1F == blockHeight) setMotion(); @@ -206,7 +212,7 @@ else if (motionZ > 0) { if (particleScale < endScale) setExpired(); - else if (particleScale < scaleAlpha) {// scale / 1.65) { + else if (particleScale < scaleAlpha) { if (FBP.randomFadingSpeed) particleAlpha *= 0.565F * endMult; else @@ -229,14 +235,14 @@ else if (particleScale < scaleAlpha) {// scale / 1.65) { // PHYSICS if (FBP.entityCollision) { - worldObj.getEntitiesInAABBexcluding(null, this.getEntityBoundingBox(), null).forEach(entityIn -> { + worldObj.getEntitiesWithinAABB(Entity.class, this.getEntityBoundingBox()).forEach(entityIn -> { if (!entityIn.noClip) { double d0 = this.posX - entityIn.posX; double d1 = this.posZ - entityIn.posZ; double d2 = MathHelper.abs_max(d0, d1); if (d2 >= 0.009999999776482582D) { - d2 = (double) MathHelper.sqrt_double(d2); + d2 = (double) Math.sqrt(d2); d0 = d0 / d2; d1 = d1 / d2; @@ -250,10 +256,7 @@ else if (particleScale < scaleAlpha) {// scale / 1.65) { this.motionZ += d1 * d3 / 20; if (!FBP.legacyMode) - calculateYAngle(); // ROTATE THE PARTICLE - // DEPENDING - // ON THE NEW MOTION - // DIRECTION + calculateYAngle(); if (!FBP.frozen) this.isCollided = false; } @@ -276,7 +279,7 @@ else if (particleScale < scaleAlpha) {// scale / 1.65) { modeDebounce = false; } - public void renderParticle(VertexBuffer worldRendererIn, Entity entityIn, float partialTicks, float rotationX, + public void renderParticle(VertexBuffer worldObjRendererIn, Entity entityIn, float partialTicks, float rotationX, float rotationZ, float rotationYZ, float rotationXY, float rotationXZ) { if (!FBP.isEnabled() && particleMaxAge != 0) particleMaxAge = 0; @@ -328,7 +331,7 @@ public void renderParticle(VertexBuffer worldRendererIn, Entity entityIn, float AngleZ = angleZ; // SMOOTH ROTATION - if (FBP.smoothTransitions && !FBP.frozen) { + if (FBP.smoothTransitions && !this.isCollided && !FBP.frozen) { AngleX = prevAngleX + (angleX - prevAngleX) * partialTicks; if (FBP.legacyMode) { @@ -340,17 +343,18 @@ public void renderParticle(VertexBuffer worldRendererIn, Entity entityIn, float } // RENDER - worldRendererIn.setTranslation(f5, f6, f7); + worldObjRendererIn.setTranslation(f5, f6, f7); - if (FBP.cartoonMode) { - renderCartonQuads(worldRendererIn, FBPMathHelper.rotateCubeXYZ(AngleX, AngleY, AngleZ, f4 / 10), + GlStateManager.enableCull(); + + if (FBP.cartoonMode) + renderCartonQuads(worldObjRendererIn, FBPMathHelper.rotateCubeXYZ(AngleX, AngleY, AngleZ, f4 / 20), i >> 16 & 65535, i & 65535, f1, f3, alpha); - } else { - renderQuads(worldRendererIn, FBPMathHelper.rotateCubeXYZ(AngleX, AngleY, AngleZ, f4 / 10), i >> 16 & 65535, - i & 65535, alpha); - } + else + renderQuads(worldObjRendererIn, FBPMathHelper.rotateCubeXYZ(AngleX, AngleY, AngleZ, f4 / 20), + i >> 16 & 65535, i & 65535, alpha); - worldRendererIn.setTranslation(0, 0, 0); + worldObjRendererIn.setTranslation(0, 0, 0); } public int getBrightnessForRender(float p_189214_1_) { @@ -365,19 +369,17 @@ public int getBrightnessForRender(float p_189214_1_) { } void renderCartonQuads(VertexBuffer buf, ArrayList vec, int j, int k, float f1, float f2, float alpha) { - j2 = (int) (j * 0.9D); - k2 = (int) (k * 0.75D); + brightness = 1; - vec.forEach(vector -> { + vec.stream().forEach(vector -> { if (vecIndex == 4) { - j2 *= 0.965D; - k2 *= 0.975D; - + brightness *= 0.95; vecIndex = 0; } - buf.pos(vector[0], vector[1], vector[2]).tex(f1, f2).color(particleRed, particleGreen, particleBlue, alpha) - .lightmap(j2, k2).endVertex(); + buf.pos(vector[0], vector[1], vector[2]).tex(f1, f2) + .color(particleRed * brightness, particleGreen * brightness, particleBlue * brightness, alpha) + .lightmap(j, k).endVertex(); vecIndex++; }); @@ -386,19 +388,17 @@ void renderCartonQuads(VertexBuffer buf, ArrayList vec, int j, int k, } void renderQuads(VertexBuffer buf, ArrayList vec, int j, int k, float alpha) { - j2 = (int) (j * 0.925D); - k2 = (int) (k * 0.65D); + brightness = 1; - vec.forEach(vector -> { + vec.stream().forEach(vector -> { if (vecIndex == 4) { - j2 *= 0.975D; - k2 *= 0.975D; - + brightness *= 0.95; vecIndex = 0; } buf.pos(vector[0], vector[1], vector[2]).tex(par[vecIndex][0], par[vecIndex][1]) - .color(particleRed, particleGreen, particleBlue, alpha).lightmap(j2, k2).endVertex(); + .color(particleRed * brightness, particleGreen * brightness, particleBlue * brightness, alpha) + .lightmap(j, k).endVertex(); vecIndex++; }); @@ -407,8 +407,8 @@ void renderQuads(VertexBuffer buf, ArrayList vec, int j, int k, float } private void calculateYAngle() { - double angleSin = Math.toDegrees( - Math.asin(motionX / (speedMult = MathHelper.sqrt_double(motionX * motionX + motionZ * motionZ)))); + double angleSin = Math + .toDegrees(Math.asin(motionX / (speedMult = Math.sqrt(motionX * motionX + motionZ * motionZ)))); speedMult *= 200; diff --git a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java index ee0e284..7a361ee 100644 --- a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java +++ b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java @@ -1,6 +1,5 @@ package com.TominoCZ.FBP.particle; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -32,7 +31,6 @@ public class FBPParticleEmitter extends ParticleEmitter { IBlockState prevSourceState; List toAdd = new LinkedList(); - List toRemove = new ArrayList(); public FBPParticleEmitter(World w, Queue q) { super(w, new EntityItem(w), EnumParticleTypes.BLOCK_CRACK); @@ -58,16 +56,24 @@ public void onUpdate() { try { Class c = Particle.class; - prevSourceState = (IBlockState) ReflectionHelper - .findField(ParticleDigging.class, "sourceState", "field_174847_a").get(particle); - - mX = (double) ReflectionHelper.findField(c, "motionX", "field_187129_i").get(particle); - mY = (double) ReflectionHelper.findField(c, "motionY", "field_187130_j").get(particle); - mZ = (double) ReflectionHelper.findField(c, "motionZ", "field_187131_k").get(particle); + ReflectionHelper.setPrivateValue(c, particle, 0, "field_70544_f", "particleScale"); - X = (double) ReflectionHelper.findField(c, "posX", "field_187126_f").get(particle); - Y = (double) ReflectionHelper.findField(c, "posY", "field_187127_g").get(particle); - Z = (double) ReflectionHelper.findField(c, "posZ", "field_187128_h").get(particle); + prevSourceState = (IBlockState) ReflectionHelper + .findField(ParticleDigging.class, "field_174847_a", "sourceState").get(particle); + + if (prevSourceState != null + && (!(prevSourceState.getBlock() instanceof BlockLiquid) + && !(FBP.frozen && !FBP.spawnWhileFrozen)) + && (FBP.spawnRedstoneBlockParticles + || prevSourceState.getBlock() != Blocks.REDSTONE_BLOCK)) { + mX = ReflectionHelper.findField(c, "field_187129_i", "motionX").getDouble(particle); + mY = ReflectionHelper.findField(c, "field_187130_j", "motionY").getDouble(particle); + mZ = ReflectionHelper.findField(c, "field_187131_k", "motionZ").getDouble(particle); + + X = ReflectionHelper.findField(c, "field_187126_f", "posX").getDouble(particle); + Y = ReflectionHelper.findField(c, "field_187127_g", "posY").getDouble(particle); + Z = ReflectionHelper.findField(c, "field_187128_h", "posZ").getDouble(particle); + } } catch (Exception e) { if (Minecraft.getMinecraft().thePlayer.onGround) { if ((prevSourceState = worldObj.getBlockState( @@ -76,17 +82,14 @@ public void onUpdate() { } } } - if (!(prevSourceState.getBlock() instanceof BlockLiquid) && !(FBP.frozen && !FBP.spawnWhileFrozen)) { - if (FBP.spawnRedstoneBlockParticles ? true : prevSourceState.getBlock() != Blocks.REDSTONE_BLOCK) - toAdd.add(new FBPParticleDigging(worldObj, X, Y, Z, mX, mY, mZ, prevSourceState)); - } + if (prevSourceState != null + && (!(prevSourceState.getBlock() instanceof BlockLiquid) + && !(FBP.frozen && !FBP.spawnWhileFrozen)) + && (FBP.spawnRedstoneBlockParticles || prevSourceState.getBlock() != Blocks.REDSTONE_BLOCK)) + toAdd.add(new FBPParticleDigging(worldObj, X, Y, Z, mX, mY, mZ, prevSourceState)); - toRemove.add(particle); + particle.setExpired(); }); - if (!toRemove.isEmpty()) { - queue.removeAll(toRemove); - toRemove.clear(); - } if (!toAdd.isEmpty()) { queue.addAll(toAdd); toAdd.clear(); diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 2df5222..a4f5464 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -3,7 +3,7 @@ "modid": "fbp", "name": "Fancy Block Particles", "description": "3D Digging particles! YAY!", - "version": "2.0.1", + "version": "2.1", "mcversion": "1.10.2", "url": "https://minecraft.curseforge.com/projects/fancy-block-particles", "updateUrl": "", From 4190bdd5971074ce7524116f7a07084e1ce439b1 Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Wed, 22 Mar 2017 02:25:33 +0000 Subject: [PATCH 2/2] Made FBPParticleEmitter run at effectively non-reflective speed (roughly 70 times faster than before) --- .../FBP/particle/FBPParticleEmitter.java | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java index 7a361ee..9c36c80 100644 --- a/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java +++ b/src/main/java/com/TominoCZ/FBP/particle/FBPParticleEmitter.java @@ -1,11 +1,14 @@ package com.TominoCZ.FBP.particle; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.util.LinkedList; import java.util.List; import java.util.Queue; import com.TominoCZ.FBP.FBP; +import com.google.common.base.Throwables; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; @@ -24,6 +27,30 @@ import net.minecraftforge.fml.relauncher.ReflectionHelper; public class FBPParticleEmitter extends ParticleEmitter { + private static final MethodHandle setParticleScale; + private static final MethodHandle getParticleSourceState; + private static final MethodHandle getParticleMotionX; + private static final MethodHandle getParticleMotionY; + private static final MethodHandle getParticleMotionZ; + private static final MethodHandle getParticlePosX; + private static final MethodHandle getParticlePosY; + private static final MethodHandle getParticlePosZ; + static { + MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + try { + setParticleScale = lookup.unreflectSetter(ReflectionHelper.findField(Particle.class, "field_70544_f", "particleScale")); + getParticleSourceState = lookup.unreflectGetter(ReflectionHelper.findField(ParticleDigging.class, "field_174847_a", "sourceState")); + getParticleMotionX = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187129_i", "motionX")); + getParticleMotionY = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187130_j", "motionY")); + getParticleMotionZ = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187131_k", "motionZ")); + getParticlePosX = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187126_f", "posX")); + getParticlePosY = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187127_g", "posY")); + getParticlePosZ = lookup.unreflectGetter(ReflectionHelper.findField(Particle.class, "field_187128_h", "posZ")); + } catch (IllegalAccessException e) { + throw Throwables.propagate(e); + } + } + double X, Y, Z, mX, mY, mZ; Queue queue; @@ -54,25 +81,23 @@ public void onUpdate() { if (queue != null && !Minecraft.getMinecraft().isGamePaused() && FBP.isEnabled()) { queue.stream().filter(particle -> particle instanceof ParticleDigging).forEach(particle -> { try { - Class c = Particle.class; - ReflectionHelper.setPrivateValue(c, particle, 0, "field_70544_f", "particleScale"); + setParticleScale.invokeExact(particle, 0f); - prevSourceState = (IBlockState) ReflectionHelper - .findField(ParticleDigging.class, "field_174847_a", "sourceState").get(particle); + prevSourceState = (IBlockState) getParticleSourceState.invokeExact((ParticleDigging)particle); if (prevSourceState != null && (!(prevSourceState.getBlock() instanceof BlockLiquid) - && !(FBP.frozen && !FBP.spawnWhileFrozen)) + && !(FBP.frozen && !FBP.spawnWhileFrozen)) && (FBP.spawnRedstoneBlockParticles - || prevSourceState.getBlock() != Blocks.REDSTONE_BLOCK)) { - mX = ReflectionHelper.findField(c, "field_187129_i", "motionX").getDouble(particle); - mY = ReflectionHelper.findField(c, "field_187130_j", "motionY").getDouble(particle); - mZ = ReflectionHelper.findField(c, "field_187131_k", "motionZ").getDouble(particle); - - X = ReflectionHelper.findField(c, "field_187126_f", "posX").getDouble(particle); - Y = ReflectionHelper.findField(c, "field_187127_g", "posY").getDouble(particle); - Z = ReflectionHelper.findField(c, "field_187128_h", "posZ").getDouble(particle); + || prevSourceState.getBlock() != Blocks.REDSTONE_BLOCK)) { + mX = (double)getParticleMotionX.invokeExact(particle); + mY = (double)getParticleMotionY.invokeExact(particle); + mZ = (double)getParticleMotionZ.invokeExact(particle); + + X = (double)getParticlePosX.invokeExact(particle); + Y = (double)getParticlePosY.invokeExact(particle); + Z = (double)getParticlePosZ.invokeExact(particle); } } catch (Exception e) { if (Minecraft.getMinecraft().thePlayer.onGround) { @@ -81,6 +106,9 @@ public void onUpdate() { prevSourceState = Blocks.LAVA.getDefaultState(); } } + } catch (Throwable throwable) { + // invokeExact throws Throwable, so we have to catch it + throw Throwables.propagate(throwable); } if (prevSourceState != null && (!(prevSourceState.getBlock() instanceof BlockLiquid)