Thinking via Pipes

- Pondering for Pumps, Smart Pipes, Valves
This commit is contained in:
simibubi 2021-06-24 11:49:46 +02:00
parent e4a340deef
commit 9a020dd02a
11 changed files with 776 additions and 94 deletions

View file

@ -248,6 +248,8 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
}
protected void spawnProcessingParticles(FluidStack fluid) {
if (isVirtual())
return;
Vector3d vec = VecHelper.getCenterOf(pos);
vec = vec.subtract(0, 8 / 16f, 0);
IParticleData particle = FluidFX.getFluidParticle(fluid);
@ -257,6 +259,8 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
protected static int SPLASH_PARTICLE_COUNT = 20;
protected void spawnSplash(FluidStack fluid) {
if (isVirtual())
return;
Vector3d vec = VecHelper.getCenterOf(pos);
vec = vec.subtract(0, 2 - 5 / 16f, 0);
IParticleData particle = FluidFX.getFluidParticle(fluid);

View file

@ -91,6 +91,13 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
return ActionResultType.SUCCESS;
}
public BlockState getAxisState(Axis axis) {
BlockState defaultState = getDefaultState();
for (Direction d : Iterate.directions)
defaultState = defaultState.with(FACING_TO_PROPERTY_MAP.get(d), d.getAxis() == axis);
return defaultState;
}
@Nullable
private Axis getAxis(IBlockReader world, BlockPos pos, BlockState state) {
return FluidPropagator.getStraightPipeAxis(state);

View file

@ -241,6 +241,9 @@ public class PonderIndex {
// Fluids
// ProgressTM
// [##### ####. ..... .....]
PonderRegistry.forComponents(AllBlocks.FLUID_PIPE)
.addStoryBoard("fluid_pipe/flow", PipeScenes::flow, PonderTag.FLUIDS)
.addStoryBoard("fluid_pipe/interaction", PipeScenes::interaction)
@ -248,18 +251,18 @@ public class PonderIndex {
PonderRegistry.forComponents(AllBlocks.COPPER_CASING)
.addStoryBoard("fluid_pipe/encasing", PipeScenes::encasing);
PonderRegistry.forComponents(AllBlocks.MECHANICAL_PUMP)
.addStoryBoard("debug/scene_1", PumpScenes::flow, PonderTag.FLUIDS, PonderTag.KINETIC_APPLIANCES)
.addStoryBoard("debug/scene_1", PumpScenes::speed);
.addStoryBoard("mechanical_pump/flow", PumpScenes::flow, PonderTag.FLUIDS, PonderTag.KINETIC_APPLIANCES)
.addStoryBoard("mechanical_pump/speed", PumpScenes::speed);
PonderRegistry.forComponents(AllBlocks.FLUID_VALVE)
.addStoryBoard("debug/scene_1", PipeScenes::valve, PonderTag.FLUIDS, PonderTag.KINETIC_APPLIANCES);
.addStoryBoard("fluid_valve", PipeScenes::valve, PonderTag.FLUIDS, PonderTag.KINETIC_APPLIANCES);
PonderRegistry.forComponents(AllBlocks.SMART_FLUID_PIPE)
.addStoryBoard("debug/scene_1", PipeScenes::smart, PonderTag.FLUIDS);
.addStoryBoard("smart_pipe", PipeScenes::smart, PonderTag.FLUIDS);
PonderRegistry.forComponents(AllBlocks.FLUID_TANK)
.addStoryBoard("debug/scene_1", FluidTankScenes::storage, PonderTag.FLUIDS)
.addStoryBoard("debug/scene_1", FluidTankScenes::sizes);
.addStoryBoard("fluid_tank/storage", FluidTankScenes::storage, PonderTag.FLUIDS)
.addStoryBoard("fluid_tank/sizes", FluidTankScenes::sizes);
PonderRegistry.forComponents(AllBlocks.CREATIVE_FLUID_TANK)
.addStoryBoard("debug/scene_1", FluidTankScenes::creative, PonderTag.FLUIDS, PonderTag.CREATIVE)
.addStoryBoard("debug/scene_1", FluidTankScenes::sizes);
.addStoryBoard("fluid_tank/storage_creative", FluidTankScenes::creative, PonderTag.FLUIDS, PonderTag.CREATIVE)
.addStoryBoard("fluid_tank/sizes_creative", FluidTankScenes::sizes);
PonderRegistry.forComponents(AllBlocks.HOSE_PULLEY)
.addStoryBoard("debug/scene_1", HosePulleyScenes::intro, PonderTag.FLUIDS, PonderTag.KINETIC_APPLIANCES)
.addStoryBoard("debug/scene_1", HosePulleyScenes::level)

View file

@ -1,30 +1,214 @@
package com.simibubi.create.foundation.ponder.content.fluid;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllFluids;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.fluids.FluidFX;
import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.ponder.ElementLink;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
import com.simibubi.create.foundation.ponder.Selection;
import com.simibubi.create.foundation.ponder.content.PonderPalette;
import com.simibubi.create.foundation.ponder.elements.InputWindowElement;
import com.simibubi.create.foundation.ponder.elements.WorldSectionElement;
import com.simibubi.create.foundation.ponder.instructions.EmitParticlesInstruction.Emitter;
import com.simibubi.create.foundation.utility.Pointing;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class FluidTankScenes {
public static void storage(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("fluid_tank_storage", "Storing Fluids in Fluid Tanks");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.showBasePlate();
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
/*
* Fluid Tanks can be used to store large amounts of fluid
*
* Pipe networks can push and pull fluids from any side
*
* Comparators can read the current fill level of a fluid tank
*
* In Survival Mode, Fluids cannot be added or taken manually
*
* You can use Basins, Item Drains and Spouts to drain or fill fluid containing items
*/
BlockPos tankPos = util.grid.at(3, 1, 2);
Selection chocolate = util.select.fromTo(1, 5, 0, 0, 8, 1);
Selection tank = util.select.fromTo(3, 1, 2, 3, 2, 2);
Selection largeCog1 = util.select.position(3, 0, 5);
Selection kinetics1 = util.select.fromTo(2, 1, 5, 2, 1, 3)
.add(util.select.position(2, 2, 4));
Selection largeCog2 = util.select.position(6, 0, 1);
Selection comparatorStuff = util.select.fromTo(2, 1, 1, 2, 1, 0);
Selection pump = util.select.position(1, 1, 3);
BlockPos pumpPos = util.grid.at(1, 1, 3);
Selection spoutstuff = util.select.fromTo(3, 1, 0, 5, 3, 2)
.substract(tank);
Selection pipe = util.select.fromTo(1, 1, 2, 1, 1, 5)
.add(util.select.position(1, 0, 5))
.add(util.select.position(2, 1, 2));
ElementLink<WorldSectionElement> tankLink = scene.world.showIndependentSection(tank, Direction.NORTH);
scene.world.moveSection(tankLink, util.vector.of(0, 0, -1), 0);
scene.idle(5);
ElementLink<WorldSectionElement> chocLink = scene.world.showIndependentSection(chocolate, Direction.NORTH);
scene.world.moveSection(chocLink, util.vector.of(2, -4, 3), 0);
scene.idle(10);
scene.overlay.showOutline(PonderPalette.GREEN, chocLink, util.select.fromTo(3, 1, 3, 2, 4, 4), 40);
scene.idle(10);
scene.overlay.showLine(PonderPalette.GREEN, util.vector.of(3, 1, 2), util.vector.of(2, 1, 3), 30);
scene.overlay.showLine(PonderPalette.GREEN, util.vector.of(3, 3, 2), util.vector.of(2, 5, 3), 30);
scene.overlay.showLine(PonderPalette.GREEN, util.vector.of(4, 3, 2), util.vector.of(4, 5, 3), 30);
scene.overlay.showOutline(PonderPalette.GREEN, tankLink, util.select.fromTo(3, 1, 1, 3, 2, 1), 40);
scene.idle(10);
scene.overlay.showText(40)
.text("Fluid Tanks can be used to store large amounts of fluid")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.blockSurface(util.grid.at(3, 2, 1), Direction.WEST));
scene.idle(50);
scene.world.hideIndependentSection(chocLink, Direction.DOWN);
scene.idle(5);
FluidStack content = new FluidStack(AllFluids.CHOCOLATE.get()
.getStillFluid(), 16000);
scene.world.modifyTileEntity(tankPos, FluidTankTileEntity.class, te -> te.getTankInventory()
.fill(content, FluidAction.EXECUTE));
scene.idle(25);
scene.world.moveSection(tankLink, util.vector.of(0, 0, 1), 10);
scene.idle(5);
scene.world.setKineticSpeed(pump, 0);
scene.world.showSection(pipe, Direction.EAST);
scene.idle(10);
scene.world.showSection(largeCog1, Direction.UP);
scene.world.showSection(kinetics1, Direction.WEST);
scene.idle(10);
scene.world.setBlock(util.grid.at(1, -1, 5), AllBlocks.FLUID_TANK.getDefaultState(), false);
scene.world.setKineticSpeed(pump, 128);
scene.idle(5);
Selection pumpRedstone = util.select.fromTo(2, 1, 4, 2, 2, 4);
Selection pumpCogs = util.select.fromTo(2, 1, 3, 1, 1, 3);
scene.world.toggleRedstonePower(pumpRedstone);
scene.world.multiplyKineticSpeed(pumpCogs, -1);
scene.world.propagatePipeChange(pumpPos);
scene.effects.rotationDirectionIndicator(pumpPos);
scene.world.modifyTileEntity(util.grid.at(2, 0, 5), FluidTankTileEntity.class, te -> te.getTankInventory()
.fill(content, FluidAction.EXECUTE));
scene.idle(20);
for (int i = 0; i < 4; i++) {
scene.world.modifyTileEntity(tankPos, FluidTankTileEntity.class, te -> te.getTankInventory()
.drain(2000, FluidAction.EXECUTE));
scene.idle(5);
}
scene.overlay.showText(60)
.text("Pipe networks can push and pull fluids from any side")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.centerOf(1, 1, 2));
scene.idle(40);
scene.world.toggleRedstonePower(pumpRedstone);
scene.world.multiplyKineticSpeed(pumpCogs, -1);
scene.world.propagatePipeChange(pumpPos);
scene.effects.rotationDirectionIndicator(pumpPos);
for (int i = 0; i < 4; i++) {
scene.world.modifyTileEntity(tankPos, FluidTankTileEntity.class, te -> te.getTankInventory()
.fill(FluidHelper.copyStackWithAmount(content, 2000), FluidAction.EXECUTE));
scene.idle(5);
}
scene.idle(40);
scene.world.hideSection(largeCog1, Direction.DOWN);
scene.world.hideSection(kinetics1, Direction.SOUTH);
scene.world.hideSection(pipe, Direction.WEST);
scene.idle(10);
scene.world.showSection(comparatorStuff, Direction.SOUTH);
scene.idle(5);
scene.world.moveSection(tankLink, util.vector.of(-1, 0, 0), 10);
scene.idle(10);
scene.world.toggleRedstonePower(comparatorStuff);
scene.world.modifyTileNBT(util.select.position(2, 1, 0), NixieTubeTileEntity.class,
nbt -> nbt.putInt("RedstoneStrength", 15));
scene.overlay.showText(50)
.text("The contained fluid can be measured by a Comparator")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.blockSurface(util.grid.at(2, 1, 1), Direction.DOWN)
.add(0, 1 / 8f, 0));
scene.idle(50);
scene.world.hideSection(comparatorStuff, Direction.EAST);
scene.idle(20);
ItemStack bucket = new ItemStack(Items.BUCKET, 1);
scene.overlay.showControls(
new InputWindowElement(util.vector.blockSurface(util.grid.at(2, 2, 2), Direction.NORTH), Pointing.RIGHT)
.showing(AllIcons.I_MTD_CLOSE)
.withItem(bucket),
40);
scene.idle(7);
scene.overlay.showSelectionWithText(util.select.fromTo(2, 1, 2, 2, 2, 2), 70)
.text("However, in Survival Mode Fluids cannot be added or taken manually")
.attachKeyFrame()
.colored(PonderPalette.RED)
.placeNearTarget()
.pointAt(util.vector.blockSurface(util.grid.at(2, 2, 2), Direction.WEST));
scene.idle(80);
scene.world.modifyTileEntity(util.grid.at(4, 3, 0), SpoutTileEntity.class,
te -> te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
.ifPresent(ifh -> ifh.fill(content, FluidAction.EXECUTE)));
scene.world.moveSection(tankLink, util.vector.of(0, 0, 1), 7);
scene.world.multiplyKineticSpeed(spoutstuff, -1);
scene.world.multiplyKineticSpeed(largeCog2, -1);
scene.idle(7);
ElementLink<WorldSectionElement> spoutLink = scene.world.showIndependentSection(spoutstuff, Direction.SOUTH);
ElementLink<WorldSectionElement> largeCogLink = scene.world.showIndependentSection(largeCog2, Direction.UP);
scene.world.moveSection(spoutLink, util.vector.of(-1, 0, 1), 0);
scene.world.moveSection(largeCogLink, util.vector.of(-1, 0, 1), 0);
scene.idle(20);
scene.overlay.showOutline(PonderPalette.GREEN, new Object(), util.select.position(2, 1, 1), 50);
scene.idle(5);
scene.overlay.showOutline(PonderPalette.GREEN, new Object(), util.select.position(3, 3, 1), 50);
scene.idle(5);
scene.overlay.showText(80)
.text("You can use Basins, Item Drains and Spouts to drain or fill fluid containing items")
.attachKeyFrame()
.colored(PonderPalette.GREEN)
.placeNearTarget()
.pointAt(util.vector.topOf(2, 1, 1));
scene.idle(90);
ItemStack chocBucket = AllFluids.CHOCOLATE.get()
.getAttributes()
.getBucket(new FluidStack(FluidHelper.convertToStill(AllFluids.CHOCOLATE.get()), 1000));
scene.world.createItemOnBeltLike(util.grid.at(3, 1, 0), Direction.WEST, chocBucket);
scene.idle(40);
scene.world.modifyTileNBT(util.select.position(util.grid.at(4, 3, 0)), SpoutTileEntity.class,
nbt -> nbt.putInt("ProcessingTicks", 20));
scene.idle(20);
scene.world.removeItemsFromBelt(util.grid.at(4, 1, 0));
scene.world.createItemOnBeltLike(util.grid.at(4, 1, 0), Direction.UP, chocBucket);
for (int i = 0; i < 10; i++) {
scene.effects.emitParticles(util.vector.topOf(3, 1, 1)
.add(0, 1 / 16f, 0),
Emitter.simple(FluidFX.getFluidParticle(content),
VecHelper.offsetRandomly(Vector3d.ZERO, Create.RANDOM, .1f)),
1, 1);
}
}

View file

@ -1,11 +1,18 @@
package com.simibubi.create.foundation.ponder.content.fluid;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllFluids;
import com.simibubi.create.content.contraptions.fluids.PumpBlock;
import com.simibubi.create.content.contraptions.fluids.actors.ItemDrainTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidValveTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.GlassFluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.SmartFluidPipeTileEntity;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity;
import com.simibubi.create.content.contraptions.processing.BasinTileEntity;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.ponder.ElementLink;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
@ -21,6 +28,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.state.BooleanProperty;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
@ -28,6 +36,7 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class PipeScenes {
@ -364,42 +373,226 @@ public class PipeScenes {
public static void valve(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("valve_pipe", "Controlling Fluid flow using Valves");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
scene.showBasePlate();
/*
* Valve pipes propagate flows in a straight line
*
* When given Rotational Force in the closing direction, the valve will stop the
* fluid flow
*
* It can be re-opened by reversing the input rotation
*/
Selection cogs = util.select.fromTo(5, 0, 2, 5, 1, 2);
Selection tank1 = util.select.fromTo(3, 1, 3, 3, 2, 3);
Selection tank2 = util.select.fromTo(1, 1, 3, 1, 2, 3);
BlockPos valvePos = util.grid.at(2, 1, 1);
BlockPos handlePos = util.grid.at(2, 2, 1);
BlockPos pumpPos = util.grid.at(4, 1, 2);
Selection pipes1 = util.select.fromTo(4, 1, 3, 4, 1, 1);
Selection pipes2 = util.select.fromTo(3, 1, 1, 1, 1, 1);
Selection pipes3 = util.select.fromTo(0, 1, 1, 0, 1, 3);
scene.world.setKineticSpeed(pipes1, 0);
scene.world.propagatePipeChange(pumpPos);
scene.world.setBlock(valvePos, AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X), false);
scene.world.setBlock(util.grid.at(3, 1, 1), Blocks.AIR.getDefaultState(), false);
scene.world.setBlock(util.grid.at(3, 1, 1), AllBlocks.GLASS_FLUID_PIPE.getDefaultState()
.with(GlassFluidPipeBlock.AXIS, Axis.X), false);
scene.idle(5);
scene.world.showSection(tank1, Direction.NORTH);
scene.idle(5);
scene.world.showSection(tank2, Direction.NORTH);
scene.idle(10);
scene.world.showSection(pipes1, Direction.WEST);
scene.idle(5);
scene.world.showSection(pipes2, Direction.SOUTH);
scene.idle(5);
scene.world.showSection(pipes3, Direction.EAST);
scene.idle(15);
scene.world.destroyBlock(valvePos);
scene.world.restoreBlocks(util.select.position(valvePos));
scene.overlay.showText(60)
.placeNearTarget()
.text("Valve pipes help control fluids propagating through pipe networks")
.attachKeyFrame()
.pointAt(util.vector.blockSurface(valvePos, Direction.WEST));
scene.idle(75);
scene.world.showSection(cogs, Direction.WEST);
scene.idle(10);
scene.world.setKineticSpeed(util.select.position(pumpPos), 64);
scene.world.propagatePipeChange(pumpPos);
scene.overlay.showText(60)
.placeNearTarget()
.text("Their shaft input controls whether fluid is currently allowed through")
.attachKeyFrame()
.pointAt(util.vector.topOf(valvePos));
scene.idle(60);
scene.world.showSection(util.select.position(handlePos), Direction.DOWN);
scene.idle(15);
Selection valveKinetics = util.select.fromTo(2, 1, 1, 2, 2, 1);
scene.world.setKineticSpeed(valveKinetics, 16);
scene.effects.rotationSpeedIndicator(handlePos);
scene.world.modifyTileEntity(valvePos, FluidValveTileEntity.class, te -> te.onSpeedChanged(0));
scene.idle(22);
scene.world.modifyBlock(valvePos, s -> s.with(FluidValveBlock.ENABLED, true), false);
scene.effects.indicateSuccess(valvePos);
scene.idle(5);
scene.world.setKineticSpeed(valveKinetics, 0);
scene.overlay.showText(60)
.placeNearTarget()
.text("Given Rotational Force in the opening direction, the valve will open up")
.attachKeyFrame()
.pointAt(util.vector.blockSurface(valvePos, Direction.NORTH));
scene.idle(90);
scene.overlay.showText(50)
.placeNearTarget()
.text("It can be closed again by reversing the input rotation")
.attachKeyFrame()
.pointAt(util.vector.blockSurface(valvePos, Direction.NORTH));
scene.idle(40);
scene.world.setKineticSpeed(valveKinetics, -16);
scene.effects.rotationSpeedIndicator(handlePos);
scene.world.modifyTileEntity(valvePos, FluidValveTileEntity.class, te -> te.onSpeedChanged(0));
scene.idle(22);
scene.world.modifyBlock(valvePos, s -> s.with(FluidValveBlock.ENABLED, false), false);
scene.effects.indicateRedstone(valvePos);
scene.world.propagatePipeChange(pumpPos);
scene.idle(5);
scene.world.setKineticSpeed(valveKinetics, 0);
}
public static void smart(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("smart_pipe", "Controlling Fluid flow using Smart Pipes");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.configureBasePlate(1, 0, 5);
scene.showBasePlate();
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
/*
* Smart pipes propagate flows in a straight line
*
* When placed directly at the source, they can specify the type of fluid to
* extract
*
* Simply Right-Click their filter slot with any item containing the desired
* fluid
*
* When placed further down a pipe network, smart pipes will only let matching
* fluids continue past
*
* In this configuration, their filter has no impact on whether a fluid can
* enter the pipe network
*/
Selection tank1 = util.select.fromTo(4, 1, 3, 4, 2, 3);
Selection tank2 = util.select.fromTo(4, 1, 4, 4, 2, 4);
Selection additionalPipes = util.select.fromTo(3, 1, 4, 1, 1, 4);
Selection mainPipes = util.select.fromTo(3, 1, 3, 1, 1, 1);
Selection kinetics1 = util.select.fromTo(0, 0, 2, 0, 0, 5);
Selection kinetics2 = util.select.position(1, 0, 5);
BlockPos basinPos = util.grid.at(4, 1, 1);
BlockPos pumpPos = util.grid.at(1, 1, 2);
Selection pump = util.select.position(1, 1, 2);
Selection basin = util.select.position(basinPos);
BlockPos smartPos = util.grid.at(3, 1, 1);
scene.world.setBlock(util.grid.at(3, 1, 3), AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X), false);
scene.world.setBlock(smartPos, AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X), false);
scene.world.setBlock(util.grid.at(2, 1, 3), AllBlocks.GLASS_FLUID_PIPE.getDefaultState()
.with(GlassFluidPipeBlock.AXIS, Axis.X), false);
scene.world.setBlock(util.grid.at(1, 1, 3), AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X)
.with(FluidPipeBlock.NORTH, true)
.with(FluidPipeBlock.WEST, false), false);
scene.world.showSection(basin, Direction.DOWN);
scene.idle(5);
scene.world.showSection(tank1, Direction.DOWN);
scene.idle(5);
scene.world.showSection(mainPipes, Direction.EAST);
scene.idle(15);
scene.world.destroyBlock(smartPos);
scene.world.restoreBlocks(util.select.position(smartPos));
Vector3d filterVec = util.vector.topOf(smartPos)
.subtract(0.25, 0, 0);
scene.overlay.showText(50)
.placeNearTarget()
.text("Smart pipes can help control flows by fluid type")
.attachKeyFrame()
.pointAt(filterVec);
scene.idle(60);
scene.overlay.showSelectionWithText(util.select.position(basinPos), 80)
.placeNearTarget()
.colored(PonderPalette.GREEN)
.text("When placed directly at the source, they can specify the type of fluid to extract")
.attachKeyFrame()
.pointAt(filterVec);
scene.idle(90);
FluidStack chocolate = new FluidStack(FluidHelper.convertToStill(AllFluids.CHOCOLATE.get()), 1000);
ItemStack bucket = AllFluids.CHOCOLATE.get()
.getAttributes()
.getBucket(chocolate);
ItemStack milkBucket = new ItemStack(Items.MILK_BUCKET);
scene.overlay.showControls(new InputWindowElement(filterVec, Pointing.DOWN).rightClick()
.withItem(bucket), 80);
scene.idle(7);
scene.world.setFilterData(util.select.position(3, 1, 1), SmartFluidPipeTileEntity.class, bucket);
scene.idle(10);
scene.overlay.showText(60)
.placeNearTarget()
.attachKeyFrame()
.text("Simply Right-Click their filter slot with any item containing the desired fluid")
.pointAt(filterVec);
scene.idle(50);
scene.world.showSection(kinetics2, Direction.WEST);
scene.world.setKineticSpeed(kinetics2, 64);
scene.idle(5);
scene.world.showSection(kinetics1, Direction.EAST);
scene.world.setKineticSpeed(kinetics1, -64);
scene.idle(10);
scene.world.setKineticSpeed(pump, 128);
scene.world.propagatePipeChange(pumpPos);
scene.idle(120);
scene.world.setKineticSpeed(util.select.everywhere(), 0);
scene.world.propagatePipeChange(pumpPos);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.idle(15);
scene.world.showSection(tank2, Direction.DOWN);
scene.world.showSection(additionalPipes, Direction.NORTH);
scene.world.setBlock(util.grid.at(3, 1, 1), AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X), true);
scene.idle(10);
for (int i = 0; i < 3; i++) {
BlockPos pos = util.grid.at(1 + i, 1, 3);
scene.world.destroyBlock(pos);
scene.world.restoreBlocks(util.select.position(pos));
scene.idle(2);
}
scene.idle(15);
scene.world.modifyTileEntity(basinPos, BasinTileEntity.class,
te -> te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
.ifPresent(ifh -> ifh.fill(chocolate, FluidAction.EXECUTE)));
scene.idle(10);
scene.overlay.showText(80)
.placeNearTarget()
.colored(PonderPalette.GREEN)
.text("When placed further down a pipe network, smart pipes will only let matching fluids continue")
.attachKeyFrame()
.pointAt(filterVec.add(-1, 0, 2));
scene.idle(90);
scene.overlay.showControls(new InputWindowElement(filterVec.add(-1, 0, 3), Pointing.DOWN).rightClick()
.withItem(milkBucket), 30);
scene.idle(7);
scene.world.setFilterData(util.select.position(2, 1, 4), SmartFluidPipeTileEntity.class, milkBucket);
scene.idle(30);
scene.overlay.showControls(new InputWindowElement(filterVec.add(-1, 0, 2), Pointing.DOWN).rightClick()
.withItem(bucket), 30);
scene.idle(7);
scene.world.setFilterData(util.select.position(2, 1, 3), SmartFluidPipeTileEntity.class, bucket);
scene.idle(30);
scene.world.setKineticSpeed(kinetics2, 64);
scene.world.setKineticSpeed(kinetics1, -64);
scene.world.setKineticSpeed(pump, 128);
scene.world.propagatePipeChange(pumpPos);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.idle(40);
}
}

