diff --git a/src/main/java/com/simibubi/create/AllSpecialTextures.java b/src/main/java/com/simibubi/create/AllSpecialTextures.java index 6cccf5b714..27f11391a4 100644 --- a/src/main/java/com/simibubi/create/AllSpecialTextures.java +++ b/src/main/java/com/simibubi/create/AllSpecialTextures.java @@ -11,6 +11,7 @@ public enum AllSpecialTextures { BLANK("blank.png"), CHECKERED("checkerboard.png"), THIN_CHECKERED("thin_checkerboard.png"), + CUTOUT_CHECKERED("cutout_checkerboard.png"), HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"), SELECTION("selection.png"), diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 0225deada1..cce060912b 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -43,6 +43,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity; import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity; +import com.simibubi.create.content.contraptions.fluids.FluidPipeTileEntity; import com.simibubi.create.content.contraptions.fluids.FluidTankRenderer; import com.simibubi.create.content.contraptions.fluids.FluidTankTileEntity; import com.simibubi.create.content.contraptions.fluids.PumpRenderer; @@ -57,7 +58,11 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Sequen import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity; -import com.simibubi.create.content.contraptions.relays.encased.*; +import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftRenderer; +import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftTileEntity; +import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer; import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer; import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity; import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity; @@ -86,7 +91,12 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity; import com.simibubi.create.content.logistics.block.packager.PackagerRenderer; import com.simibubi.create.content.logistics.block.packager.PackagerTileEntity; -import com.simibubi.create.content.logistics.block.redstone.*; +import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer; +import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer; +import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity; +import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity; +import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity; import com.simibubi.create.content.logistics.block.transposer.LinkedTransposerTileEntity; import com.simibubi.create.content.logistics.block.transposer.TransposerTileEntity; import com.simibubi.create.content.schematics.block.SchematicTableTileEntity; @@ -95,6 +105,7 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity; import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer; import com.tterrag.registrate.util.entry.TileEntityEntry; import com.tterrag.registrate.util.nullness.NonNullFunction; + import net.minecraft.tileentity.TileEntityType; public class AllTileEntities { @@ -191,6 +202,11 @@ public class AllTileEntities { .renderer(() -> PumpRenderer::new) .register(); + public static final TileEntityEntry FLUID_PIPE = Create.registrate() + .tileEntity("fluid_pipe", (NonNullFunction, ? extends FluidPipeTileEntity>) FluidPipeTileEntity::new) + .validBlocks(AllBlocks.FLUID_PIPE) + .register(); + public static final TileEntityEntry FLUID_TANK = Create.registrate() .tileEntity("fluid_tank", (NonNullFunction, ? extends FluidTankTileEntity>) FluidTankTileEntity::new) .validBlocks(AllBlocks.FLUID_TANK) diff --git a/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java b/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java index aa087c7c77..47b109c2f1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java +++ b/src/main/java/com/simibubi/create/content/contraptions/KineticDebugger.java @@ -43,7 +43,7 @@ public class KineticDebugger { VoxelShape shape = world.getBlockState(toOutline) .getRenderShape(world, toOutline); - if (te.getTheoreticalSpeed() != 0) + if (te.getTheoreticalSpeed() != 0 && !shape.isEmpty()) CreateClient.outliner.chaseAABB("kineticSource", shape.getBoundingBox() .offset(toOutline)) .lineWidth(1 / 16f) diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java index 0239271202..e376fe4887 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/KineticTileEntity.java @@ -178,7 +178,7 @@ public abstract class KineticTileEntity extends SmartTileEntity } @Override - public CompoundNBT write(CompoundNBT compound) { + protected void write(CompoundNBT compound, boolean clientPacket) { compound.putFloat("Speed", speed); if (needsSpeedUpdate()) @@ -202,7 +202,7 @@ public abstract class KineticTileEntity extends SmartTileEntity compound.put("Network", networkTag); } - return super.write(compound); + super.write(compound, clientPacket); } public boolean needsSpeedUpdate() { @@ -210,12 +210,13 @@ public abstract class KineticTileEntity extends SmartTileEntity } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { + boolean overStressedBefore = overStressed; clearKineticInformation(); // DO NOT READ kinetic information when placed after movement if (wasMoved) { - super.read(compound); + super.read(compound, clientPacket); return; } @@ -235,14 +236,9 @@ public abstract class KineticTileEntity extends SmartTileEntity overStressed = capacity < stress && StressImpact.isEnabled(); } - super.read(compound); - } + super.read(compound, clientPacket); - @Override - public void readClientUpdate(CompoundNBT tag) { - boolean overStressedBefore = overStressed; - super.readClientUpdate(tag); - if (overStressedBefore != overStressed && speed != 0) + if (clientPacket && overStressedBefore != overStressed && speed != 0) effects.triggerOverStressedEffect(); } @@ -450,7 +446,7 @@ public abstract class KineticTileEntity extends SmartTileEntity public int getFlickerScore() { return flickerTally; } - + public static float convertToDirection(float axisSpeed, Direction d) { return d.getAxisDirection() == AxisDirection.POSITIVE ? axisSpeed : -axisSpeed; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java index 5ac4e1b759..d6152bc98c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingKineticTileEntity.java @@ -58,21 +58,21 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("Progress", destroyProgress); compound.putInt("NextTick", ticksUntilNextProgress); if (breakingPos != null) compound.put("Breaking", NBTUtil.writeBlockPos(breakingPos)); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { destroyProgress = compound.getInt("Progress"); ticksUntilNextProgress = compound.getInt("NextTick"); if (compound.contains("Breaking")) breakingPos = NBTUtil.readBlockPos(compound.getCompound("Breaking")); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java index 686fbc86fe..31a5ffad32 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PloughBlock.java @@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.actors; import java.util.UUID; import com.mojang.authlib.GameProfile; -import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java index e67a32739e..49d35a7c49 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/clock/CuckooClockTileEntity.java @@ -39,23 +39,23 @@ public class CuckooClockTileEntity extends KineticTileEntity { super(type); animationType = Animation.NONE; } - + @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - if (sendAnimationUpdate) - NBTHelper.writeEnum(compound, "Animation", animationType); - sendAnimationUpdate = false; - return super.writeToClient(compound); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - if (tag.contains("Animation")) { - animationType = NBTHelper.readEnum(tag, "Animation", Animation.class); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket && compound.contains("Animation")) { + animationType = NBTHelper.readEnum(compound, "Animation", Animation.class); animationProgress.lastValue = 0; animationProgress.value = 0; } - super.readClientUpdate(tag); + } + + @Override + public void write(CompoundNBT compound, boolean clientPacket) { + if (clientPacket && sendAnimationUpdate) + NBTHelper.writeEnum(compound, "Animation", animationType); + sendAnimationUpdate = false; + super.write(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java index 8bace4b110..2ec5599702 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crafter/MechanicalCrafterTileEntity.java @@ -123,7 +123,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.put("Inventory", inventory.serializeNBT()); CompoundNBT inputNBT = new CompoundNBT(); @@ -138,43 +138,19 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { compound.putInt("CountDown", countDown); compound.putBoolean("Cover", covered); - return super.write(compound); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT tag) { - if (reRender) { - tag.putBoolean("Redraw", true); + super.write(compound, clientPacket); + + if (clientPacket && reRender) { + compound.putBoolean("Redraw", true); reRender = false; } - return super.writeToClient(tag); } @Override - public void readClientUpdate(CompoundNBT tag) { - if (tag.contains("Redraw")) - world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16); - + protected void read(CompoundNBT compound, boolean clientPacket) { Phase phaseBefore = phase; GroupedItems before = this.groupedItems; - - super.readClientUpdate(tag); - - if (phaseBefore != phase && phase == Phase.CRAFTING) - groupedItemsBeforeCraft = before; - if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) { - Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING); - Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75) - .add(VecHelper.getCenterOf(pos)); - Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState()); - vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1)); - world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0); - } - - } - - @Override - public void read(CompoundNBT compound) { + inventory.deserializeNBT(compound.getCompound("Inventory")); input.read(compound.getCompound("ConnectedInput")); groupedItems = GroupedItems.read(compound.getCompound("GroupedItems")); @@ -186,7 +162,22 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { this.phase = phase; countDown = compound.getInt("CountDown"); covered = compound.getBoolean("Cover"); - super.read(compound); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (compound.contains("Redraw")) + world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16); + if (phaseBefore != phase && phase == Phase.CRAFTING) + groupedItemsBeforeCraft = before; + if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) { + Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING); + Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75) + .add(VecHelper.getCenterOf(pos)); + Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState()); + vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1)); + world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0); + } } @Override @@ -293,7 +284,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { Vec3d vec = facingVec.scale(.65) .add(VecHelper.getCenterOf(pos)); Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) - .mul(VecHelper.planeByNormal(facingVec)) + .mul(VecHelper.axisAlingedPlaneOf(facingVec)) .normalize() .scale(progress * .5f) .add(vec); @@ -307,7 +298,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { for (int i = 0; i < 10; i++) { Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) - .mul(VecHelper.planeByNormal(facingVec)) + .mul(VecHelper.axisAlingedPlaneOf(facingVec)) .normalize() .scale(.25f); Vec3d offset2 = randVec.add(vec); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java index c1af6a112a..492cc9dcf7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crank/HandCrankTileEntity.java @@ -38,15 +38,15 @@ public class HandCrankTileEntity extends GeneratingKineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("InUse", inUse); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { inUse = compound.getInt("InUse"); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java index 3f5eeec54b..b4aa3ffb7d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/crusher/CrushingWheelControllerTileEntity.java @@ -215,19 +215,17 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { if (hasEntity()) compound.put("Entity", NBTUtil.writeUniqueId(entityUUID)); compound.put("Inventory", inventory.serializeNBT()); compound.putFloat("Speed", crushingspeed); - - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { - super.read(compound); - + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); if (compound.contains("Entity") && !isFrozen() && !isOccupied()) { entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity")); this.searchForEntity = true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java index 825b15adda..c286ed1cc7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerTileEntity.java @@ -51,11 +51,10 @@ import net.minecraftforge.items.ItemHandlerHelper; public class DeployerTileEntity extends KineticTileEntity { - private static final List> EXTRACTING_LOCATIONS = Arrays - .asList(Direction.values()) - .stream() - .map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite())) - .collect(Collectors.toList()); + private static final List> EXTRACTING_LOCATIONS = Arrays.asList(Direction.values()) + .stream() + .map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite())) + .collect(Collectors.toList()); private FilteringBehaviour filtering; private ExtractingBehaviour extracting; @@ -167,7 +166,8 @@ public class DeployerTileEntity extends KineticTileEntity { return; } - if (filtering.getFilter().isEmpty() && stack.isEmpty()) + if (filtering.getFilter() + .isEmpty() && stack.isEmpty()) extracting.extract(1); Direction facing = getBlockState().get(FACING); @@ -182,12 +182,16 @@ public class DeployerTileEntity extends KineticTileEntity { state = State.EXPANDING; Vec3d movementVector = getMovementVector(); - Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f)); - Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f)); + Vec3d rayOrigin = VecHelper.getCenterOf(pos) + .add(movementVector.scale(3 / 2f)); + Vec3d rayTarget = VecHelper.getCenterOf(pos) + .add(movementVector.scale(5 / 2f)); RayTraceContext rayTraceContext = new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player); BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext); - reach = (float) (.5f + Math.min(result.getHitVec().subtract(rayOrigin).length(), .75f)); + reach = (float) (.5f + Math.min(result.getHitVec() + .subtract(rayOrigin) + .length(), .75f)); timer = 1000; sendData(); @@ -226,7 +230,9 @@ public class DeployerTileEntity extends KineticTileEntity { if (!(otherTile instanceof DeployerTileEntity)) return false; DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile; - if (world.getBlockState(otherDeployer).get(FACING).getOpposite() != facing || deployerTile.mode != Mode.PUNCH) + if (world.getBlockState(otherDeployer) + .get(FACING) + .getOpposite() != facing || deployerTile.mode != Mode.PUNCH) return false; boop = true; @@ -295,13 +301,15 @@ public class DeployerTileEntity extends KineticTileEntity { } protected void tryDisposeOfItems() { - boolean noInv = extracting.getInventories().isEmpty(); + boolean noInv = extracting.getInventories() + .isEmpty(); for (Iterator iterator = overflowItems.iterator(); iterator.hasNext();) { ItemStack itemStack = iterator.next(); if (noInv) { Vec3d offset = getMovementVector(); - Vec3d outPos = VecHelper.getCenterOf(pos).add(offset.scale(-.65f)); + Vec3d outPos = VecHelper.getCenterOf(pos) + .add(offset.scale(-.65f)); Vec3d motion = offset.scale(-.25f); ItemEntity e = new ItemEntity(world, outPos.x, outPos.y, outPos.z, itemStack.copy()); e.setMotion(motion); @@ -328,11 +336,12 @@ public class DeployerTileEntity extends KineticTileEntity { protected Vec3d getMovementVector() { if (!AllBlocks.DEPLOYER.has(getBlockState())) return Vec3d.ZERO; - return new Vec3d(getBlockState().get(FACING).getDirectionVec()); + return new Vec3d(getBlockState().get(FACING) + .getDirectionVec()); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { state = NBTHelper.readEnum(compound, "State", State.class); mode = NBTHelper.readEnum(compound, "Mode", Mode.class); timer = compound.getInt("Timer"); @@ -340,48 +349,45 @@ public class DeployerTileEntity extends KineticTileEntity { overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND)); if (compound.contains("HeldItem")) heldItem = ItemStack.read(compound.getCompound("HeldItem")); - super.read(compound); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + reach = compound.getFloat("Reach"); + if (compound.contains("Particle")) { + ItemStack particleStack = ItemStack.read(compound.getCompound("Particle")); + SandPaperItem.spawnParticles(VecHelper.getCenterOf(pos) + .add(getMovementVector().scale(2f)), particleStack, this.world); + } } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { NBTHelper.writeEnum(compound, "Mode", mode); NBTHelper.writeEnum(compound, "State", state); compound.putInt("Timer", timer); if (player != null) { - compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT()); + compound.put("HeldItem", player.getHeldItemMainhand() + .serializeNBT()); ListNBT invNBT = new ListNBT(); player.inventory.write(invNBT); compound.put("Inventory", invNBT); compound.put("Overflow", NBTHelper.writeItemList(overflowItems)); } - return super.write(compound); - } + + super.write(compound, clientPacket); - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { + if (!clientPacket) + return; compound.putFloat("Reach", reach); - if (player != null) { - compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT()); - if (player.spawnedItemEffects != null) { - compound.put("Particle", player.spawnedItemEffects.serializeNBT()); - player.spawnedItemEffects = null; - } + if (player == null) + return; + compound.put("HeldItem", player.getHeldItemMainhand() + .serializeNBT()); + if (player.spawnedItemEffects != null) { + compound.put("Particle", player.spawnedItemEffects.serializeNBT()); + player.spawnedItemEffects = null; } - return super.writeToClient(compound); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - reach = tag.getFloat("Reach"); - if (tag.contains("Particle")) { - ItemStack particleStack = ItemStack.read(tag.getCompound("Particle")); - SandPaperItem - .spawnParticles(VecHelper.getCenterOf(pos).add(getMovementVector().scale(2f)), particleStack, - this.world); - } - - super.readClientUpdate(tag); } private IItemHandlerModifiable createHandler() { @@ -395,7 +401,7 @@ public class DeployerTileEntity extends KineticTileEntity { public AllBlockPartials getHandPose() { return mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING - : heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING; + : heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java index b0e415670f..124409bb74 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/AirCurrent.java @@ -165,7 +165,7 @@ public class AirCurrent { .get(BlockStateProperties.FACING); pushing = source.getAirFlowDirection() == direction; Vec3d directionVec = new Vec3d(direction.getDirectionVec()); - Vec3d planeVec = VecHelper.planeByNormal(directionVec); + Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec); // 4 Rays test for holes in the shapes blocking the flow float offsetDistance = .25f; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java index a504543736..6a881f464b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/EncasedFanTileEntity.java @@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlo import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.CKinetics; + import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; @@ -30,21 +31,17 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity { } @Override - public void readClientUpdate(CompoundNBT tag) { - super.readClientUpdate(tag); - airCurrent.rebuild(); - } - - @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); isGenerator = compound.getBoolean("Generating"); + if (clientPacket) + airCurrent.rebuild(); } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Generating", isGenerator); - return super.write(compound); + super.write(compound, clientPacket); } @Override @@ -77,10 +74,12 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity { return false; BlockState checkState = world.getBlockState(pos.down()); - if (!checkState.getBlock().isIn(AllBlockTags.FAN_HEATERS.tag)) + if (!checkState.getBlock() + .isIn(AllBlockTags.FAN_HEATERS.tag)) return false; - if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) + if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL) + .isAtLeast(BlazeBurnerBlock.HeatLevel.FADING)) return false; if (checkState.has(BlockStateProperties.LIT) && !checkState.get(BlockStateProperties.LIT)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java index 81ce41fb2b..9275405953 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/fan/NozzleTileEntity.java @@ -38,26 +38,30 @@ public class NozzleTileEntity extends SmartTileEntity { } @Override - public void addBehaviours(List behaviours) { - } + public void addBehaviours(List behaviours) {} @Override - public CompoundNBT writeToClient(CompoundNBT compound) { + protected void write(CompoundNBT compound, boolean clientPacket) { + super.write(compound, clientPacket); + if (!clientPacket) + return; compound.putFloat("Range", range); compound.putBoolean("Pushing", pushing); - return super.writeToClient(compound); } - + @Override - public void readClientUpdate(CompoundNBT tag) { - range = tag.getFloat("Range"); - pushing = tag.getBoolean("Pushing"); - super.readClientUpdate(tag); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (!clientPacket) + return; + range = compound.getFloat("Range"); + pushing = compound.getBoolean("Pushing"); } @Override public void initialize() { - fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING).getOpposite()); + fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING) + .getOpposite()); super.initialize(); } @@ -72,24 +76,26 @@ public class NozzleTileEntity extends SmartTileEntity { Vec3d center = VecHelper.getCenterOf(pos); if (world.isRemote && range != 0) { if (world.rand.nextInt( - MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) { + MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) { Vec3d start = VecHelper.offsetRandomly(center, world.rand, pushing ? 1 : range / 2); - Vec3d motion = center.subtract(start).normalize() - .scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1)); + Vec3d motion = center.subtract(start) + .normalize() + .scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1)); world.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z); } } for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { Entity entity = iterator.next(); - Vec3d diff = entity.getPositionVec().subtract(center); + Vec3d diff = entity.getPositionVec() + .subtract(center); if (!(entity instanceof PlayerEntity) && world.isRemote) continue; double distance = diff.length(); if (distance > range || entity.isSneaking() - || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { + || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { iterator.remove(); continue; } @@ -98,8 +104,10 @@ public class NozzleTileEntity extends SmartTileEntity { continue; float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f; - Vec3d pushVec = diff.normalize().scale((range - distance) * (pushing ? 1 : -1)); - entity.setMotion(entity.getMotion().add(pushVec.scale(factor))); + Vec3d pushVec = diff.normalize() + .scale((range - distance) * (pushing ? 1 : -1)); + entity.setMotion(entity.getMotion() + .add(pushVec.scale(factor))); entity.fallDistance = 0; entity.velocityChanged = true; } @@ -125,7 +133,8 @@ public class NozzleTileEntity extends SmartTileEntity { return 0; if (fan.getSpeed() == 0) return 0; - pushing = fan.getAirFlowDirection() == fan.getBlockState().get(EncasedFanBlock.FACING); + pushing = fan.getAirFlowDirection() == fan.getBlockState() + .get(EncasedFanBlock.FACING); return fan.getMaxDistance(); } @@ -140,11 +149,12 @@ public class NozzleTileEntity extends SmartTileEntity { AxisAlignedBB bb = new AxisAlignedBB(center, center).grow(range / 2f); for (Entity entity : world.getEntitiesWithinAABB(Entity.class, bb)) { - Vec3d diff = entity.getPositionVec().subtract(center); + Vec3d diff = entity.getPositionVec() + .subtract(center); double distance = diff.length(); if (distance > range || entity.isSneaking() - || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { + || (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) { continue; } @@ -164,7 +174,7 @@ public class NozzleTileEntity extends SmartTileEntity { continue; iterator.remove(); } - + if (!pushing && pushingEntities.size() > 256 && !world.isRemote) { world.createExplosion(null, center.x, center.y, center.z, 2, Mode.NONE); for (Iterator iterator = pushingEntities.iterator(); iterator.hasNext();) { @@ -178,8 +188,9 @@ public class NozzleTileEntity extends SmartTileEntity { private boolean canSee(Entity entity) { RayTraceContext context = new RayTraceContext(entity.getPositionVec(), VecHelper.getCenterOf(pos), - BlockMode.COLLIDER, FluidMode.NONE, entity); - return pos.equals(world.rayTraceBlocks(context).getPos()); + BlockMode.COLLIDER, FluidMode.NONE, entity); + return pos.equals(world.rayTraceBlocks(context) + .getPos()); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java index c55e0ed0fb..6c91f6d7e2 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/flywheel/FlywheelTileEntity.java @@ -53,30 +53,21 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity { } @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - return super.writeToClient(compound); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - super.readClientUpdate(tag); - visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed()); - } - - @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putFloat("GeneratedSpeed", generatedSpeed); compound.putFloat("GeneratedCapacity", generatedCapacity); compound.putInt("Cooldown", stoppingCooldown); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { generatedSpeed = compound.getFloat("GeneratedSpeed"); generatedCapacity = compound.getFloat("GeneratedCapacity"); stoppingCooldown = compound.getInt("Cooldown"); - super.read(compound); + super.read(compound, clientPacket); + if (clientPacket) + visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed()); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java index 434c6883c6..8e3bab94b0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/millstone/MillstoneTileEntity.java @@ -116,19 +116,19 @@ public class MillstoneTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("Timer", timer); compound.put("InputInventory", inputInv.serializeNBT()); compound.put("OutputInventory", outputInv.serializeNBT()); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { timer = compound.getInt("Timer"); inputInv.deserializeNBT(compound.getCompound("InputInventory")); outputInv.deserializeNBT(compound.getCompound("OutputInventory")); - super.read(compound); + super.read(compound, clientPacket); } public int getProcessingSpeed() { 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 a0086e9f5e..4095972728 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 @@ -109,17 +109,17 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { running = compound.getBoolean("Running"); runningTicks = compound.getInt("Ticks"); - super.read(compound); + super.read(compound, clientPacket); } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Running", running); compound.putInt("Ticks", runningTicks); - return super.write(compound); + super.write(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index 94ffcfdd28..9091d4935a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -15,6 +15,7 @@ import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour; +import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.entity.Entity; @@ -25,7 +26,6 @@ import net.minecraft.item.crafting.ICraftingRecipe; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; import net.minecraft.particles.ItemParticleData; import net.minecraft.particles.ParticleTypes; import net.minecraft.tileentity.TileEntityType; @@ -85,37 +85,30 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { running = compound.getBoolean("Running"); mode = Mode.values()[compound.getInt("Mode")]; finished = compound.getBoolean("Finished"); runningTicks = compound.getInt("Ticks"); - super.read(compound); + super.read(compound, clientPacket); + + if (clientPacket) { + NBTHelper.iterateCompoundList(compound.getList("ParticleItems", NBT.TAG_COMPOUND), + c -> pressedItems.add(ItemStack.read(c))); + spawnParticles(); + } } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Running", running); compound.putInt("Mode", mode.ordinal()); compound.putBoolean("Finished", finished); compound.putInt("Ticks", runningTicks); - return super.write(compound); - } + super.write(compound, clientPacket); - @Override - public CompoundNBT writeToClient(CompoundNBT tag) { - ListNBT particleItems = new ListNBT(); - pressedItems.forEach(stack -> particleItems.add(stack.serializeNBT())); - tag.put("ParticleItems", particleItems); - return super.writeToClient(tag); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - super.readClientUpdate(tag); - ListNBT particleItems = tag.getList("ParticleItems", NBT.TAG_COMPOUND); - particleItems.forEach(nbt -> pressedItems.add(ItemStack.read((CompoundNBT) nbt))); - spawnParticles(); + if (clientPacket) + compound.put("ParticleItems", NBTHelper.writeCompoundList(pressedItems, ItemStack::serializeNBT)); } @Override @@ -301,7 +294,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { CombinedItemFluidList remaining = new CombinedItemFluidList(); inputs.forEachItemStack(stack -> remaining.add(stack.copy())); - basinFluidInv.ifPresent(fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy()))); + basinFluidInv.ifPresent( + fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy()))); Ingredients: for (Ingredient ingredient : ingredients) { for (ItemStack stack : remaining.getItemStacks()) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java index e127b162b2..660a744a23 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/saw/SawTileEntity.java @@ -94,15 +94,15 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.put("Inventory", inventory.serializeNBT()); compound.putInt("RecipeIndex", recipeIndex); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); inventory.deserializeNBT(compound.getCompound("Inventory")); recipeIndex = compound.getInt("RecipeIndex"); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 236c6d5c32..737806082a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -797,7 +797,7 @@ public abstract class Contraption { Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis) .getDirectionVec()); - Vec3d planeByNormal = VecHelper.planeByNormal(vec); + Vec3d planeByNormal = VecHelper.axisAlingedPlaneOf(vec); Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ) .add(planeByNormal.scale(-maxDiff)); Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java index f0d47fc0ff..05ab6b777a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java @@ -476,7 +476,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD BearingContraption bc = (BearingContraption) getContraption(); Direction facing = bc.getFacing(); Vec3d activeAreaOffset = actor.getActiveAreaOffset(context); - if (activeAreaOffset.mul(VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec()))) + if (activeAreaOffset.mul(VecHelper.axisAlingedPlaneOf(new Vec3d(facing.getDirectionVec()))) .equals(Vec3d.ZERO)) { if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) { context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis() diff --git a/src/main/java/ContraptionInteractionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java similarity index 94% rename from src/main/java/ContraptionInteractionHandler.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java index 2ad46f8671..36ada9e88f 100644 --- a/src/main/java/ContraptionInteractionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionHandler.java @@ -1,7 +1,6 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; import org.apache.commons.lang3.mutable.MutableObject; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.RaycastHelper; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java index d137d9c31c..f610c284c9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java @@ -227,26 +227,26 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } @Override - public CompoundNBT write(CompoundNBT tag) { - tag.putBoolean("Running", running); - tag.putFloat("HourAngle", hourAngle); - tag.putFloat("MinuteAngle", minuteAngle); - return super.write(tag); + public void write(CompoundNBT compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putFloat("HourAngle", hourAngle); + compound.putFloat("MinuteAngle", minuteAngle); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT tag) { - running = tag.getBoolean("Running"); - hourAngle = tag.getFloat("HourAngle"); - minuteAngle = tag.getFloat("MinuteAngle"); - super.read(tag); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { + protected void read(CompoundNBT compound, boolean clientPacket) { float hourAngleBefore = hourAngle; float minuteAngleBefore = minuteAngle; - super.readClientUpdate(tag); + + running = compound.getBoolean("Running"); + hourAngle = compound.getFloat("HourAngle"); + minuteAngle = compound.getFloat("MinuteAngle"); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (running) { clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle); clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index 9a013ba7dc..1f37137013 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -102,27 +102,25 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp } @Override - public CompoundNBT write(CompoundNBT tag) { - tag.putBoolean("Running", running); - tag.putBoolean("Windmill", isWindmill); - tag.putFloat("Angle", angle); - tag.putFloat("LastGenerated", lastGeneratedSpeed); - return super.write(tag); + public void write(CompoundNBT compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putBoolean("Windmill", isWindmill); + compound.putFloat("Angle", angle); + compound.putFloat("LastGenerated", lastGeneratedSpeed); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT tag) { - running = tag.getBoolean("Running"); - isWindmill = tag.getBoolean("Windmill"); - angle = tag.getFloat("Angle"); - lastGeneratedSpeed = tag.getFloat("LastGenerated"); - super.read(tag); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { + protected void read(CompoundNBT compound, boolean clientPacket) { float angleBefore = angle; - super.readClientUpdate(tag); + running = compound.getBoolean("Running"); + isWindmill = compound.getBoolean("Windmill"); + angle = compound.getFloat("Angle"); + lastGeneratedSpeed = compound.getFloat("LastGenerated"); + super.read(compound, clientPacket); + + if (!clientPacket) + return; if (running) { clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle); angle = angleBefore; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java index 515aa88679..c86c4a61e5 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueItem.java @@ -81,7 +81,7 @@ public class SuperGlueItem extends Item { @OnlyIn(Dist.CLIENT) public static void spawnParticles(World world, BlockPos pos, Direction direction, boolean fullBlock) { Vec3d vec = new Vec3d(direction.getDirectionVec()); - Vec3d plane = VecHelper.planeByNormal(vec); + Vec3d plane = VecHelper.axisAlingedPlaneOf(vec); Vec3d facePos = VecHelper.getCenterOf(pos) .add(vec.scale(.5f)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java index 097daf4196..4d8a1f381d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueRenderer.java @@ -6,6 +6,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllItems; import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.Minecraft; @@ -63,7 +64,9 @@ public class SuperGlueRenderer extends EntityRenderer { Direction face = entity.getFacingDirection(); ms.push(); - AngleHelper.applyRotation(face, ms); + MatrixStacker.of(ms) + .rotateY(AngleHelper.horizontalAngle(face)) + .rotateX(AngleHelper.verticalAngle(face)); Entry peek = ms.peek(); Vec3d[][] quads = { quad1, quad2 }; @@ -87,7 +90,7 @@ public class SuperGlueRenderer extends EntityRenderer { Vec3d diff = new Vec3d(Direction.SOUTH.getDirectionVec()); Vec3d extension = diff.normalize() .scale(1 / 32f - 1 / 128f); - Vec3d plane = VecHelper.planeByNormal(diff); + Vec3d plane = VecHelper.axisAlingedPlaneOf(diff); Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z) .getAxis(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java index b9c4ea478f..c7148ec541 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java @@ -145,50 +145,38 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme } @Override - public CompoundNBT write(CompoundNBT tag) { - tag.putBoolean("Running", running); - tag.putBoolean("Waiting", waitingForSpeedChange); - tag.putFloat("Offset", offset); - return super.write(tag); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - if (forceMove) { + protected void write(CompoundNBT compound, boolean clientPacket) { + compound.putBoolean("Running", running); + compound.putBoolean("Waiting", waitingForSpeedChange); + compound.putFloat("Offset", offset); + super.write(compound, clientPacket); + + if (clientPacket && forceMove) { compound.putBoolean("ForceMovement", forceMove); forceMove = false; } - return super.writeToClient(compound); } @Override - public void read(CompoundNBT tag) { - running = tag.getBoolean("Running"); - waitingForSpeedChange = tag.getBoolean("Waiting"); - offset = tag.getFloat("Offset"); - super.read(tag); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - boolean forceMovement = tag.contains("ForceMovement"); + protected void read(CompoundNBT compound, boolean clientPacket) { + boolean forceMovement = compound.contains("ForceMovement"); float offsetBefore = offset; - super.readClientUpdate(tag); - if (forceMovement) { - if (movedContraption != null) { - applyContraptionPosition(); - } - } else { - if (running) { - clientOffsetDiff = offset - offsetBefore; - offset = offsetBefore; - } + running = compound.getBoolean("Running"); + waitingForSpeedChange = compound.getBoolean("Waiting"); + offset = compound.getFloat("Offset"); + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (forceMovement) + applyContraptionPosition(); + else if (running) { + clientOffsetDiff = offset - offsetBefore; + offset = offsetBefore; } - if (!running) movedContraption = null; - } public abstract void disassemble(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java index 7433a9407a..74720c6176 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java @@ -29,15 +29,15 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { } @Override - public void read(CompoundNBT tag) { - extensionLength = tag.getInt("ExtensionLength"); - super.read(tag); + protected void read(CompoundNBT compound, boolean clientPacket) { + extensionLength = compound.getInt("ExtensionLength"); + super.read(compound, clientPacket); } @Override - public CompoundNBT write(CompoundNBT tag) { + protected void write(CompoundNBT tag, boolean clientPacket) { tag.putInt("ExtensionLength", extensionLength); - return super.write(tag); + super.write(tag, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 122d7be6c0..04d0e1e81a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; + import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.IWaterLoggable; @@ -168,15 +169,15 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { } @Override - public void read(CompoundNBT tag) { - initialOffset = tag.getInt("InitialOffset"); - super.read(tag); + protected void read(CompoundNBT compound, boolean clientPacket) { + initialOffset = compound.getInt("InitialOffset"); + super.read(compound, clientPacket); } @Override - public CompoundNBT write(CompoundNBT tag) { - tag.putInt("InitialOffset", initialOffset); - return super.write(tag); + public void write(CompoundNBT compound, boolean clientPacket) { + compound.putInt("InitialOffset", initialOffset); + super.write(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java index 3232188eab..c7f39e7b9d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/waterwheel/WaterWheelTileEntity.java @@ -24,8 +24,8 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity { } @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); if (compound.contains("Flows")) { for (Direction d : Direction.values()) setFlow(d, compound.getCompound("Flows") @@ -39,13 +39,13 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { CompoundNBT flows = new CompoundNBT(); for (Direction d : Direction.values()) flows.putFloat(d.getName(), this.flows.get(d)); compound.put("Flows", flows); - return super.write(compound); + super.write(compound, clientPacket); } public void setFlow(Direction direction, float speed) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java index d7ae0d73b1..9b03c90d2f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java @@ -87,17 +87,20 @@ public class CombinedFluidHandler implements IFluidHandler { @Nonnull @Override public FluidStack drain(int maxDrain, FluidAction action) { - FluidStack stack = new FluidStack(tanks[0].getFluid(), 0); for (int i = 0; i < tanks.length; i++) { - if (tanks[i].isFluidEqual(stack)) { + if (stack.isEmpty() || tanks[i].isFluidEqual(stack)) { int newDrainAmount = MathHelper.clamp(stack.getAmount() + tanks[i].getAmount(), 0, maxDrain); if (action == FluidAction.EXECUTE) { tanks[i].shrink(newDrainAmount - stack.getAmount()); if (tanks[i].isEmpty()) tanks[i] = FluidStack.EMPTY; } + if (stack.isEmpty()) + stack = tanks[i].copy(); + if (stack.isEmpty()) + continue; stack.setAmount(newDrainAmount); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java new file mode 100644 index 0000000000..0e9492909e --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetwork.java @@ -0,0 +1,355 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableList; +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; + +public class FluidNetwork { + + BlockFace pumpLocation; + Map>> pipeGraph; + List flows; + Set targets; + Set rangeEndpoints; + Map previousFlow; + + boolean connectToPumps; + int waitForUnloadedNetwork; + + public FluidNetwork() { + pipeGraph = new HashMap<>(); + flows = new ArrayList<>(); + targets = new HashSet<>(); + rangeEndpoints = new HashSet<>(); + previousFlow = new HashMap<>(); + } + + public boolean hasEndpoints() { + for (FluidNetworkFlow pipeFlow : flows) + if (pipeFlow.hasValidTargets()) + return true; + return false; + } + + public Collection getEndpoints(boolean pulling) { + if (!pulling) { + for (FluidNetworkFlow pipeFlow : flows) + return pipeFlow.outputEndpoints; + return Collections.emptySet(); + } + + List list = new ArrayList<>(); + for (FluidNetworkFlow pipeFlow : flows) { + if (!pipeFlow.hasValidTargets()) + continue; + list.add(pipeFlow.source); + } + return list; + } + + public void tick(IWorld world, PumpTileEntity pumpTE) { + if (connectToPumps) { + connectToOtherFNs(world, pumpTE); + connectToPumps = false; + } + } + + public void tickFlows(IWorld world, PumpTileEntity pumpTE, boolean pulling, float speed) { + if (connectToPumps) + return; + initFlows(pumpTE, pulling); + previousFlow.clear(); + flows.forEach(ep -> ep.tick(world, speed)); + } + + private void initFlows(PumpTileEntity pumpTE, boolean pulling) { + if (targets.isEmpty()) + return; + if (!flows.isEmpty()) + return; + World world = pumpTE.getWorld(); + if (pulling) { + targets.forEach(ne -> flows.add(new FluidNetworkFlow(this, ne, world, pulling))); + } else { + PumpEndpoint pumpEndpoint = new PumpEndpoint(pumpLocation.getOpposite(), pumpTE); + flows.add(new FluidNetworkFlow(this, pumpEndpoint, world, pulling)); + } + } + + public void connectToOtherFNs(IWorld world, PumpTileEntity pump) { + List> frontier = new ArrayList<>(); + Set visited = new HashSet<>(); + int maxDistance = FluidPropagator.getPumpRange() * 2; + frontier.add(Pair.of(-1, pumpLocation.getPos())); + + while (!frontier.isEmpty()) { + Pair entry = frontier.remove(0); + int distance = entry.getFirst(); + BlockPos currentPos = entry.getSecond(); + + if (!world.isAreaLoaded(currentPos, 0)) + continue; + if (visited.contains(currentPos)) + continue; + visited.add(currentPos); + + List connections; + if (currentPos.equals(pumpLocation.getPos())) { + connections = ImmutableList.of(pumpLocation.getFace()); + } else { + BlockState currentState = world.getBlockState(currentPos); + FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos); + if (pipe == null) + continue; + connections = FluidPropagator.getPipeConnections(currentState, pipe); + } + + for (Direction face : connections) { + BlockFace blockFace = new BlockFace(currentPos, face); + BlockPos connectedPos = blockFace.getConnectedPos(); + BlockState connectedState = world.getBlockState(connectedPos); + + if (connectedPos.equals(pumpLocation.getPos())) + continue; + if (!world.isAreaLoaded(connectedPos, 0)) + continue; + if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING) + .getAxis() == face.getAxis()) { + TileEntity tileEntity = world.getTileEntity(connectedPos); + if (tileEntity instanceof PumpTileEntity) { + PumpTileEntity otherPump = (PumpTileEntity) tileEntity; + if (otherPump.networks == null) + continue; + + otherPump.networks.forEach(fn -> { + int nearest = Integer.MAX_VALUE; + BlockFace argNearest = null; + for (BlockFace pumpEndpoint : fn.rangeEndpoints) { + if (pumpEndpoint.isEquivalent(pumpLocation)) { + argNearest = pumpEndpoint; + break; + } + Pair> pair = + pipeGraph.get(pumpEndpoint.getConnectedPos()); + if (pair == null) + continue; + Integer distanceFromPump = pair.getFirst(); + Map pipeConnections = pair.getSecond(); + + if (!pipeConnections.containsKey(pumpEndpoint.getOppositeFace())) + continue; + if (nearest <= distanceFromPump) + continue; + nearest = distanceFromPump; + argNearest = pumpEndpoint; + + } + if (argNearest != null) { + InterPumpEndpoint endpoint = new InterPumpEndpoint(world, argNearest.getOpposite(), + pump, otherPump, pumpLocation, fn.pumpLocation); + targets.add(endpoint); + fn.targets.add(endpoint.opposite(world)); + } + }); + + } + continue; + } + if (visited.contains(connectedPos)) + continue; + if (distance > maxDistance) + continue; + FluidPipeBehaviour targetPipe = FluidPropagator.getPipe(world, connectedPos); + if (targetPipe == null) + continue; + if (targetPipe.isConnectedTo(connectedState, face.getOpposite())) + frontier.add(Pair.of(distance + 1, connectedPos)); + } + } + + } + + public void assemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) { + Map openEnds = pumpTE.getOpenEnds(pumpLocation.getFace()); + openEnds.values() + .forEach(OpenEndedPipe::markStale); + + this.pumpLocation = pumpLocation; + if (!collectEndpoint(world, pumpLocation, openEnds, 0)) { + + List> frontier = new ArrayList<>(); + Set visited = new HashSet<>(); + int maxDistance = FluidPropagator.getPumpRange(); + frontier.add(Pair.of(0, pumpLocation.getConnectedPos())); + + while (!frontier.isEmpty()) { + Pair entry = frontier.remove(0); + int distance = entry.getFirst(); + BlockPos currentPos = entry.getSecond(); + + if (!world.isAreaLoaded(currentPos, 0)) + continue; + if (visited.contains(currentPos)) + continue; + visited.add(currentPos); + BlockState currentState = world.getBlockState(currentPos); + FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos); + if (pipe == null) + continue; + + for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) { + BlockFace blockFace = new BlockFace(currentPos, face); + BlockPos connectedPos = blockFace.getConnectedPos(); + + if (connectedPos.equals(pumpLocation.getPos())) { + addEntry(blockFace.getPos(), blockFace.getFace(), true, distance); + continue; + } + if (!world.isAreaLoaded(connectedPos, 0)) + continue; + if (collectEndpoint(world, blockFace, openEnds, distance)) + continue; + if (FluidPropagator.getPipe(world, connectedPos) == null) + continue; + if (visited.contains(connectedPos)) + continue; + if (distance + 1 >= maxDistance) { + rangeEndpoints.add(blockFace); + addEntry(currentPos, face, false, distance); + FluidPropagator.showBlockFace(blockFace) + .lineWidth(1 / 8f) + .colored(0xff0000); + continue; + } + + addConnection(connectedPos, currentPos, face.getOpposite(), distance); + frontier.add(Pair.of(distance + 1, connectedPos)); + } + } + } + + Set staleEnds = new HashSet<>(); + openEnds.entrySet() + .forEach(e -> { + if (e.getValue() + .isStale()) + staleEnds.add(e.getKey()); + }); + staleEnds.forEach(openEnds::remove); + + connectToPumps = true; + } + + private FluidNetworkEndpoint reuseOrCreateOpenEnd(IWorld world, Map openEnds, + BlockFace toCreate) { + OpenEndedPipe openEndedPipe = null; + if (openEnds.containsKey(toCreate)) { + openEndedPipe = openEnds.get(toCreate); + openEndedPipe.unmarkStale(); + } else { + openEndedPipe = new OpenEndedPipe(toCreate); + openEnds.put(toCreate, openEndedPipe); + } + return new FluidNetworkEndpoint(world, toCreate, openEndedPipe.getCapability()); + + } + + private boolean collectEndpoint(IWorld world, BlockFace blockFace, Map openEnds, + int distance) { + BlockPos connectedPos = blockFace.getConnectedPos(); + BlockState connectedState = world.getBlockState(connectedPos); + + // other pipe, no endpoint + FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, connectedPos); + if (pipe != null && pipe.isConnectedTo(connectedState, blockFace.getOppositeFace())) + return false; + TileEntity tileEntity = world.getTileEntity(connectedPos); + + // fluid handler endpoint + Direction face = blockFace.getFace(); + if (tileEntity != null) { + LazyOptional capability = + tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite()); + if (capability.isPresent()) { + targets.add(new FluidNetworkEndpoint(world, blockFace, capability)); + addEntry(blockFace.getPos(), face, false, distance); + FluidPropagator.showBlockFace(blockFace) + .colored(0x00b7c2) + .lineWidth(1 / 8f); + return true; + } + } + + // open endpoint + if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING) + .getAxis() == face.getAxis()) { + rangeEndpoints.add(blockFace); + addEntry(blockFace.getPos(), face, false, distance); + return true; + } + if (!FluidPropagator.isOpenEnd(world, blockFace.getPos(), face)) + return false; + + targets.add(reuseOrCreateOpenEnd(world, openEnds, blockFace)); + addEntry(blockFace.getPos(), face, false, distance); + FluidPropagator.showBlockFace(blockFace) + .colored(0xb700c2) + .lineWidth(1 / 8f); + return true; + } + + private void addConnection(BlockPos from, BlockPos to, Direction direction, int distance) { + addEntry(from, direction, true, distance); + addEntry(to, direction.getOpposite(), false, distance + 1); + } + + private void addEntry(BlockPos pos, Direction direction, boolean outbound, int distance) { + if (!pipeGraph.containsKey(pos)) + pipeGraph.put(pos, Pair.of(distance, new HashMap<>())); + pipeGraph.get(pos) + .getSecond() + .put(direction, outbound); + } + + public void reAssemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) { + rangeEndpoints.clear(); + targets.clear(); + pipeGraph.clear(); + assemble(world, pumpTE, pumpLocation); + } + + public void remove(IWorld world) { + clearFlows(world, false); + } + + public void clearFlows(IWorld world, boolean saveState) { + for (FluidNetworkFlow networkFlow : flows) { + if (!networkFlow.getFluidStack() + .isEmpty()) + networkFlow.addToSkippedConnections(world); + networkFlow.resetFlow(world); + } + flows.clear(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkEndpoint.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkEndpoint.java new file mode 100644 index 0000000000..0dc2b25c29 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkEndpoint.java @@ -0,0 +1,168 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.lang.ref.WeakReference; + +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.Pair; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IWorld; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; + +class FluidNetworkEndpoint { + BlockFace location; + protected LazyOptional handler; + + public FluidNetworkEndpoint(IWorld world, BlockFace location, LazyOptional handler) { + this.location = location; + this.handler = handler; + this.handler.addListener($ -> onHandlerInvalidated(world)); + } + + protected void onHandlerInvalidated(IWorld world) { + IFluidHandler tank = handler.orElse(null); + if (tank != null) + return; + TileEntity tileEntity = world.getTileEntity(location.getConnectedPos()); + if (tileEntity == null) + return; + LazyOptional capability = + tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, location.getOppositeFace()); + if (capability.isPresent()) { + handler = capability; + handler.addListener($ -> onHandlerInvalidated(world)); + } + } + + public FluidStack provideFluid() { + IFluidHandler tank = provideHandler().orElse(null); + if (tank == null) + return FluidStack.EMPTY; + return tank.drain(1, FluidAction.SIMULATE); + } + + public LazyOptional provideHandler() { + return handler; + } + +} + +class PumpEndpoint extends FluidNetworkEndpoint { + + PumpTileEntity pumpTE; + + public PumpEndpoint(BlockFace location, PumpTileEntity pumpTE) { + super(pumpTE.getWorld(), location, LazyOptional.empty()); + this.pumpTE = pumpTE; + } + + @Override + protected void onHandlerInvalidated(IWorld world) {} + + @Override + public FluidStack provideFluid() { + return pumpTE.providedFluid; + } + +} + +class InterPumpEndpoint extends FluidNetworkEndpoint { + + Couple>> pumps; + + private InterPumpEndpoint(IWorld world, BlockFace location, LazyOptional handler) { + super(world, location, handler); + } + + public InterPumpEndpoint(IWorld world, BlockFace location, PumpTileEntity source, PumpTileEntity interfaced, + BlockFace sourcePos, BlockFace interfacedPos) { + this(world, location, LazyOptional.empty()); + handler = LazyOptional.of(() -> new InterPumpFluidHandler(this)); + pumps = Couple.create(Pair.of(sourcePos, new WeakReference<>(source)), + Pair.of(interfacedPos, new WeakReference<>(interfaced))); + } + + public InterPumpEndpoint opposite(IWorld world) { + InterPumpEndpoint interPumpEndpoint = new InterPumpEndpoint(world, this.location.getOpposite(), handler); + interPumpEndpoint.pumps = pumps.copy(); + return interPumpEndpoint; + } + + public Couple>> getPumps() { + return pumps; + } + + public boolean isPulling(boolean first) { + Pair> pair = getPumps().get(first); + PumpTileEntity pumpTileEntity = pair.getSecond() + .get(); + if (pumpTileEntity == null || pumpTileEntity.isRemoved()) + return false; + return pumpTileEntity.isPullingOnSide(pumpTileEntity.isFront(pair.getFirst() + .getFace())); + } + + public int getTransferSpeed(boolean first) { + PumpTileEntity pumpTileEntity = getPumps().get(first) + .getSecond() + .get(); + if (pumpTileEntity == null || pumpTileEntity.isRemoved()) + return 0; + return pumpTileEntity.getFluidTransferSpeed(); + } + + @Override + public LazyOptional provideHandler() { + if (isPulling(true) == isPulling(false)) + return LazyOptional.empty(); + if (getTransferSpeed(true) > getTransferSpeed(false)) + return LazyOptional.empty(); + return super.provideHandler(); + } + + @Override + public FluidStack provideFluid() { + if (!provideHandler().isPresent()) + return FluidStack.EMPTY; + + Couple>> pumps = getPumps(); + for (boolean current : Iterate.trueAndFalse) { + if (isPulling(current)) + continue; + + Pair> pair = pumps.get(current); + BlockFace blockFace = pair.getFirst(); + PumpTileEntity pumpTileEntity = pair.getSecond() + .get(); + if (pumpTileEntity == null) + continue; + if (pumpTileEntity.networks == null) + continue; + FluidNetwork fluidNetwork = pumpTileEntity.networks.get(pumpTileEntity.isFront(blockFace.getFace())); + for (FluidNetworkFlow fluidNetworkFlow : fluidNetwork.flows) { + for (FluidNetworkEndpoint fne : fluidNetworkFlow.outputEndpoints) { + if (!(fne instanceof InterPumpEndpoint)) + continue; + InterPumpEndpoint ipe = (InterPumpEndpoint) fne; + if (!ipe.location.isEquivalent(location)) + continue; + + FluidStack heldFluid = fluidNetworkFlow.fluidStack; + if (heldFluid.isEmpty()) + return heldFluid; + FluidStack copy = heldFluid.copy(); + copy.setAmount(1); + return heldFluid; + } + } + } + return FluidStack.EMPTY; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkFlow.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkFlow.java new file mode 100644 index 0000000000..93ba80f0c4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidNetworkFlow.java @@ -0,0 +1,304 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import net.minecraftforge.fluids.FluidStack; + +class FluidNetworkFlow { + + @FunctionalInterface + static interface PipeFlowConsumer { + void accept(FluidPipeBehaviour pipe, Direction face, boolean inbound); + } + + /** + * + */ + private final FluidNetwork activePipeNetwork; + FluidNetworkEndpoint source; + FluidStack fluidStack; + Set flowPointers; + + Set outputEndpoints; + boolean pumpReached; + + boolean pulling; + float speed; + + public FluidNetworkFlow(FluidNetwork activePipeNetwork, FluidNetworkEndpoint source, IWorld world, + boolean pulling) { + this.activePipeNetwork = activePipeNetwork; + this.source = source; + this.pulling = pulling; + flowPointers = new HashSet<>(); + outputEndpoints = new HashSet<>(); + fluidStack = FluidStack.EMPTY; + tick(world, 0); + } + + void resetFlow(IWorld world) { + fluidStack = FluidStack.EMPTY; + flowPointers.clear(); + outputEndpoints.clear(); + pumpReached = false; + forEachPipeFlow(world, (pipe, face, inbound) -> pipe.removeFlow(this, face, inbound)); + } + + void addToSkippedConnections(IWorld world) { + forEachPipeFlow(world, (pipe, face, inbound) -> { + if (!pipe.fluid.isFluidEqual(fluidStack)) + return; + BlockFace blockFace = new BlockFace(pipe.getPos(), face); + this.activePipeNetwork.previousFlow.put(blockFace, pipe.fluid); + }); + } + + void forEachPipeFlow(IWorld world, FluidNetworkFlow.PipeFlowConsumer consumer) { + Set flowPointers = new HashSet<>(); + flowPointers.add(getSource()); + + // Update all branches of this flow, and create new ones if necessary + while (!flowPointers.isEmpty()) { + List toAdd = new ArrayList<>(); + for (Iterator iterator = flowPointers.iterator(); iterator.hasNext();) { + BlockFace flowPointer = iterator.next(); + BlockPos currentPos = flowPointer.getPos(); + FluidPipeBehaviour pipe = getPipeInTree(world, currentPos); + if (pipe == null) { + iterator.remove(); + continue; + } + Map directions = this.activePipeNetwork.pipeGraph.get(currentPos) + .getSecond(); + for (Entry entry : directions.entrySet()) { + boolean inbound = entry.getValue() != pulling; + Direction face = entry.getKey(); + if (inbound && face != flowPointer.getFace()) + continue; + consumer.accept(pipe, face, inbound); + if (inbound) + continue; + toAdd.add(new BlockFace(currentPos.offset(face), face.getOpposite())); + } + iterator.remove(); + } + flowPointers.addAll(toAdd); + } + } + + void tick(IWorld world, float speed) { + boolean skipping = speed == 0; + Map previousFlow = this.activePipeNetwork.previousFlow; + if (skipping && previousFlow.isEmpty()) + return; + + this.speed = speed; + FluidStack provideFluid = source.provideFluid(); + if (!fluidStack.isEmpty() && !fluidStack.isFluidEqual(provideFluid)) { + resetFlow(world); + return; + } + + fluidStack = provideFluid; + + // There is currently no unfinished flow being followed + if (flowPointers.isEmpty()) { + + // The fluid source has run out -> reset + if (fluidStack.isEmpty()) { + if (hasValidTargets()) + resetFlow(world); + return; + } + + // Keep the flows if all is well + if (hasValidTargets()) + return; + + // Start a new flow from or towards the pump + BlockFace source = getSource(); + if (tryConnectTo(world, source.getOpposite())) + return; + flowPointers.add(source); + } + + boolean skipped = false; + Set pausedPointers = new HashSet<>(); + + do { + skipped = false; + List toAdd = null; + + // Update all branches of this flow, and create new ones if necessary + for (Iterator iterator = flowPointers.iterator(); iterator.hasNext();) { + BlockFace flowPointer = iterator.next(); + BlockPos currentPos = flowPointer.getPos(); + + if (pausedPointers.contains(flowPointer)) + continue; + + FluidPipeBehaviour pipe = getPipeInTree(world, currentPos); + if (pipe == null) { + iterator.remove(); + continue; + } + + Map directions = this.activePipeNetwork.pipeGraph.get(currentPos) + .getSecond(); + boolean inboundComplete = false; + boolean allFlowsComplete = true; + BlockState state = world.getBlockState(currentPos); + + // First loop only inbound flows of a pipe to see if they have reached the + // center + for (boolean inboundPass : Iterate.trueAndFalse) { + if (!inboundPass && !inboundComplete) + break; + + // For all connections of the pipe tree of the pump + for (Entry entry : directions.entrySet()) { + Boolean awayFromPump = entry.getValue(); + Direction direction = entry.getKey(); + boolean inbound = awayFromPump != pulling; + + if (inboundPass && direction != flowPointer.getFace()) + continue; + if (!inboundPass && inbound) + continue; + if (!pipe.canTransferToward(fluidStack, state, direction, inbound)) + continue; + + BlockFace blockface = new BlockFace(currentPos, direction); + + if (!pipe.hasStartedFlow(this, direction, inbound)) + pipe.addFlow(this, direction, inbound); + if (skipping && canSkip(previousFlow, blockface)) { + pipe.skipFlow(direction, inbound); + FluidPropagator.showBlockFace(blockface) + .colored(0x0) + .lineWidth(1 / 8f); + skipped = true; + } + + if (!pipe.hasCompletedFlow(direction, inbound)) { + allFlowsComplete = false; + continue; + } + + if (inboundPass) { + inboundComplete = true; + continue; + } + + // Outward pass, check if any target was reached + tryConnectTo(world, blockface); + } + } + + if (!allFlowsComplete && !skipping) + continue; + + // Create a new flow branch at each outward pipe connection + for (Entry entry : directions.entrySet()) { + if (entry.getValue() != pulling) + continue; + Direction face = entry.getKey(); + BlockFace addedBlockFace = new BlockFace(currentPos.offset(face), face.getOpposite()); + if (skipping && !canSkip(previousFlow, addedBlockFace)) { + allFlowsComplete = false; + continue; + } + if (toAdd == null) + toAdd = new ArrayList<>(); + toAdd.add(addedBlockFace); + } + + if (!allFlowsComplete && skipping) { + pausedPointers.add(flowPointer); + continue; + } + + iterator.remove(); + + } // End of branch loop + + if (toAdd != null) + flowPointers.addAll(toAdd); + + } while (skipping && skipped); + } + + private boolean canSkip(Map previousFlow, BlockFace blockface) { + return previousFlow.containsKey(blockface) && previousFlow.get(blockface) + .isFluidEqual(fluidStack); + } + + private boolean tryConnectTo(IWorld world, BlockFace blockface) { + // Pulling flow, target is the pump + if (pulling) { + if (!this.activePipeNetwork.pumpLocation.getOpposite() + .equals(blockface)) + return false; + pumpReached = true; + TileEntity targetTE = world.getTileEntity(this.activePipeNetwork.pumpLocation.getPos()); + if (targetTE instanceof PumpTileEntity) + ((PumpTileEntity) targetTE).setProvidedFluid(fluidStack); + FluidPropagator.showBlockFace(this.activePipeNetwork.pumpLocation) + .colored(0x799351) + .lineWidth(1 / 8f); + return true; + } + + // Pushing flow, targets are the endpoints + for (FluidNetworkEndpoint networkEndpoint : this.activePipeNetwork.targets) { + if (!networkEndpoint.location.isEquivalent(blockface)) + continue; + outputEndpoints.add(networkEndpoint); + FluidPropagator.showBlockFace(blockface) + .colored(0x799351) + .lineWidth(1 / 8f); + return !(networkEndpoint instanceof InterPumpEndpoint); + } + + return false; + } + + private BlockFace getSource() { + return pulling ? source.location : this.activePipeNetwork.pumpLocation.getOpposite(); + } + + private FluidPipeBehaviour getPipeInTree(IWorld world, BlockPos currentPos) { + if (!world.isAreaLoaded(currentPos, 0)) + return null; + if (!this.activePipeNetwork.pipeGraph.containsKey(currentPos)) + return null; + return TileEntityBehaviour.get(world, currentPos, FluidPipeBehaviour.TYPE); + } + + boolean hasValidTargets() { + return pumpReached || !outputEndpoints.isEmpty(); + } + + public float getSpeed() { + return speed; + } + + public FluidStack getFluidStack() { + return fluidStack; + } +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBehaviour.java new file mode 100644 index 0000000000..26984c7ae2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBehaviour.java @@ -0,0 +1,478 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.KineticDebugger; +import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; +import com.simibubi.create.foundation.utility.Couple; +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.Pair; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.particles.BlockParticleData; +import net.minecraft.particles.IParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.DistExecutor; + +public abstract class FluidPipeBehaviour extends TileEntityBehaviour { + + public static BehaviourType TYPE = new BehaviourType<>(); + + // Direction -> (inboundflows{}, outwardflows{}) + Map> allFlows; + FluidStack fluid; + Couple collision; + + public FluidPipeBehaviour(SmartTileEntity te) { + super(te); + allFlows = new IdentityHashMap<>(); + fluid = FluidStack.EMPTY; + } + + @Override + public BehaviourType getType() { + return TYPE; + } + + public void notifyNetwork() { + FluidPropagator.propagateChangedPipe(this.getWorld(), tileEntity.getPos(), tileEntity.getBlockState()); + } + + public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) { + return isConnectedTo(state, direction); + } + + public abstract boolean isConnectedTo(BlockState state, Direction direction); + + public float getRimRadius(BlockState state, Direction direction) { + return 1 / 4f + 1 / 64f; + } + + public boolean hasStartedFlow(FluidNetworkFlow flow, Direction face, boolean inbound) { + return allFlows.containsKey(face) && allFlows.get(face) + .get(inbound) + .hasFlow(flow); + } + + public boolean hasCompletedFlow(Direction face, boolean inbound) { + return allFlows.containsKey(face) && allFlows.get(face) + .get(inbound) + .isCompleted(); + } + + @Override + public void write(CompoundNBT compound, boolean client) { + compound.put("Fluid", fluid.writeToNBT(new CompoundNBT())); + ListNBT flows = new ListNBT(); + for (Direction face : Iterate.directions) + for (boolean inbound : Iterate.trueAndFalse) { + LerpedFloat flowProgress = getFlowProgress(face, inbound); + if (flowProgress == null) + continue; + CompoundNBT nbt = new CompoundNBT(); + NBTHelper.writeEnum(nbt, "Face", face); + nbt.putBoolean("In", inbound); + nbt.put("Progress", flowProgress.writeNBT()); + flows.add(nbt); + } + compound.put("Flows", flows); + } + + @Override + public void read(CompoundNBT compound, boolean client) { + fluid = FluidStack.loadFluidStackFromNBT(compound.getCompound("Fluid")); + + if (client) { + for (Direction face : Iterate.directions) + if (allFlows.containsKey(face)) + allFlows.get(face) + .forEach(pf -> pf.progress = null); + } + + NBTHelper.iterateCompoundList(compound.getList("Flows", NBT.TAG_COMPOUND), nbt -> { + Direction face = NBTHelper.readEnum(nbt, "Face", Direction.class); + boolean inbound = nbt.getBoolean("In"); + LerpedFloat progress = createFlowProgress(0); + progress.readNBT(nbt.getCompound("Progress"), false); + addFlow(null, face, inbound); + setFlowProgress(face, inbound, progress); + }); + + if (!client) + return; + + for (Direction face : Iterate.directions) { + if (!allFlows.containsKey(face)) + return; + Couple couple = allFlows.get(face); + if (couple.get(true).progress == null && couple.get(false).progress == null) + allFlows.remove(face); + if (allFlows.isEmpty()) + clear(); + } + } + + public void addFlow(@Nullable FluidNetworkFlow flow, Direction face, boolean inbound) { + if (flow != null) { + FluidStack fluid = flow.getFluidStack(); + if (!this.fluid.isEmpty() && !fluid.isFluidEqual(this.fluid)) { + collision = Couple.create(this.fluid, fluid); + return; + } + this.fluid = fluid; + } + + if (!allFlows.containsKey(face)) { + allFlows.put(face, Couple.create(PipeFlows::new)); + if (inbound) + spawnSplashOnRim(face); + } + + if (flow != null) { + PipeFlows flows = allFlows.get(face) + .get(inbound); + flows.addFlow(flow); + contentsChanged(); + } + } + + public void removeFlow(FluidNetworkFlow flow, Direction face, boolean inbound) { + if (!allFlows.containsKey(face)) + return; + Couple couple = allFlows.get(face); + couple.get(inbound) + .removeFlow(flow); + if (!couple.get(true) + .isActive() + && !couple.get(false) + .isActive()) + allFlows.remove(face); + if (allFlows.isEmpty()) + clear(); + } + + public void setFlowProgress(Direction face, boolean inbound, LerpedFloat progress) { + if (!allFlows.containsKey(face)) + return; + allFlows.get(face) + .get(inbound).progress = progress; + } + + public LerpedFloat getFlowProgress(Direction face, boolean inbound) { + if (!allFlows.containsKey(face)) + return null; + return allFlows.get(face) + .get(inbound).progress; + } + + public void skipFlow(Direction face, boolean inbound) { + if (!allFlows.containsKey(face)) + return; + Couple couple = allFlows.get(face); + couple.get(inbound) + .skip(); + } + + public void clear() { + allFlows.clear(); + fluid = FluidStack.EMPTY; + contentsChanged(); + } + + public void spawnParticles() { + DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner); + } + + public void spawnSplashOnRim(Direction face) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnSplashOnRimInner(face)); + } + + public static final int MAX_PARTICLE_RENDER_DISTANCE = 20; + public static final int SPLASH_PARTICLE_AMOUNT = 10; + public static final float IDLE_PARTICLE_SPAWN_CHANCE = 1 / 100f; + public static final Random r = new Random(); + + @OnlyIn(Dist.CLIENT) + private void spawnParticlesInner() { + if (!isRenderEntityWithinDistance()) + return; + if (fluid.isEmpty()) + return; + + World world = Minecraft.getInstance().world; + BlockPos pos = tileEntity.getPos(); + BlockState state = world.getBlockState(pos); + + for (Direction face : Iterate.directions) { + boolean open = FluidPropagator.isOpenEnd(world, pos, face); + if (isConnectedTo(state, face)) { + if (open) { + spawnPouringLiquid(world, state, fluid, face, 1); + continue; + } + if (r.nextFloat() < IDLE_PARTICLE_SPAWN_CHANCE) + spawnRimParticles(world, state, fluid, face, 1); + } + } + } + + @OnlyIn(Dist.CLIENT) + private void spawnSplashOnRimInner(Direction face) { + if (!isRenderEntityWithinDistance()) + return; + if (fluid.isEmpty()) + return; + World world = Minecraft.getInstance().world; + BlockPos pos = tileEntity.getPos(); + BlockState state = world.getBlockState(pos); + spawnRimParticles(world, state, fluid, face, 20); + } + + @OnlyIn(Dist.CLIENT) + private void spawnRimParticles(World world, BlockState state, FluidStack fluid, Direction side, int amount) { + BlockPos pos = tileEntity.getPos(); + if (FluidPropagator.isOpenEnd(world, pos, side)) { + spawnPouringLiquid(world, state, fluid, side, amount); + return; + } + + IParticleData particle = null; + if (FluidHelper.isWater(fluid.getFluid())) + particle = ParticleTypes.DRIPPING_WATER; + if (FluidHelper.isLava(fluid.getFluid())) + particle = ParticleTypes.DRIPPING_LAVA; + // TODO: Generic drip particle type for forge fluids + + if (particle == null) + return; + + float rimRadius = getRimRadius(state, side); + Vec3d directionVec = new Vec3d(side.getDirectionVec()); + + for (int i = 0; i < amount; i++) { + Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, 1) + .normalize(); + vec = VecHelper.clampComponentWise(vec, rimRadius) + .mul(VecHelper.axisAlingedPlaneOf(directionVec)) + .add(directionVec.scale(.45 + r.nextFloat() / 16f)); + Vec3d m = vec; + vec = vec.add(VecHelper.getCenterOf(pos)); + + world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z); + } + } + + @OnlyIn(Dist.CLIENT) + private void spawnPouringLiquid(World world, BlockState state, FluidStack fluid, Direction side, int amount) { + IParticleData particle = new BlockParticleData(ParticleTypes.BLOCK, fluid.getFluid() + .getDefaultState() + .getBlockState()); + float rimRadius = getRimRadius(state, side); + Vec3d directionVec = new Vec3d(side.getDirectionVec()); + + Couple couple = allFlows.get(side); + if (couple == null) + return; + couple.forEachWithContext((flow, inbound) -> { + if (flow.progress == null) + return; + for (int i = 0; i < amount; i++) { + Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, rimRadius); + vec = vec.mul(VecHelper.axisAlingedPlaneOf(directionVec)) + .add(directionVec.scale(.5 + r.nextFloat() / 4f)); + Vec3d m = vec; + Vec3d centerOf = VecHelper.getCenterOf(tileEntity.getPos()); + vec = vec.add(centerOf); + if (inbound) { + vec = vec.add(m); + m = centerOf.add(directionVec.scale(.5)).subtract(vec).scale(3); + } + world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z); + } + }); + + } + + @OnlyIn(Dist.CLIENT) + private boolean isRenderEntityWithinDistance() { + Entity renderViewEntity = Minecraft.getInstance() + .getRenderViewEntity(); + if (renderViewEntity == null) + return false; + Vec3d center = VecHelper.getCenterOf(tileEntity.getPos()); + if (renderViewEntity.getPositionVec() + .distanceTo(center) > MAX_PARTICLE_RENDER_DISTANCE) + return false; + return true; + } + + static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25); + + @Override + public void tick() { + super.tick(); + boolean isRemote = getWorld().isRemote; + + allFlows.values() + .forEach(c -> c.forEach(pf -> pf.tick(isRemote))); + + if (isRemote) { + clientTick(); + return; + } + + if (collision != null) { + FluidReactions.handlePipeFlowCollision(getWorld(), tileEntity.getPos(), collision.getFirst(), + collision.getSecond()); + collision = null; + return; + } + } + + private void clientTick() { + spawnParticles(); + + if (!KineticDebugger.isActive()) + return; + if (fluid.isEmpty()) + return; + for (Entry> entry : allFlows.entrySet()) { + Direction face = entry.getKey(); + Vec3d directionVec = new Vec3d(face.getDirectionVec()); + float size = 1 / 4f; + boolean extended = !isConnectedTo(tileEntity.getBlockState(), face.getOpposite()); + float length = extended ? .75f : .5f; + + entry.getValue() + .forEachWithContext((flow, inbound) -> { + if (flow.progress == null) + return; + float value = flow.progress.getValue(); + Vec3d start = directionVec.scale(inbound ? .5 : .5f - length); + Vec3d offset = directionVec.scale(length * (inbound ? -1 : 1)) + .scale(value); + + Vec3d scale = new Vec3d(1, 1, 1).subtract(directionVec.scale(face.getAxisDirection() + .getOffset())) + .scale(size); + AxisAlignedBB bb = + new AxisAlignedBB(start, start.add(offset)).offset(VecHelper.getCenterOf(tileEntity.getPos())) + .grow(scale.x, scale.y, scale.z); + + int color = 0x7fdbda; + if (!fluid.isEmpty()) { + Fluid fluid2 = fluid.getFluid(); + if (fluid2 == Fluids.WATER) + color = 0x1D4D9B; + if (fluid2 == Fluids.LAVA) + color = 0xFF773D; + } + + CreateClient.outliner.chaseAABB(Pair.of(this, face), bb) + .withFaceTexture(AllSpecialTextures.CUTOUT_CHECKERED) + .colored(color) + .lineWidth(1 / 16f); + }); + } + } + + private void contentsChanged() { + tileEntity.markDirty(); + tileEntity.sendData(); + } + + private LerpedFloat createFlowProgress(double speed) { + return LerpedFloat.linear() + .startWithValue(0) + .chase(1, speed, Chaser.LINEAR); + } + + class PipeFlows { + LerpedFloat progress; + Set participants; + float bestFlowStrength; + + void addFlow(FluidNetworkFlow flow) { + if (participants == null) + participants = new HashSet<>(); + participants.add(flow); + + if (progress == null) { + progress = createFlowProgress(flow.getSpeed()); + } + } + + boolean hasFlow(FluidNetworkFlow flow) { + return participants != null && participants.contains(flow); + } + + void tick(boolean onClient) { + if (progress == null) + return; + if (!onClient) { + if (participants == null) + return; + bestFlowStrength = 0; + for (FluidNetworkFlow networkFlow : participants) + bestFlowStrength = Math.max(bestFlowStrength, networkFlow.getSpeed()); + if (isCompleted()) + return; + if (progress.updateChaseSpeed(bestFlowStrength)) + contentsChanged(); + } + progress.tickChaser(); + } + + void skip() { + progress = LerpedFloat.linear() + .startWithValue(1); + } + + void removeFlow(FluidNetworkFlow flow) { + if (participants == null) + return; + participants.remove(flow); + } + + boolean isActive() { + return participants != null && !participants.isEmpty(); + } + + boolean isCompleted() { + return progress != null && progress.getValue() == 1; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBlock.java index f3cc7c6de3..71f8698658 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeBlock.java @@ -1,15 +1,24 @@ package com.simibubi.create.content.contraptions.fluids; +import java.util.Random; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllTileEntities; import com.simibubi.create.foundation.utility.Iterate; + import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.FlowingFluidBlock; import net.minecraft.block.IWaterLoggable; import net.minecraft.block.SixWayBlock; import net.minecraft.fluid.Fluids; import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; +import net.minecraft.network.DebugPacketSender; import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; @@ -17,141 +26,210 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.ILightReader; import net.minecraft.world.IWorld; +import net.minecraft.world.TickPriority; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; -import javax.annotation.Nullable; - public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable { - public FluidPipeBlock(Properties properties) { - super(4 / 16f, properties); - this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false)); - } + public FluidPipeBlock(Properties properties) { + super(4 / 16f, properties); + this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false)); + } - public static boolean isPipe(BlockState state) { - return state.getBlock() instanceof FluidPipeBlock; - } + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } - public static boolean isTank(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) { - return state.hasTileEntity() && world.getTileEntity(pos).getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite()).isPresent(); - } + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return AllTileEntities.FLUID_PIPE.create(); + } - // TODO: more generic pipe connection handling. Ideally without marker interface - public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) { - if (isPipe(neighbour) || isTank(neighbour, world, pos, blockFace)) - return true; - return neighbour.getBlock() instanceof PumpBlock && blockFace.getAxis() == neighbour.get(PumpBlock.FACING) - .getAxis(); - } + @Override + public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) { + boolean blockTypeChanged = state.getBlock() != newState.getBlock(); + if (blockTypeChanged && !world.isRemote) + FluidPropagator.propagateChangedPipe(world, pos, state); + if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity())) + world.removeTileEntity(pos); + } - public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) { - if (!isPipe(state)) - return false; - if (!state.get(FACING_TO_PROPERTY_MAP.get(direction))) - return false; - BlockPos offsetPos = pos.offset(direction); - BlockState facingState = world.getBlockState(offsetPos); - if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING) - .getAxis() == direction.getAxis()) - return false; - if (!isPipe(facingState)) - return true; - if (!isCornerOrEndPipe(world, pos, state)) - return false; - if (isStraightPipe(world, offsetPos, facingState)) - return true; - if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState)) - return true; - if (isCornerOrEndPipe(world, offsetPos, facingState)) - return direction.getAxisDirection() == AxisDirection.POSITIVE; - return false; - } + @Override + public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) { + if (world.isRemote) + return; + if (state != oldState) + world.getPendingBlockTicks() + .scheduleTick(pos, this, 1, TickPriority.HIGH); + } - public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) { - return isPipe(state) && !isStraightPipe(world, pos, state) && !shouldDrawCasing(world, pos, state); - } + @Override + public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos, + boolean isMoving) { + DebugPacketSender.func_218806_a(world, pos); + if (world.isRemote) + return; + if (otherBlock instanceof FluidPipeBlock) + return; + if (otherBlock instanceof PumpBlock) + return; + if (otherBlock instanceof FlowingFluidBlock) + return; + if (!isStraightPipe(state)) + return; + for (Direction d : Iterate.directions) { + if (!pos.offset(d) + .equals(neighborPos)) + continue; + if (!isOpenAt(state, d)) + return; + world.getPendingBlockTicks() + .scheduleTick(pos, this, 1, TickPriority.HIGH); + } + } - public static boolean isStraightPipe(ILightReader world, BlockPos pos, BlockState state) { - if (!isPipe(state)) - return false; - boolean axisFound = false; - for (Axis axis : Iterate.axes) { - Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis); - Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); - if (state.get(FACING_TO_PROPERTY_MAP.get(d1)) && state.get(FACING_TO_PROPERTY_MAP.get(d2))) - if (axisFound) - return false; - else - axisFound = true; - } - return axisFound; - } + @Override + public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) { + FluidPropagator.propagateChangedPipe(world, pos, state); + } - public static boolean shouldDrawCasing(ILightReader world, BlockPos pos, BlockState state) { - if (!isPipe(state)) - return false; - for (Axis axis : Iterate.axes) { - int connections = 0; - for (Direction direction : Iterate.directions) - if (direction.getAxis() != axis && state.get(FACING_TO_PROPERTY_MAP.get(direction))) - connections++; - if (connections > 2) - return true; - } - return false; - } + public static boolean isPipe(BlockState state) { + return state.getBlock() instanceof FluidPipeBlock; + } - @Override - protected void fillStateContainer(Builder builder) { - builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN, BlockStateProperties.WATERLOGGED); - super.fillStateContainer(builder); - } + public static boolean hasFluidCapability(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) { + return state.hasTileEntity() && world.getTileEntity(pos) + .getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite()) + .isPresent(); + } - @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { - IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos()); - return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(), - context.getPos()).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); - } + public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) { + if (isPipe(neighbour) || hasFluidCapability(neighbour, world, pos, blockFace)) + return true; + // TODO: more generic pipe connection handling. + return neighbour.getBlock() instanceof PumpBlock && blockFace.getAxis() == neighbour.get(PumpBlock.FACING) + .getAxis(); + } - @Override - public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState, - IWorld world, BlockPos pos, BlockPos neighbourPos) { - if (state.get(BlockStateProperties.WATERLOGGED)) { - world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); - } - return updateBlockState(state, direction, direction.getOpposite(), world, pos); - } + public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) { + if (!isPipe(state)) + return false; + if (!isOpenAt(state, direction)) + return false; + BlockPos offsetPos = pos.offset(direction); + BlockState facingState = world.getBlockState(offsetPos); + if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING) + .getAxis() == direction.getAxis()) + return false; + if (!isPipe(facingState)) + return true; + if (!isCornerOrEndPipe(world, pos, state)) + return false; + if (isStraightPipe(facingState)) + return true; + if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState)) + return true; + if (isCornerOrEndPipe(world, offsetPos, facingState)) + return direction.getAxisDirection() == AxisDirection.POSITIVE; + return false; + } - public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore, - ILightReader world, BlockPos pos) { - // Update sides that are not ignored - for (Direction d : Iterate.directions) - if (d != ignore) - state = state.with(FACING_TO_PROPERTY_MAP.get(d), - canConnectTo(world, pos.offset(d), world.getBlockState(pos.offset(d)), d.getOpposite())); + private static boolean isOpenAt(BlockState state, Direction direction) { + return state.get(FACING_TO_PROPERTY_MAP.get(direction)); + } - // See if it has enough connections - Direction connectedDirection = null; - for (Direction d : Iterate.directions) { - if (state.get(FACING_TO_PROPERTY_MAP.get(d))) { - if (connectedDirection != null) - return state; - connectedDirection = d; - } - } + public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) { + return isPipe(state) && !isStraightPipe(state) && !shouldDrawCasing(world, pos, state); + } - // Add opposite end if only one connection - if (connectedDirection != null) - return state.with(FACING_TO_PROPERTY_MAP.get(connectedDirection.getOpposite()), true); + public static boolean isStraightPipe(BlockState state) { + if (!isPipe(state)) + return false; + boolean axisFound = false; + for (Axis axis : Iterate.axes) { + Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis); + Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); + if (isOpenAt(state, d1) && isOpenAt(state, d2)) + if (axisFound) + return false; + else + axisFound = true; + } + return axisFound; + } - // Use preferred - return state.with(FACING_TO_PROPERTY_MAP.get(preferredDirection), true) - .with(FACING_TO_PROPERTY_MAP.get(preferredDirection.getOpposite()), true); - } + public static boolean shouldDrawCasing(ILightReader world, BlockPos pos, BlockState state) { + if (!isPipe(state)) + return false; + for (Axis axis : Iterate.axes) { + int connections = 0; + for (Direction direction : Iterate.directions) + if (direction.getAxis() != axis && isOpenAt(state, direction)) + connections++; + if (connections > 2) + return true; + } + return false; + } - @Override - public IFluidState getFluidState(BlockState state) { - return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState(); - } + @Override + protected void fillStateContainer(Builder builder) { + builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN, BlockStateProperties.WATERLOGGED); + super.fillStateContainer(builder); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + IFluidState ifluidstate = context.getWorld() + .getFluidState(context.getPos()); + return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(), + context.getPos()).with(BlockStateProperties.WATERLOGGED, + Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); + } + + @Override + public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState, + IWorld world, BlockPos pos, BlockPos neighbourPos) { + if (state.get(BlockStateProperties.WATERLOGGED)) { + world.getPendingFluidTicks() + .scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); + } + return updateBlockState(state, direction, direction.getOpposite(), world, pos); + } + + public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore, + ILightReader world, BlockPos pos) { + // Update sides that are not ignored + for (Direction d : Iterate.directions) + if (d != ignore) + state = state.with(FACING_TO_PROPERTY_MAP.get(d), + canConnectTo(world, pos.offset(d), world.getBlockState(pos.offset(d)), d.getOpposite())); + + // See if it has enough connections + Direction connectedDirection = null; + for (Direction d : Iterate.directions) { + if (isOpenAt(state, d)) { + if (connectedDirection != null) + return state; + connectedDirection = d; + } + } + + // Add opposite end if only one connection + if (connectedDirection != null) + return state.with(FACING_TO_PROPERTY_MAP.get(connectedDirection.getOpposite()), true); + + // Use preferred + return state.with(FACING_TO_PROPERTY_MAP.get(preferredDirection), true) + .with(FACING_TO_PROPERTY_MAP.get(preferredDirection.getOpposite()), true); + } + + @Override + public IFluidState getFluidState(BlockState state) { + return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) + : Fluids.EMPTY.getDefaultState(); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeTileEntity.java new file mode 100644 index 0000000000..50df900fb8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPipeTileEntity.java @@ -0,0 +1,39 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.util.List; + +import com.simibubi.create.foundation.tileEntity.SmartTileEntity; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; + +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; + +public class FluidPipeTileEntity extends SmartTileEntity { + + FluidPipeBehaviour behaviour; + + public FluidPipeTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + } + + @Override + public void addBehaviours(List behaviours) { + behaviour = new StandardPipeBehaviour(this); + behaviours.add(behaviour); + } + + class StandardPipeBehaviour extends FluidPipeBehaviour { + + public StandardPipeBehaviour(SmartTileEntity te) { + super(te); + } + + @Override + public boolean isConnectedTo(BlockState state, Direction direction) { + return FluidPipeBlock.isPipe(state) && state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction)); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java new file mode 100644 index 0000000000..a650077372 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidPropagator.java @@ -0,0 +1,128 @@ +package com.simibubi.create.content.contraptions.fluids; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.mutable.MutableObject; + +import com.simibubi.create.AllBlocks; +import com.simibubi.create.CreateClient; +import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; + +public class FluidPropagator { + + public static FluidPipeBehaviour getPipe(IBlockReader reader, BlockPos pos) { + return TileEntityBehaviour.get(reader, pos, FluidPipeBehaviour.TYPE); + } + + public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) { + BlockPos connectedPos = pos.offset(side); + BlockState connectedState = reader.getBlockState(connectedPos); + FluidPipeBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos); + if (pipe != null && pipe.isConnectedTo(connectedState, side.getOpposite())) + return false; + if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING) + .getAxis() == side.getAxis()) + return false; + if (Block.hasSolidSide(connectedState, reader, connectedPos, side.getOpposite())) + return false; + if (!(connectedState.getMaterial() + .isReplaceable() && connectedState.getBlockHardness(reader, connectedPos) != -1) + && !connectedState.has(BlockStateProperties.WATERLOGGED)) + return false; + return true; + } + + public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) { + List frontier = new ArrayList<>(); + Set visited = new HashSet<>(); + + frontier.add(pipePos); + + // Visit all connected pumps to update their network + while (!frontier.isEmpty()) { + BlockPos currentPos = frontier.remove(0); + if (visited.contains(currentPos)) + continue; + visited.add(currentPos); + BlockState currentState = currentPos.equals(pipePos) ? pipeState : world.getBlockState(currentPos); + FluidPipeBehaviour pipe = getPipe(world, currentPos); + if (pipe == null) + continue; + for (Direction direction : getPipeConnections(currentState, pipe)) { + BlockPos target = currentPos.offset(direction); + if (!world.isAreaLoaded(target, 0)) + continue; + + TileEntity tileEntity = world.getTileEntity(target); + BlockState targetState = world.getBlockState(target); + if (tileEntity instanceof PumpTileEntity) { + if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.get(PumpBlock.FACING) + .getAxis() != direction.getAxis()) + continue; + PumpTileEntity pump = (PumpTileEntity) tileEntity; + pump.updatePipesOnSide(direction.getOpposite()); + continue; + } + if (visited.contains(target)) + continue; + FluidPipeBehaviour targetPipe = getPipe(world, target); + if (targetPipe == null) + continue; + if (targetPipe.isConnectedTo(targetState, direction.getOpposite())) + frontier.add(target); + } + } + } + + public static List getPipeConnections(BlockState state, FluidPipeBehaviour pipe) { + List list = new ArrayList<>(); + for (Direction d : Iterate.directions) + if (pipe.isConnectedTo(state, d)) + list.add(d); + return list; + } + + public static int getPumpRange() { + return AllConfigs.SERVER.fluids.mechanicalPumpRange.get(); + } + + public static OutlineParams showBlockFace(BlockFace face) { + MutableObject params = new MutableObject<>(new OutlineParams()); + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + Vec3d directionVec = new Vec3d(face.getFace() + .getDirectionVec()); + Vec3d scaleVec = directionVec.scale(-.25f * face.getFace() + .getAxisDirection() + .getOffset()); + directionVec = directionVec.scale(.5f); + params.setValue(CreateClient.outliner.showAABB(face, + FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos()))) + .grow(scaleVec.x, scaleVec.y, scaleVec.z) + .grow(1 / 16f))); + }); + return params.getValue(); + } + + static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25); + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java new file mode 100644 index 0000000000..c15d2a40ae --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidReactions.java @@ -0,0 +1,37 @@ +package com.simibubi.create.content.contraptions.fluids; + +import com.simibubi.create.foundation.fluid.FluidHelper; +import com.simibubi.create.foundation.utility.BlockHelper; + +import net.minecraft.block.Blocks; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.fluid.IFluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; + +public class FluidReactions { + + public static void handlePipeFlowCollision(World world, BlockPos pos, FluidStack fluid, FluidStack fluid2) { + Fluid f1 = fluid.getFluid(); + Fluid f2 = fluid2.getFluid(); + BlockHelper.destroyBlock(world, pos, 1); + if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA) + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + } + + public static void handlePipeSpillCollision(World world, BlockPos pos, Fluid pipeFluid, IFluidState worldFluid) { + Fluid pf = FluidHelper.convertToStill(pipeFluid); + Fluid wf = worldFluid.getFluid(); + if (pf == Fluids.WATER && wf == Fluids.LAVA) + world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState()); + if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA) + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + else if (pf == Fluids.LAVA && wf == Fluids.WATER) + world.setBlockState(pos, Blocks.STONE.getDefaultState()); + else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER) + world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState()); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTankBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTankBlock.java index c2ec410268..ffb931aede 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTankBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/FluidTankBlock.java @@ -182,7 +182,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE 0) { + syncCooldown--; + if (syncCooldown == 0 && queuedSync) + sendData(); + } if (updateConnectivity) updateConnectivity(); if (fluidLevel != null) @@ -96,7 +106,7 @@ public class FluidTankTileEntity extends SmartTileEntity { FluidAttributes attributes = newFluidStack.getFluid() .getAttributes(); - int luminosity = attributes.getLuminosity(newFluidStack) / 2; + int luminosity = (int) (attributes.getLuminosity(newFluidStack) / 1.2f); boolean reversed = attributes.isLighterThanAir(); int maxY = (int) ((getFillState() * height) + 1); @@ -116,6 +126,11 @@ public class FluidTankTileEntity extends SmartTileEntity { } } } + + if (!world.isRemote) { + markDirty(); + sendData(); + } } protected void setLuminosity(int luminosity) { @@ -162,6 +177,7 @@ public class FluidTankTileEntity extends SmartTileEntity { getWorld().setBlockState(pos, state, 22); } + refreshCapability(); markDirty(); sendData(); } @@ -173,6 +189,23 @@ public class FluidTankTileEntity extends SmartTileEntity { te.setWindows(!te.window); } + public void sendDataImmediately() { + syncCooldown = 0; + queuedSync = false; + sendData(); + } + + @Override + public void sendData() { + if (syncCooldown > 0) { + queuedSync = true; + return; + } + super.sendData(); + queuedSync = false; + syncCooldown = SYNC_RATE; + } + public void setWindows(boolean window) { this.window = window; for (int yOffset = 0; yOffset < height; yOffset++) { @@ -213,10 +246,18 @@ public class FluidTankTileEntity extends SmartTileEntity { if (controller.equals(this.controller)) return; this.controller = controller; + refreshCapability(); markDirty(); sendData(); } + private void refreshCapability() { + LazyOptional oldCap = fluidCapability; + fluidCapability = LazyOptional.of(() -> isController() ? tankInventory + : getControllerTE() != null ? getControllerTE().tankInventory : new FluidTank(0)); + oldCap.invalidate(); + } + public BlockPos getController() { return isController() ? pos : controller; } @@ -236,39 +277,38 @@ public class FluidTankTileEntity extends SmartTileEntity { } @Override - public void read(CompoundNBT tag) { - super.read(tag); - updateConnectivity = tag.contains("Uninitialized"); - luminosity = tag.getInt("Luminosity"); - controller = null; - - if (tag.contains("Controller")) - controller = NBTUtil.readBlockPos(tag.getCompound("Controller")); - - if (isController()) { - window = tag.getBoolean("Window"); - width = tag.getInt("Size"); - height = tag.getInt("Height"); - tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier()); - tankInventory.readFromNBT(tag.getCompound("TankContent")); - if (tankInventory.getSpace() < 0) - tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE); - } - - if (tag.contains("ForceFluidLevel") || fluidLevel == null) - fluidLevel = new InterpolatedChasingValue().start(getFillState()) - .withSpeed(1 / 2f); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); + BlockPos controllerBefore = controller; int prevSize = width; int prevHeight = height; int prevLum = luminosity; + + updateConnectivity = compound.contains("Uninitialized"); + luminosity = compound.getInt("Luminosity"); + controller = null; - super.readClientUpdate(tag); + if (compound.contains("Controller")) + controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); + if (isController()) { + window = compound.getBoolean("Window"); + width = compound.getInt("Size"); + height = compound.getInt("Height"); + tankInventory.setCapacity(getTotalTankSize() * getCapacityMultiplier()); + tankInventory.readFromNBT(compound.getCompound("TankContent")); + if (tankInventory.getSpace() < 0) + tankInventory.drain(-tankInventory.getSpace(), FluidAction.EXECUTE); + } + + if (compound.contains("ForceFluidLevel") || fluidLevel == null) + fluidLevel = new InterpolatedChasingValue().start(getFillState()) + .withSpeed(1 / 2f); + + if (!clientPacket) + return; + boolean changeOfController = controllerBefore == null ? controller != null : !controllerBefore.equals(controller); if (changeOfController || prevSize != width || prevHeight != height) { @@ -279,15 +319,17 @@ public class FluidTankTileEntity extends SmartTileEntity { } if (isController()) { float fillState = getFillState(); - if (tag.contains("ForceFluidLevel") || fluidLevel == null) - fluidLevel = new InterpolatedChasingValue().start(fillState) - .withSpeed(1 / 2f); + if (compound.contains("ForceFluidLevel") || fluidLevel == null) + fluidLevel = new InterpolatedChasingValue().start(fillState); fluidLevel.target(fillState); } if (luminosity != prevLum && hasWorld()) world.getChunkProvider() - .getLightManager() - .checkBlock(pos); + .getLightManager() + .checkBlock(pos); + + if (compound.contains("LazySync")) + fluidLevel.withSpeed(compound.contains("LazySync") ? 1 / 8f : 1 / 2f); } protected float getFillState() { @@ -295,44 +337,42 @@ public class FluidTankTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT tag) { + public void write(CompoundNBT compound, boolean clientPacket) { if (updateConnectivity) - tag.putBoolean("Uninitialized", true); + compound.putBoolean("Uninitialized", true); if (!isController()) - tag.put("Controller", NBTUtil.writeBlockPos(controller)); + compound.put("Controller", NBTUtil.writeBlockPos(controller)); if (isController()) { - tag.putBoolean("Window", window); - tag.put("TankContent", tankInventory.writeToNBT(new CompoundNBT())); - tag.putInt("Size", width); - tag.putInt("Height", height); + compound.putBoolean("Window", window); + compound.put("TankContent", tankInventory.writeToNBT(new CompoundNBT())); + compound.putInt("Size", width); + compound.putInt("Height", height); } - tag.putInt("Luminosity", luminosity); - return super.write(tag); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { + compound.putInt("Luminosity", luminosity); + super.write(compound, clientPacket); + + if (!clientPacket) + return; if (forceFluidLevelUpdate) compound.putBoolean("ForceFluidLevel", true); + if (queuedSync) + compound.putBoolean("LazySync", true); forceFluidLevelUpdate = false; - return super.writeToClient(compound); } @Nonnull @Override public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) { - FluidTankTileEntity controller = getControllerTE(); - if (controller != null) - return controller.fluidCapability.cast(); - } + if (!fluidCapability.isPresent()) + refreshCapability(); + if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + return fluidCapability.cast(); return super.getCapability(cap, side); } @Override public void remove() { super.remove(); - fluidCapability.invalidate(); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/InterPumpFluidHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/InterPumpFluidHandler.java new file mode 100644 index 0000000000..34e0bd8e1a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/InterPumpFluidHandler.java @@ -0,0 +1,44 @@ +package com.simibubi.create.content.contraptions.fluids; + +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.templates.FluidTank; + +public class InterPumpFluidHandler extends FluidTank { + + InterPumpEndpoint endpoint; + + public InterPumpFluidHandler(InterPumpEndpoint endpoint) { + super(Integer.MAX_VALUE); + this.endpoint = endpoint; + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + if (resource.isEmpty()) + return 0; + int maxInput = Math.min(resource.getAmount(), Math.max(getTransferCapacity() - getFluidAmount(), 0)); + FluidStack toInsert = resource.copy(); + toInsert.setAmount(maxInput); + FluidPropagator.showBlockFace(endpoint.location).colored(0x77d196).lineWidth(1/4f); + return super.fill(toInsert, action); + } + + @Override + public FluidStack drain(int maxDrain, FluidAction action) { + return super.drain(maxDrain, action); + } + + public FluidStack provide() { + FluidStack heldFluid = getFluid(); + if (heldFluid.isEmpty()) + return heldFluid; + FluidStack copy = heldFluid.copy(); + copy.setAmount(1); + return copy; + } + + private int getTransferCapacity() { + return Math.min(endpoint.getTransferSpeed(true), endpoint.getTransferSpeed(false)); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java new file mode 100644 index 0000000000..5aff361b38 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/OpenEndedPipe.java @@ -0,0 +1,170 @@ +package com.simibubi.create.content.contraptions.fluids; + +import javax.annotation.Nullable; + +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Iterate; + +import net.minecraft.block.BlockState; +import net.minecraft.block.FlowingFluidBlock; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.fluid.IFluidState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.templates.FluidTank; + +public class OpenEndedPipe { + + World world; + + private OpenEndFluidHandler fluidHandler; + private BlockPos outputPos; + private boolean wasPulling; + private boolean stale; + + public OpenEndedPipe(BlockFace face) { + fluidHandler = new OpenEndFluidHandler(); + outputPos = face.getConnectedPos(); + } + + public void tick(World world, boolean pulling) { + this.world = world; + if (!world.isAreaLoaded(outputPos, 0)) + return; + if (pulling != wasPulling) { + if (pulling) + fluidHandler.clear(); + wasPulling = pulling; + } + + BlockState state = world.getBlockState(outputPos); + IFluidState fluidState = state.getFluidState(); + boolean waterlog = state.has(BlockStateProperties.WATERLOGGED); + + if (!waterlog && !state.getMaterial() + .isReplaceable()) + return; + + // TODO different pipe end types + if (pulling) { + if (fluidState.isEmpty() || !fluidState.isSource()) + return; + if (!fluidHandler.tryCollectFluid(fluidState.getFluid())) + return; + if (waterlog) { + world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3); + return; + } + world.setBlockState(outputPos, fluidState.getBlockState() + .with(FlowingFluidBlock.LEVEL, 14), 3); + return; + } + + Fluid providedFluid = fluidHandler.tryProvidingFluid(); + if (providedFluid == null) + return; + if (!fluidState.isEmpty() && fluidState.getFluid() != providedFluid) { + FluidReactions.handlePipeSpillCollision(world, outputPos, providedFluid, fluidState); + return; + } + if (fluidState.isSource()) + return; + if (waterlog) { + if (providedFluid.getFluid() != Fluids.WATER) + return; + world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3); + return; + } + world.setBlockState(outputPos, providedFluid.getDefaultState() + .getBlockState(), 3); + } + + public LazyOptional getCapability() { + return LazyOptional.of(() -> fluidHandler); + } + + public CompoundNBT writeToNBT(CompoundNBT compound) { + fluidHandler.writeToNBT(compound); + compound.putBoolean("Pulling", wasPulling); + return compound; + } + + public void readNBT(CompoundNBT compound) { + fluidHandler.readFromNBT(compound); + wasPulling = compound.getBoolean("Pulling"); + } + + public void markStale() { + stale = true; + } + + public void unmarkStale() { + stale = false; + } + + public boolean isStale() { + return stale; + } + + private class OpenEndFluidHandler extends FluidTank { + + public OpenEndFluidHandler() { + super(1500); + } + + @Override + public int fill(FluidStack resource, FluidAction action) { + // Never allow being filled when a source is attached + if (world == null) + return 0; + if (!world.isAreaLoaded(outputPos, 0)) + return 0; + BlockState state = world.getBlockState(outputPos); + IFluidState fluidState = state.getFluidState(); + if (!fluidState.isEmpty() && fluidState.getFluid() != resource.getFluid()) { + FluidReactions.handlePipeSpillCollision(world, outputPos, resource.getFluid(), fluidState); + return 0; + } + if (fluidState.isSource()) + return 0; + if (!(state.has(BlockStateProperties.WATERLOGGED) && resource.getFluid() == Fluids.WATER) + && !state.getMaterial() + .isReplaceable()) + return 0; + + // Never allow being filled above 1000 + FluidStack insertable = resource.copy(); + insertable.setAmount(Math.min(insertable.getAmount(), Math.max(1000 - getFluidAmount(), 0))); + return super.fill(insertable, action); + } + + public boolean tryCollectFluid(Fluid fluid) { + for (boolean simulate : Iterate.trueAndFalse) + if (super.fill(new FluidStack(fluid, 1000), + simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != 1000) + return false; + return true; + } + + @Nullable + public Fluid tryProvidingFluid() { + Fluid fluid = getFluid().getFluid(); + for (boolean simulate : Iterate.trueAndFalse) + if (drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE).getAmount() != 1000) + return null; + return fluid; + } + + public void clear() { + setFluid(FluidStack.EMPTY); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java index 788dcee2f3..a130652076 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpBlock.java @@ -1,14 +1,23 @@ package com.simibubi.create.content.contraptions.fluids; +import java.util.Map; + +import org.apache.commons.lang3.mutable.MutableBoolean; + import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Iterate; + import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.IWaterLoggable; import net.minecraft.fluid.Fluids; import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; +import net.minecraft.item.ItemUseContext; +import net.minecraft.network.DebugPacketSender; import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; @@ -20,71 +29,137 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; +import net.minecraftforge.fluids.FluidStack; public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable { - public PumpBlock(Properties p_i48415_1_) { - super(p_i48415_1_); - setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false)); - } + public PumpBlock(Properties p_i48415_1_) { + super(p_i48415_1_); + setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false)); + } - @Override - public boolean hasTileEntity(BlockState state) { - return true; - } + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } - @Override - public TileEntity createTileEntity(BlockState state, IBlockReader world) { - return AllTileEntities.MECHANICAL_PUMP.create(); - } + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return AllTileEntities.MECHANICAL_PUMP.create(); + } - @Override - public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { - return originalState.with(FACING, originalState.get(FACING) - .getOpposite()); - } + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + return originalState.with(FACING, originalState.get(FACING) + .getOpposite()); + } - @Override - public Axis getRotationAxis(BlockState state) { - return state.get(FACING) - .getAxis(); - } + @Override + public BlockState updateAfterWrenched(BlockState newState, ItemUseContext context) { + BlockState state = super.updateAfterWrenched(newState, context); + World world = context.getWorld(); + BlockPos pos = context.getPos(); + if (world.isRemote) + return state; + TileEntity tileEntity = world.getTileEntity(pos); + if (!(tileEntity instanceof PumpTileEntity)) + return state; + PumpTileEntity pump = (PumpTileEntity) tileEntity; + if (pump.networks == null) + return state; - @Override - public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_, - ISelectionContext p_220053_4_) { - return AllShapes.PUMP.get(state.get(FACING)); - } + FluidNetwork apn1 = pump.networks.get(true); + FluidNetwork apn2 = pump.networks.get(false); - @Override - public boolean hasIntegratedCogwheel(IWorldReader world, BlockPos pos, BlockState state) { - return true; - } + // Collect pipes that can be skipped + apn1.clearFlows(world, true); + apn2.clearFlows(world, true); - @Override - public IFluidState getFluidState(BlockState state) { - return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState(); - } + // Swap skipsets as the networks change sides + Map skippedConnections = apn1.previousFlow; + apn1.previousFlow = apn2.previousFlow; + apn2.previousFlow = skippedConnections; - @Override - protected void fillStateContainer(Builder builder) { - builder.add(BlockStateProperties.WATERLOGGED); - super.fillStateContainer(builder); - } + // Init networks next tick + pump.networksToUpdate.forEach(MutableBoolean::setTrue); + pump.networks.swap(); + pump.reversed = !pump.reversed; - @Override - public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState, - IWorld world, BlockPos pos, BlockPos neighbourPos) { - if (state.get(BlockStateProperties.WATERLOGGED)) { - world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); - } - return state; - } + return state; + } - @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { - IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos()); - return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); - } + @Override + public Axis getRotationAxis(BlockState state) { + return state.get(FACING) + .getAxis(); + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_, + ISelectionContext p_220053_4_) { + return AllShapes.PUMP.get(state.get(FACING)); + } + + @Override + public boolean hasIntegratedCogwheel(IWorldReader world, BlockPos pos, BlockState state) { + return true; + } + + @Override + public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos, + boolean isMoving) { + DebugPacketSender.func_218806_a(world, pos); + if (world.isRemote) + return; + if (otherBlock instanceof FluidPipeBlock) + return; + TileEntity tileEntity = world.getTileEntity(pos); + if (!(tileEntity instanceof PumpTileEntity)) + return; + PumpTileEntity pump = (PumpTileEntity) tileEntity; + Direction facing = state.get(FACING); + for (boolean front : Iterate.trueAndFalse) { + Direction side = front ? facing : facing.getOpposite(); + if (!pos.offset(side) + .equals(neighborPos)) + continue; + pump.updatePipesOnSide(side); + } + } + + @Override + public IFluidState getFluidState(BlockState state) { + return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) + : Fluids.EMPTY.getDefaultState(); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(BlockStateProperties.WATERLOGGED); + super.fillStateContainer(builder); + } + + @Override + public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState, + IWorld world, BlockPos pos, BlockPos neighbourPos) { + if (state.get(BlockStateProperties.WATERLOGGED)) { + world.getPendingFluidTicks() + .scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); + } + return state; + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + IFluidState ifluidstate = context.getWorld() + .getFluidState(context.getPos()); + return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED, + Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); + } + + public static boolean isPump(BlockState state) { + return state.getBlock() instanceof PumpBlock; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java index 34e46dfb2f..579445cb8e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpRenderer.java @@ -31,7 +31,7 @@ public class PumpRenderer extends KineticTileEntityRenderer { PumpTileEntity pump = (PumpTileEntity) te; Vec3d rotationOffset = new Vec3d(.5, 14 / 16f, .5); BlockState blockState = te.getBlockState(); - float angle = MathHelper.lerp(pump.arrowDirection.get(partialTicks), 0, 90) - 90; + float angle = MathHelper.lerp(pump.arrowDirection.getValue(partialTicks), 0, 90) - 90; for (float yRot : new float[] { 0, 90 }) { ms.push(); SuperByteBuffer arrow = AllBlockPartials.MECHANICAL_PUMP_ARROW.renderOn(blockState); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java index 02f00736e3..bae4cdf862 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PumpTileEntity.java @@ -1,29 +1,349 @@ package com.simibubi.create.content.contraptions.fluids; -import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.commons.lang3.mutable.MutableBoolean; + +import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.foundation.utility.BlockFace; +import com.simibubi.create.foundation.utility.Couple; +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 net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; public class PumpTileEntity extends KineticTileEntity { - InterpolatedChasingValue arrowDirection; + LerpedFloat arrowDirection; + Couple networks; + Couple> openEnds; + Couple networksToUpdate; + + boolean reversed; + FluidStack providedFluid; public PumpTileEntity(TileEntityType typeIn) { super(typeIn); - arrowDirection = new InterpolatedChasingValue(); - arrowDirection.start(1); + arrowDirection = LerpedFloat.linear() + .startWithValue(1); + networksToUpdate = Couple.create(MutableBoolean::new); + openEnds = Couple.create(HashMap::new); + setProvidedFluid(FluidStack.EMPTY); + } + + @Override + public void initialize() { + super.initialize(); + reversed = getSpeed() < 0; } @Override public void tick() { super.tick(); + float speed = getSpeed(); + if (world.isRemote) { - float speed = getSpeed(); - if (speed != 0) - arrowDirection.target(Math.signum(speed)); - arrowDirection.tick(); + if (speed == 0) + return; + arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP); + arrowDirection.tickChaser(); + return; + } + + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return; + Direction face = blockState.get(PumpBlock.FACING); + MutableBoolean networkUpdated = new MutableBoolean(false); + + if (networks == null) { + networks = Couple.create(new FluidNetwork(), new FluidNetwork()); + networks.forEachWithContext((fn, front) -> { + BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite()); + fn.assemble(world, this, blockFace); + FluidPropagator.showBlockFace(blockFace) + .lineWidth(1 / 8f); + }); + networkUpdated.setTrue(); + } + + networksToUpdate.forEachWithContext((update, front) -> { + if (update.isFalse()) + return; + FluidNetwork activePipeNetwork = networks.get(front); + if (activePipeNetwork == null) + return; + BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite()); + activePipeNetwork.reAssemble(world, this, blockFace); + FluidPropagator.showBlockFace(blockFace) + .lineWidth(1 / 8f); + update.setFalse(); + networkUpdated.setTrue(); + }); + + if (networkUpdated.isTrue()) + return; + + networks.forEach(fn -> fn.tick(world, this)); + + if (speed == 0) + return; + if (speed < 0 != reversed) { + networks.forEachWithContext((fn, current) -> fn.clearFlows(world, true)); + reversed = speed < 0; + return; + } + + boolean pullingSide = isPullingOnSide(true); + float flowSpeed = Math.abs(speed) / 256f; + + networks.forEachWithContext((fn, front) -> { + boolean pulling = isPullingOnSide(front); + fn.tickFlows(world, this, pulling, flowSpeed); + openEnds.get(front) + .values() + .forEach(oep -> oep.tick(world, pulling)); + }); + + if (!networks.get(pullingSide) + .hasEndpoints()) { + setProvidedFluid(FluidStack.EMPTY); + return; + } + + if (networks.getFirst() + .hasEndpoints() + && networks.getSecond() + .hasEndpoints()) { + performTransfer(); + } + + } + + @Override + public void remove() { + super.remove(); + if (networks != null) + networks.forEachWithContext((fn, current) -> fn.clearFlows(world, false)); + } + + private void performTransfer() { + boolean input = isPullingOnSide(true); + Collection inputs = networks.get(input) + .getEndpoints(true); + Collection outputs = networks.get(!input) + .getEndpoints(false); + + int flowSpeed = getFluidTransferSpeed(); + FluidStack transfer = FluidStack.EMPTY; + for (boolean simulate : Iterate.trueAndFalse) { + FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE; + + List availableInputs = new ArrayList<>(inputs); + while (!availableInputs.isEmpty() && transfer.getAmount() < flowSpeed) { + int diff = flowSpeed - transfer.getAmount(); + int dividedTransfer = diff / availableInputs.size(); + int remainder = diff % availableInputs.size(); + + for (Iterator iterator = availableInputs.iterator(); iterator.hasNext();) { + int toTransfer = dividedTransfer; + if (remainder > 0) { + toTransfer++; + remainder--; + } + + FluidNetworkEndpoint ne = iterator.next(); + IFluidHandler handler = ne.provideHandler() + .orElse(null); + if (handler == null) { + iterator.remove(); + continue; + } + FluidStack drained = handler.drain(toTransfer, action); + if (drained.isEmpty()) { + iterator.remove(); + continue; + } + if (transfer.isFluidEqual(drained) || transfer.isEmpty()) { + if (drained.getAmount() < toTransfer) + iterator.remove(); + FluidStack copy = drained.copy(); + copy.setAmount(drained.getAmount() + transfer.getAmount()); + transfer = copy; + continue; + } + iterator.remove(); + continue; + } + + } + + List availableOutputs = new ArrayList<>(outputs); + while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) { + int dividedTransfer = transfer.getAmount() / availableOutputs.size(); + int remainder = transfer.getAmount() % availableOutputs.size(); + + for (Iterator iterator = availableOutputs.iterator(); iterator.hasNext();) { + FluidNetworkEndpoint ne = iterator.next(); + int toTransfer = dividedTransfer; + if (remainder > 0) { + toTransfer++; + remainder--; + } + + if (transfer.isEmpty()) + break; + IFluidHandler handler = ne.provideHandler() + .orElse(null); + if (handler == null) { + iterator.remove(); + continue; + } + + FluidStack divided = transfer.copy(); + divided.setAmount(toTransfer); + int fill = handler.fill(divided, action); + transfer.setAmount(transfer.getAmount() - fill); + if (fill < toTransfer) + iterator.remove(); + } + + } + + flowSpeed -= transfer.getAmount(); + transfer = FluidStack.EMPTY; } } + public int getFluidTransferSpeed() { + float rotationSpeed = Math.abs(getSpeed()); + int flowSpeed = (int) (rotationSpeed / 2f); + if (rotationSpeed != 0 && flowSpeed == 0) + flowSpeed = 1; + return flowSpeed; + } + + @Override + public void write(CompoundNBT compound, boolean clientPacket) { + compound.putBoolean("Reversed", reversed); + serializeOpenEnds(compound); + super.write(compound, clientPacket); + } + + @Override + protected void read(CompoundNBT compound, boolean clientPacket) { + reversed = compound.getBoolean("Reversed"); + deserializeOpenEnds(compound); + super.read(compound, clientPacket); + } + + public void updatePipesOnSide(Direction side) { + if (!isSideAccessible(side)) + return; + updatePipeNetwork(isFront(side)); + } + + protected boolean isFront(Direction side) { + if (networks == null) + return false; + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return false; + Direction front = blockState.get(PumpBlock.FACING); + boolean isFront = side == front; + return isFront; + } + + protected void updatePipeNetwork(boolean front) { + if (networks != null) + networks.get(front) + .clearFlows(world, true); + networksToUpdate.get(front) + .setTrue(); + if (getSpeed() == 0 || (isPullingOnSide(front)) && networks != null) + setProvidedFluid(FluidStack.EMPTY); + } + + public boolean isSideAccessible(Direction side) { + BlockState blockState = getBlockState(); + if (!(blockState.getBlock() instanceof PumpBlock)) + return false; + return blockState.get(PumpBlock.FACING) + .getAxis() == side.getAxis(); + } + + public boolean isPullingOnSide(boolean front) { + return front == reversed; + } + + public Map getOpenEnds(Direction side) { + return openEnds.get(isFront(side)); + } + + private void serializeOpenEnds(CompoundNBT compound) { + compound.put("OpenEnds", openEnds.serializeEach(m -> { + CompoundNBT compoundNBT = new CompoundNBT(); + ListNBT entries = new ListNBT(); + m.entrySet() + .forEach(e -> { + CompoundNBT innerCompound = new CompoundNBT(); + innerCompound.put("Pos", e.getKey() + .serializeNBT()); + e.getValue() + .writeToNBT(innerCompound); + entries.add(innerCompound); + }); + compoundNBT.put("Entries", entries); + return compoundNBT; + })); + } + + private void deserializeOpenEnds(CompoundNBT compound) { + openEnds = Couple.deserializeEach(compound.getList("OpenEnds", NBT.TAG_COMPOUND), c -> { + Map map = new HashMap<>(); + NBTHelper.iterateCompoundList(c.getList("Entries", NBT.TAG_COMPOUND), innerCompound -> { + BlockFace key = BlockFace.fromNBT(innerCompound.getCompound("Pos")); + OpenEndedPipe value = new OpenEndedPipe(key); + value.readNBT(innerCompound); + map.put(key, value); + }); + return map; + }); + + compound.put("OpenEnds", openEnds.serializeEach(m -> { + CompoundNBT compoundNBT = new CompoundNBT(); + ListNBT entries = new ListNBT(); + m.entrySet() + .forEach(e -> { + CompoundNBT innerCompound = new CompoundNBT(); + innerCompound.put("Pos", e.getKey() + .serializeNBT()); + e.getValue() + .writeToNBT(innerCompound); + entries.add(innerCompound); + }); + compoundNBT.put("Entries", entries); + return compoundNBT; + })); + } + + public void setProvidedFluid(FluidStack providedFluid) { + this.providedFluid = providedFluid; + } + } 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 f96fc63842..f7c36dbba1 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 @@ -118,8 +118,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); inputItemInventory.deserializeNBT(compound.getCompound("InputItems")); outputItemInventory.deserializeNBT(compound.getCompound("OutputItems")); if (compound.contains("fluids")) @@ -128,15 +128,14 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } @Override - public CompoundNBT write(CompoundNBT compound) { - super.write(compound); + public void write(CompoundNBT compound, boolean clientPacket) { + super.write(compound, clientPacket); compound.put("InputItems", inputItemInventory.serializeNBT()); compound.put("OutputItems", outputItemInventory.serializeNBT()); fluidInventory.ifPresent(combinedFuidHandler -> { ListNBT nbt = combinedFuidHandler.getListNBT(); compound.put("fluids", nbt); }); - return compound; } public void onEmptied() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java index c33559a344..dac3dc3083 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerTileEntity.java @@ -155,17 +155,17 @@ public class BlazeBurnerTileEntity extends SmartTileEntity { public void addBehaviours(List behaviours) {} @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("fuelLevel", activeFuel.ordinal()); compound.putInt("burnTimeRemaining", remainingBurnTime); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { activeFuel = FuelType.values()[compound.getInt("fuelLevel")]; remainingBurnTime = compound.getInt("burnTimeRemaining"); - super.read(compound); + super.read(compound, clientPacket); } /** diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java index 717436fd82..b52e47ee2e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java @@ -103,21 +103,21 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("InstructionIndex", currentInstruction); compound.putInt("InstructionDuration", currentInstructionDuration); compound.putInt("Timer", timer); compound.put("Instructions", Instruction.serializeAll(instructions)); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { currentInstruction = compound.getInt("InstructionIndex"); currentInstructionDuration = compound.getInt("InstructionDuration"); timer = compound.getInt("Timer"); instructions = Instruction.deserializeAll(compound.getList("Instructions", NBT.TAG_COMPOUND)); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java index dc6ae7376e..d19ce518db 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltTileEntity.java @@ -79,8 +79,7 @@ public class BeltTileEntity extends KineticTileEntity { @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); - behaviours.add(new DirectBeltInputBehaviour(this) - .setInsertionHandler(this::tryInsertingFromSide)); + behaviours.add(new DirectBeltInputBehaviour(this).setInsertionHandler(this::tryInsertingFromSide)); behaviours.add(new TransportedItemStackHandlerBehaviour(this, this::applyToAllItems) .withStackPlacement(this::getWorldPositionOf)); } @@ -175,7 +174,7 @@ public class BeltTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { if (controller != null) compound.put("Controller", NBTUtil.writeBlockPos(controller)); compound.putBoolean("IsController", isController()); @@ -186,23 +185,12 @@ public class BeltTileEntity extends KineticTileEntity { if (isController()) compound.put("Inventory", getInventory().write()); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void readClientUpdate(CompoundNBT tag) { - CasingType casingBefore = casing; - super.readClientUpdate(tag); - if (casingBefore != casing) { - requestModelDataUpdate(); - if (hasWorld()) - world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16); - } - } - - @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); if (compound.getBoolean("IsController")) controller = pos; @@ -219,7 +207,16 @@ public class BeltTileEntity extends KineticTileEntity { if (isController()) getInventory().read(compound.getCompound("Inventory")); + CasingType casingBefore = casing; casing = NBTHelper.readEnum(compound, "Casing", CasingType.class); + + if (!clientPacket) + return; + if (casingBefore == casing) + return; + requestModelDataUpdate(); + if (hasWorld()) + world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16); } @Override @@ -397,16 +394,17 @@ public class BeltTileEntity extends KineticTileEntity { BeltTileEntity nextBeltController = getControllerTE(); ItemStack inserted = transportedStack.stack; ItemStack empty = ItemStack.EMPTY; - + if (nextBeltController == null) return inserted; BeltInventory nextInventory = nextBeltController.getInventory(); - + TileEntity teAbove = world.getTileEntity(pos.up()); if (teAbove instanceof BrassTunnelTileEntity) { BrassTunnelTileEntity tunnelTE = (BrassTunnelTileEntity) teAbove; if (tunnelTE.hasDistributionBehaviour()) { - if (!tunnelTE.getStackToDistribute().isEmpty()) + if (!tunnelTE.getStackToDistribute() + .isEmpty()) return inserted; if (!tunnelTE.testFlapFilter(side.getOpposite(), inserted)) return inserted; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java index cc82735039..3cf1cc57a0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AbstractEncasedShaftBlock.java @@ -1,6 +1,9 @@ package com.simibubi.create.content.contraptions.relays.encased; +import javax.annotation.Nullable; + import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; + import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -11,8 +14,6 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorldReader; -import javax.annotation.Nullable; - @MethodsReturnNonnullByDefault public abstract class AbstractEncasedShaftBlock extends RotatedPillarKineticBlock { public AbstractEncasedShaftBlock(Properties properties) { @@ -30,7 +31,6 @@ public abstract class AbstractEncasedShaftBlock extends RotatedPillarKineticBloc } @Override - @SuppressWarnings("deprecation") public PushReaction getPushReaction(@Nullable BlockState state) { return PushReaction.PUSH_ONLY; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java index c86f923629..80d831b84b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/AdjustablePulleyTileEntity.java @@ -17,15 +17,15 @@ public class AdjustablePulleyTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("Signal", signal); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { signal = compound.getInt("Signal"); - super.read(compound); + super.read(compound, clientPacket); } public float getModifier() { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java index 54e7717b72..9e381f491b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/encased/GearshiftBlock.java @@ -15,10 +15,8 @@ import net.minecraft.state.BooleanProperty; import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorldReader; import net.minecraft.world.TickPriority; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java index 0e56be79f4..3969af7543 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/gauge/GaugeTileEntity.java @@ -21,17 +21,17 @@ public class GaugeTileEntity extends KineticTileEntity implements IHaveGoggleInf } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putFloat("Value", dialTarget); compound.putInt("Color", color); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { dialTarget = compound.getFloat("Value"); color = compound.getInt("Color"); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java index b423dadfaf..969fc6ab2b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/observer/BeltObserverTileEntity.java @@ -73,15 +73,15 @@ public class BeltObserverTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("TurnOff", turnOffTicks); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { turnOffTicks = compound.getInt("TurnOff"); - super.read(compound); + super.read(compound, clientPacket); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java index 123476662c..d48faab5ce 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BeltTunnelTileEntity.java @@ -52,38 +52,18 @@ public class BeltTunnelTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { ListNBT flapsNBT = new ListNBT(); for (Direction direction : flaps.keySet()) flapsNBT.add(IntNBT.of(direction.getIndex())); compound.put("Flaps", flapsNBT); - return super.write(compound); - } + super.write(compound, clientPacket); - @Override - public void read(CompoundNBT compound) { - Set newFlaps = new HashSet<>(6); - ListNBT flapsNBT = compound.getList("Flaps", NBT.TAG_INT); - for (INBT inbt : flapsNBT) - if (inbt instanceof IntNBT) - newFlaps.add(Direction.byIndex(((IntNBT) inbt).getInt())); - - for (Direction d : Iterate.directions) - if (!newFlaps.contains(d)) - flaps.remove(d); - else if (!flaps.containsKey(d)) - flaps.put(d, new InterpolatedChasingValue().start(.25f) - .target(0) - .withSpeed(.05f)); + if (!clientPacket) + return; - super.read(compound); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT tag) { - CompoundNBT writeToClient = super.writeToClient(tag); + flapsNBT = new ListNBT(); if (!flapsToSend.isEmpty()) { - ListNBT flapsNBT = new ListNBT(); for (Pair pair : flapsToSend) { CompoundNBT flap = new CompoundNBT(); flap.putInt("Flap", pair.getKey() @@ -91,22 +71,38 @@ public class BeltTunnelTileEntity extends SmartTileEntity { flap.putBoolean("FlapInward", pair.getValue()); flapsNBT.add(flap); } - writeToClient.put("TriggerFlaps", flapsNBT); + compound.put("TriggerFlaps", flapsNBT); flapsToSend.clear(); } - return writeToClient; } @Override - public void readClientUpdate(CompoundNBT tag) { - super.readClientUpdate(tag); - if (tag.contains("TriggerFlaps")) { - ListNBT flapsNBT = tag.getList("TriggerFlaps", NBT.TAG_COMPOUND); - for (INBT inbt : flapsNBT) { - CompoundNBT flap = (CompoundNBT) inbt; - Direction side = Direction.byIndex(flap.getInt("Flap")); - flap(side, flap.getBoolean("FlapInward")); - } + protected void read(CompoundNBT compound, boolean clientPacket) { + Set newFlaps = new HashSet<>(6); + ListNBT flapsNBT = compound.getList("Flaps", NBT.TAG_INT); + for (INBT inbt : flapsNBT) + if (inbt instanceof IntNBT) + newFlaps.add(Direction.byIndex(((IntNBT) inbt).getInt())); + + for (Direction d : Iterate.directions) + if (!newFlaps.contains(d)) + flaps.remove(d); + else if (!flaps.containsKey(d)) + flaps.put(d, new InterpolatedChasingValue().start(.25f) + .target(0) + .withSpeed(.05f)); + + super.read(compound, clientPacket); + + if (!clientPacket) + return; + if (!compound.contains("TriggerFlaps")) + return; + flapsNBT = compound.getList("TriggerFlaps", NBT.TAG_COMPOUND); + for (INBT inbt : flapsNBT) { + CompoundNBT flap = (CompoundNBT) inbt; + Direction side = Direction.byIndex(flap.getInt("Flap")); + flap(side, flap.getBoolean("FlapInward")); } } @@ -131,12 +127,12 @@ public class BeltTunnelTileEntity extends SmartTileEntity { if (!positive && shape == Shape.T_RIGHT) continue; } - + BlockState funnelState = world.getBlockState(getPos().offset(direction)); - if (funnelState.getBlock() instanceof BeltFunnelBlock) + if (funnelState.getBlock() instanceof BeltFunnelBlock) if (funnelState.get(BeltFunnelBlock.HORIZONTAL_FACING) == direction.getOpposite()) continue; - + flaps.put(direction, new InterpolatedChasingValue().start(.25f) .target(0) .withSpeed(.05f)); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java index 97b70ce995..53f6f312dc 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/belts/tunnel/BrassTunnelTileEntity.java @@ -328,7 +328,7 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("ConnectedLeft", connectedLeft); compound.putBoolean("ConnectedRight", connectedRight); @@ -344,14 +344,16 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { return nbt; })); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { + boolean wasConnectedLeft = connectedLeft; + boolean wasConnectedRight = connectedRight; + connectedLeft = compound.getBoolean("ConnectedLeft"); connectedRight = compound.getBoolean("ConnectedRight"); - stackToDistribute = ItemStack.read(compound.getCompound("StackToDistribute")); distributionProgress = compound.getFloat("DistributionProgress"); distributionDistanceLeft = compound.getInt("DistanceLeft"); @@ -362,14 +364,10 @@ public class BrassTunnelTileEntity extends BeltTunnelTileEntity { return Pair.of(pos, face); }); - super.read(compound); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - boolean wasConnectedLeft = connectedLeft; - boolean wasConnectedRight = connectedRight; - super.readClientUpdate(tag); + super.read(compound, clientPacket); + + if (!clientPacket) + return; if (wasConnectedLeft != connectedLeft || wasConnectedRight != connectedRight) { requestModelDataUpdate(); if (hasWorld()) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java index 0e65b0f997..18acba30a4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/chute/ChuteTileEntity.java @@ -277,22 +277,22 @@ public class ChuteTileEntity extends SmartTileEntity implements IHaveGoggleInfor } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.put("Item", item.serializeNBT()); compound.putFloat("ItemPosition", itemPosition.value); compound.putFloat("Pull", pull); compound.putFloat("Push", push); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { ItemStack previousItem = item; item = ItemStack.read(compound.getCompound("Item")); itemPosition.lastValue = itemPosition.value = compound.getFloat("ItemPosition"); pull = compound.getFloat("Pull"); push = compound.getFloat("Push"); - super.read(compound); + super.read(compound, clientPacket); if (hasWorld() && world.isRemote && !previousItem.equals(item, false) && !item.isEmpty()) { if (world.rand.nextInt(3) != 0) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java index c813c00c9e..6ee3adc327 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/depot/DepotTileEntity.java @@ -93,20 +93,20 @@ public class DepotTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { if (heldItem != null) compound.put("HeldItem", heldItem.serializeNBT()); compound.put("OutputBuffer", processingOutputBuffer.serializeNBT()); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { heldItem = null; if (compound.contains("HeldItem")) heldItem = TransportedItemStack.read(compound.getCompound("HeldItem")); processingOutputBuffer.deserializeNBT(compound.getCompound("OutputBuffer")); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AdjustableRepeaterTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/diodes/AdjustableRepeaterTileEntity.java index 96daf19943..7c4515a1c3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/diodes/AdjustableRepeaterTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/diodes/AdjustableRepeaterTileEntity.java @@ -43,17 +43,17 @@ public class AdjustableRepeaterTileEntity extends SmartTileEntity { } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { state = compound.getInt("State"); charging = compound.getBoolean("Charging"); - super.read(compound); + super.read(compound, clientPacket); } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("State", state); compound.putBoolean("Charging", charging); - return super.write(compound); + super.write(compound, clientPacket); } private int step(StepContext context) { diff --git a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java index 007898fe3b..d369d04688 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/funnel/FunnelTileEntity.java @@ -218,23 +218,23 @@ public class FunnelTileEntity extends SmartTileEntity { return getBlockState().getBlock() instanceof BeltFunnelBlock && getBlockState().get(BeltFunnelBlock.SHAPE) == Shape.RETRACTED; } - + @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - if (sendFlap != 0) { + protected void write(CompoundNBT compound, boolean clientPacket) { + super.write(compound, clientPacket); + if (clientPacket && sendFlap != 0) { compound.putInt("Flap", sendFlap); sendFlap = 0; } - return super.writeToClient(compound); } - + @Override - public void readClientUpdate(CompoundNBT tag) { - if (tag.contains("Flap")) { - int direction = tag.getInt("Flap"); + protected void read(CompoundNBT compound, boolean clientPacket) { + super.read(compound, clientPacket); + if (clientPacket && compound.contains("Flap")) { + int direction = compound.getInt("Flap"); flap.set(direction); } - super.readClientUpdate(tag); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateTileEntity.java index 18a3199549..e2e7a21619 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/inventories/AdjustableCrateTileEntity.java @@ -142,18 +142,18 @@ public class AdjustableCrateTileEntity extends CrateTileEntity implements INamed } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Main", true); compound.putInt("AllowedAmount", allowedAmount); compound.put("Inventory", inventory.serializeNBT()); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { allowedAmount = compound.getInt("AllowedAmount"); inventory.deserializeNBT(compound.getCompound("Inventory")); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 77be7ffc73..7b477ec191 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -272,8 +272,8 @@ public class ArmTileEntity extends KineticTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { - super.write(compound); + public void write(CompoundNBT compound, boolean clientPacket) { + super.write(compound, clientPacket); ListNBT pointsNBT = new ListNBT(); inputs.stream() @@ -288,32 +288,24 @@ public class ArmTileEntity extends KineticTileEntity { compound.put("HeldItem", heldItem.serializeNBT()); compound.putInt("TargetPointIndex", chasedPointIndex); compound.putFloat("MovementProgress", chasedPointProgress); - return compound; } @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - super.writeToClient(compound); - return compound; - } - - @Override - public void read(CompoundNBT compound) { - super.read(compound); + protected void read(CompoundNBT compound, boolean clientPacket) { + int previousIndex = chasedPointIndex; + Phase previousPhase = phase; + ListNBT interactionPointTagBefore = interactionPointTag; + + super.read(compound, clientPacket); heldItem = ItemStack.read(compound.getCompound("HeldItem")); phase = NBTHelper.readEnum(compound, "Phase", Phase.class); chasedPointIndex = compound.getInt("TargetPointIndex"); chasedPointProgress = compound.getFloat("MovementProgress"); interactionPointTag = compound.getList("InteractionPoints", NBT.TAG_COMPOUND); - } - - @Override - public void readClientUpdate(CompoundNBT tag) { - int previousIndex = chasedPointIndex; - Phase previousPhase = phase; - ListNBT interactionPointTagBefore = interactionPointTag; - super.readClientUpdate(tag); - + + if (!clientPacket) + return; + boolean ceiling = isOnCeiling(); if (interactionPointTagBefore == null || interactionPointTagBefore.size() != interactionPointTag.size()) updateInteractionPoints = true; diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java index 2e32a5f5e3..99558c5d1f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/AnalogLeverTileEntity.java @@ -23,18 +23,18 @@ public class AnalogLeverTileEntity extends SmartTileEntity implements IHaveGoggl } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putInt("State", state); compound.putInt("ChangeTimer", lastChange); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { state = compound.getInt("State"); lastChange = compound.getInt("ChangeTimer"); clientState.target(state); - super.read(compound); + super.read(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java index 45840b2465..65205b6b69 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/RedstoneLinkTileEntity.java @@ -64,18 +64,18 @@ public class RedstoneLinkTileEntity extends SmartTileEntity { } @Override - public CompoundNBT write(CompoundNBT compound) { + public void write(CompoundNBT compound, boolean clientPacket) { compound.putBoolean("Transmitter", transmitter); compound.putInt("Receive", getReceivedSignal()); compound.putBoolean("ReceivedChanged", receivedSignalChanged); compound.putInt("Transmit", transmittedSignal); - return super.write(compound); + super.write(compound, clientPacket); } @Override - public void read(CompoundNBT compound) { + protected void read(CompoundNBT compound, boolean clientPacket) { transmitter = compound.getBoolean("Transmitter"); - super.read(compound); + super.read(compound, clientPacket); receivedSignal = compound.getInt("Receive"); receivedSignalChanged = compound.getBoolean("ReceivedChanged"); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java index 3a1b924a3c..af7e59e8dd 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/StockpileSwitchTileEntity.java @@ -36,25 +36,23 @@ public class StockpileSwitchTileEntity extends SmartTileEntity { } @Override - public void read(CompoundNBT compound) { - + protected void read(CompoundNBT compound, boolean clientPacket) { onWhenAbove = compound.getFloat("OnAbove"); offWhenBelow = compound.getFloat("OffBelow"); currentLevel = compound.getFloat("Current"); powered = compound.getBoolean("Powered"); - super.read(compound); + super.read(compound, clientPacket); } @Override - public CompoundNBT write(CompoundNBT compound) { - + public void write(CompoundNBT compound, boolean clientPacket) { compound.putFloat("OnAbove", onWhenAbove); compound.putFloat("OffBelow", offWhenBelow); compound.putFloat("Current", currentLevel); compound.putBoolean("Powered", powered); - return super.write(compound); + super.write(compound, clientPacket); } public float getLevel() { diff --git a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java index bc73d43892..73e532dc4a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/item/filter/AbstractFilterScreen.java @@ -6,7 +6,6 @@ import static net.minecraft.util.text.TextFormatting.GRAY; import java.util.Collections; import java.util.List; -import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.content.logistics.item.filter.FilterScreenPacket.Option; import com.simibubi.create.foundation.gui.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.AllGuiTextures; @@ -20,7 +19,6 @@ import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import net.minecraft.client.gui.widget.Widget; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.text.ITextComponent; diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java index c28ad8bc90..d80dcea622 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonTileEntity.java @@ -7,9 +7,9 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltPart; import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; +import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; import com.simibubi.create.content.schematics.ItemRequirement; import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; @@ -162,19 +162,13 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } @Override - public void read(CompoundNBT compound) { - inventory.deserializeNBT(compound.getCompound("Inventory")); - - if (compound.contains("CurrentPos")) - currentPos = NBTUtil.readBlockPos(compound.getCompound("CurrentPos")); - - readClientUpdate(compound); - super.read(compound); - } - - @Override - public void readClientUpdate(CompoundNBT compound) { - + protected void read(CompoundNBT compound, boolean clientPacket) { + if (!clientPacket) { + inventory.deserializeNBT(compound.getCompound("Inventory")); + if (compound.contains("CurrentPos")) + currentPos = NBTUtil.readBlockPos(compound.getCompound("CurrentPos")); + } + // Gui information statusMsg = compound.getString("Status"); schematicProgress = compound.getFloat("Progress"); @@ -184,23 +178,24 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC blocksPlaced = compound.getInt("AmountPlaced"); blocksToPlace = compound.getInt("AmountToPlace"); printingEntityIndex = compound.getInt("EntityProgress"); - + missingItem = null; if (compound.contains("MissingItem")) missingItem = ItemStack.read(compound.getCompound("MissingItem")); - + // Settings CompoundNBT options = compound.getCompound("Options"); replaceMode = options.getInt("ReplaceMode"); skipMissing = options.getBoolean("SkipMissing"); replaceTileEntities = options.getBoolean("ReplaceTileEntities"); - + // Printer & Flying Blocks if (compound.contains("Target")) target = NBTUtil.readBlockPos(compound.getCompound("Target")); if (compound.contains("FlyingBlocks")) readFlyingBlocks(compound); + super.read(compound, clientPacket); } protected void readFlyingBlocks(CompoundNBT compound) { @@ -239,22 +234,16 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } @Override - public CompoundNBT write(CompoundNBT compound) { - compound.put("Inventory", inventory.serializeNBT()); - - if (state == State.RUNNING) { - compound.putBoolean("Running", true); - if (currentPos != null) - compound.put("CurrentPos", NBTUtil.writeBlockPos(currentPos)); + public void write(CompoundNBT compound, boolean clientPacket) { + if (!clientPacket) { + compound.put("Inventory", inventory.serializeNBT()); + if (state == State.RUNNING) { + compound.putBoolean("Running", true); + if (currentPos != null) + compound.put("CurrentPos", NBTUtil.writeBlockPos(currentPos)); + } } - - writeToClient(compound); - return super.write(compound); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - + // Gui information compound.putFloat("Progress", schematicProgress); compound.putFloat("PaperProgress", bookPrintingProgress); @@ -264,17 +253,17 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC compound.putInt("AmountPlaced", blocksPlaced); compound.putInt("AmountToPlace", blocksToPlace); compound.putInt("EntityProgress", printingEntityIndex); - + if (missingItem != null) compound.put("MissingItem", missingItem.serializeNBT()); - + // Settings CompoundNBT options = new CompoundNBT(); options.putInt("ReplaceMode", replaceMode); options.putBoolean("SkipMissing", skipMissing); options.putBoolean("ReplaceTileEntities", replaceTileEntities); compound.put("Options", options); - + // Printer & Flying Blocks if (target != null) compound.put("Target", NBTUtil.writeBlockPos(target)); @@ -283,7 +272,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC tagBlocks.add(b.serializeNBT()); compound.put("FlyingBlocks", tagBlocks); - return compound; + super.write(compound, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/config/CFluids.java b/src/main/java/com/simibubi/create/foundation/config/CFluids.java index 580fec6adc..d90eaa7a4f 100644 --- a/src/main/java/com/simibubi/create/foundation/config/CFluids.java +++ b/src/main/java/com/simibubi/create/foundation/config/CFluids.java @@ -4,6 +4,7 @@ public class CFluids extends ConfigBase { public ConfigInt fluidTankCapacity = i(8, 1, "fluidTankCapacity", Comments.buckets, Comments.fluidTankCapacity); public ConfigInt fluidTankMaxHeight = i(32, 1, "fluidTankMaxHeight", Comments.blocks, Comments.fluidTankMaxHeight); + public ConfigInt mechanicalPumpRange = i(16, 1, "mechanicalPumpRange", Comments.blocks, Comments.mechanicalPumpRange); @Override public String getName() { @@ -15,6 +16,7 @@ public class CFluids extends ConfigBase { static String buckets = "[in Buckets]"; static String fluidTankCapacity = "The amount of liquid a tank can hold per block."; static String fluidTankMaxHeight = "The maximum height a fluid tank can reach."; + static String mechanicalPumpRange = "The maximum distance a mechanical pump can push or pull liquids on either side."; } } diff --git a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java index ad9fb00a6a..edbf986bb4 100644 --- a/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java +++ b/src/main/java/com/simibubi/create/foundation/fluid/FluidHelper.java @@ -2,7 +2,10 @@ package com.simibubi.create.foundation.fluid; import javax.annotation.Nullable; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.ForgeFlowingFluid; import net.minecraftforge.fluids.capability.IFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction; import net.minecraftforge.fluids.capability.IFluidHandlerItem; @@ -13,6 +16,34 @@ public class FluidHelper { ITEM_TO_TANK, TANK_TO_ITEM; } + public static boolean isWater(Fluid fluid) { + return convertToStill(fluid) == Fluids.WATER; + } + + public static boolean isLava(Fluid fluid) { + return convertToStill(fluid) == Fluids.LAVA; + } + + public static Fluid convertToFlowing(Fluid fluid) { + if (fluid == Fluids.WATER) + return Fluids.FLOWING_WATER; + if (fluid == Fluids.LAVA) + return Fluids.FLOWING_LAVA; + if (fluid instanceof ForgeFlowingFluid) + return ((ForgeFlowingFluid) fluid).getFlowingFluid(); + return fluid; + } + + public static Fluid convertToStill(Fluid fluid) { + if (fluid == Fluids.FLOWING_WATER) + return Fluids.WATER; + if (fluid == Fluids.FLOWING_LAVA) + return Fluids.LAVA; + if (fluid instanceof ForgeFlowingFluid) + return ((ForgeFlowingFluid) fluid).getStillFluid(); + return fluid; + } + @Nullable public static FluidExchange exchange(IFluidHandler fluidTank, IFluidHandlerItem fluidItem, FluidExchange preferred, int maxAmount) { diff --git a/src/main/java/com/simibubi/create/foundation/fluid/FluidRenderer.java b/src/main/java/com/simibubi/create/foundation/fluid/FluidRenderer.java index 4e5e7c41e3..905a0d273c 100644 --- a/src/main/java/com/simibubi/create/foundation/fluid/FluidRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/fluid/FluidRenderer.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.fluid; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack.Entry; import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.MatrixStacker; @@ -62,8 +63,9 @@ public class FluidRenderer { .translateBack(center); boolean X = side.getAxis() == Axis.X; + int darkColor = ColorHelper.mixColors(color, 0xff000011, 1/4f); renderTiledHorizontalFace(X ? xMax : zMax, side, X ? zMin : xMin, yMin, X ? zMax : xMax, yMax, builder, - ms, light, color, fluidTexture); + ms, light, darkColor, fluidTexture); ms.pop(); continue; diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/PosBoundSmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/tileEntity/PosBoundSmartTileEntity.java deleted file mode 100644 index 2a3da1db6f..0000000000 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/PosBoundSmartTileEntity.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.simibubi.create.foundation.tileEntity; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.math.BlockPos; - -public abstract class PosBoundSmartTileEntity extends SmartTileEntity { - - private boolean newPositionVisited; - - public PosBoundSmartTileEntity(TileEntityType tileEntityTypeIn) { - super(tileEntityTypeIn); - newPositionVisited = true; - } - - @Override - public void initialize() { - if (!world.isRemote && newPositionVisited) { - newPositionVisited = false; - initInNewPosition(); - } - super.initialize(); - } - - @Override - public void read(CompoundNBT compound) { - long positionInTag = new BlockPos(compound.getInt("x"), compound.getInt("y"), compound.getInt("z")).toLong(); - long positionKey = compound.getLong("BoundPosition"); - - newPositionVisited = false; - if (!hasWorld() || !world.isRemote) { - if (positionInTag != positionKey) { - removePositionDependentData(compound); - newPositionVisited = true; - } - } - - super.read(compound); - } - - /** - * Server-only. When this TE realizes, that it's reading its tag in a different - * position, it should remove all position dependent information here. - * - * @param nbt - */ - protected void removePositionDependentData(CompoundNBT nbt) { - - } - - /** - * Server-only. When a TE has been created or moved, it will call this before the - * regular init. - */ - protected void initInNewPosition() { - - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java index eeb6663ce8..25c74b7d7f 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/SmartTileEntity.java @@ -38,8 +38,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka * Gets called just before reading tile data for behaviours. Register anything * here that depends on your custom te data. */ - public void addBehavioursDeferred(List behaviours) { - } + public void addBehavioursDeferred(List behaviours) {} @Override public void tick() { @@ -53,44 +52,61 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka lazyTick(); } - behaviours.values().forEach(TileEntityBehaviour::tick); + behaviours.values() + .forEach(TileEntityBehaviour::tick); } public void initialize() { - behaviours.values().forEach(TileEntityBehaviour::initialize); + behaviours.values() + .forEach(TileEntityBehaviour::initialize); lazyTick(); } - public void updateClient(CompoundNBT compound) { - behaviours.values().forEach(tb -> tb.updateClient(compound)); + @Override + public final CompoundNBT write(CompoundNBT compound) { + write(compound, false); + return compound; } @Override - public CompoundNBT write(CompoundNBT compound) { - behaviours.values().forEach(tb -> tb.writeNBT(compound)); - return super.write(compound); + public final CompoundNBT writeToClient(CompoundNBT compound) { + write(compound, true); + return compound; + } + + @Override + public final void readClientUpdate(CompoundNBT tag) { + read(tag, true); } @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - behaviours.values().forEach(tb -> tb.writeToClient(compound)); - return super.writeToClient(compound); + public final void read(CompoundNBT tag) { + read(tag, false); } - @Override - public void read(CompoundNBT compound) { + /** + * Hook only these in future subclasses of STE + */ + protected void read(CompoundNBT compound, boolean clientPacket) { if (firstNbtRead) { firstNbtRead = false; ArrayList list = new ArrayList<>(); addBehavioursDeferred(list); list.forEach(b -> behaviours.put(b.getType(), b)); } - super.read(compound); - forEachBehaviour(tb -> tb.readNBT(compound)); - - if (world != null && world.isRemote) - updateClient(compound); + behaviours.values() + .forEach(tb -> tb.read(compound, clientPacket)); + } + + + /** + * Hook only these in future subclasses of STE + */ + protected void write(CompoundNBT compound, boolean clientPacket) { + super.write(compound); + behaviours.values() + .forEach(tb -> tb.write(compound, clientPacket)); } @Override @@ -107,12 +123,13 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka public void lazyTick() { } - + protected void forEachBehaviour(Consumer action) { - behaviours.values().forEach(tb -> { - if (!tb.isPaused()) - action.accept(tb); - }); + behaviours.values() + .forEach(tb -> { + if (!tb.isPaused()) + action.accept(tb); + }); } protected void putBehaviour(TileEntityBehaviour behaviour) { diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java index c6aa76d99a..dd89490aa6 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/TileEntityBehaviour.java @@ -37,15 +37,11 @@ public abstract class TileEntityBehaviour { } - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { } - - public void updateClient(CompoundNBT nbt) { - - } - - public void writeNBT(CompoundNBT nbt) { + + public void write(CompoundNBT nbt, boolean clientPacket) { } @@ -111,8 +107,4 @@ public abstract class TileEntityBehaviour { return ste.getBehaviour(type); } - public CompoundNBT writeToClient(CompoundNBT compound) { - return compound; - } - } diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringBehaviour.java index 9dbffb81a9..79148ad8a1 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/FilteringBehaviour.java @@ -52,30 +52,26 @@ public class FilteringBehaviour extends TileEntityBehaviour { } @Override - public void writeNBT(CompoundNBT nbt) { + public void write(CompoundNBT nbt, boolean clientPacket) { nbt.put("Filter", getFilter().serializeNBT()); nbt.putInt("FilterAmount", count); - super.writeNBT(nbt); + + if (clientPacket && forceClientState) { + nbt.putBoolean("ForceScrollable", true); + forceClientState = false; + } + super.write(nbt, clientPacket); } @Override - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { filter = ItemStack.read(nbt.getCompound("Filter")); count = nbt.getInt("FilterAmount"); if (nbt.contains("ForceScrollable")) { scrollableValue = count; ticksUntilScrollPacket = -1; } - super.readNBT(nbt); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - if (forceClientState) { - compound.putBoolean("ForceScrollable", true); - forceClientState = false; - } - return super.writeToClient(compound); + super.read(nbt, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java index 7dc6bf4e3a..93127fd132 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/filtering/SidedFilteringBehaviour.java @@ -35,12 +35,12 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { sidedFilters = new IdentityHashMap<>(); updateFilterPresence(); } - + @Override public void initialize() { super.initialize(); } - + public FilteringBehaviour get(Direction side) { return sidedFilters.get(side); } @@ -59,40 +59,27 @@ public class SidedFilteringBehaviour extends FilteringBehaviour { } @Override - public void writeNBT(CompoundNBT nbt) { + public void write(CompoundNBT nbt, boolean clientPacket) { nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> { CompoundNBT compound = new CompoundNBT(); compound.putInt("Side", entry.getKey() .getIndex()); entry.getValue() - .writeNBT(compound); + .write(compound, clientPacket); return compound; })); - super.writeNBT(nbt); + super.write(nbt, clientPacket); } @Override - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { NBTHelper.iterateCompoundList(nbt.getList("Filters", NBT.TAG_COMPOUND), compound -> { Direction face = Direction.byIndex(compound.getInt("Side")); if (sidedFilters.containsKey(face)) sidedFilters.get(face) - .readNBT(compound); + .read(compound, clientPacket); }); - super.readNBT(nbt); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT nbt) { - nbt.put("Filters", NBTHelper.writeCompoundList(sidedFilters.entrySet(), entry -> { - CompoundNBT compound = new CompoundNBT(); - compound.putInt("Side", entry.getKey() - .getIndex()); - entry.getValue() - .writeToClient(compound); - return compound; - })); - return super.writeToClient(nbt); + super.read(nbt, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/SingleTargetAutoExtractingBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/SingleTargetAutoExtractingBehaviour.java index 763b830344..3c2f267973 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/SingleTargetAutoExtractingBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/inventory/SingleTargetAutoExtractingBehaviour.java @@ -33,15 +33,15 @@ public class SingleTargetAutoExtractingBehaviour extends AutoExtractingBehaviour } @Override - public void writeNBT(CompoundNBT nbt) { + public void write(CompoundNBT nbt, boolean clientPacket) { nbt.putBoolean("Advantage", advantageOnNextSync); - super.writeNBT(nbt); + super.write(nbt, clientPacket); } @Override - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { advantageOnNextSync = nbt.getBoolean("Advantage"); - super.readNBT(nbt); + super.read(nbt, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkBehaviour.java index 6d96d6a9b7..651fd7828d 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/linked/LinkBehaviour.java @@ -116,26 +116,26 @@ public class LinkBehaviour extends TileEntityBehaviour { } @Override - public void writeNBT(CompoundNBT compound) { - super.writeNBT(compound); - compound.put("FrequencyFirst", frequencyFirst.getStack() + public void write(CompoundNBT nbt, boolean clientPacket) { + super.write(nbt, clientPacket); + nbt.put("FrequencyFirst", frequencyFirst.getStack() .write(new CompoundNBT())); - compound.put("FrequencyLast", frequencyLast.getStack() + nbt.put("FrequencyLast", frequencyLast.getStack() .write(new CompoundNBT())); - compound.putLong("LastKnownPosition", tileEntity.getPos() + nbt.putLong("LastKnownPosition", tileEntity.getPos() .toLong()); } @Override - public void readNBT(CompoundNBT compound) { + public void read(CompoundNBT nbt, boolean clientPacket) { long positionInTag = tileEntity.getPos() .toLong(); - long positionKey = compound.getLong("LastKnownPosition"); + long positionKey = nbt.getLong("LastKnownPosition"); newPosition = positionInTag != positionKey; - super.readNBT(compound); - frequencyFirst = new Frequency(ItemStack.read(compound.getCompound("FrequencyFirst"))); - frequencyLast = new Frequency(ItemStack.read(compound.getCompound("FrequencyLast"))); + super.read(nbt, clientPacket); + frequencyFirst = new Frequency(ItemStack.read(nbt.getCompound("FrequencyFirst"))); + frequencyLast = new Frequency(ItemStack.read(nbt.getCompound("FrequencyLast"))); } public void setFrequency(boolean first, ItemStack stack) { diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueBehaviour.java index a9585d8834..9f0f3c0890 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/scrollvalue/ScrollValueBehaviour.java @@ -51,28 +51,23 @@ public class ScrollValueBehaviour extends TileEntityBehaviour { } @Override - public void writeNBT(CompoundNBT nbt) { + public void write(CompoundNBT nbt, boolean clientPacket) { nbt.putInt("ScrollValue", value); - super.writeNBT(nbt); + if (clientPacket && forceClientState) { + nbt.putBoolean("ForceScrollable", true); + forceClientState = false; + } + super.write(nbt, clientPacket); } @Override - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { value = nbt.getInt("ScrollValue"); if (nbt.contains("ForceScrollable")) { ticksUntilScrollPacket = -1; scrollableValue = value; } - super.readNBT(nbt); - } - - @Override - public CompoundNBT writeToClient(CompoundNBT compound) { - if (forceClientState) { - compound.putBoolean("ForceScrollable", true); - forceClientState = false; - } - return super.writeToClient(compound); + super.read(nbt, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/simple/DeferralBehaviour.java b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/simple/DeferralBehaviour.java index b9a195aa74..59db72bcfd 100644 --- a/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/simple/DeferralBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/behaviour/simple/DeferralBehaviour.java @@ -21,15 +21,15 @@ public class DeferralBehaviour extends TileEntityBehaviour { } @Override - public void writeNBT(CompoundNBT nbt) { + public void write(CompoundNBT nbt, boolean clientPacket) { nbt.putBoolean("NeedsUpdate", needsUpdate); - super.writeNBT(nbt); + super.write(nbt, clientPacket); } @Override - public void readNBT(CompoundNBT nbt) { + public void read(CompoundNBT nbt, boolean clientPacket) { needsUpdate = nbt.getBoolean("NeedsUpdate"); - super.readNBT(nbt); + super.read(nbt, clientPacket); } @Override diff --git a/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java b/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java index f42a9f6c0f..9884e71c41 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java @@ -1,20 +1,9 @@ package com.simibubi.create.foundation.utility; -import com.mojang.blaze3d.matrix.MatrixStack; - -import net.minecraft.client.renderer.Vector3f; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; public class AngleHelper { - - @OnlyIn(Dist.CLIENT) - public static void applyRotation(Direction direction, MatrixStack ms) { - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(AngleHelper.horizontalAngle(direction))); - ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(AngleHelper.verticalAngle(direction))); - } public static float horizontalAngle(Direction facing) { float angle = facing.getHorizontalAngle(); @@ -39,8 +28,8 @@ public class AngleHelper { return (float) (angle * 180 / Math.PI); } - public static float angleLerp(float pct, float current, float target) { - return current + getShortestAngleDiff(current, target) * pct; + public static float angleLerp(double pct, double current, double target) { + return (float) (current + getShortestAngleDiff(current, target) * pct); } public static float getShortestAngleDiff(double current, double target) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/BlockFace.java b/src/main/java/com/simibubi/create/foundation/utility/BlockFace.java new file mode 100644 index 0000000000..272c6adc8a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/BlockFace.java @@ -0,0 +1,52 @@ +package com.simibubi.create.foundation.utility; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +public class BlockFace extends Pair { + + public BlockFace(BlockPos first, Direction second) { + super(first, second); + } + + public boolean isEquivalent(BlockFace other) { + if (equals(other)) + return true; + return getConnectedPos().equals(other.getPos()) && getPos().equals(other.getConnectedPos()); + } + + public BlockPos getPos() { + return getFirst(); + } + + public Direction getFace() { + return getSecond(); + } + + public Direction getOppositeFace() { + return getSecond().getOpposite(); + } + + public BlockFace getOpposite() { + return new BlockFace(getConnectedPos(), getOppositeFace()); + } + + public BlockPos getConnectedPos() { + return getPos().offset(getFace()); + } + + public CompoundNBT serializeNBT() { + CompoundNBT compoundNBT = new CompoundNBT(); + compoundNBT.put("Pos", NBTUtil.writeBlockPos(getPos())); + NBTHelper.writeEnum(compoundNBT, "Face", getFace()); + return compoundNBT; + } + + public static BlockFace fromNBT(CompoundNBT compound) { + return new BlockFace(NBTUtil.readBlockPos(compound.getCompound("Pos")), + NBTHelper.readEnum(compound, "Face", Direction.class)); + } + +} 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 5645c30e68..fd391dbefc 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Couple.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Couple.java @@ -1,38 +1,49 @@ package com.simibubi.create.foundation.utility; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; + public class Couple extends Pair { private static Couple TRUE_AND_FALSE = Couple.create(true, false); - + protected Couple(T first, T second) { super(first, second); } - + public static Couple create(T first, T second) { return new Couple<>(first, second); } - + + public static Couple create(Supplier factory) { + return new Couple<>(factory.get(), factory.get()); + } + public T get(boolean first) { return first ? getFirst() : getSecond(); } - + public void set(boolean first, T value) { if (first) setFirst(value); else setSecond(value); } - + @Override public Couple copy() { return create(first, second); } - + public Couple map(Function function) { return Couple.create(function.apply(first), function.apply(second)); } @@ -41,11 +52,11 @@ public class Couple extends Pair { setFirst(function.apply(getFirst())); setSecond(function.apply(getSecond())); } - + public void replaceWithContext(BiFunction function) { replaceWithParams(function, TRUE_AND_FALSE); } - + public void replaceWithParams(BiFunction function, Couple values) { setFirst(function.apply(getFirst(), values.getFirst())); setSecond(function.apply(getSecond(), values.getSecond())); @@ -55,18 +66,27 @@ public class Couple extends Pair { consumer.accept(getFirst()); consumer.accept(getSecond()); } - + public void forEachWithContext(BiConsumer consumer) { forEachWithParams(consumer, TRUE_AND_FALSE); } - + public void forEachWithParams(BiConsumer function, Couple values) { function.accept(getFirst(), values.getFirst()); function.accept(getSecond(), values.getSecond()); } - + public Couple swap() { return Couple.create(second, first); } - + + public ListNBT serializeEach(Function serializer) { + return NBTHelper.writeCompoundList(ImmutableList.of(first, second), serializer); + } + + public static Couple deserializeEach(ListNBT list, Function deserializer) { + List readCompoundList = NBTHelper.readCompoundList(list, deserializer); + return new Couple<>(readCompoundList.get(0), readCompoundList.get(1)); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java b/src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java new file mode 100644 index 0000000000..073f2fc07a --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/LerpedFloat.java @@ -0,0 +1,128 @@ +package com.simibubi.create.foundation.utility; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.MathHelper; + +// Can replace all Interpolated value classes +// InterpolatedChasingValue, InterpolatedValue, InterpolatedChasingAngle, InterpolatedAngle +public class LerpedFloat { + + Interpolater interpolater; + float previousValue; + float value; + + Chaser chaseFunction; + float chaseTarget; + float chaseSpeed; + + boolean forcedSync; + + public LerpedFloat(Interpolater interpolater) { + this.interpolater = interpolater; + startWithValue(0); + forcedSync = true; + } + + public static LerpedFloat linear() { + return new LerpedFloat((p, c, t) -> (float) MathHelper.lerp(p, c, t)); + } + + public static LerpedFloat angular() { + return new LerpedFloat(AngleHelper::angleLerp); + } + + public LerpedFloat startWithValue(double value) { + float f = (float) value; + this.previousValue = f; + this.chaseTarget = f; + this.value = f; + return this; + } + + public LerpedFloat chase(double value, double speed, Chaser chaseFunction) { + this.chaseTarget = (float) value; + this.chaseSpeed = (float) speed; + this.chaseFunction = chaseFunction; + return this; + } + + public boolean updateChaseSpeed(double speed) { + float prevSpeed = this.chaseSpeed; + this.chaseSpeed = (float) speed; + return !MathHelper.epsilonEquals(prevSpeed, speed); + } + + public void tickChaser() { + previousValue = value; + if (chaseFunction == null) + return; + if (MathHelper.epsilonEquals((double) value, chaseTarget)) { + value = chaseTarget; + return; + } + value = chaseFunction.chase(value, chaseSpeed, chaseTarget); + } + + public void setValue(double value) { + this.previousValue = this.value; + this.value = (float) value; + } + + public float getValue() { + return getValue(1); + } + + public float getValue(float partialTicks) { + return MathHelper.lerp(partialTicks, previousValue, value); + } + + public float getChaseTarget() { + return chaseTarget; + } + + public void forceNextSync() { + forcedSync = true; + } + + public CompoundNBT writeNBT() { + CompoundNBT compoundNBT = new CompoundNBT(); + compoundNBT.putFloat("Speed", chaseSpeed); + compoundNBT.putFloat("Target", chaseTarget); + compoundNBT.putFloat("Value", value); + if (forcedSync) + compoundNBT.putBoolean("Force", true); + forcedSync = false; + return compoundNBT; + } + + public void readNBT(CompoundNBT compoundNBT, boolean clientPacket) { + if (!clientPacket || compoundNBT.contains("Force")) + startWithValue(compoundNBT.getFloat("Value")); + readChaser(compoundNBT); + } + + private void readChaser(CompoundNBT compoundNBT) { + chaseSpeed = compoundNBT.getFloat("Speed"); + chaseTarget = compoundNBT.getFloat("Target"); + } + + @FunctionalInterface + public interface Interpolater { + float interpolate(double progress, double current, double target); + } + + @FunctionalInterface + public interface Chaser { + + public static final Chaser IDLE = (c, s, t) -> (float) c; + public static final Chaser EXP = exp(Double.MAX_VALUE); + public static final Chaser LINEAR = (c, s, t) -> (float) (c + MathHelper.clamp(t - c, -s, s)); + + public static Chaser exp(double maxEffectiveSpeed) { + return (c, s, t) -> (float) (c + MathHelper.clamp((t - c) * s, -maxEffectiveSpeed, maxEffectiveSpeed)); + } + + float chase(double current, double speed, double target); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index 99fbffc69e..d5cac157ae 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -68,10 +68,14 @@ public class VecHelper { vec.z + (r.nextFloat() - .5f) * 2 * radius); } - public static Vec3d planeByNormal(Vec3d vec) { + public static Vec3d axisAlingedPlaneOf(Vec3d vec) { vec = vec.normalize(); return new Vec3d(1, 1, 1).subtract(Math.abs(vec.x), Math.abs(vec.y), Math.abs(vec.z)); } + + public static Vec3d axisAlingedPlaneOf(Direction face) { + return axisAlingedPlaneOf(new Vec3d(face.getDirectionVec())); + } public static ListNBT writeNBT(Vec3d vec) { ListNBT listnbt = new ListNBT(); @@ -114,12 +118,17 @@ public class VecHelper { .scale(maxLength) : vec; } + public static Vec3d clampComponentWise(Vec3d vec, float maxLength) { + return new Vec3d(MathHelper.clamp(vec.x, -maxLength, maxLength), MathHelper.clamp(vec.y, -maxLength, maxLength), + MathHelper.clamp(vec.z, -maxLength, maxLength)); + } + public static Vec3d project(Vec3d vec, Vec3d ontoVec) { if (ontoVec.equals(Vec3d.ZERO)) return Vec3d.ZERO; return ontoVec.scale(vec.dotProduct(ontoVec) / ontoVec.lengthSquared()); } - + @Nullable public static Vec3d intersectSphere(Vec3d origin, Vec3d lineDirection, Vec3d sphereCenter, double radius) { if (lineDirection.equals(Vec3d.ZERO)) diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java index 014d8c8ace..06f7beb9f8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java @@ -58,7 +58,7 @@ public class BlockClusterOutline extends Outline { Vec3d center = VecHelper.getCenterOf(pos); Vec3d offset = new Vec3d(face.getDirectionVec()); - Vec3d plane = VecHelper.planeByNormal(offset); + Vec3d plane = VecHelper.axisAlingedPlaneOf(offset); Axis axis = face.getAxis(); offset = offset.scale(1 / 2f + 1 / 64d); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java index a8dcb297ac..d7ad3d190a 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java @@ -61,7 +61,7 @@ public abstract class Outline { float lineWidth = params.getLineWidth(); Vec3d extension = diff.normalize() .scale(lineWidth / 2); - Vec3d plane = VecHelper.planeByNormal(diff); + Vec3d plane = VecHelper.axisAlingedPlaneOf(diff); Direction face = Direction.getFacingFromVector(diff.x, diff.y, diff.z); Axis axis = face.getAxis(); diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java index 67ee4f80b2..07c7a55cfa 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outliner.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.utility.outliner; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -110,7 +111,7 @@ public class Outliner { // Maintenance public Outliner() { - outlines = new HashMap<>(); + outlines = Collections.synchronizedMap(new HashMap<>()); } public void tickOutlines() { diff --git a/src/main/resources/assets/create/lang/default/advancements.json b/src/main/resources/assets/create/lang/default/advancements.json index 9efbca048d..ea54a7ea97 100644 --- a/src/main/resources/assets/create/lang/default/advancements.json +++ b/src/main/resources/assets/create/lang/default/advancements.json @@ -39,7 +39,7 @@ "advancement.create.electron_tube": "Beep boop", "advancement.create.electron_tube.desc": "Make some Electron Tubes, useful in crafting less primitive machinery.", "advancement.create.mechanical_saw": "Stationary Chopping", - "advancement.create.mechanical_saw.desc": "Place and power a Mechanical mechanical_saw", + "advancement.create.mechanical_saw.desc": "Place and power a Mechanical Saw", "advancement.create.basin": "Basin Operation", "advancement.create.basin.desc": "Place a basin and try throwing items into it.", "advancement.create.mixer": "Mixin' it Up", diff --git a/src/main/resources/assets/create/lang/default/messages.json b/src/main/resources/assets/create/lang/default/messages.json index bd91c8762b..7868655e1a 100644 --- a/src/main/resources/assets/create/lang/default/messages.json +++ b/src/main/resources/assets/create/lang/default/messages.json @@ -7,7 +7,7 @@ "death.attack.create.fan_fire": "%1$s was burned to death by hot air", "death.attack.create.fan_lava": "%1$s was burned to death by lava fan", "death.attack.create.mechanical_drill": "%1$s was impaled by Mechanical mechanical_drill", - "death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical mechanical_saw", + "death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical Saw", "death.attack.create.cuckoo_clock_explosion": "%1$s was blown up by tampered cuckoo clock", "create.block.deployer.damage_source_name": "a rogue Deployer", "create.block.cart_assembler.invalid": "Place your Cart Assembler on a rail block", @@ -23,7 +23,7 @@ "create.recipe.pressing": "Pressing", "create.recipe.mixing": "Mixing", "create.recipe.packing": "Compacting", - "create.recipe.mechanical_sawing": "mechanical_sawing", + "create.recipe.mechanical_sawing": "Sawing", "create.recipe.mechanical_crafting": "Mechanical Crafting", "create.recipe.block_cutting": "Block Cutting", "create.recipe.blockzapper_upgrade": "Handheld Blockzapper", diff --git a/src/main/resources/assets/create/models/block/mechanical_pump/block.json b/src/main/resources/assets/create/models/block/mechanical_pump/block.json index 0d3583084c..859edf2944 100644 --- a/src/main/resources/assets/create/models/block/mechanical_pump/block.json +++ b/src/main/resources/assets/create/models/block/mechanical_pump/block.json @@ -13,10 +13,10 @@ "to": [12, 12, 12], "rotation": {"angle": 0, "axis": "y", "origin": [8, 7, 8]}, "faces": { - "north": {"uv": [0, 8, 4, 12], "texture": "#3"}, - "east": {"uv": [0, 8, 4, 12], "texture": "#3"}, - "south": {"uv": [0, 8, 4, 12], "texture": "#3"}, - "west": {"uv": [0, 8, 4, 12], "texture": "#3"} + "north": {"uv": [0, 6, 4, 10], "texture": "#3"}, + "east": {"uv": [0, 6, 4, 10], "texture": "#3"}, + "south": {"uv": [0, 6, 4, 10], "texture": "#3"}, + "west": {"uv": [0, 6, 4, 10], "texture": "#3"} } }, { diff --git a/src/main/resources/assets/create/models/block/mechanical_pump/cog.json b/src/main/resources/assets/create/models/block/mechanical_pump/cog.json index 615d7cf839..aa1befa09e 100644 --- a/src/main/resources/assets/create/models/block/mechanical_pump/cog.json +++ b/src/main/resources/assets/create/models/block/mechanical_pump/cog.json @@ -76,20 +76,6 @@ "up": {"uv": [0, 6, 6, 8.5], "rotation": 180, "texture": "#5"}, "down": {"uv": [0, 6, 6, 8.5], "texture": "#5"} } - }, - { - "name": "GearCaseOuter", - "from": [4, 4, 4.5], - "to": [12, 12, 11.5], - "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 6.5]}, - "faces": { - "north": {"uv": [1, 1, 5, 5], "rotation": 180, "texture": "#5"}, - "east": {"uv": [6, 4.5, 10, 8], "rotation": 270, "texture": "#5"}, - "south": {"uv": [1, 1, 5, 5], "texture": "#5"}, - "west": {"uv": [6, 4.5, 10, 8], "rotation": 90, "texture": "#5"}, - "up": {"uv": [6, 4.5, 10, 8], "rotation": 180, "texture": "#5"}, - "down": {"uv": [6, 4.5, 10, 8], "texture": "#5"} - } } ], "display": { @@ -130,7 +116,7 @@ { "name": "cogwheel", "origin": [8, 8, 8], - "children": [0, 1, 2, 3, 4, 5] + "children": [0, 1, 2, 3, 4] } ] } \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/special/cutout_checkerboard.png b/src/main/resources/assets/create/textures/special/cutout_checkerboard.png new file mode 100644 index 0000000000..a8e1876626 Binary files /dev/null and b/src/main/resources/assets/create/textures/special/cutout_checkerboard.png differ