Broken Breaking

- Painful implementation of virtual block breaking overlay
- Scenes for the Mechanical Drill
This commit is contained in:
simibubi 2021-03-14 21:12:02 +01:00
parent a40d0f58c2
commit a8dc4f3622
15 changed files with 365 additions and 15 deletions

View file

@ -90,6 +90,7 @@ public class PonderScene {
int currentTime;
public PonderScene(PonderWorld world, ResourceLocation component, Collection<PonderTag> tags) {
world.scene = this;
pointOfInterest = Vec3d.ZERO;
textIndex = 1;
@ -234,6 +235,7 @@ public class PonderScene {
world.renderEntities(ms, buffer, info, pt);
world.renderParticles(ms, buffer, info, pt);
outliner.renderOutlines(ms, buffer, pt);
ms.pop();
}
@ -409,10 +411,10 @@ public class PonderScene {
}
public MatrixStack apply(MatrixStack ms) {
return apply(ms, AnimationTickHolder.getPartialTicks(world));
return apply(ms, AnimationTickHolder.getPartialTicks(world), false);
}
public MatrixStack apply(MatrixStack ms, float pt) {
public MatrixStack apply(MatrixStack ms, float pt, boolean overlayCompatible) {
ms.translate(width / 2, height / 2, 200 + offset);
MatrixStacker.of(ms)
@ -428,9 +430,18 @@ public class PonderScene {
float f = 30 * scaleFactor;
if (!overlayCompatible) {
ms.scale(f, -f, f);
ms.translate((basePlateSize + basePlateOffsetX) / -2f, -1f + yOffset,
(basePlateSize + basePlateOffsetZ) / -2f);
} else {
// For block breaking overlay; Don't ask
ms.scale(f, f, f);
ms.translate((basePlateSize + basePlateOffsetX) / -2f, -yOffset,
(basePlateSize + basePlateOffsetZ) / -2f);
float y = (float) (0.5065 * Math.pow(2.2975, Math.log(1 / scaleFactor) / Math.log(2))) / 30;
ms.scale(y, -y, -y);
}
return ms;
}

View file

@ -366,7 +366,7 @@ public class PonderUI extends AbstractSimiScreen {
ms.push();
story.transform.updateScreenParams(width, height, slide);
story.transform.apply(ms, partialTicks);
story.transform.apply(ms, partialTicks, false);
story.transform.updateSceneRVE();
story.renderScene(buffer, ms, partialTicks);
buffer.draw();

View file

@ -47,8 +47,11 @@ import net.minecraftforge.registries.ForgeRegistries;
public class PonderWorld extends SchematicWorld {
public PonderScene scene;
protected Map<BlockPos, BlockState> originalBlocks;
protected Map<BlockPos, TileEntity> originalTileEntities;
protected Map<BlockPos, Integer> blockBreakingProgressions;
protected List<Entity> originalEntities;
protected PonderWorldParticles particles;
@ -61,6 +64,7 @@ public class PonderWorld extends SchematicWorld {
super(anchor, original);
originalBlocks = new HashMap<>();
originalTileEntities = new HashMap<>();
blockBreakingProgressions = new HashMap<>();
originalEntities = new ArrayList<>();
particles = new PonderWorldParticles(this);
@ -82,6 +86,7 @@ public class PonderWorld extends SchematicWorld {
entities.clear();
blocks.clear();
tileEntities.clear();
blockBreakingProgressions.clear();
renderedTileEntities.clear();
originalBlocks.forEach((k, v) -> blocks.put(k, v));
originalTileEntities.forEach((k, v) -> {
@ -226,6 +231,17 @@ public class PonderWorld extends SchematicWorld {
}
}
public void setBlockBreakingProgress(BlockPos pos, int damage) {
if (damage == 0)
blockBreakingProgressions.remove(pos);
else
blockBreakingProgressions.put(pos, damage - 1);
}
public Map<BlockPos, Integer> getBlockBreakingProgressions() {
return blockBreakingProgressions;
}
public void addBlockDestroyEffects(BlockPos pos, BlockState state) {
VoxelShape voxelshape = state.getShape(this, pos);
if (voxelshape.isEmpty())

View file

@ -370,6 +370,21 @@ public class SceneBuilder {
public class WorldInstructions {
public void incrementBlockBreakingProgress(BlockPos pos) {
addInstruction(scene -> {
PonderWorld world = scene.getWorld();
int progress = world.getBlockBreakingProgressions()
.getOrDefault(pos, -1) + 1;
if (progress == 9) {
world.addBlockDestroyEffects(pos, world.getBlockState(pos));
world.destroyBlock(pos, false);
world.setBlockBreakingProgress(pos, 0);
scene.forEach(WorldSectionElement.class, WorldSectionElement::queueRedraw);
} else
world.setBlockBreakingProgress(pos, progress + 1);
});
}
public void showSection(Selection selection, Direction fadeInDirection) {
addInstruction(new DisplayWorldSectionInstruction(15, fadeInDirection, selection,
Optional.of(scene::getBaseWorldSection)));

View file

@ -0,0 +1,203 @@
package com.simibubi.create.foundation.ponder.content;
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.EntityElement;
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.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.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class MechanicalDrillScenes {
public static void breaker(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_drill", "Breaking Blocks with the Mechanical Drill");
scene.configureBasePlate(0, 0, 5);
scene.world.setKineticSpeed(util.select.layer(0), -8);
scene.world.setKineticSpeed(util.select.layer(1), 16);
scene.world.showSection(util.select.layer(0), Direction.UP);
scene.idle(5);
scene.world.showSection(util.select.fromTo(4, 1, 2, 5, 1, 2), Direction.DOWN);
scene.idle(10);
scene.world.showSection(util.select.position(3, 1, 2), Direction.EAST);
scene.idle(20);
BlockPos breakingPos = util.grid.at(2, 1, 2);
scene.world.showSection(util.select.position(2, 1, 2), Direction.DOWN);
scene.idle(5);
for (int i = 0; i < 10; i++) {
scene.idle(10);
scene.world.incrementBlockBreakingProgress(breakingPos);
if (i == 1) {
scene.overlay.showText(80)
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.topOf(breakingPos))
.text("When given Rotational Force, a Mechanical Drill will break blocks directly in front of it");
}
}
scene.world.hideSection(util.select.position(breakingPos), Direction.UP);
ElementLink<EntityElement> plankEntity = scene.world.createItemEntity(util.vector.centerOf(breakingPos),
util.vector.of(0, .1f, 0), new ItemStack(Items.OAK_PLANKS));
scene.idle(20);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> 4 * f);
scene.effects.rotationSpeedIndicator(breakingPos.east(3));
scene.idle(20);
scene.world.modifyEntity(plankEntity, Entity::remove);
scene.world.setBlock(breakingPos, Blocks.OAK_PLANKS.getDefaultState(), false);
scene.world.showSection(util.select.position(breakingPos), Direction.DOWN);
scene.idle(5);
for (int i = 0; i < 10; i++) {
scene.idle(3);
scene.world.incrementBlockBreakingProgress(breakingPos);
if (i == 2) {
scene.overlay.showText(80)
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.topOf(breakingPos.east()))
.text("Its mining speed depends on the Rotational Input");
}
}
scene.world.createItemEntity(util.vector.centerOf(breakingPos), util.vector.of(0, .1f, 0),
new ItemStack(Items.OAK_PLANKS));
}
public static void contraption(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_drill_contraption", "Using Mechanical Drills on Contraptions");
scene.configureBasePlate(0, 0, 6);
scene.world.showSection(util.select.layer(0), Direction.UP);
Selection kinetics = util.select.fromTo(5, 1, 2, 5, 1, 6);
scene.idle(5);
ElementLink<WorldSectionElement> pistonHead =
scene.world.showIndependentSection(util.select.fromTo(5, 1, 1, 7, 1, 1), Direction.DOWN);
scene.world.moveSection(pistonHead, util.vector.of(0, 0, 1), 0);
scene.world.showSection(kinetics, Direction.DOWN);
scene.idle(5);
ElementLink<WorldSectionElement> contraption =
scene.world.showIndependentSection(util.select.fromTo(4, 2, 3, 4, 1, 2), Direction.DOWN);
scene.idle(5);
scene.world.showSectionAndMerge(util.select.position(3, 1, 3), Direction.EAST, contraption);
scene.idle(5);
scene.world.showSectionAndMerge(util.select.position(3, 1, 2), Direction.EAST, contraption);
scene.world.showSectionAndMerge(util.select.position(3, 2, 3), Direction.EAST, contraption);
scene.idle(5);
scene.world.showSectionAndMerge(util.select.position(3, 2, 2), Direction.EAST, contraption);
scene.overlay.showText(60)
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.topOf(util.grid.at(3, 2, 3)))
.text("Whenever Drills are moved as part of an animated Contraption...");
scene.idle(70);
Selection drills = util.select.fromTo(3, 1, 2, 3, 2, 3);
Selection planks = util.select.fromTo(1, 1, 2, 1, 2, 3);
scene.world.showSection(planks, Direction.DOWN);
scene.world.setKineticSpeed(util.select.position(4, 0, 6), -8);
scene.world.setKineticSpeed(kinetics, 16);
scene.world.setKineticSpeed(drills, 16);
scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20);
scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20);
scene.idle(20);
scene.world.setKineticSpeed(drills, 64);
BlockPos p1 = util.grid.at(1, 1, 2);
BlockPos p2 = util.grid.at(1, 1, 3);
BlockPos p3 = util.grid.at(1, 2, 2);
BlockPos p4 = util.grid.at(1, 2, 3);
for (int i = 0; i < 10; i++) {
scene.idle(3);
scene.world.incrementBlockBreakingProgress(p1);
scene.world.incrementBlockBreakingProgress(p2);
scene.world.incrementBlockBreakingProgress(p3);
scene.world.incrementBlockBreakingProgress(p4);
if (i == 2) {
scene.overlay.showText(80)
.placeNearTarget()
.pointAt(util.vector.topOf(p3))
.text("...they will break blocks the contraption runs them into");
}
}
Vec3d m = util.vector.of(-.1, 0, 0);
ItemStack item = new ItemStack(Items.OAK_PLANKS);
scene.world.createItemEntity(util.vector.centerOf(p1), m, item);
scene.world.createItemEntity(util.vector.centerOf(p2), m, item);
scene.world.createItemEntity(util.vector.centerOf(p3), m, item);
scene.world.createItemEntity(util.vector.centerOf(p4), m, item);
scene.world.setKineticSpeed(drills, 16);
scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20);
scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20);
scene.idle(20);
scene.world.setKineticSpeed(drills, 0);
scene.idle(20);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f);
scene.world.moveSection(pistonHead, util.vector.of(2, 0, 0), 40);
scene.world.moveSection(contraption, util.vector.of(2, 0, 0), 40);
scene.world.hideSection(planks, Direction.UP);
scene.idle(40);
scene.world.setBlocks(planks, Blocks.OAK_PLANKS.getDefaultState(), false);
scene.world.modifyEntities(ItemEntity.class, Entity::remove);
scene.world.glueBlockOnto(util.grid.at(4, 3, 2), Direction.DOWN, contraption);
scene.overlay.showText(60)
.attachKeyFrame()
.placeNearTarget()
.pointAt(util.vector.blockSurface(util.grid.at(4, 3, 2), Direction.WEST))
.text("Inventories attached to the Contraption will pick up their drops automatically");
scene.idle(70);
scene.world.showSection(planks, Direction.DOWN);
scene.world.modifyKineticSpeed(util.select.everywhere(), f -> -f);
scene.world.setKineticSpeed(drills, 16);
scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20);
scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20);
scene.idle(20);
scene.world.setKineticSpeed(drills, 64);
for (int i = 0; i < 10; i++) {
scene.idle(3);
scene.world.incrementBlockBreakingProgress(p1);
scene.world.incrementBlockBreakingProgress(p2);
scene.world.incrementBlockBreakingProgress(p3);
scene.world.incrementBlockBreakingProgress(p4);
}
scene.world.setKineticSpeed(drills, 16);
scene.world.moveSection(pistonHead, util.vector.of(-1, 0, 0), 20);
scene.world.moveSection(contraption, util.vector.of(-1, 0, 0), 20);
scene.idle(20);
scene.world.setKineticSpeed(drills, 0);
scene.idle(10);
scene.overlay.showControls(new InputWindowElement(util.vector.topOf(2, 3, 2), Pointing.DOWN)
.withItem(new ItemStack(Blocks.OAK_PLANKS)), 60);
scene.idle(20);
}
}

View file

@ -0,0 +1,38 @@
package com.simibubi.create.foundation.ponder.content;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
public class MechanicalSawScenes {
public static void processing(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_saw_processing", "Processing Items on the Mechanical Saw");
scene.configureBasePlate(0, 0, 5);
scene.world.showSection(util.select.layer(0), Direction.UP);
BlockPos shaftPos = util.grid.at(2, 1, 3);
scene.idle(5);
scene.world.showSection(util.select.layersFrom(1), Direction.DOWN);
}
public static void treeCutting(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_saw_breaker", "Cutting Trees with the Mechanical Saw");
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);
}
public static void contraption(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("mechanical_saw_contraption", "Using Mechanical Saws on Contraptions");
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);
}
}

