From dbfe7f93fa174b4bd2fec51b795c2f869c879122 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 6 Nov 2020 19:45:38 +0100 Subject: [PATCH] Spinny vortex - Crushing wheels no longer z-fight with chutes - Improved rendering of items and fluids inside basins --- .../com/simibubi/create/AllParticleTypes.java | 1 + .../mixer/MechanicalMixerTileEntity.java | 56 ++-- .../content/contraptions/fluids/FluidFX.java | 10 +- .../fluids/particle/BasinFluidParticle.java | 100 +++++++ .../fluids/particle/FluidParticleData.java | 3 +- .../fluids/particle/FluidStackParticle.java | 37 ++- .../processing/BasinRenderer.java | 110 +++++--- .../processing/BasinTileEntity.java | 255 ++++++++++++++++-- .../fluid/SmartFluidTankBehaviour.java | 10 + .../create/foundation/utility/Couple.java | 38 ++- .../foundation/utility/IntAttached.java | 37 +++ .../block/belt_funnel/block_extended.json | 17 +- .../block/belt_funnel/block_retracted.json | 19 +- .../create/models/block/crushing_wheel.json | 175 ++++++------ .../assets/create/particles/basin_fluid.json | 1 + .../textures/block/crushing_wheel_body.png | Bin 1363 -> 826 bytes 16 files changed, 672 insertions(+), 197 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/IntAttached.java create mode 100644 src/main/resources/assets/create/particles/basin_fluid.json diff --git a/src/main/java/com/simibubi/create/AllParticleTypes.java b/src/main/java/com/simibubi/create/AllParticleTypes.java index b3d85867a..03726b2ef 100644 --- a/src/main/java/com/simibubi/create/AllParticleTypes.java +++ b/src/main/java/com/simibubi/create/AllParticleTypes.java @@ -30,6 +30,7 @@ public enum AllParticleTypes { HEATER_PARTICLE(HeaterParticleData::new), CUBE(CubeParticleData::new), FLUID_PARTICLE(FluidParticleData::new), + BASIN_FLUID(FluidParticleData::new), FLUID_DRIP(FluidParticleData::new) ; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java index 7177d4fac..7e1e92bc0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java @@ -5,6 +5,7 @@ import java.util.Optional; import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.content.contraptions.components.press.MechanicalPressTileEntity; +import com.simibubi.create.content.contraptions.fluids.FluidFX; import com.simibubi.create.content.contraptions.fluids.potion.PotionMixingRecipeManager; import com.simibubi.create.content.contraptions.processing.BasinOperatingTileEntity; import com.simibubi.create.content.contraptions.processing.BasinTileEntity; @@ -12,6 +13,8 @@ import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.ITriggerable; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.item.SmartInventory; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.inventory.IInventory; @@ -19,6 +22,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.IParticleData; import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntityType; @@ -86,6 +90,9 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { running = compound.getBoolean("Running"); runningTicks = compound.getInt("Ticks"); super.read(compound, clientPacket); + + if (clientPacket && hasWorld()) + getBasin().ifPresent(bte -> bte.setAreFluidsMoving(running && runningTicks <= 20)); } @Override @@ -127,7 +134,6 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { if (runningTicks != 20) runningTicks++; } - } public void renderParticles() { @@ -135,24 +141,38 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { if (!basin.isPresent() || world == null) return; - SmartInventory inputs = basin.get() - .getInputInventory(); - for (int slot = 0; slot < inputs.getSlots(); slot++) { - ItemStack stackInSlot = inputs.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; - - ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot); - float angle = world.rand.nextFloat() * 360; - Vec3d offset = new Vec3d(0, 0, 0.25f); - offset = VecHelper.rotate(offset, angle, Axis.Y); - Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y) - .add(0, .25f, 0); - - Vec3d center = offset.add(VecHelper.getCenterOf(pos)); - target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f); - world.addParticle(data, center.x, center.y - 2, center.z, target.x, target.y, target.z); + for (SmartInventory inv : basin.get() + .getInvs()) { + for (int slot = 0; slot < inv.getSlots(); slot++) { + ItemStack stackInSlot = inv.getStackInSlot(slot); + if (stackInSlot.isEmpty()) + continue; + ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot); + spillParticle(data); + } } + + for (SmartFluidTankBehaviour behaviour : basin.get() + .getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + spillParticle(FluidFX.getFluidParticle(tankSegment.getRenderedFluid())); + } + } + } + + protected void spillParticle(IParticleData data) { + float angle = world.rand.nextFloat() * 360; + Vec3d offset = new Vec3d(0, 0, 0.25f); + offset = VecHelper.rotate(offset, angle, Axis.Y); + Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y) + .add(0, .25f, 0); + Vec3d center = offset.add(VecHelper.getCenterOf(pos)); + target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f); + world.addParticle(data, center.x, center.y - 1.75f, center.z, target.x, target.y, target.z); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java index dd9e02978..6f02282af 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidFX.java @@ -45,10 +45,6 @@ public class FluidFX { } public static IParticleData getFluidParticle(FluidStack fluid) { - if (FluidHelper.hasBlockState(fluid.getFluid())) - return new BlockParticleData(ParticleTypes.BLOCK, fluid.getFluid() - .getDefaultState() - .getBlockState()); return new FluidParticleData(AllParticleTypes.FLUID_PARTICLE.get(), fluid); } @@ -82,17 +78,17 @@ public class FluidFX { public static void spawnPouringLiquid(World world, BlockPos pos, int amount, IParticleData particle, float rimRadius, Vec3d directionVec, boolean inbound) { for (int i = 0; i < amount; i++) { - Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, rimRadius); + Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, rimRadius * .75f); vec = vec.mul(VecHelper.axisAlingedPlaneOf(directionVec)) .add(directionVec.scale(.5 + r.nextFloat() / 4f)); - Vec3d m = vec; + Vec3d m = vec.scale(1 / 4f); Vec3d centerOf = VecHelper.getCenterOf(pos); vec = vec.add(centerOf); if (inbound) { vec = vec.add(m); m = centerOf.add(directionVec.scale(.5)) .subtract(vec) - .scale(3); + .scale(1 / 16f); } world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java new file mode 100644 index 000000000..44c1bafab --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/BasinFluidParticle.java @@ -0,0 +1,100 @@ +package com.simibubi.create.content.contraptions.fluids.particle; + +import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.simibubi.create.AllBlocks; +import com.simibubi.create.content.contraptions.processing.BasinTileEntity; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.Quaternion; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; + +public class BasinFluidParticle extends FluidStackParticle { + + BlockPos basinPos; + Vec3d targetPos; + Vec3d centerOfBasin; + float yOffset; + + public BasinFluidParticle(World world, FluidStack fluid, double x, double y, double z, double vx, double vy, + double vz) { + super(world, fluid, x, y, z, vx, vy, vz); + particleGravity = 0; + motionX = 0; + motionY = 0; + motionZ = 0; + yOffset = world.rand.nextFloat() * 1 / 32f; + posY += yOffset; + particleScale = 0; + maxAge = 60; + Vec3d currentPos = new Vec3d(posX, posY, posZ); + basinPos = new BlockPos(currentPos); + centerOfBasin = VecHelper.getCenterOf(basinPos); + + if (vx != 0) { + maxAge = 20; + Vec3d centerOf = VecHelper.getCenterOf(basinPos); + Vec3d diff = currentPos.subtract(centerOf) + .mul(1, 0, 1) + .normalize() + .scale(.375); + targetPos = centerOf.add(diff); + prevPosX = posX = centerOfBasin.x; + prevPosZ = posZ = centerOfBasin.z; + } + } + + @Override + public void tick() { + super.tick(); + particleScale = targetPos != null ? Math.max(1 / 32f, ((1f * age) / maxAge) / 8) + : 1 / 8f * (1 - ((Math.abs(age - (maxAge / 2)) / (1f * maxAge)))); + + if (age % 2 == 0) { + if (!AllBlocks.BASIN.has(world.getBlockState(basinPos))) { + setExpired(); + return; + } + + TileEntity tileEntity = world.getTileEntity(basinPos); + if (tileEntity instanceof BasinTileEntity) { + float totalUnits = ((BasinTileEntity) tileEntity).getTotalFluidUnits(); + if (totalUnits < 1) + totalUnits = 0; + float fluidLevel = MathHelper.clamp(totalUnits / 2000, 0, 1); + posY = 2 / 16f + basinPos.getY() + 12 / 16f * fluidLevel + yOffset; + } + + } + + if (targetPos != null) { + float progess = (1f * age) / maxAge; + Vec3d currentPos = centerOfBasin.add(targetPos.subtract(centerOfBasin) + .scale(progess)); + posX = currentPos.x; + posZ = currentPos.z; + } + } + + @Override + public void buildGeometry(IVertexBuilder vb, ActiveRenderInfo info, float pt) { + Quaternion rotation = info.getRotation(); + Quaternion prevRotation = new Quaternion(rotation); + rotation.set(1, 0, 0, 1); + rotation.normalize(); + super.buildGeometry(vb, info, pt); + rotation.set(0, 0, 0, 1); + rotation.multiply(prevRotation); + } + + @Override + protected boolean canEvaporate() { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java index 6e06adf33..2812d3d76 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidParticleData.java @@ -30,7 +30,8 @@ public class FluidParticleData implements IParticleData, ICustomParticleData getFactory() { - return (data, world, x, y, z, vx, vy, vz) -> new FluidStackParticle(world, data.fluid, x, y, z, vx, vy, vz); + return (data, world, x, y, z, vx, vy, vz) -> FluidStackParticle.create(data.type, world, data.fluid, x, y, z, + vx, vy, vz); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java index 82a269418..d0868a468 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/particle/FluidStackParticle.java @@ -1,5 +1,6 @@ package com.simibubi.create.content.contraptions.fluids.particle; +import com.simibubi.create.AllParticleTypes; import com.simibubi.create.content.contraptions.fluids.potion.PotionFluid; import com.simibubi.create.foundation.utility.ColorHelper; @@ -7,6 +8,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.particle.IParticleRenderType; import net.minecraft.client.particle.SpriteTexturedParticle; import net.minecraft.inventory.container.PlayerContainer; +import net.minecraft.particles.ParticleType; import net.minecraft.particles.ParticleTypes; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -17,6 +19,13 @@ public class FluidStackParticle extends SpriteTexturedParticle { private final float field_217588_H; private FluidStack fluid; + public static FluidStackParticle create(ParticleType type, World world, FluidStack fluid, double x, + double y, double z, double vx, double vy, double vz) { + if (type == AllParticleTypes.BASIN_FLUID.get()) + return new BasinFluidParticle(world, fluid, x, y, z, vx, vy, vz); + return new FluidStackParticle(world, fluid, x, y, z, vx, vy, vz); + } + public FluidStackParticle(World world, FluidStack fluid, double x, double y, double z, double vx, double vy, double vz) { super(world, x, y, z, vx, vy, vz); @@ -34,14 +43,25 @@ public class FluidStackParticle extends SpriteTexturedParticle { this.multiplyColor(fluid.getFluid() .getAttributes() .getColor(fluid)); + + this.motionX = vx; + this.motionY = vy; + this.motionZ = vz; this.particleScale /= 2.0F; this.field_217587_G = this.rand.nextFloat() * 3.0F; this.field_217588_H = this.rand.nextFloat() * 3.0F; } - public IParticleRenderType getRenderType() { - return IParticleRenderType.TERRAIN_SHEET; + @Override + protected int getBrightnessForRender(float p_189214_1_) { + int brightnessForRender = super.getBrightnessForRender(p_189214_1_); + int skyLight = brightnessForRender >> 20; + int blockLight = (brightnessForRender >> 4) & 0xf; + blockLight = Math.max(blockLight, fluid.getFluid() + .getAttributes() + .getLuminosity(fluid)); + return (skyLight << 20) | (blockLight << 4); } protected void multiplyColor(int color) { @@ -69,13 +89,13 @@ public class FluidStackParticle extends SpriteTexturedParticle { @Override public void tick() { super.tick(); - if (!(fluid.getFluid() instanceof PotionFluid)) + if (!canEvaporate()) return; if (onGround) setExpired(); if (!isExpired) return; - if (!onGround && world.rand.nextFloat() < 1/8f) + if (!onGround && world.rand.nextFloat() < 1 / 8f) return; Vec3d rgb = ColorHelper.getRGB(fluid.getFluid() @@ -83,5 +103,14 @@ public class FluidStackParticle extends SpriteTexturedParticle { .getColor(fluid)); world.addParticle(ParticleTypes.ENTITY_EFFECT, posX, posY, posZ, rgb.x, rgb.y, rgb.z); } + + protected boolean canEvaporate() { + return fluid.getFluid() instanceof PotionFluid; + } + + @Override + public IParticleRenderType getRenderType() { + return IParticleRenderType.TERRAIN_SHEET; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java index 148309b28..bfb965e46 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinRenderer.java @@ -7,14 +7,20 @@ import com.simibubi.create.foundation.fluid.FluidRenderer; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.IntAttached; +import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -33,35 +39,92 @@ public class BasinRenderer extends SmartTileEntityRenderer { int light, int overlay) { super.renderSafe(basin, partialTicks, ms, buffer, light, overlay); - renderFluids(basin, partialTicks, ms, buffer, light, overlay); + float fluidLevel = renderFluids(basin, partialTicks, ms, buffer, light, overlay); + float level = MathHelper.clamp(fluidLevel - .3f, .125f, .6f); ms.push(); + BlockPos pos = basin.getPos(); ms.translate(.5, .2f, .5); + MatrixStacker.of(ms) + .rotateY(basin.ingredientRotation.getValue(partialTicks)); + Random r = new Random(pos.hashCode()); + Vec3d baseVector = new Vec3d(.125, level, 0); IItemHandlerModifiable inv = basin.itemCapability.orElse(new ItemStackHandler()); + int itemCount = 0; + for (int slot = 0; slot < inv.getSlots(); slot++) + if (!inv.getStackInSlot(slot) + .isEmpty()) + itemCount++; + + if (itemCount == 1) + baseVector = new Vec3d(0, level, 0); + + float anglePartition = 360f / itemCount; for (int slot = 0; slot < inv.getSlots(); slot++) { ItemStack stack = inv.getStackInSlot(slot); if (stack.isEmpty()) continue; + ms.push(); + + if (fluidLevel > 0) { + ms.translate(0, + (MathHelper.sin(AnimationTickHolder.getRenderTick() / 12f + anglePartition * itemCount) + 1.5f) * 1 + / 32f, + 0); + } + + Vec3d itemPosition = VecHelper.rotate(baseVector, anglePartition * itemCount, Axis.Y); + ms.translate(itemPosition.x, itemPosition.y, itemPosition.z); + MatrixStacker.of(ms) + .rotateY(anglePartition * itemCount + 35) + .rotateX(65); + for (int i = 0; i <= stack.getCount() / 8; i++) { ms.push(); - Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, .25f); - Vec3d vec2 = VecHelper.offsetRandomly(Vec3d.ZERO, r, .5f); + Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, 1 / 16f); ms.translate(vec.x, vec.y, vec.z); - ms.multiply(new Vector3f((float) vec2.z, (float) vec2.y, 0).getDegreesQuaternion((float) vec2.x * 180)); - - Minecraft.getInstance() - .getItemRenderer() - .renderItem(stack, TransformType.GROUND, light, overlay, ms, buffer); + renderItem(ms, buffer, light, overlay, stack); ms.pop(); } - ms.translate(0, 1 / 64f, 0); + ms.pop(); + + itemCount--; } ms.pop(); + BlockState blockState = basin.getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return; + Direction direction = blockState.get(BasinBlock.FACING); + if (direction == Direction.DOWN) + return; + Vec3d directionVec = new Vec3d(direction.getDirectionVec()); + Vec3d outVec = VecHelper.getCenterOf(BlockPos.ZERO) + .add(directionVec.scale(.55) + .subtract(0, 1 / 2f, 0)); + + for (IntAttached intAttached : basin.visualizedOutputItems) { + float progress = 1 - (intAttached.getFirst() - partialTicks) / BasinTileEntity.OUTPUT_ANIMATION_TIME; + ms.push(); + MatrixStacker.of(ms) + .translate(outVec) + .translate(new Vec3d(0, Math.max(-.55f, -(progress * progress * 2)), 0)) + .translate(directionVec.scale(progress * .5f)) + .rotateY(AngleHelper.horizontalAngle(direction)) + .rotateX(progress * 180); + renderItem(ms, buffer, light, overlay, intAttached.getValue()); + ms.pop(); + } + } + + protected void renderItem(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay, ItemStack stack) { + Minecraft.getInstance() + .getItemRenderer() + .renderItem(stack, TransformType.GROUND, light, overlay, ms, buffer); } protected float renderFluids(BasinTileEntity basin, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer, @@ -69,26 +132,7 @@ public class BasinRenderer extends SmartTileEntityRenderer { SmartFluidTankBehaviour inputFluids = basin.getBehaviour(SmartFluidTankBehaviour.INPUT); SmartFluidTankBehaviour outputFluids = basin.getBehaviour(SmartFluidTankBehaviour.OUTPUT); SmartFluidTankBehaviour[] tanks = { inputFluids, outputFluids }; - int renderedFluids = 0; - float totalUnits = 0; - - for (SmartFluidTankBehaviour behaviour : tanks) { - if (behaviour == null) - continue; - for (TankSegment tankSegment : behaviour.getTanks()) { - if (tankSegment.getRenderedFluid() - .isEmpty()) - continue; - float units = tankSegment.getTotalUnits(partialTicks); - if (units < 1) - continue; - totalUnits += units; - renderedFluids++; - } - } - - if (renderedFluids == 0) - return 0; + float totalUnits = basin.getTotalFluidUnits(); if (totalUnits < 1) return 0; @@ -111,8 +155,8 @@ public class BasinRenderer extends SmartTileEntityRenderer { float units = tankSegment.getTotalUnits(partialTicks); if (units < 1) continue; - - float partial = units / totalUnits; + + float partial = MathHelper.clamp(units / totalUnits, 0, 1); xMax += partial * 12 / 16f; FluidRenderer.renderTiledFluidBB(renderedFluid, xMin, yMin, zMin, xMax, yMax, zMax, buffer, ms, light, false); @@ -121,7 +165,7 @@ public class BasinRenderer extends SmartTileEntityRenderer { } } - return fluidLevel; + return yMax; } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java index f7a4c6d6e..12a4dcca4 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java @@ -1,11 +1,18 @@ package com.simibubi.create.content.contraptions.processing; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Random; import javax.annotation.Nonnull; +import com.simibubi.create.AllParticleTypes; import com.simibubi.create.AllTags; +import com.simibubi.create.content.contraptions.components.mixer.MechanicalMixerTileEntity; +import com.simibubi.create.content.contraptions.fluids.FluidFX; +import com.simibubi.create.content.contraptions.fluids.particle.FluidParticleData; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock; import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel; import com.simibubi.create.foundation.fluid.CombinedTankWrapper; @@ -16,21 +23,32 @@ import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.fluid.SmartFluidTankBehaviour.TankSegment; +import com.simibubi.create.foundation.utility.AnimationTickHolder; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.IntAttached; import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.LerpedFloat; +import com.simibubi.create.foundation.utility.LerpedFloat.Chaser; +import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.IParticleData; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; @@ -44,25 +62,44 @@ import net.minecraftforge.items.wrapper.CombinedInvWrapper; public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity { + private boolean areFluidsMoving; + LerpedFloat ingredientRotationSpeed; + LerpedFloat ingredientRotation; + public BasinInventory inputInventory; public SmartFluidTankBehaviour inputTank; protected SmartInventory outputInventory; protected SmartFluidTankBehaviour outputTank; + private FilteringBehaviour filtering; + private boolean contentsChanged; + + private Couple invs; + private Couple tanks; protected LazyOptional itemCapability; protected LazyOptional fluidCapability; - private FilteringBehaviour filtering; - private boolean contentsChanged; + public static final int OUTPUT_ANIMATION_TIME = 10; + List> visualizedOutputItems; + List> visualizedOutputFluids; public BasinTileEntity(TileEntityType type) { super(type); inputInventory = new BasinInventory(9, this); inputInventory.whenContentsChanged($ -> contentsChanged = true); outputInventory = new BasinInventory(9, this).forbidInsertion(); - + areFluidsMoving = false; itemCapability = LazyOptional.of(() -> new CombinedInvWrapper(inputInventory, outputInventory)); contentsChanged = true; + ingredientRotation = LerpedFloat.angular() + .startWithValue(0); + ingredientRotationSpeed = LerpedFloat.linear() + .startWithValue(0); + + invs = Couple.create(inputInventory, outputInventory); + tanks = Couple.create(inputTank, outputTank); + visualizedOutputItems = Collections.synchronizedList(new ArrayList<>()); + visualizedOutputFluids = Collections.synchronizedList(new ArrayList<>()); } @Override @@ -78,6 +115,7 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt outputTank = new SmartFluidTankBehaviour(SmartFluidTankBehaviour.OUTPUT, this, 2, 1000, true).forbidInsertion(); behaviours.add(inputTank); behaviours.add(outputTank); + fluidCapability = LazyOptional.of(() -> { LazyOptional inputCap = inputTank.getCapability(); LazyOptional outputCap = outputTank.getCapability(); @@ -90,6 +128,15 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt super.read(compound, clientPacket); inputInventory.deserializeNBT(compound.getCompound("InputItems")); outputInventory.deserializeNBT(compound.getCompound("OutputItems")); + + if (!clientPacket) + return; + + NBTHelper.iterateCompoundList(compound.getList("VisualizedItems", NBT.TAG_COMPOUND), + c -> visualizedOutputItems.add(IntAttached.with(OUTPUT_ANIMATION_TIME, ItemStack.read(c)))); + NBTHelper.iterateCompoundList(compound.getList("VisualizedFluids", NBT.TAG_COMPOUND), + c -> visualizedOutputFluids + .add(IntAttached.with(OUTPUT_ANIMATION_TIME, FluidStack.loadFluidStackFromNBT(c)))); } @Override @@ -97,6 +144,16 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt super.write(compound, clientPacket); compound.put("InputItems", inputInventory.serializeNBT()); compound.put("OutputItems", outputInventory.serializeNBT()); + + if (!clientPacket) + return; + + compound.put("VisualizedItems", NBTHelper.writeCompoundList(visualizedOutputItems, ia -> ia.getValue() + .serializeNBT())); + compound.put("VisualizedFluids", NBTHelper.writeCompoundList(visualizedOutputFluids, ia -> ia.getValue() + .writeToNBT(new CompoundNBT()))); + visualizedOutputItems.clear(); + visualizedOutputFluids.clear(); } public void onEmptied() { @@ -129,11 +186,26 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt @Override public void lazyTick() { super.lazyTick(); + if (!world.isRemote) + return; + TileEntity tileEntity = world.getTileEntity(pos.up(2)); + if (!(tileEntity instanceof MechanicalMixerTileEntity)) { + setAreFluidsMoving(false); + return; + } + MechanicalMixerTileEntity mixer = (MechanicalMixerTileEntity) tileEntity; + setAreFluidsMoving(mixer.running && mixer.runningTicks <= 20); } @Override public void tick() { super.tick(); + if (world.isRemote) { + createFluidParticles(); + tickVisualizedOutputs(); + ingredientRotationSpeed.tickChaser(); + ingredientRotation.setValue(ingredientRotation.getValue() + ingredientRotationSpeed.getValue()); + } if (!contentsChanged) return; contentsChanged = false; @@ -143,7 +215,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt BlockPos toUpdate = pos.up() .offset(offset); BlockState stateToUpdate = world.getBlockState(toUpdate); - if (stateToUpdate.getBlock() instanceof BasinBlock && stateToUpdate.get(BasinBlock.FACING) == offset.getOpposite()) { + if (stateToUpdate.getBlock() instanceof BasinBlock + && stateToUpdate.get(BasinBlock.FACING) == offset.getOpposite()) { TileEntity te = world.getTileEntity(toUpdate); if (te instanceof BasinTileEntity) ((BasinTileEntity) te).contentsChanged = true; @@ -151,6 +224,32 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } } + public float getTotalFluidUnits() { + int renderedFluids = 0; + float totalUnits = 0; + + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.getRenderedFluid() + .isEmpty()) + continue; + float units = tankSegment.getTotalUnits(0); + if (units < 1) + continue; + totalUnits += units; + renderedFluids++; + } + } + + if (renderedFluids == 0) + return 0; + if (totalUnits < 1) + return 0; + return totalUnits; + } + private Optional getOperator() { if (world == null) return Optional.empty(); @@ -224,6 +323,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt if (!ItemHandlerHelper.insertItemStacked(targetInv, itemStack.copy(), simulate) .isEmpty()) return false; + else if (!simulate) + visualizedOutputItems.add(IntAttached.withZero(itemStack)); if (targetTank == null) return false; @@ -231,10 +332,145 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt if (targetTank.fill(fluidStack.copy(), simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != fluidStack .getAmount()) return false; + else if (!simulate) + visualizedOutputFluids.add(IntAttached.withZero(fluidStack)); return true; } + public void readOnlyItems(CompoundNBT compound) { + inputInventory.deserializeNBT(compound.getCompound("InputItems")); + outputInventory.deserializeNBT(compound.getCompound("OutputItems")); + } + + public static HeatLevel getHeatLevelOf(BlockState state) { + if (state.has(BlazeBurnerBlock.HEAT_LEVEL)) + return state.get(BlazeBurnerBlock.HEAT_LEVEL); + return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; + } + + public Couple getTanks() { + return tanks; + } + + public Couple getInvs() { + return invs; + } + + // client things + + private void tickVisualizedOutputs() { + visualizedOutputFluids.forEach(IntAttached::decrement); + visualizedOutputItems.forEach(IntAttached::decrement); + visualizedOutputFluids.removeIf(IntAttached::isOrBelowZero); + visualizedOutputItems.removeIf(IntAttached::isOrBelowZero); + } + + private void createFluidParticles() { + Random r = world.rand; + + if (!visualizedOutputFluids.isEmpty()) + createOutputFluidParticles(r); + + if (!areFluidsMoving && r.nextFloat() > 1 / 8f) + return; + + int segments = 0; + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) + if (!tankSegment.isEmpty(0)) + segments++; + } + if (segments < 2) + return; + + float totalUnits = getTotalFluidUnits(); + if (totalUnits == 0) + return; + float fluidLevel = MathHelper.clamp(totalUnits / 2000, 0, 1); + float rim = 2 / 16f; + float space = 12 / 16f; + float surface = pos.getY() + rim + space * fluidLevel + 1 / 32f; + + if (areFluidsMoving) { + createMovingFluidParticles(surface, segments); + return; + } + + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + float x = pos.getX() + rim + space * r.nextFloat(); + float z = pos.getZ() + rim + space * r.nextFloat(); + world.addOptionalParticle( + new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), x, + surface, z, 0, 0, 0); + } + } + } + + private void createOutputFluidParticles(Random r) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof BasinBlock)) + return; + Direction direction = blockState.get(BasinBlock.FACING); + if (direction == Direction.DOWN) + return; + Vec3d directionVec = new Vec3d(direction.getDirectionVec()); + Vec3d outVec = VecHelper.getCenterOf(pos) + .add(directionVec.scale(.65) + .subtract(0, 1 / 4f, 0)); + Vec3d outMotion = directionVec.scale(1 / 16f) + .add(0, -1 / 16f, 0); + + for (int i = 0; i < 3; i++) { + visualizedOutputFluids.forEach(ia -> { + FluidStack fluidStack = ia.getValue(); + IParticleData fluidParticle = FluidFX.getFluidParticle(fluidStack); + Vec3d m = VecHelper.offsetRandomly(outMotion, r, 1 / 16f); + world.addOptionalParticle(fluidParticle, outVec.x, outVec.y, outVec.z, m.x, m.y, m.z); + }); + } + } + + private void createMovingFluidParticles(float surface, int segments) { + Vec3d pointer = new Vec3d(1, 0, 0).scale(1 / 16f); + float interval = 360f / segments; + Vec3d centerOf = VecHelper.getCenterOf(pos); + float intervalOffset = (AnimationTickHolder.ticks * 18) % 360; + + int currentSegment = 0; + for (SmartFluidTankBehaviour behaviour : getTanks()) { + if (behaviour == null) + continue; + for (TankSegment tankSegment : behaviour.getTanks()) { + if (tankSegment.isEmpty(0)) + continue; + float angle = interval * (1 + currentSegment) + intervalOffset; + Vec3d vec = centerOf.add(VecHelper.rotate(pointer, angle, Axis.Y)); + world.addOptionalParticle( + new FluidParticleData(AllParticleTypes.BASIN_FLUID.get(), tankSegment.getRenderedFluid()), + vec.getX(), surface, vec.getZ(), 1, 0, 0); + currentSegment++; + } + } + } + + public boolean areFluidsMoving() { + return areFluidsMoving; + } + + public boolean setAreFluidsMoving(boolean areFluidsMoving) { + this.areFluidsMoving = areFluidsMoving; + ingredientRotationSpeed.chase(areFluidsMoving ? 20 : 0, .1f, Chaser.EXP); + return areFluidsMoving; + } + class BasinValueBox extends ValueBoxTransform.Sided { @Override @@ -249,15 +485,4 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } } - - public void readOnlyItems(CompoundNBT compound) { - inputInventory.deserializeNBT(compound.getCompound("InputItems")); - outputInventory.deserializeNBT(compound.getCompound("OutputItems")); - } - - public static HeatLevel getHeatLevelOf(BlockState state) { - if (state.has(BlazeBurnerBlock.HEAT_LEVEL)) - return state.get(BlazeBurnerBlock.HEAT_LEVEL); - return AllTags.AllBlockTags.FAN_HEATERS.matches(state) ? HeatLevel.SMOULDERING : HeatLevel.NONE; - } } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java index 44dadd97f..069b04075 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/fluid/SmartFluidTankBehaviour.java @@ -267,6 +267,16 @@ public class SmartFluidTankBehaviour extends TileEntityBehaviour { .isEmpty()) renderedFluid = tank.getFluid(); } + + public boolean isEmpty(float partialTicks) { + FluidStack renderedFluid = getRenderedFluid(); + if (renderedFluid.isEmpty()) + return true; + float units = getTotalUnits(partialTicks); + if (units < 1) + return true; + return false; + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/Couple.java b/src/main/java/com/simibubi/create/foundation/utility/Couple.java index fd391dbef..0df6950b6 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Couple.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Couple.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.utility; +import java.util.Iterator; import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -12,7 +13,7 @@ import com.google.common.collect.ImmutableList; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; -public class Couple extends Pair { +public class Couple extends Pair implements Iterable { private static Couple TRUE_AND_FALSE = Couple.create(true, false); @@ -62,7 +63,8 @@ public class Couple extends Pair { setSecond(function.apply(getSecond(), values.getSecond())); } - public void forEach(Consumer consumer) { + @Override + public void forEach(Consumer consumer) { consumer.accept(getFirst()); consumer.accept(getSecond()); } @@ -89,4 +91,36 @@ public class Couple extends Pair { return new Couple<>(readCompoundList.get(0), readCompoundList.get(1)); } + @Override + public Iterator iterator() { + return new Couplerator<>(this); + } + + private static class Couplerator implements Iterator { + + int state; + private Couple couple; + + public Couplerator(Couple couple) { + this.couple = couple; + state = 0; + } + + @Override + public boolean hasNext() { + return state != 2; + } + + @Override + public T next() { + state++; + if (state == 1) + return couple.first; + if (state == 2) + return couple.second; + return null; + } + + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/IntAttached.java b/src/main/java/com/simibubi/create/foundation/utility/IntAttached.java new file mode 100644 index 000000000..6353b0d2d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/IntAttached.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.utility; + +public class IntAttached extends Pair { + + protected IntAttached(Integer first, V second) { + super(first, second); + } + + public static IntAttached with(int number, V value) { + return new IntAttached<>(number, value); + } + + public static IntAttached withZero(V value) { + return new IntAttached<>(0, value); + } + + public boolean isZero() { + return first.intValue() == 0; + } + + public boolean isOrBelowZero() { + return first.intValue() <= 0; + } + + public void increment() { + first++; + } + + public void decrement() { + first--; + } + + public V getValue() { + return getSecond(); + } + +} diff --git a/src/main/resources/assets/create/models/block/belt_funnel/block_extended.json b/src/main/resources/assets/create/models/block/belt_funnel/block_extended.json index 579fd216b..dca272755 100644 --- a/src/main/resources/assets/create/models/block/belt_funnel/block_extended.json +++ b/src/main/resources/assets/create/models/block/belt_funnel/block_extended.json @@ -123,23 +123,10 @@ "up": {"uv": [6, 0, 8, 6], "rotation": 90, "texture": "#3"} } }, - { - "name": "BackBottom", - "from": [3.9, -2, 18], - "to": [12.1, 2, 26], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, -4, 17]}, - "faces": { - "east": {"uv": [12, 12, 14, 16], "rotation": 270, "texture": "#7"}, - "south": {"uv": [8, 13, 12, 15], "rotation": 180, "texture": "#7"}, - "west": {"uv": [12, 12, 14, 16], "rotation": 270, "texture": "#7"}, - "up": {"uv": [8, 12, 12, 16], "rotation": 180, "texture": "#7"}, - "down": {"uv": [8, 12, 12, 16], "rotation": 180, "texture": "#7"} - } - }, { "name": "Back", "from": [2.1, -2.1, 14], - "to": [13.9, 13.9, 17.9], + "to": [13.9, 13.95, 18.1], "rotation": {"angle": 0, "axis": "y", "origin": [8, -8, 6]}, "faces": { "north": {"uv": [0, 4, 16, 16], "rotation": 90, "texture": "#5"}, @@ -204,7 +191,7 @@ { "name": "Base", "origin": [9, -4, 8], - "children": [9, 10, 11, 12, 13] + "children": [9, 10, 11, 12] } ] } diff --git a/src/main/resources/assets/create/models/block/belt_funnel/block_retracted.json b/src/main/resources/assets/create/models/block/belt_funnel/block_retracted.json index e026af2fc..3eafc8c41 100644 --- a/src/main/resources/assets/create/models/block/belt_funnel/block_retracted.json +++ b/src/main/resources/assets/create/models/block/belt_funnel/block_retracted.json @@ -108,23 +108,10 @@ "down": {"uv": [0, 0, 1, 6], "texture": "#particle"} } }, - { - "name": "BackBottom", - "from": [3.9, -2, 18], - "to": [12.1, 2, 26], - "rotation": {"angle": -22.5, "axis": "x", "origin": [8, -4, 17]}, - "faces": { - "east": {"uv": [12, 12, 14, 16], "rotation": 270, "texture": "#7"}, - "south": {"uv": [8, 13, 12, 15], "rotation": 180, "texture": "#7"}, - "west": {"uv": [12, 12, 14, 16], "rotation": 270, "texture": "#7"}, - "up": {"uv": [8, 12, 12, 16], "rotation": 180, "texture": "#7"}, - "down": {"uv": [8, 12, 12, 16], "rotation": 180, "texture": "#7"} - } - }, { "name": "Back", "from": [2.1, -2.1, 14], - "to": [13.9, 13.9, 17.9], + "to": [13.9, 13.95, 18.1], "rotation": {"angle": 0, "axis": "y", "origin": [8, -8.1, 6]}, "faces": { "east": {"uv": [0, 0, 16, 4], "rotation": 90, "texture": "#5"}, @@ -196,8 +183,8 @@ { "name": "Base", "origin": [9, -4, 8], - "children": [8, 9, 10, 11, 12] + "children": [8, 9, 10, 11] } ] - }, 13] + }, 12] } \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/crushing_wheel.json b/src/main/resources/assets/create/models/block/crushing_wheel.json index 738682e22..021c59f45 100644 --- a/src/main/resources/assets/create/models/block/crushing_wheel.json +++ b/src/main/resources/assets/create/models/block/crushing_wheel.json @@ -3,11 +3,10 @@ "parent": "create:block/large_wheels", "textures": { "6": "create:block/crushing_wheel_body", - "spruce_log_top": "block/spruce_log", + "spruce_log_top": "create:block/smooth_dark_log_top", "axis_top": "create:block/axis_top", "axis": "create:block/axis", "crushing_wheel": "create:block/crushing_wheel", - "spruce_log": "block/spruce_log", "particle": "block/polished_andesite" }, "elements": [ @@ -27,68 +26,69 @@ }, { "name": "B1", - "from": [2, 2, -8], - "to": [9, 14, 7], - "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [2, 1.95, -8], + "to": [9, 14.05, 7], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [7.5, 6, 11, 12], "texture": "#6"}, "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "west": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "up": {"uv": [0, 9.5, 7.5, 13], "rotation": 270, "texture": "#6"}, "down": {"uv": [0, 9.5, 7.5, 13], "rotation": 90, "texture": "#6"} } }, { "name": "B2", - "from": [2, 2.1, -8], - "to": [10, 13.9, 7], + "from": [2, 1.9, -8], + "to": [10, 14.1, 7], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { - "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "north": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 270, "texture": "#6"}, + "west": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 270, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 90, "texture": "#6"} } }, { "name": "B3", - "from": [2, 2, -8], - "to": [9, 14, 7], - "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [2, 1.95, -8], + "to": [9, 14.05, 7], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [11, 0, 14.5, 6], "texture": "#6"}, "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "west": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 270, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 90, "texture": "#6"} } }, { "name": "B4", - "from": [2, 2.1, -8], - "to": [10, 13.9, 7], - "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8]}, + "from": [2, 1.9, -8], + "to": [10, 14.1, 7], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 8.05, 8]}, "faces": { - "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "north": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "up": {"uv": [8.5, 12.5, 16, 16], "rotation": 270, "texture": "#6"}, + "west": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 270, "texture": "#6"}, "down": {"uv": [8.5, 12.5, 16, 16], "rotation": 90, "texture": "#6"} } }, { "name": "B5", - "from": [-8, 2, 7], - "to": [7, 14, 14], - "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [-8, 1.95, 7], + "to": [7, 14.05, 14], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "south": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "west": {"uv": [7.5, 6, 11, 12], "texture": "#6"}, "up": {"uv": [0, 9.5, 7.5, 13], "rotation": 180, "texture": "#6"}, "down": {"uv": [0, 9.5, 7.5, 13], "rotation": 180, "texture": "#6"} @@ -96,26 +96,27 @@ }, { "name": "B6", - "from": [-8, 2.1, 6], - "to": [7, 13.9, 14], + "from": [-8, 1.9, 6], + "to": [7, 14.1, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "west": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 180, "texture": "#6"}, + "south": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "west": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 180, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 180, "texture": "#6"} } }, { "name": "B7", - "from": [-8, 2, 7], - "to": [7, 14, 14], - "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [-8, 1.95, 7], + "to": [7, 14.05, 14], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "south": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "west": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 180, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 180, "texture": "#6"} @@ -123,26 +124,26 @@ }, { "name": "B8", - "from": [-8, 2.1, 6], - "to": [7, 13.9, 14], - "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8]}, + "from": [-8, 1.9, 6], + "to": [7, 14.1, 14], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "west": {"uv": [11, 0, 14.5, 6], "texture": "#6"}, - "up": {"uv": [8.5, 12.5, 16, 16], "rotation": 180, "texture": "#6"}, + "south": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "west": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 180, "texture": "#6"}, "down": {"uv": [8.5, 12.5, 16, 16], "rotation": 180, "texture": "#6"} } }, { "name": "B9", - "from": [7, 2, 9], - "to": [14, 14, 24], - "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [7, 1.95, 9], + "to": [14, 14.05, 24], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "east": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "south": {"uv": [7.5, 6, 11, 12], "texture": "#6"}, "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "up": {"uv": [0, 9.5, 7.5, 13], "rotation": 90, "texture": "#6"}, @@ -151,26 +152,27 @@ }, { "name": "B10", - "from": [6, 2.1, 9], - "to": [14, 13.9, 24], + "from": [6, 1.9, 9], + "to": [14, 14.1, 24], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "east": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "south": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 90, "texture": "#6"}, + "up": {"uv": [0, 6, 7.5, 10], "rotation": 90, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 270, "texture": "#6"} } }, { "name": "B11", - "from": [7, 2, 9], - "to": [14, 14, 24], - "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [7, 1.95, 9], + "to": [14, 14.05, 24], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "south": {"uv": [11, 0, 14.5, 6], "texture": "#6"}, + "east": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "south": {"uv": [7.5, 6, 11, 12], "texture": "#6"}, "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "up": {"uv": [8.5, 12.5, 16, 16], "rotation": 90, "texture": "#6"}, "down": {"uv": [8.5, 12.5, 16, 16], "rotation": 270, "texture": "#6"} @@ -178,25 +180,25 @@ }, { "name": "B12", - "from": [6, 2.1, 9], - "to": [14, 13.9, 24], - "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8]}, + "from": [6, 1.9, 9], + "to": [14, 14.1, 24], + "rotation": {"angle": 45, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "east": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "south": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 90, "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 90, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 270, "texture": "#6"} } }, { "name": "B13", - "from": [9, 2, 2], - "to": [24, 14, 9], - "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [9, 1.95, 2], + "to": [24, 14.05, 9], + "rotation": {"angle": -22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { - "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "north": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "east": {"uv": [7.5, 6, 11, 12], "texture": "#6"}, "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "west": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, @@ -206,24 +208,25 @@ }, { "name": "B14", - "from": [9, 2.1, 2], - "to": [24, 13.9, 10], + "from": [9, 1.9, 2], + "to": [24, 14.1, 10], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { - "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "east": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "north": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "east": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "west": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "texture": "#6"}, + "up": {"uv": [0, 7.5, 7.5, 11.5], "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "texture": "#6"} } }, { "name": "B15", - "from": [9, 2, 2], - "to": [24, 14, 9], - "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 8, 8]}, + "from": [9, 1.95, 2], + "to": [24, 14.05, 9], + "rotation": {"angle": 22.5, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { - "north": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, + "north": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, "east": {"uv": [11, 0, 14.5, 6], "texture": "#6"}, "south": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "west": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, @@ -233,15 +236,15 @@ }, { "name": "B16", - "from": [2, 2.1, -8], - "to": [10, 13.9, 7], - "rotation": {"angle": -45, "axis": "y", "origin": [8, 8, 8]}, + "from": [2, 1.9, -8], + "to": [10, 14.1, 7], + "rotation": {"angle": -45, "axis": "y", "origin": [8, 7.95, 8]}, "faces": { - "north": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, + "north": {"uv": [3.5, 0, 7.5, 6], "texture": "#6"}, "east": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, "south": {"uv": [7.5, 0, 11, 6], "texture": "#6"}, - "west": {"uv": [0, 0, 7.5, 6], "texture": "#6"}, - "up": {"uv": [0, 6, 7.5, 9.5], "rotation": 270, "texture": "#6"}, + "west": {"uv": [1.5, 6, 7.5, 0], "rotation": 180, "texture": "#6"}, + "up": {"uv": [0, 6.5, 7.5, 10.5], "rotation": 270, "texture": "#6"}, "down": {"uv": [0, 6, 7.5, 9.5], "rotation": 90, "texture": "#6"} } }, @@ -251,18 +254,18 @@ "to": [12, 15, 12], "shade": false, "faces": { - "north": {"uv": [4, 1, 12, 15], "texture": "#spruce_log"}, - "east": {"uv": [4, 1, 12, 15], "texture": "#spruce_log"}, - "south": {"uv": [4, 1, 12, 15], "texture": "#spruce_log"}, - "west": {"uv": [4, 1, 12, 15], "texture": "#spruce_log"}, + "north": {"uv": [4, 1, 12, 15], "texture": "#spruce_log_top"}, + "east": {"uv": [4, 1, 12, 15], "texture": "#spruce_log_top"}, + "south": {"uv": [4, 1, 12, 15], "texture": "#spruce_log_top"}, + "west": {"uv": [4, 1, 12, 15], "texture": "#spruce_log_top"}, "up": {"uv": [4, 4, 12, 12], "texture": "#spruce_log_top"}, "down": {"uv": [4, 4, 12, 12], "texture": "#spruce_log_top"} } }, { "name": "Cover", - "from": [-4, 1.9, -4], - "to": [20, 14.1, 20], + "from": [-4, 1.85, -4], + "to": [20, 14.15, 20], "faces": { "up": {"uv": [2, 2, 14, 14], "texture": "#crushing_wheel"}, "down": {"uv": [2, 2, 14, 14], "texture": "#crushing_wheel"} @@ -276,4 +279,4 @@ "children": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] } ] -} +} \ No newline at end of file diff --git a/src/main/resources/assets/create/particles/basin_fluid.json b/src/main/resources/assets/create/particles/basin_fluid.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/src/main/resources/assets/create/particles/basin_fluid.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/crushing_wheel_body.png b/src/main/resources/assets/create/textures/block/crushing_wheel_body.png index 542f0f54183bd173edf16b8af5238e8b422a8918..4bb0b9cffb850ede1b7f761ff965f5244753535c 100644 GIT binary patch delta 766 zcmcc2wTo?nBnLAC1B1(wu45Aw73%i}_=LDFSvqISrZwHYbAS?U9ql#s4aMcfS-HjO zS?R6q9qpYRwGEA36DD-`_H=f4O`9>jx4*BauXp;)8Tm!!&21eWU7gcr&sw%(c~?)* zoOyF6O`g1P@uITIy85Q(mbUhu{{Ff1=S`k6xvRHl%CxDyeSH(APU)M_KXv-F=C=Cw zy2hr-GiNSYI=8gAu&Sc0ATOt-y`{dXzP`44-ogbL*%>ou&#J1a>geofZfUNoudA%8 zEGaGN>gmqS&WwtU0=jsW&Y>zGWnU8H7yO?@AdIS>p--(we4?FrJ>zaq7sn6_|Jp#_ z^4SJFTPlTCB-}caeeKi6b#pIoz3p)=WzAi$!-@0FJojGro6mp4du@9`v}k$h ziUb>WBj$izTgo_74u(B_zR*cYrsDs$Bdc`>~&j(JPjdy;vXr^#(TzJ3nNhqcQD{-ypmO<{ETQ@{Gf z6sf1>_D#q56(+3In=uOWUs-y4Sl6jEeea+@*!s+PQtZ#Bp&RQyQv&!^819w1%$TF>` Rr-12#!PC{xWt~$(6951Sk8c0~ delta 1327 zcmV+~1m9nlFEsl1jq09+va?8J4A6!n3xx#O z*rWT&p?fG04$;bTgymL+0C;}GOMk(DF(z}lToeumDHQZGHJa_ATFf!0Di5 zKbfKQQIeGe11lqAK;=Sl?1ZxRjn}ux>2y-1Ql(z6$GmVLr1nr=QA&Nf&VRf<;xPdZ zfhZ8b?U5Q@vCr8{tFcL<@ zqXu1wt+E`zTEOG=@@SP+DivyVyX4l*@D1z^9<3Oap`0Gd5PK*G#O0UQSDE+tiJ2Ex z6pPBpa#_{*xXj^jkW912wm3Ork5fxC5`d@c4%K*?L(U0|P?+rf4lTu(sgN;^ zn-y#Tl;REm61z#R1S?<&_?pd5o2nXM3?O&G#aN8iHa7V^w-IFCtY8D+W|S8;K)Ffj z0pP(v@BuU_F)(PD-SWSqBh~3@w7GGG=Qi6+;b)BcfGD)a9Dh702Tz(243c*TiWV0a znf!h~Hy&OSSYr7sU<2S%#J1lv`!?nvO`W9QYElo~%xR~{f{%I~^3?c#V2&TbakKmM=clBS6?xjTPM5fXdqqPX0ceDu3x`O*RHHk zsaoW_0H+6V<9~tX!Q5q-OgtMaLsSl24=+TbQSN^8VD2(RmZQ`jJowe*E6?E6nWIBa z#C~f|58!8>GQ_t+bajokx8E5`&7R-WoOHOq$30;lyi^%xl6(A&M9k(YRLZ8QRV`8C zAT@U*vfcdn=3wp8Wu8bVtbprbAY}L~_qqBMjxN#h;eP>r^X;A43;sD^18{TI$_47E zZ#q;0lmaM000}0e(9-e>eSZ5k8}Q}V-@o*QX2TzbSH-PQZm}1|OY-MM{?rI2=Wkxy zJn4k53JKryDrs^qI5z{%s-$U^1)Q4!XI0YV90mjDW&j`xtO*C6C