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 132f9f65d..eb5bc626c 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 @@ -171,7 +171,9 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity implements public void tick() { super.tick(); - if (!world.isRemote && airCurrentUpdateCooldown-- <= 0) { + boolean server = !world.isRemote || isVirtual(); + + if (server && airCurrentUpdateCooldown-- <= 0) { airCurrentUpdateCooldown = AllConfigs.SERVER.kinetics.fanBlockCheckRate.get(); updateAirFlow = true; } diff --git a/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java index a4b4a22f5..f6db492b5 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java +++ b/src/main/java/com/simibubi/create/foundation/gui/UIRenderHelper.java @@ -21,7 +21,8 @@ public class UIRenderHelper { RenderSystem.recordRenderCall(() -> { MainWindow mainWindow = Minecraft.getInstance().getWindow(); framebuffer = new Framebuffer(mainWindow.getFramebufferWidth(), mainWindow.getFramebufferHeight(), true, Minecraft.IS_RUNNING_ON_MAC); - framebuffer.deleteFramebuffer(); + framebuffer.setFramebufferColor(0, 0, 0, 0); +// framebuffer.deleteFramebuffer(); }); } diff --git a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java index b8d55dead..fe208b5ff 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/SceneBuilder.java @@ -317,6 +317,14 @@ public class SceneBuilder { addInstruction(scene -> scene.linkElement(parrot, link)); return link; } + + public ElementLink flappyBirb(Vec3d location) { + ElementLink link = new ElementLink<>(ParrotElement.class); + ParrotElement parrot = ParrotElement.flappy(location); + addInstruction(new CreateParrotInstruction(10, Direction.DOWN, parrot)); + addInstruction(scene -> scene.linkElement(parrot, link)); + return link; + } public ElementLink birbPartying(Vec3d location) { ElementLink link = new ElementLink<>(ParrotElement.class); @@ -566,6 +574,14 @@ public class SceneBuilder { resolve.ifPresent(tis -> tis.locked = stalled); }); } + + public void changeBeltItemTo(ElementLink link, ItemStack newStack) { + addInstruction(scene -> { + BeltItemElement resolve = scene.resolve(link); + if (resolve != null) + resolve.ifPresent(tis -> tis.stack = newStack); + }); + } public void setKineticSpeed(Selection selection, float speed) { modifyKineticSpeed(selection, f -> speed); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java b/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java new file mode 100644 index 000000000..8d52c8113 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/FanScenes.java @@ -0,0 +1,297 @@ +package com.simibubi.create.foundation.ponder.content; + +import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack; +import com.simibubi.create.content.logistics.block.depot.DepotTileEntity; +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.elements.BeltItemElement; +import com.simibubi.create.foundation.ponder.elements.EntityElement; +import com.simibubi.create.foundation.ponder.elements.InputWindowElement; +import com.simibubi.create.foundation.ponder.elements.ParrotElement; +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 net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class FanScenes { + + public static void direction(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_direction", "Air flow of Encased Fans"); + scene.configureBasePlate(0, 1, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); +// scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f); + scene.idle(5); + scene.world.showSection(util.select.fromTo(3, 1, 0, 3, 1, 5) + .add(util.select.position(3, 2, 4)), Direction.DOWN); + scene.world.showSection(util.select.fromTo(2, 1, 5, 1, 1, 5), Direction.DOWN); + scene.idle(10); + + BlockPos fanPos = util.grid.at(1, 1, 4); + scene.world.showSection(util.select.position(fanPos), Direction.SOUTH); + + scene.idle(40); + scene.effects.rotationDirectionIndicator(fanPos.south()); + + ElementLink flappyBirb = scene.special.flappyBirb(util.vector.topOf(1, 0, 3)); + scene.idle(2); + scene.special.rotateParrot(flappyBirb, 0, 235, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, -2.5), 30); + scene.idle(20); + + scene.overlay.showText(80) + .text("Encased Fans use Rotational Force to create an Air Current") + .placeNearTarget() + .pointAt(util.vector.topOf(fanPos)); + scene.idle(90); + + BlockPos leverPos = util.grid.at(3, 2, 4); + Selection reverse = util.select.fromTo(3, 1, 5, 1, 1, 4); + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reverse, f -> -f); + scene.effects.rotationDirectionIndicator(fanPos.south()); + scene.special.rotateParrot(flappyBirb, 0, 215 * 2, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, 2.5), 30); + scene.idle(31); + + scene.overlay.showText(60) + .text("Strength and Direction of Flow depends on the Rotational Input") + .placeNearTarget() + .pointAt(util.vector.topOf(fanPos)); + scene.markAsFinished(); + scene.idle(70); + + scene.world.toggleRedstonePower(util.select.fromTo(leverPos, leverPos.down())); + scene.effects.indicateRedstone(leverPos); + scene.world.modifyKineticSpeed(reverse, f -> -f); + scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 4 * f); + scene.effects.rotationSpeedIndicator(fanPos.south()); + scene.special.rotateParrot(flappyBirb, 0, 245 * 4, 0, 30); + scene.special.moveParrot(flappyBirb, util.vector.of(0, 0, -20), 30); + + } + + public static void processing(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_processing", "Processing Items using Encased Fans"); + scene.configureBasePlate(1, 0, 5); + scene.world.showSection(util.select.layer(0) + .substract(util.select.position(0, 0, 4)), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.fromTo(6, 1, 2, 5, 1, 2) + .add(util.select.position(1, 1, 2)), Direction.DOWN); + scene.idle(25); + + BlockPos blockPos = util.grid.at(4, 1, 2); + + // blasting start + + ElementLink blockInFront = + scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.SOUTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.world.setBlock(blockPos, Blocks.LAVA.getDefaultState(), false); + scene.idle(10); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 80) + .colored(PonderPalette.RED) + .text("When passing through lava, the Air Flow becomes Heated"); + scene.idle(80); + + ItemStack stack = new ItemStack(Items.GOLD_ORE); + ItemStack smelted = new ItemStack(Items.GOLD_INGOT); + + ElementLink entityLink = scene.world.createItemEntity(util.vector.centerOf(blockPos.west(2) + .up(2)), util.vector.of(0, 0.1, 0), stack); + scene.idle(15); + scene.world.modifyEntity(entityLink, e -> e.setMotion(-0.2f, 0, 0)); + Vec3d itemVec = util.vector.blockSurface(util.grid.at(1, 1, 2), Direction.EAST) + .add(0.1, 0, 0); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(stack), 20); + scene.idle(20); + scene.effects.emitParticles(itemVec.add(0, 0.2f, 0), Emitter.simple(ParticleTypes.LARGE_SMOKE, Vec3d.ZERO), 1, + 60); + + scene.overlay.showText(80) + .colored(PonderPalette.WHITE) + .pointAt(itemVec) + .placeNearTarget() + .text("Items caught in the area will be smelted"); + + scene.idle(60); + scene.world.modifyEntities(ItemEntity.class, ie -> ie.setItem(smelted)); + scene.idle(40); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(smelted), 20); + scene.idle(20); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(20); + + scene.overlay.showText(80) + .colored(PonderPalette.RED) + .pointAt(itemVec) + .placeNearTarget() + .text("Food items thrown here would be incinerated"); + scene.idle(40); + + // smoking start + + BlockState campfire = Blocks.FIRE.getDefaultState(); + scene.world.hideIndependentSection(blockInFront, Direction.NORTH); + scene.idle(15); + scene.world.setBlock(util.grid.at(3, 1, 0), campfire, false); + scene.world.setBlock(blockPos, campfire, true); + blockInFront = scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.NORTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.idle(50); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 60) + .colored(PonderPalette.BLACK) + .text("Instead, a setup for Smoking using Fire should be used for them"); + scene.idle(80); + + // washing start + + BlockState water = Blocks.WATER.getDefaultState(); + scene.world.hideIndependentSection(blockInFront, Direction.NORTH); + scene.idle(15); + scene.world.setBlock(util.grid.at(3, 1, 0), water, false); + scene.world.setBlock(blockPos, water, true); + blockInFront = scene.world.showIndependentSection(util.select.position(3, 1, 0), Direction.NORTH); + scene.world.moveSection(blockInFront, util.vector.of(1, 0, 2), 0); + scene.idle(20); + + scene.overlay.showSelectionWithText(util.select.fromTo(blockPos, blockPos.west(2)), 60) + .colored(PonderPalette.MEDIUM) + .text("Air Flows passing through water create a Washing Setup"); + scene.idle(70); + + stack = AllItems.CRUSHED_GOLD.asStack(); + ItemStack washed = new ItemStack(Items.GOLD_NUGGET, 16); + + entityLink = scene.world.createItemEntity(util.vector.centerOf(blockPos.west(2) + .up(2)), util.vector.of(0, 0.1, 0), stack); + scene.idle(15); + scene.world.modifyEntity(entityLink, e -> e.setMotion(-0.2f, 0, 0)); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(stack), 20); + scene.idle(20); + scene.effects.emitParticles(itemVec.add(0, 0.2f, 0), Emitter.simple(ParticleTypes.SPIT, Vec3d.ZERO), 1, 60); + + scene.overlay.showText(50) + .colored(PonderPalette.WHITE) + .pointAt(itemVec) + .placeNearTarget() + .text("Some interesting new processing can be done with it"); + + scene.idle(60); + scene.world.modifyEntities(ItemEntity.class, ie -> ie.setItem(washed)); + scene.overlay.showControls(new InputWindowElement(itemVec, Pointing.DOWN).withItem(washed), 20); + scene.idle(20); + scene.world.modifyEntities(ItemEntity.class, Entity::remove); + scene.idle(20); + + scene.overlay.showText(100) + .colored(PonderPalette.RED) + .pointAt(util.vector.topOf(blockPos.east())) + .placeNearTarget() + .text("The Speed of the Fan does NOT affect the processing speed, only its range"); + scene.world.destroyBlock(util.grid.at(1, 1, 2)); + scene.idle(110); + + ElementLink cogs = scene.world.makeSectionIndependent(util.select.fromTo(6, 1, 2, 6, 0, 3) + .add(util.select.fromTo(4, 0, 2, 5, 0, 2))); + scene.world.modifyKineticSpeed(util.select.position(5, 2, 2), f -> f / 3f); + scene.world.moveSection(cogs, util.vector.of(0, 1, 0), 15); + scene.world.moveSection(blockInFront, util.vector.of(0, 1, 0), 15); + scene.world.destroyBlock(blockPos.east()); + scene.world.showSection(util.select.position(blockPos.east() + .up()), Direction.DOWN); + scene.world.setBlock(blockPos.up(), Blocks.WATER.getDefaultState(), false); + + ItemStack sand = new ItemStack(Items.SAND); + ItemStack clay = new ItemStack(Items.CLAY_BALL); + + scene.idle(20); + BlockPos depos = util.grid.at(3, 4, 2); + ElementLink depot = + scene.world.showIndependentSection(util.select.position(depos), Direction.DOWN); + scene.world.moveSection(depot, util.vector.of(-1, -3, 0), 0); + scene.world.createItemOnBeltLike(depos, Direction.NORTH, sand); + scene.idle(10); + Vec3d depotTop = util.vector.topOf(2, 1, 2) + .add(0, 0.25, 0); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vec3d.ZERO), .5f, 30); + scene.idle(30); + scene.world.modifyTileNBT(util.select.position(depos), DepotTileEntity.class, + nbt -> nbt.put("HeldItem", new TransportedItemStack(clay).serializeNBT())); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vec3d.ZERO), .5f, 30); + scene.overlay.showText(90) + .pointAt(depotTop) + .text("Fan Processing can also be applied to Items on Depots and Belts"); + + scene.idle(100); + scene.world.moveSection(depot, util.vector.of(-1, 0, 0), 15); + scene.idle(15); + ElementLink largeCog = + scene.world.showIndependentSection(util.select.position(1, 2, 4), Direction.UP); + ElementLink belt = + scene.world.showIndependentSection(util.select.fromTo(3, 3, 1, 1, 3, 3), Direction.DOWN); + scene.world.moveSection(largeCog, util.vector.of(-1, -2, 0), 0); + scene.world.moveSection(belt, util.vector.of(-1, -2, 0), 0); + ElementLink transported = + scene.world.createItemOnBelt(util.grid.at(3, 3, 3), Direction.SOUTH, sand); + scene.idle(60); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vec3d.ZERO), .5f, 25); + scene.idle(25); + scene.world.changeBeltItemTo(transported, new ItemStack(Items.CLAY_BALL)); + scene.effects.emitParticles(depotTop, Emitter.simple(ParticleTypes.SPIT, Vec3d.ZERO), .5f, 25); + scene.idle(60); + + scene.world.setKineticSpeed(util.select.position(1, 2, 4) + .add(util.select.fromTo(3, 3, 1, 1, 3, 3)), 0); + + } + + public static void source(SceneBuilder scene, SceneBuildingUtil util) { + scene.title("fan_source", "Generating Rotational Force using Encased Fans"); + scene.configureBasePlate(0, 0, 5); + scene.world.showSection(util.select.layer(0), Direction.UP); + scene.idle(5); + scene.world.showSection(util.select.layer(1), Direction.DOWN); + scene.idle(10); + scene.world.showSection(util.select.layersFrom(2), Direction.DOWN); + scene.idle(10); + BlockPos rightFan = util.grid.at(1, 2, 2); + scene.overlay.showText(80) + .text("Fans facing down into a source of heat can provide Rotational Force") + .placeNearTarget() + .pointAt(util.vector.blockSurface(rightFan, Direction.WEST)); + scene.idle(80); + + for (BlockPos pos : new BlockPos[] { rightFan, util.grid.at(3, 2, 2) }) { + scene.idle(10); + scene.world.toggleRedstonePower(util.select.position(pos.north())); + scene.effects.indicateRedstone(pos.north()); + scene.world.setKineticSpeed(util.select.fromTo(pos, pos.up()), 4); + scene.effects.rotationSpeedIndicator(pos.up()); + } + + scene.overlay.showText(90) + .text("When given a Redstone Signal, the Fans will start providing power") + .colored(PonderPalette.RED) + .placeNearTarget() + .pointAt(util.vector.blockSurface(rightFan, Direction.WEST)); + scene.markAsFinished(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java index ffc35cb0c..63ad820b8 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/content/PonderIndex.java @@ -41,6 +41,11 @@ public class PonderIndex { PonderRegistry.addStoryBoard(AllBlocks.CLUTCH, "clutch", KineticsScenes::clutch); PonderRegistry.addStoryBoard(AllBlocks.GEARSHIFT, "gearshift", KineticsScenes::gearshift); + PonderRegistry.forComponents(AllBlocks.ENCASED_FAN) + .addStoryBoard("fan/direction", FanScenes::direction) + .addStoryBoard("fan/processing", FanScenes::processing) + .addStoryBoard("fan/source", FanScenes::source); + PonderRegistry.addStoryBoard(AllBlocks.CREATIVE_MOTOR, "creative_motor", KineticsScenes::creativeMotor); PonderRegistry.addStoryBoard(AllBlocks.WATER_WHEEL, "water_wheel", KineticsScenes::waterWheel); PonderRegistry.addStoryBoard(AllBlocks.HAND_CRANK, "hand_crank", KineticsScenes::handCrank); diff --git a/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java b/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java index 38bc429ed..abcbfd691 100644 --- a/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java +++ b/src/main/java/com/simibubi/create/foundation/ponder/elements/ParrotElement.java @@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.foundation.ponder.PonderScene; import com.simibubi.create.foundation.ponder.PonderWorld; import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.MatrixStacker; import net.minecraft.client.Minecraft; @@ -42,6 +43,12 @@ public class ParrotElement extends AnimatedSceneElement { return parrotElement; } + public static ParrotElement flappy(Vec3d location) { + ParrotElement parrotElement = new ParrotElement(location); + parrotElement.pose = parrotElement.new FlappyPose(); + return parrotElement; + } + protected ParrotElement(Vec3d location) { this.location = location; } @@ -61,18 +68,19 @@ public class ParrotElement extends AnimatedSceneElement { if (entity == null) return; - entity.prevPosX = entity.getX(); - entity.prevPosY = entity.getY(); - entity.prevPosZ = entity.getZ(); entity.ticksExisted++; entity.prevRotationYawHead = entity.rotationYawHead; entity.oFlapSpeed = entity.flapSpeed; entity.oFlap = entity.flap; entity.onGround = true; - entity.prevRotationYaw = entity.rotationYaw; - entity.prevRotationPitch = entity.rotationPitch; pose.tick(scene); + + entity.prevPosX = entity.getX(); + entity.prevPosY = entity.getY(); + entity.prevPosZ = entity.getZ(); + entity.prevRotationYaw = entity.rotationYaw; + entity.prevRotationPitch = entity.rotationPitch; } public void setPositionOffset(Vec3d position, boolean immediate) { @@ -153,6 +161,28 @@ public class ParrotElement extends AnimatedSceneElement { } + class FlappyPose extends ParrotPose { + + @Override + void create(PonderWorld world) { + super.create(world); + } + + @Override + void tick(PonderScene scene) { + double length = entity.getPositionVec() + .subtract(entity.prevPosX, entity.prevPosY, entity.prevPosZ) + .length(); + entity.onGround = false; + double phase = Math.min(length * 15, 8); + float f = (float) ((AnimationTickHolder.getTicks() % 100) * phase); + entity.flapSpeed = MathHelper.sin(f) + 1; + if (length == 0) + entity.flapSpeed = 0; + } + + } + class SpinOnComponentPose extends ParrotPose { private BlockPos componentPos; diff --git a/src/main/resources/ponder/fan/direction.nbt b/src/main/resources/ponder/fan/direction.nbt new file mode 100644 index 000000000..08e9d0236 Binary files /dev/null and b/src/main/resources/ponder/fan/direction.nbt differ diff --git a/src/main/resources/ponder/fan/processing.nbt b/src/main/resources/ponder/fan/processing.nbt new file mode 100644 index 000000000..00de4c3fe Binary files /dev/null and b/src/main/resources/ponder/fan/processing.nbt differ diff --git a/src/main/resources/ponder/fan/source.nbt b/src/main/resources/ponder/fan/source.nbt new file mode 100644 index 000000000..0c351c645 Binary files /dev/null and b/src/main/resources/ponder/fan/source.nbt differ