View file

@ -1,53 +1,344 @@
package com.simibubi.create.foundation.ponder.content.fluid;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.fluids.PumpBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.GlassFluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.foundation.ponder.ElementLink;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
import com.simibubi.create.foundation.ponder.Selection;
import com.simibubi.create.foundation.ponder.content.PonderPalette;
import com.simibubi.create.foundation.ponder.elements.InputWindowElement;
import com.simibubi.create.foundation.ponder.elements.WorldSectionElement;
import com.simibubi.create.foundation.utility.Pointing;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class PumpScenes {
public static void flow(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_pump_flow", "Fluid Transportation using Mechanical Pumps");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.showBasePlate();
scene.world.multiplyKineticSpeed(util.select.everywhere(), -1);
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
/*
* Mechanical Pumps govern the flow of their attached pipe networks
*
* When powered, their arrow indicates the direction of flow
*
* The network behind is now pulling fluids...
*
* ...while the network in front is transferring it outward
*
* Reversing the input rotation reverses the direction of flow
*
* Use a Wrench to reverse the orientation of pumps manually
*/
BlockPos pumpPos = util.grid.at(2, 1, 1);
Selection tank1 = util.select.fromTo(0, 2, 3, 0, 1, 3);
Selection tank2 = util.select.fromTo(4, 2, 3, 4, 1, 3);
Selection pipes = util.select.fromTo(3, 1, 3, 1, 1, 1);
Selection largeCog = util.select.position(5, 0, 1);
Selection kinetics = util.select.fromTo(5, 1, 0, 2, 1, 0);
BlockPos leverPos = util.grid.at(4, 2, 0);
Selection pump = util.select.position(pumpPos);
scene.world.setBlock(pumpPos, AllBlocks.FLUID_PIPE.get()
.getAxisState(Axis.X), false);
scene.world.showSection(tank1, Direction.DOWN);
scene.idle(5);
scene.world.showSection(tank2, Direction.DOWN);
scene.idle(5);
scene.world.showSection(pipes, Direction.NORTH);
scene.idle(15);
scene.world.destroyBlock(pumpPos);
scene.world.restoreBlocks(pump);
scene.world.setKineticSpeed(pump, 0);
scene.idle(15);
scene.overlay.showText(60)
.text("Mechanical Pumps govern the flow of their attached pipe networks")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.topOf(pumpPos));
scene.idle(70);
scene.world.showSection(largeCog, Direction.UP);
scene.idle(5);
scene.world.showSection(kinetics, Direction.SOUTH);
scene.world.showSection(util.select.position(leverPos), Direction.SOUTH);
scene.idle(10);
scene.world.setKineticSpeed(pump, 64);
scene.world.propagatePipeChange(pumpPos);
scene.effects.rotationDirectionIndicator(pumpPos.north());
scene.idle(15);
scene.overlay.showText(60)
.text("When powered, their arrow indicates the direction of flow")
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.topOf(pumpPos)
.subtract(0.5f, 0.125f, 0));
AxisAlignedBB bb1 = new AxisAlignedBB(Vector3d.ZERO, Vector3d.ZERO).grow(.25, .25, 0)
.offset(0, 0, .25);
AxisAlignedBB bb2 = new AxisAlignedBB(Vector3d.ZERO, Vector3d.ZERO).grow(.25, .25, 1.25);
scene.idle(65);
Object in = new Object();
Object out = new Object();
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb1.offset(util.vector.centerOf(3, 1, 3)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb2.offset(util.vector.centerOf(3, 1, 2)), 50);
scene.idle(10);
scene.overlay.showText(50)
.text("The network behind is now pulling fluids...")
.attachKeyFrame()
.placeNearTarget()
.colored(PonderPalette.INPUT)
.pointAt(util.vector.centerOf(3, 1, 2));
scene.idle(60);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb1.offset(util.vector.centerOf(1, 1, 1)
.add(0, 0, -.5)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb2.offset(util.vector.centerOf(1, 1, 2)), 50);
scene.idle(10);
scene.overlay.showText(50)
.text("...while the network in front is transferring it outward")
.placeNearTarget()
.colored(PonderPalette.OUTPUT)
.pointAt(util.vector.centerOf(1, 1, 2));
scene.idle(70);
scene.world.toggleRedstonePower(util.select.fromTo(4, 2, 0, 4, 1, 0));
scene.effects.indicateRedstone(leverPos);
scene.world.multiplyKineticSpeed(util.select.fromTo(3, 1, 0, 2, 1, 1), -1);
scene.effects.rotationDirectionIndicator(pumpPos.north());
scene.world.propagatePipeChange(pumpPos);
scene.idle(15);
scene.overlay.showText(70)
.text("Reversing the input rotation reverses the direction of flow")
.placeNearTarget()
.attachKeyFrame()
.pointAt(util.vector.topOf(pumpPos)
.subtract(0.5f, 0.125f, 0));
scene.idle(25);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb1.offset(util.vector.centerOf(1, 1, 3)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb2.offset(util.vector.centerOf(1, 1, 2)), 30);
scene.idle(15);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb1.offset(util.vector.centerOf(3, 1, 1)
.add(0, 0, -.5)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb2.offset(util.vector.centerOf(3, 1, 2)), 30);
scene.idle(55);
scene.overlay.showControls(new InputWindowElement(util.vector.topOf(pumpPos), Pointing.DOWN).rightClick()
.withWrench(), 40);
scene.idle(7);
scene.world.modifyBlock(pumpPos, s -> s.with(PumpBlock.FACING, Direction.EAST), true);
scene.overlay.showText(70)
.attachKeyFrame()
.pointAt(util.vector.centerOf(2, 1, 1))
.placeNearTarget()
.text("Use a Wrench to reverse the orientation of pumps manually");
scene.world.propagatePipeChange(pumpPos);
scene.idle(40);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb1.offset(util.vector.centerOf(3, 1, 3)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.INPUT, in, bb2.offset(util.vector.centerOf(3, 1, 2)), 30);
scene.idle(15);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb1.offset(util.vector.centerOf(1, 1, 1)
.add(0, 0, -.5)), 3);
scene.idle(2);
scene.overlay.chaseBoundingBoxOutline(PonderPalette.OUTPUT, out, bb2.offset(util.vector.centerOf(1, 1, 2)), 30);
scene.idle(25);
}
public static void speed(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_pump_speed", "Throughput of Mechanical Pumps");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.showBasePlate();
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
// scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
/*
* Regardless of speed, Mechanical Pumps affect pipes up to 16 blocks away
*
* Speeding up the input rotation changes the speed of flows building...
*
* ...aswell as how quickly fluids are transferred
*
* Parallel pumps combine their speed within shared pipe connections
*
* Alternating their orientation can help lining up their flow directions
*/
Selection largeCog = util.select.position(5, 0, 3);
Selection cogs = util.select.fromTo(5, 1, 4, 2, 1, 4)
.add(util.select.position(2, 1, 3));
BlockPos pumpPos = util.grid.at(2, 1, 2);
Selection pump = util.select.position(pumpPos);
Selection tank1 = util.select.fromTo(4, 1, 2, 4, 2, 2);
Selection tank2 = util.select.fromTo(0, 1, 2, 0, 2, 2);
Selection megapipe1 = util.select.fromTo(0, 3, 5, 1, 4, 2);
Selection megapipe2 = util.select.fromTo(3, 3, 1, 5, 6, 2);
scene.world.modifyTileEntity(util.grid.at(0, 1, 2), FluidTankTileEntity.class, te -> te.getTankInventory()
.drain(3000, FluidAction.EXECUTE));
BlockPos east = pumpPos.east();
scene.world.setBlock(east, Blocks.AIR.getDefaultState(), false);
scene.world.setBlock(east, AllBlocks.GLASS_FLUID_PIPE.getDefaultState()
.with(GlassFluidPipeBlock.AXIS, Axis.X), false);
scene.world.setBlock(pumpPos.south(), AllBlocks.COGWHEEL.getDefaultState()
.with(CogWheelBlock.AXIS, Axis.X), false);
Selection southPump = util.select.position(pumpPos.south());
scene.world.setKineticSpeed(southPump, 32);
scene.world.setKineticSpeed(pump, 0);
scene.world.showSection(pump, Direction.DOWN);
scene.idle(10);
ElementLink<WorldSectionElement> mp1 = scene.world.showIndependentSection(megapipe1, Direction.EAST);
scene.world.moveSection(mp1, util.vector.of(0, -3, 0), 0);
scene.idle(5);
ElementLink<WorldSectionElement> mp2 = scene.world.showIndependentSection(megapipe2, Direction.WEST);
scene.world.moveSection(mp2, util.vector.of(0, -3, 0), 0);
scene.idle(15);
scene.overlay.showText(70)
.attachKeyFrame()
.pointAt(util.vector.topOf(pumpPos))
.placeNearTarget()
.text("Regardless of speed, Mechanical Pumps affect pipes connected up to 16 blocks away");
scene.idle(75);
scene.world.hideIndependentSection(mp1, Direction.WEST);
scene.idle(5);
scene.world.hideIndependentSection(mp2, Direction.EAST);
scene.idle(15);
scene.world.showSection(tank1, Direction.DOWN);
scene.idle(2);
scene.world.showSection(util.select.position(east), Direction.DOWN);
scene.idle(5);
BlockPos west = pumpPos.west();
scene.world.showSection(util.select.position(west), Direction.DOWN);
scene.idle(2);
scene.world.showSection(tank2, Direction.DOWN);
scene.idle(5);
scene.world.showSection(largeCog, Direction.UP);
scene.world.showSection(cogs, Direction.SOUTH);
scene.idle(10);
scene.world.setKineticSpeed(util.select.position(pumpPos), -32);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.world.propagatePipeChange(pumpPos);
scene.idle(40);
scene.world.multiplyKineticSpeed(util.select.everywhere(), 4);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.world.propagatePipeChange(pumpPos);
scene.idle(20);
scene.overlay.showText(60)
.attachKeyFrame()
.pointAt(util.vector.topOf(pumpPos))
.placeNearTarget()
.text("Speeding up the input rotation changes the speed of flow propagation...");
scene.idle(70);
scene.overlay.showText(50)
.pointAt(util.vector.blockSurface(util.grid.at(0, 1, 2), Direction.WEST))
.placeNearTarget()
.text("...aswell as how quickly fluids are transferred");
scene.idle(60);
BlockState pipeState = AllBlocks.FLUID_PIPE.getDefaultState()
.with(FluidPipeBlock.DOWN, false)
.with(FluidPipeBlock.UP, false);
scene.world.setKineticSpeed(util.select.everywhere(), 0);
scene.idle(20);
scene.world.setBlock(east, pipeState, true);
scene.world.setBlock(west, pipeState, true);
scene.idle(5);
scene.world.setBlock(east.north(), pipeState.with(FluidPipeBlock.NORTH, false)
.with(FluidPipeBlock.EAST, false), false);
scene.world.setBlock(east.south(), pipeState.with(FluidPipeBlock.SOUTH, false)
.with(FluidPipeBlock.EAST, false), false);
scene.world.showSection(util.select.position(east.north()), Direction.DOWN);
scene.world.showSection(util.select.position(east.south()), Direction.DOWN);
scene.idle(5);
Selection northPump = util.select.position(pumpPos.north());
scene.world.setBlock(west.north(), pipeState.with(FluidPipeBlock.NORTH, false)
.with(FluidPipeBlock.WEST, false), false);
scene.world.setBlock(west.south(), pipeState.with(FluidPipeBlock.SOUTH, false)
.with(FluidPipeBlock.WEST, false), false);
scene.world.showSection(util.select.position(west.north()), Direction.DOWN);
scene.world.showSection(util.select.position(west.south()), Direction.DOWN);
scene.idle(10);
scene.world.restoreBlocks(southPump);
scene.world.modifyBlock(pumpPos.south(), s -> s.with(PumpBlock.FACING, Direction.EAST), false);
scene.world.setKineticSpeed(util.select.everywhere(), 0);
scene.world.showSection(northPump, Direction.DOWN);
scene.world.modifyBlock(pumpPos.north(), s -> s.with(PumpBlock.FACING, Direction.EAST), false);
scene.idle(10);
scene.world.setKineticSpeed(util.select.everywhere(), -16);
scene.world.setKineticSpeed(northPump, 16);
scene.world.setKineticSpeed(southPump, 16);
scene.world.setKineticSpeed(largeCog, 8);
scene.idle(20);
scene.overlay.showSelectionWithText(util.select.fromTo(2, 1, 1, 2, 1, 3), 60)
.attachKeyFrame()
.colored(PonderPalette.GREEN)
.pointAt(util.vector.topOf(pumpPos))
.placeNearTarget()
.text("Pumps can combine their throughputs within shared pipe networks");
scene.idle(70);
scene.overlay
.showControls(new InputWindowElement(util.vector.topOf(pumpPos.south()), Pointing.DOWN).rightClick()
.withWrench(), 30);
scene.idle(7);
scene.world.modifyBlock(pumpPos.south(), s -> s.with(PumpBlock.FACING, Direction.WEST), true);
scene.idle(30);
scene.overlay
.showControls(new InputWindowElement(util.vector.topOf(pumpPos.north()), Pointing.DOWN).rightClick()
.withWrench(), 30);
scene.idle(7);
scene.world.modifyBlock(pumpPos.north(), s -> s.with(PumpBlock.FACING, Direction.WEST), true);
scene.idle(30);
scene.overlay.showText(70)
.attachKeyFrame()
.pointAt(util.vector.topOf(pumpPos.north())
.subtract(0.5f, 0.125f, 0))
.placeNearTarget()
.text("Alternating their orientation can help align their flow directions");
scene.idle(40);
scene.world.multiplyKineticSpeed(util.select.everywhere(), 8);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.effects.rotationSpeedIndicator(pumpPos.north());
scene.effects.rotationSpeedIndicator(pumpPos.south());
scene.world.propagatePipeChange(pumpPos);
scene.world.propagatePipeChange(pumpPos.north());
scene.world.propagatePipeChange(pumpPos.south());
scene.idle(100);
scene.world.multiplyKineticSpeed(util.select.everywhere(), -1);
scene.effects.rotationSpeedIndicator(pumpPos);
scene.effects.rotationSpeedIndicator(pumpPos.north());
scene.effects.rotationSpeedIndicator(pumpPos.south());
scene.world.propagatePipeChange(pumpPos);
scene.world.propagatePipeChange(pumpPos.north());
scene.world.propagatePipeChange(pumpPos.south());
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.