View file

@ -79,14 +79,14 @@ public class PonderIndex {
// Chassis & Super Glue
PonderRegistry.forComponents(AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS)
.addStoryBoard("chassis/linear_group", ChassisScenes::linearGroup)
.addStoryBoard("chassis/linear_group", ChassisScenes::linearGroup, PonderTag.CONTRAPTION_ASSEMBLY)
.addStoryBoard("chassis/linear_attachment", ChassisScenes::linearAttachement);
PonderRegistry.forComponents(AllBlocks.RADIAL_CHASSIS)
.addStoryBoard("chassis/radial", ChassisScenes::radial);
.addStoryBoard("chassis/radial", ChassisScenes::radial, PonderTag.CONTRAPTION_ASSEMBLY);
PonderRegistry.forComponents(AllItems.SUPER_GLUE)
.addStoryBoard("super_glue", ChassisScenes::superGlue);
.addStoryBoard("super_glue", ChassisScenes::superGlue, PonderTag.CONTRAPTION_ASSEMBLY);
PonderRegistry.forComponents(AllBlocks.STICKER)
.addStoryBoard("sticker", RedstoneScenes::sticker);
.addStoryBoard("sticker", RedstoneScenes::sticker, PonderTag.CONTRAPTION_ASSEMBLY);
// Mechanical Piston
PonderRegistry.forComponents(AllBlocks.MECHANICAL_PISTON, AllBlocks.STICKY_MECHANICAL_PISTON)
@ -129,7 +129,6 @@ public class PonderIndex {
PonderTag.KINETIC_APPLIANCES, PonderTag.MOVEMENT_ANCHOR);
PonderRegistry.addStoryBoard(AllBlocks.GANTRY_CARRIAGE, "gantry/intro", GantryScenes::introForPinion,
PonderTag.KINETIC_APPLIANCES, PonderTag.MOVEMENT_ANCHOR);
PonderRegistry.forComponents(AllBlocks.GANTRY_SHAFT, AllBlocks.GANTRY_CARRIAGE)
.addStoryBoard("gantry/redstone", GantryScenes::redstone)
.addStoryBoard("gantry/direction", GantryScenes::direction)
@ -141,6 +140,14 @@ public class PonderIndex {
.addStoryBoard("portable_interface/redstone", MovementActorScenes::psiRedstone);
PonderRegistry.forComponents(AllBlocks.REDSTONE_CONTACT)
.addStoryBoard("redstone_contact", RedstoneScenes::contact);
PonderRegistry.forComponents(AllBlocks.MECHANICAL_SAW)
.addStoryBoard("mechanical_saw/processing", MechanicalSawScenes::processing, PonderTag.KINETIC_APPLIANCES)
.addStoryBoard("mechanical_saw/breaker", MechanicalSawScenes::treeCutting)
.addStoryBoard("mechanical_saw/contraption", MechanicalSawScenes::contraption, PonderTag.CONTRAPTION_ACTOR);
PonderRegistry.forComponents(AllBlocks.MECHANICAL_DRILL)
.addStoryBoard("mechanical_drill/breaker", MechanicalDrillScenes::breaker, PonderTag.KINETIC_APPLIANCES)
.addStoryBoard("mechanical_drill/contraption", MechanicalDrillScenes::contraption,
PonderTag.CONTRAPTION_ACTOR);
// Debug scenes, can be found in game via the Brass Hand
if (EDITOR_MODE)
@ -273,6 +280,15 @@ public class PonderIndex {
.add(AllBlocks.GANTRY_CARRIAGE)
.add(AllBlocks.CART_ASSEMBLER);
PonderRegistry.tags.forTag(PonderTag.CONTRAPTION_ASSEMBLY)
.add(AllBlocks.LINEAR_CHASSIS)
.add(AllBlocks.SECONDARY_LINEAR_CHASSIS)
.add(AllBlocks.RADIAL_CHASSIS)
.add(AllItems.SUPER_GLUE)
.add(AllBlocks.STICKER)
.add(Blocks.SLIME_BLOCK)
.add(Blocks.field_226907_mc_); // honey block
PonderRegistry.tags.forTag(PonderTag.CONTRAPTION_ACTOR)
.add(AllBlocks.MECHANICAL_HARVESTER)
.add(AllBlocks.MECHANICAL_PLOUGH)

View file

@ -2,6 +2,7 @@ package com.simibubi.create.foundation.ponder.content;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.gui.GuiGameElement;
import com.simibubi.create.foundation.gui.IScreenRenderable;
import com.simibubi.create.foundation.ponder.PonderLocalization;
@ -54,6 +55,10 @@ public class PonderTag implements IScreenRenderable {
.defaultLang("Contraption Actors",
"Components which expose special behaviour when attached to a moving contraption"),
CONTRAPTION_ASSEMBLY = new PonderTag("contraption_assembly").item(AllItems.SUPER_GLUE.get(), true, false)
.defaultLang("Block Attachment Utility",
"Tools and Components used to assemble structures moved as an animated Contraption"),
// FLUID_TRANSFER = new PonderTag("fluid_transfer").idAsIcon(),
//
// OPEN_INVENTORY = new PonderTag("open_inventory").item(AllBlocks.BASIN.get()

View file

@ -0,0 +1,18 @@
package com.simibubi.create.foundation.ponder.content;
import com.simibubi.create.foundation.ponder.SceneBuilder;
import com.simibubi.create.foundation.ponder.SceneBuildingUtil;
import net.minecraft.util.Direction;
public class TemplateScenes {
public static void templateMethod(SceneBuilder scene, SceneBuildingUtil util) {
scene.title("", "");
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);
}
}

View file

@ -2,12 +2,16 @@ package com.simibubi.create.foundation.ponder.elements;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.mojang.blaze3d.vertex.MatrixApplyingVertexBuilder;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.ponder.PonderScene;
import com.simibubi.create.foundation.ponder.PonderWorld;
@ -16,7 +20,6 @@ import com.simibubi.create.foundation.render.Compartment;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.render.SuperByteBufferCache;
import com.simibubi.create.foundation.render.TileEntityRenderHelper;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.Pair;
@ -33,6 +36,7 @@ import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.model.ModelBakery;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.fluid.IFluidState;
@ -274,7 +278,31 @@ public class WorldSectionElement extends AnimatedSceneElement {
transformMS(ms, pt);
world.pushFakeLight(light);
renderTileEntities(world, ms, buffer, pt);
renderBlockBreakingProgress(world, ms, buffer, pt);
world.popLight();
Map<BlockPos, Integer> blockBreakingProgressions = world.getBlockBreakingProgressions();
MatrixStack overlayMS = null;
for (Entry<BlockPos, Integer> entry : blockBreakingProgressions.entrySet()) {
BlockPos pos = entry.getKey();
if (!section.test(pos))
continue;
if (overlayMS == null) {
overlayMS = new MatrixStack();
world.scene.getTransform()
.apply(overlayMS, pt, true);
transformMS(overlayMS, pt);
}
ms.push();
ms.translate(pos.getX(), pos.getY(), pos.getZ());
IVertexBuilder builder = new MatrixApplyingVertexBuilder(
buffer.getBuffer(ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(entry.getValue())), overlayMS.peek());
Minecraft.getInstance()
.getBlockRendererDispatcher()
.renderModel(world.getBlockState(BlockPos.ZERO), pos, world, ms, builder, EmptyModelData.INSTANCE);
ms.pop();
}
}
protected void renderStructure(PonderWorld world, MatrixStack ms, IRenderTypeBuffer buffer, RenderType type,

Binary file not shown.

Binary file not shown.