From a97418e784b82c5e6c92581cabd891146b275469 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Mon, 27 Apr 2020 14:04:06 +0200 Subject: [PATCH] Better Schematics - Visual rework to Schematic items and their interface - Written Schematics can now be re-used in Schematic Tables - Schematic and Quill selection is now smoother and more precise - Schematics no longer re-render their preview every time they are re-positioned - Schematic tools now move, rotate or flip the schematic more smoothly - Schematic tools now render the new cuboid outlines rather than plain GL lines - Fixed Schematics not rendering TileEntities in their preview - Fixed inconsistent shifting when rotating Schematics with an "odd by even" size - Fixed typo in Mechanical Press tooltip --- .../simibubi/create/AllSpecialTextures.java | 2 + .../com/simibubi/create/ClientEvents.java | 2 - .../com/simibubi/create/CreateClient.java | 5 - .../gui/widgets/InterpolatedChasingAngle.java | 12 + .../gui/widgets/InterpolatedChasingValue.java | 16 +- .../foundation/utility/RaycastHelper.java | 6 +- .../foundation/utility/WrappedWorld.java | 37 +- .../utility/outliner/AABBOutline.java | 77 +++- .../utility/outliner/ChasingAABBOutline.java | 50 +++ .../foundation/utility/outliner/Outline.java | 17 +- .../utility/outliner/OutlineParticle.java | 18 +- .../utility/render/StructureRenderer.java | 111 ++++++ .../contraptions/ChassisRangeDisplay.java | 3 +- .../contraptions/ContraptionRenderer.java | 94 +---- .../modules/schematics/SchematicWorld.java | 29 +- .../block/SchematicTableContainer.java | 3 +- .../block/SchematicannonTileEntity.java | 6 +- .../client/SchematicAndQuillHandler.java | 264 +++++++------- .../client/SchematicEditScreen.java | 48 ++- .../schematics/client/SchematicHandler.java | 338 +++++++----------- .../schematics/client/SchematicHologram.java | 200 ----------- ...y.java => SchematicHotbarSlotOverlay.java} | 2 +- .../schematics/client/SchematicRenderer.java | 166 +++++++++ .../client/SchematicTransformation.java | 208 +++++++++++ .../schematics/client/tools/DeployTool.java | 94 +++-- .../schematics/client/tools/FlipTool.java | 83 ++++- .../client/tools/ISchematicTool.java | 1 + .../schematics/client/tools/MoveTool.java | 22 +- .../client/tools/MoveVerticalTool.java | 5 +- .../schematics/client/tools/RotateTool.java | 38 +- .../client/tools/SchematicToolBase.java | 145 ++++---- .../schematics/item/SchematicItem.java | 44 ++- .../packet/SchematicPlacePacket.java | 2 +- .../resources/assets/create/lang/en_us.json | 4 +- .../assets/create/textures/gui/background.png | Bin 179 -> 150 bytes .../assets/create/textures/gui/widgets.png | Bin 2795 -> 2992 bytes .../textures/item/blueprint_and_quill.png | Bin 368 -> 518 bytes .../create/textures/item/blueprint_empty.png | Bin 317 -> 373 bytes .../create/textures/item/blueprint_filled.png | Bin 340 -> 436 bytes .../create/textures/special/checkerboard.png | Bin 0 -> 156 bytes .../special/highlighted_checkerboard.png | Bin 0 -> 156 bytes 41 files changed, 1302 insertions(+), 850 deletions(-) create mode 100644 src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java create mode 100644 src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java delete mode 100644 src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java rename src/main/java/com/simibubi/create/modules/schematics/client/{BlueprintHotbarOverlay.java => SchematicHotbarSlotOverlay.java} (90%) create mode 100644 src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java create mode 100644 src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java create mode 100644 src/main/resources/assets/create/textures/special/checkerboard.png create mode 100644 src/main/resources/assets/create/textures/special/highlighted_checkerboard.png diff --git a/src/main/java/com/simibubi/create/AllSpecialTextures.java b/src/main/java/com/simibubi/create/AllSpecialTextures.java index e8a3f15fa..bba4fc2a7 100644 --- a/src/main/java/com/simibubi/create/AllSpecialTextures.java +++ b/src/main/java/com/simibubi/create/AllSpecialTextures.java @@ -9,6 +9,8 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; public enum AllSpecialTextures { BLANK("blank.png"), + CHECKERED("checkerboard.png"), + HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"), SELECTION("selection.png"), ; diff --git a/src/main/java/com/simibubi/create/ClientEvents.java b/src/main/java/com/simibubi/create/ClientEvents.java index 8f2db88e6..aa113445c 100644 --- a/src/main/java/com/simibubi/create/ClientEvents.java +++ b/src/main/java/com/simibubi/create/ClientEvents.java @@ -67,8 +67,6 @@ public class ClientEvents { @SubscribeEvent public static void onRenderWorld(RenderWorldLastEvent event) { CreateClient.schematicHandler.render(); - CreateClient.schematicAndQuillHandler.render(); - CreateClient.schematicHologram.render(); KineticDebugger.renderSourceOutline(); ChassisRangeDisplay.renderOutlines(event.getPartialTicks()); TerrainZapperRenderHandler.render(); diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 6809029d2..d0ccbd321 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -16,7 +16,6 @@ import com.simibubi.create.modules.contraptions.components.contraptions.Contrapt import com.simibubi.create.modules.schematics.ClientSchematicLoader; import com.simibubi.create.modules.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.modules.schematics.client.SchematicHandler; -import com.simibubi.create.modules.schematics.client.SchematicHologram; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; @@ -40,10 +39,8 @@ public class CreateClient { public static ClientSchematicLoader schematicSender; public static SchematicHandler schematicHandler; - public static SchematicHologram schematicHologram; public static SchematicAndQuillHandler schematicAndQuillHandler; public static SuperByteBufferCache bufferCache; - public static int renderTicks; public static void addListeners(IEventBus modEventBus) { DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { @@ -58,7 +55,6 @@ public class CreateClient { public static void clientInit(FMLClientSetupEvent event) { schematicSender = new ClientSchematicLoader(); schematicHandler = new SchematicHandler(); - schematicHologram = new SchematicHologram(); schematicAndQuillHandler = new SchematicAndQuillHandler(); bufferCache = new SuperByteBufferCache(); @@ -81,7 +77,6 @@ public class CreateClient { schematicSender.tick(); schematicAndQuillHandler.tick(); schematicHandler.tick(); - schematicHologram.tick(); ChassisRangeDisplay.clientTick(); } diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java new file mode 100644 index 000000000..3dc30905e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.gui.widgets; + +import com.simibubi.create.foundation.utility.AngleHelper; + +public class InterpolatedChasingAngle extends InterpolatedChasingValue { + + @Override + protected float getCurrentDiff() { + return AngleHelper.getShortestAngleDiff(value, getTarget()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java index e18b5f6d4..92a3efe88 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java @@ -7,11 +7,15 @@ public class InterpolatedChasingValue extends InterpolatedValue { float eps = 1 / 4096f; public void tick() { - float diff = target - value; + float diff = getCurrentDiff(); if (Math.abs(diff) < eps) return; set(value + (diff) * speed); } + + protected float getCurrentDiff() { + return getTarget() - value; + } public InterpolatedChasingValue withSpeed(float speed) { this.speed = speed; @@ -22,5 +26,15 @@ public class InterpolatedChasingValue extends InterpolatedValue { this.target = target; return this; } + + public InterpolatedChasingValue start(float value) { + lastValue = this.value = value; + target(value); + return this; + } + + public float getTarget() { + return target; + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java b/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java index c35a68d1c..69c555ff0 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java @@ -28,7 +28,7 @@ public class RaycastHelper { return rayTraceUntil(origin, target, predicate); } - private static Vec3d getTraceTarget(PlayerEntity playerIn, double range, Vec3d origin) { + public static Vec3d getTraceTarget(PlayerEntity playerIn, double range, Vec3d origin) { float f = playerIn.rotationPitch; float f1 = playerIn.rotationYaw; float f2 = MathHelper.cos(-f1 * 0.017453292F - (float) Math.PI); @@ -42,7 +42,7 @@ public class RaycastHelper { return vec3d1; } - private static Vec3d getTraceOrigin(PlayerEntity playerIn) { + public static Vec3d getTraceOrigin(PlayerEntity playerIn) { double d0 = playerIn.posX; double d1 = playerIn.posY + (double) playerIn.getEyeHeight(); double d2 = playerIn.posZ; @@ -50,7 +50,7 @@ public class RaycastHelper { return vec3d; } - private static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate predicate) { + public static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate predicate) { if (Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z)) return null; if (Double.isNaN(end.x) || Double.isNaN(end.y) || Double.isNaN(end.z)) diff --git a/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java b/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java index 3c7092e7d..d1aabd515 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java @@ -2,6 +2,7 @@ package com.simibubi.create.foundation.utility; import java.util.Collections; import java.util.List; +import java.util.function.Predicate; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -11,6 +12,7 @@ import net.minecraft.fluid.Fluid; import net.minecraft.item.crafting.RecipeManager; import net.minecraft.scoreboard.Scoreboard; import net.minecraft.tags.NetworkTagManager; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; @@ -33,6 +35,26 @@ public class WrappedWorld extends World { return world; } + @Override + public BlockState getBlockState(BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean hasBlockState(BlockPos p_217375_1_, Predicate p_217375_2_) { + return world.hasBlockState(p_217375_1_, p_217375_2_); + } + + @Override + public TileEntity getTileEntity(BlockPos pos) { + return world.getTileEntity(pos); + } + + @Override + public boolean setBlockState(BlockPos pos, BlockState newState, int flags) { + return world.setBlockState(pos, newState, flags); + } + @Override public int getLight(BlockPos pos) { return 15; @@ -59,8 +81,7 @@ public class WrappedWorld extends World { } @Override - public void playEvent(PlayerEntity player, int type, BlockPos pos, int data) { - } + public void playEvent(PlayerEntity player, int type, BlockPos pos, int data) {} @Override public List getPlayers() { @@ -69,13 +90,11 @@ public class WrappedWorld extends World { @Override public void playSound(PlayerEntity player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, - float volume, float pitch) { - } + float volume, float pitch) {} @Override public void playMovingSound(PlayerEntity p_217384_1_, Entity p_217384_2_, SoundEvent p_217384_3_, - SoundCategory p_217384_4_, float p_217384_5_, float p_217384_6_) { - } + SoundCategory p_217384_4_, float p_217384_5_, float p_217384_6_) {} @Override public Entity getEntityByID(int id) { @@ -94,8 +113,7 @@ public class WrappedWorld extends World { } @Override - public void registerMapData(MapData mapDataIn) { - } + public void registerMapData(MapData mapDataIn) {} @Override public int getNextMapId() { @@ -103,8 +121,7 @@ public class WrappedWorld extends World { } @Override - public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) { - } + public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} @Override public Scoreboard getScoreboard() { diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java index da9ab87dd..f899ee4b3 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java @@ -1,16 +1,29 @@ package com.simibubi.create.foundation.utility.outliner; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.foundation.utility.ColorHelper; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; +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.Vec3d; public class AABBOutline extends Outline { - private AxisAlignedBB bb = new AxisAlignedBB(new BlockPos(25, 70, 90)).expand(0, 1, 0); + protected AxisAlignedBB bb; + protected AllSpecialTextures faceTexture; + protected AllSpecialTextures highlightedTexture; + protected Direction highlightedFace; + public boolean disableCull = false; + + public AABBOutline(AxisAlignedBB bb) { + this.bb = bb; + } @Override public void render(BufferBuilder buffer) { @@ -18,8 +31,25 @@ public class AABBOutline extends Outline { Vec3d color = ColorHelper.getRGB(0xFFFFFF); float alpha = 1f; + renderBB(bb, buffer, color, alpha, !disableCull); + + draw(); + } + + public void setTextures(AllSpecialTextures faceTexture, AllSpecialTextures highlightTexture) { + this.faceTexture = faceTexture; + this.highlightedTexture = highlightTexture; + } + + public void highlightFace(Direction face) { + this.highlightedFace = face; + } + + public void renderBB(AxisAlignedBB bb, BufferBuilder buffer, Vec3d color, float alpha, boolean doCulling) { + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + boolean inside = bb.contains(projectedView); + bb = bb.grow(inside ? -1 / 128d : 1 / 128d); - AllSpecialTextures.BLANK.bind(); Vec3d xyz = new Vec3d(bb.minX, bb.minY, bb.minZ); Vec3d Xyz = new Vec3d(bb.maxX, bb.minY, bb.minZ); Vec3d xYz = new Vec3d(bb.minX, bb.maxY, bb.minZ); @@ -29,7 +59,24 @@ public class AABBOutline extends Outline { Vec3d xYZ = new Vec3d(bb.minX, bb.maxY, bb.maxZ); Vec3d XYZ = new Vec3d(bb.maxX, bb.maxY, bb.maxZ); + if (doCulling) { + GlStateManager.enableCull(); + if (inside) + GlStateManager.disableCull(); + } + + renderFace(Direction.NORTH, xYz, XYz, Xyz, xyz, buffer); + renderFace(Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, buffer); + renderFace(Direction.EAST, XYz, XYZ, XyZ, Xyz, buffer); + renderFace(Direction.WEST, xYZ, xYz, xyz, xyZ, buffer); + renderFace(Direction.UP, xYZ, XYZ, XYz, xYz, buffer); + renderFace(Direction.DOWN, xyz, Xyz, XyZ, xyZ, buffer); + + if (doCulling) + GlStateManager.enableCull(); + Vec3d start = xyz; + AllSpecialTextures.BLANK.bind(); renderAACuboidLine(start, Xyz, color, alpha, buffer); renderAACuboidLine(start, xYz, color, alpha, buffer); renderAACuboidLine(start, xyZ, color, alpha, buffer); @@ -49,7 +96,29 @@ public class AABBOutline extends Outline { renderAACuboidLine(start, xyZ, color, alpha, buffer); renderAACuboidLine(start, xYz, color, alpha, buffer); - draw(); + } + + protected void renderFace(Direction direction, Vec3d p1, Vec3d p2, Vec3d p3, Vec3d p4, BufferBuilder buffer) { + GlStateManager.texParameter(GL11.GL_TEXTURE_2D, 10242, GL11.GL_REPEAT); + GlStateManager.texParameter(GL11.GL_TEXTURE_2D, 10243, GL11.GL_REPEAT); + + if (direction == highlightedFace && highlightedTexture != null) + highlightedTexture.bind(); + else if (faceTexture != null) + faceTexture.bind(); + else + return; + + GlStateManager.depthMask(false); + Vec3d uDiff = p2.subtract(p1); + Vec3d vDiff = p4.subtract(p1); + Axis axis = direction.getAxis(); + float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); + float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); + + putQuadUV(p1, p2, p3, p4, 0, 0, maxU, maxV, new Vec3d(1, 1, 1), 1, buffer); + flush(); + GlStateManager.depthMask(true); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java new file mode 100644 index 000000000..5f6a69d59 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java @@ -0,0 +1,50 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class ChasingAABBOutline extends AABBOutline { + + AxisAlignedBB targetBB; + AxisAlignedBB prevBB; + + public ChasingAABBOutline(AxisAlignedBB bb) { + super(bb); + prevBB = bb.grow(0); + targetBB = bb.grow(0); + } + + public void target(AxisAlignedBB target) { + targetBB = target; + } + + public void tick() { + prevBB = bb; + bb = interpolateBBs(bb, targetBB, .5f); + } + + @Override + public void render(BufferBuilder buffer) { + begin(); + + Vec3d color = ColorHelper.getRGB(0xFFFFFF); + float alpha = 1f; + renderBB(interpolateBBs(prevBB, bb, Minecraft.getInstance().getRenderPartialTicks()), buffer, color, alpha, + true); + + draw(); + } + + private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) { + return new AxisAlignedBB(MathHelper.lerp(pt, current.minX, target.minX), + MathHelper.lerp(pt, current.minY, target.minY), MathHelper.lerp(pt, current.minZ, target.minZ), + MathHelper.lerp(pt, current.maxX, target.maxX), MathHelper.lerp(pt, current.maxY, target.maxY), + MathHelper.lerp(pt, current.maxZ, target.maxZ)); + } + +} 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 a0fe1646e..02030782e 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 @@ -32,7 +32,7 @@ public abstract class Outline { begin(); } - protected void renderAACuboidLine(Vec3d start, Vec3d end, Vec3d rgb, float alpha, BufferBuilder buffer) { + public void renderAACuboidLine(Vec3d start, Vec3d end, Vec3d rgb, float alpha, BufferBuilder buffer) { Vec3d diff = end.subtract(start); if (diff.x + diff.y + diff.z < 0) { Vec3d temp = start; @@ -91,11 +91,16 @@ public abstract class Outline { putQuad(a1, a2, a3, a4, rgb, alpha, buffer); } - protected void putQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, Vec3d rgb, float alpha, BufferBuilder buffer) { - putVertex(v1, rgb, 0, 0, alpha, buffer); - putVertex(v2, rgb, 1, 0, alpha, buffer); - putVertex(v3, rgb, 1, 1, alpha, buffer); - putVertex(v4, rgb, 0, 1, alpha, buffer); + public void putQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, Vec3d rgb, float alpha, BufferBuilder buffer) { + putQuadUV(v1, v2, v3, v4, 0, 0, 1, 1, rgb, alpha, buffer); + } + + public void putQuadUV(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, float minU, float minV, float maxU, + float maxV, Vec3d rgb, float alpha, BufferBuilder buffer) { + putVertex(v1, rgb, minU, minV, alpha, buffer); + putVertex(v2, rgb, maxU, minV, alpha, buffer); + putVertex(v3, rgb, maxU, maxV, alpha, buffer); + putVertex(v4, rgb, minU, maxV, alpha, buffer); } protected void putVertex(Vec3d pos, Vec3d rgb, float u, float v, float alpha, BufferBuilder buffer) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java index 80feeb1ca..83bc63d22 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java @@ -11,20 +11,20 @@ import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -public class OutlineParticle extends Particle { +public class OutlineParticle extends Particle { - private Outline outline; + protected O outline; - private OutlineParticle(Outline outline, World worldIn, double xCoordIn, double yCoordIn, double zCoordIn) { + protected OutlineParticle(O outline, World worldIn, double xCoordIn, double yCoordIn, double zCoordIn) { super(worldIn, xCoordIn, yCoordIn, zCoordIn); this.outline = outline; this.maxAge = 1024; } - public static OutlineParticle create(Outline outline) { + public static OutlineParticle create(O outline) { Minecraft mc = Minecraft.getInstance(); ClientPlayerEntity player = mc.player; - OutlineParticle effect = new OutlineParticle(outline, mc.world, player.posX, player.posY, player.posZ); + OutlineParticle effect = new OutlineParticle<>(outline, mc.world, player.posX, player.posY, player.posZ); mc.particles.addEffect(effect); return effect; } @@ -39,14 +39,12 @@ public class OutlineParticle extends Particle { GlStateManager.pushMatrix(); Vec3d view = entityIn.getProjectedView(); GlStateManager.translated(-view.x, -view.y, -view.z); - GlStateManager.depthMask(false); GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.enableBlend(); - outline.render(buffer); + getOutline().render(buffer); GlStateManager.disableBlend(); - GlStateManager.depthMask(true); GlStateManager.popMatrix(); } @@ -55,4 +53,8 @@ public class OutlineParticle extends Particle { return IParticleRenderType.CUSTOM; } + public O getOutline() { + return outline; + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java b/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java new file mode 100644 index 000000000..48916d775 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java @@ -0,0 +1,111 @@ +package com.simibubi.create.foundation.utility.render; + +import java.util.Iterator; + +import com.mojang.blaze3d.platform.GLX; +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.Create; +import com.simibubi.create.config.AllConfigs; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.WrappedWorld; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.crash.ReportedException; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class StructureRenderer { + + protected static LightingWorld lightingWorld; + + public static void renderTileEntities(World world, Vec3d position, Vec3d rotation, + Iterable customRenderTEs) { + TileEntityRendererDispatcher dispatcher = TileEntityRendererDispatcher.instance; + float pt = Minecraft.getInstance().getRenderPartialTicks(); + World prevDispatcherWorld = dispatcher.world; + + if (lightingWorld == null) + lightingWorld = new LightingWorld(world); + lightingWorld.setWorld(world); + lightingWorld.setTransform(position, rotation); + dispatcher.setWorld(lightingWorld); + + for (Iterator iterator = customRenderTEs.iterator(); iterator.hasNext();) { + TileEntity tileEntity = iterator.next(); + if (dispatcher.getRenderer(tileEntity) == null) { + iterator.remove(); + continue; + } + + try { + + BlockPos pos = tileEntity.getPos(); + if (!tileEntity.hasFastRenderer()) { + RenderHelper.enableStandardItemLighting(); + int i = lightingWorld.getCombinedLight(pos, 0); + int j = i % 65536; + int k = i / 65536; + GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, (float) j, (float) k); + GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); + } + + World prevTileWorld = tileEntity.getWorld(); + tileEntity.setWorld(lightingWorld); + GlStateManager.disableCull(); + dispatcher.render(tileEntity, pos.getX(), pos.getY(), pos.getZ(), pt, -1, true); + GlStateManager.enableCull(); + tileEntity.setWorld(prevTileWorld); + + } catch (ReportedException e) { + if (AllConfigs.CLIENT.explainRenderErrors.get()) { + Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() + + " didn't want to render while moved.\n", e); + } else { + Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() + + " didn't want to render while moved.\n"); + } + iterator.remove(); + continue; + } + } + + dispatcher.setWorld(prevDispatcherWorld); + } + + private static class LightingWorld extends WrappedWorld { + + private Vec3d offset; + private Vec3d rotation; + + public LightingWorld(World world) { + super(world); + } + + void setWorld(World world) { + this.world = world; + } + + void setTransform(Vec3d offset, Vec3d rotation) { + this.offset = offset; + this.rotation = rotation; + } + + @Override + public int getCombinedLight(BlockPos pos, int minLight) { + return super.getCombinedLight(transformPos(pos), minLight); + } + + private BlockPos transformPos(BlockPos pos) { + Vec3d vec = VecHelper.getCenterOf(pos); + vec = VecHelper.rotate(vec, rotation.x, rotation.y, rotation.z); + vec = vec.add(offset).subtract(VecHelper.getCenterOf(BlockPos.ZERO)); + return new BlockPos(vec); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java index 6714c05fc..66c967577 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java @@ -14,6 +14,7 @@ import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.foundation.utility.TessellatorHelper; import com.simibubi.create.foundation.utility.outliner.BlockClusterOutline; +import com.simibubi.create.foundation.utility.outliner.Outline; import com.simibubi.create.foundation.utility.outliner.OutlineParticle; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; @@ -32,7 +33,7 @@ public class ChassisRangeDisplay { private static class Entry { BlockClusterOutline outline; - OutlineParticle particle; + OutlineParticle particle; ChassisTileEntity te; int timer; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java index 9a03e703d..31f452a5e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java @@ -1,22 +1,16 @@ package com.simibubi.create.modules.contraptions.components.contraptions; -import java.util.Iterator; import java.util.Random; import java.util.function.Consumer; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; -import com.mojang.blaze3d.platform.GLX; -import com.mojang.blaze3d.platform.GlStateManager; -import com.simibubi.create.Create; import com.simibubi.create.CreateClient; -import com.simibubi.create.config.AllConfigs; import com.simibubi.create.foundation.utility.PlacementSimulationWorld; import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment; -import com.simibubi.create.foundation.utility.VecHelper; -import com.simibubi.create.foundation.utility.WrappedWorld; +import com.simibubi.create.foundation.utility.render.StructureRenderer; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -24,12 +18,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockModelRenderer; import net.minecraft.client.renderer.BlockRendererDispatcher; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.crash.ReportedException; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos.MutableBlockPos; import net.minecraft.util.math.Vec3d; @@ -42,7 +32,6 @@ public class ContraptionRenderer { public static final Compartment CONTRAPTION = new Compartment<>(); protected static PlacementSimulationWorld renderWorld; - protected static LightingWorld lightingWorld; public static void render(World world, Contraption c, Consumer transform, BufferBuilder buffer) { SuperByteBuffer contraptionBuffer = CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c)); @@ -52,54 +41,7 @@ public class ContraptionRenderer { } public static void renderTEsWithGL(World world, Contraption c, Vec3d position, Vec3d rotation) { - TileEntityRendererDispatcher dispatcher = TileEntityRendererDispatcher.instance; - float pt = Minecraft.getInstance().getRenderPartialTicks(); - World prevDispatcherWorld = dispatcher.world; - - if (lightingWorld == null) - lightingWorld = new LightingWorld(world); - lightingWorld.setWorld(world); - lightingWorld.setTransform(position, rotation); - dispatcher.setWorld(lightingWorld); - - for (Iterator iterator = c.customRenderTEs.iterator(); iterator.hasNext();) { - TileEntity tileEntity = iterator.next(); - if (dispatcher.getRenderer(tileEntity) == null) { - iterator.remove(); - continue; - } - - try { - - BlockPos pos = tileEntity.getPos(); - if (!tileEntity.hasFastRenderer()) { - RenderHelper.enableStandardItemLighting(); - int i = lightingWorld.getCombinedLight(pos, 0); - int j = i % 65536; - int k = i / 65536; - GLX.glMultiTexCoord2f(GLX.GL_TEXTURE1, (float) j, (float) k); - GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); - } - - World prevTileWorld = tileEntity.getWorld(); - tileEntity.setWorld(lightingWorld); - dispatcher.render(tileEntity, pos.getX(), pos.getY(), pos.getZ(), pt, -1, true); - tileEntity.setWorld(prevTileWorld); - - } catch (ReportedException e) { - if (AllConfigs.CLIENT.explainRenderErrors.get()) { - Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() - + " didn't want to render while moved.\n", e); - } else { - Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() - + " didn't want to render while moved.\n"); - } - iterator.remove(); - continue; - } - } - - dispatcher.setWorld(prevDispatcherWorld); + StructureRenderer.renderTileEntities(world, position, rotation, c.customRenderTEs); } private static SuperByteBuffer renderContraption(Contraption c) { @@ -173,36 +115,4 @@ public class ContraptionRenderer { return ((int) sky) << 20 | ((int) block) << 4; } - private static class LightingWorld extends WrappedWorld { - - private Vec3d offset; - private Vec3d rotation; - - public LightingWorld(World world) { - super(world); - } - - void setWorld(World world) { - this.world = world; - } - - void setTransform(Vec3d offset, Vec3d rotation) { - this.offset = offset; - this.rotation = rotation; - } - - @Override - public int getCombinedLight(BlockPos pos, int minLight) { - return super.getCombinedLight(transformPos(pos), minLight); - } - - private BlockPos transformPos(BlockPos pos) { - Vec3d vec = VecHelper.getCenterOf(pos); - vec = VecHelper.rotate(vec, rotation.x, rotation.y, rotation.z); - vec = vec.add(offset).subtract(VecHelper.getCenterOf(BlockPos.ZERO)); - return new BlockPos(vec); - } - - } - } diff --git a/src/main/java/com/simibubi/create/modules/schematics/SchematicWorld.java b/src/main/java/com/simibubi/create/modules/schematics/SchematicWorld.java index d780187e2..cdc1024ec 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/SchematicWorld.java +++ b/src/main/java/com/simibubi/create/modules/schematics/SchematicWorld.java @@ -1,6 +1,7 @@ package com.simibubi.create.modules.schematics; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -29,13 +30,16 @@ import net.minecraft.world.biome.Biomes; public class SchematicWorld extends WrappedWorld { private Map blocks; + private Map tileEntities; private Cuboid bounds; public BlockPos anchor; + public boolean renderMode; - public SchematicWorld(Map blocks, Cuboid bounds, BlockPos anchor, World original) { + public SchematicWorld(BlockPos anchor, World original) { super(original); - this.blocks = blocks; - this.setBounds(bounds); + this.blocks = new HashMap<>(); + this.tileEntities = new HashMap<>(); + this.bounds = new Cuboid(); this.anchor = anchor; } @@ -45,6 +49,19 @@ public class SchematicWorld extends WrappedWorld { @Override public TileEntity getTileEntity(BlockPos pos) { + if (isOutsideBuildHeight(pos)) + return null; + if (tileEntities.containsKey(pos)) + return tileEntities.get(pos); + if (!blocks.containsKey(pos.subtract(anchor))) + return null; + + BlockState blockState = getBlockState(pos); + if (blockState.hasTileEntity()) { + TileEntity tileEntity = blockState.createTileEntity(this); + tileEntities.put(pos, tileEntity); + return tileEntity; + } return null; } @@ -52,7 +69,7 @@ public class SchematicWorld extends WrappedWorld { public BlockState getBlockState(BlockPos globalPos) { BlockPos pos = globalPos.subtract(anchor); - if (pos.getY() - bounds.y == -1) { + if (pos.getY() - bounds.y == -1 && !renderMode) { return Blocks.GRASS_BLOCK.getDefaultState(); } @@ -171,4 +188,8 @@ public class SchematicWorld extends WrappedWorld { this.bounds = bounds; } + public Iterable getTileEntities() { + return tileEntities.values(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java index 1157ab797..40b71cab4 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java @@ -44,7 +44,8 @@ public class SchematicTableContainer extends Container { inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) { @Override public boolean isItemValid(ItemStack stack) { - return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack); + return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack) + || AllItems.BLUEPRINT.typeOf(stack); } }; diff --git a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java index ad3fbc63d..081ddf8e8 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java @@ -1,6 +1,5 @@ package com.simibubi.create.modules.schematics.block; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -12,7 +11,6 @@ import com.simibubi.create.config.AllConfigs; import com.simibubi.create.config.CSchematics; import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; -import com.simibubi.create.foundation.type.Cuboid; import com.simibubi.create.modules.schematics.MaterialChecklist; import com.simibubi.create.modules.schematics.SchematicWorld; import com.simibubi.create.modules.schematics.item.SchematicItem; @@ -466,7 +464,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } // Load blocks into reader - Template activeTemplate = SchematicItem.getSchematic(blueprint); + Template activeTemplate = SchematicItem.loadSchematic(blueprint); BlockPos anchor = NBTUtil.readBlockPos(blueprint.getTag().getCompound("Anchor")); if (activeTemplate.getSize().equals(BlockPos.ZERO)) { @@ -484,7 +482,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } schematicAnchor = anchor; - blockReader = new SchematicWorld(new HashMap<>(), new Cuboid(), schematicAnchor, world); + blockReader = new SchematicWorld(schematicAnchor, world); activeTemplate.addBlocksToWorld(blockReader, schematicAnchor, SchematicItem.getSettings(blueprint)); schematicLoaded = true; state = State.PAUSED; diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java index 54e45628d..c0cec4880 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java @@ -8,7 +8,6 @@ import java.nio.file.StandardOpenOption; import org.apache.commons.io.IOUtils; -import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.AllSpecialTextures; @@ -18,13 +17,13 @@ import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; -import com.simibubi.create.foundation.utility.TessellatorHelper; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.outliner.ChasingAABBOutline; +import com.simibubi.create.foundation.utility.outliner.OutlineParticle; import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.CompoundNBT; @@ -32,6 +31,7 @@ import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.util.Direction; import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Hand; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.MathHelper; @@ -49,14 +49,7 @@ public class SchematicAndQuillHandler { private Direction selectedFace; private int range = 10; - private boolean isActive() { - return isPresent() && AllItems.BLUEPRINT_AND_QUILL.typeOf(Minecraft.getInstance().player.getHeldItemMainhand()); - } - - private boolean isPresent() { - return Minecraft.getInstance() != null && Minecraft.getInstance().world != null - && Minecraft.getInstance().currentScreen == null; - } + private OutlineParticle particle; public boolean mouseScrolled(double delta) { if (!isActive()) @@ -65,27 +58,32 @@ public class SchematicAndQuillHandler { return false; if (secondPos == null) range = (int) MathHelper.clamp(range + delta, 1, 100); - if (selectedFace != null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - Vec3i vec = selectedFace.getDirectionVec(); + if (selectedFace == null) + return true; - int x = (int) (vec.getX() * delta); - int y = (int) (vec.getY() * delta); - int z = (int) (vec.getZ() * delta); + AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos); + Vec3i vec = selectedFace.getDirectionVec(); + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + if (bb.contains(projectedView)) + delta *= -1; - AxisDirection axisDirection = selectedFace.getAxisDirection(); - if (axisDirection == AxisDirection.NEGATIVE) - bb.offset(-x, -y, -z); + int x = (int) (vec.getX() * delta); + int y = (int) (vec.getY() * delta); + int z = (int) (vec.getZ() * delta); - bb.maxX = Math.max(bb.maxX - x * axisDirection.getOffset(), bb.minX); - bb.maxY = Math.max(bb.maxY - y * axisDirection.getOffset(), bb.minY); - bb.maxZ = Math.max(bb.maxZ - z * axisDirection.getOffset(), bb.minZ); + AxisDirection axisDirection = selectedFace.getAxisDirection(); + if (axisDirection == AxisDirection.NEGATIVE) + bb = bb.offset(-x, -y, -z); - firstPos = new BlockPos(bb.minX, bb.minY, bb.minZ); - secondPos = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.dimensions", bb.getXSize(), - bb.getYSize(), bb.getZSize()); - } + double maxX = Math.max(bb.maxX - x * axisDirection.getOffset(), bb.minX); + double maxY = Math.max(bb.maxY - y * axisDirection.getOffset(), bb.minY); + double maxZ = Math.max(bb.maxZ - z * axisDirection.getOffset(), bb.minZ); + bb = new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, maxX, maxY, maxZ); + + firstPos = new BlockPos(bb.minX, bb.minY, bb.minZ); + secondPos = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.dimensions", (int) bb.getXSize() + 1, + (int) bb.getYSize() + 1, (int) bb.getZSize() + 1); return true; } @@ -106,8 +104,7 @@ public class SchematicAndQuillHandler { } if (secondPos != null) { - TextInputPromptScreen guiScreenIn = new TextInputPromptScreen(this::saveSchematic, s -> { - }); + TextInputPromptScreen guiScreenIn = new TextInputPromptScreen(this::saveSchematic, s -> {}); guiScreenIn.setTitle(Lang.translate("schematicAndQuill.prompt")); guiScreenIn.setButtonTextConfirm(Lang.translate("action.saveToFile")); guiScreenIn.setButtonTextAbort(Lang.translate("action.discard")); @@ -130,6 +127,100 @@ public class SchematicAndQuillHandler { Lang.sendStatus(player, "schematicAndQuill.firstPos"); } + public void tick() { + if (!isActive()) { + if (particle != null) { + particle.setExpired(); + particle = null; + } + return; + } + + ClientPlayerEntity player = Minecraft.getInstance().player; + + if (AllKeys.ACTIVATE_TOOL.isPressed()) { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + Vec3d targetVec = player.getEyePosition(pt).add(player.getLookVec().scale(range)); + setCursor(new BlockPos(targetVec)); + + } else { + BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); + if (trace != null && trace.getType() == Type.BLOCK) { + + BlockPos hit = trace.getPos(); + boolean replaceable = player.world.getBlockState(hit) + .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); + if (trace.getFace().getAxis().isVertical() && !replaceable) + hit = hit.offset(trace.getFace()); + setCursor(hit); + } else + setCursor(null); + } + + if (particle == null) + return; + + ChasingAABBOutline outline = particle.getOutline(); + if (particle.isAlive()) + outline.tick(); + + if (secondPos == null) { + selectedFace = null; + outline.highlightFace(null); + return; + } + + AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1).grow(.45f); + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + boolean inside = bb.contains(projectedView); + + PredicateTraceResult result = + RaycastHelper.rayTraceUntil(player, 70, pos -> inside ^ bb.contains(VecHelper.getCenterOf(pos))); + selectedFace = result.missed() ? null : inside ? result.getFacing().getOpposite() : result.getFacing(); + outline.highlightFace(AllKeys.ACTIVATE_TOOL.isPressed() ? selectedFace : null); + } + + private void setCursor(BlockPos pos) { + selectedPos = pos; + AxisAlignedBB bb = getCurrentSelectionBox(); + + if (particle != null && !particle.isAlive()) + particle = null; + if (bb == null) { + if (particle != null) + particle.setExpired(); + return; + } + + if (particle == null) { + ChasingAABBOutline outline = new ChasingAABBOutline(bb); + outline.setTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED); + particle = OutlineParticle.create(outline); + } + + ChasingAABBOutline outline = particle.getOutline(); + outline.target(bb); + } + + private AxisAlignedBB getCurrentSelectionBox() { + if (secondPos == null) { + if (firstPos == null) + return selectedPos == null ? null : new AxisAlignedBB(selectedPos); + return selectedPos == null ? new AxisAlignedBB(firstPos) + : new AxisAlignedBB(firstPos, selectedPos).expand(1, 1, 1); + } + return new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1); + } + + private boolean isActive() { + return isPresent() && AllItems.BLUEPRINT_AND_QUILL.typeOf(Minecraft.getInstance().player.getHeldItemMainhand()); + } + + private boolean isPresent() { + return Minecraft.getInstance() != null && Minecraft.getInstance().world != null + && Minecraft.getInstance().currentScreen == null; + } + public void saveSchematic(String string) { Template t = new Template(); MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); @@ -160,115 +251,4 @@ public class SchematicAndQuillHandler { Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.saved", filepath); } - public void render() { - if (!isActive()) - return; - - TessellatorHelper.prepareForDrawing(); - GlStateManager.lineWidth(2); - GlStateManager.color4f(1, 1, 1, 1); - GlStateManager.disableTexture(); - - if (secondPos == null) { - // 1st Step - if (firstPos != null && selectedPos == null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, firstPos.add(1, 1, 1)); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - drawBox(min, max, true); - } - - if (firstPos != null && selectedPos != null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, selectedPos); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); - drawBox(min, max, true); - } - - if (firstPos == null && selectedPos != null) { - MutableBoundingBox bb = new MutableBoundingBox(selectedPos, selectedPos.add(1, 1, 1)); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - drawBox(min, max, true); - } - } else { - // 2nd Step - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); - drawBox(min, max, false); - - if (selectedFace != null) { - Vec3d vec = new Vec3d(selectedFace.getDirectionVec()); - Vec3d center = new Vec3d(min.add(max)).scale(1 / 2f); - Vec3d radii = new Vec3d(max.subtract(min)).scale(1 / 2f); - - Vec3d onFaceOffset = new Vec3d(1 - Math.abs(vec.x), 1 - Math.abs(vec.y), 1 - Math.abs(vec.z)) - .mul(radii); - Vec3d faceMin = center.add(vec.mul(radii).add(onFaceOffset)); - Vec3d faceMax = center.add(vec.mul(radii).subtract(onFaceOffset)); - - GlStateManager.enableTexture(); - TessellatorHelper.begin(); - AllSpecialTextures.SELECTION.bind(); - TessellatorHelper.doubleFace(Tessellator.getInstance().getBuffer(), new BlockPos(faceMin), - new BlockPos(faceMax.subtract(faceMin)), 1 / 16f * selectedFace.getAxisDirection().getOffset(), - false, false, false); - TessellatorHelper.draw(); - GlStateManager.disableTexture(); - - } - - } - - GlStateManager.lineWidth(1); - GlStateManager.enableTexture(); - TessellatorHelper.cleanUpAfterDrawing(); - } - - protected static void drawBox(BlockPos min, BlockPos max, boolean blue) { - float red = blue ? .8f : 1; - float green = blue ? .9f : 1; - WorldRenderer.drawBoundingBox(min.getX() - 1 / 16d, min.getY() + 1 / 16d, min.getZ() - 1 / 16d, - max.getX() + 1 / 16d, max.getY() + 1 / 16d, max.getZ() + 1 / 16d, red, green, 1, 1); - } - - public void tick() { - if (!isActive()) - return; - ClientPlayerEntity player = Minecraft.getInstance().player; - - selectedPos = null; - if (AllKeys.ACTIVATE_TOOL.isPressed()) { - selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) - .add(player.getLookVec().scale(range))); - } else { - BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); - if (trace != null && trace.getType() == Type.BLOCK) { - - BlockPos hit = new BlockPos(trace.getHitVec()); - boolean replaceable = player.world.getBlockState(hit) - .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); - if (trace.getFace().getAxis().isVertical() && !replaceable) - hit = hit.offset(trace.getFace()); - - selectedPos = hit; - } else { - selectedPos = null; - } - } - - if (secondPos == null) { - selectedFace = null; - return; - } - - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - bb.maxX++; - bb.maxY++; - bb.maxZ++; - - PredicateTraceResult result = RaycastHelper.rayTraceUntil(player, 70, pos -> bb.isVecInside(pos)); - selectedFace = result.missed() ? null : result.getFacing(); - } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java index eb99c1fd4..71affc6bd 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java @@ -15,9 +15,11 @@ import com.simibubi.create.foundation.utility.Lang; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTUtil; import net.minecraft.util.Mirror; import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.template.PlacementSettings; public class SchematicEditScreen extends AbstractSimiScreen { @@ -25,10 +27,10 @@ public class SchematicEditScreen extends AbstractSimiScreen { private TextFieldWidget yInput; private TextFieldWidget zInput; - private final List rotationOptions = Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", - "cw270"); - private final List mirrorOptions = Lang.translatedOptions("schematic.mirror", "none", "leftRight", - "frontBack"); + private final List rotationOptions = + Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", "cw270"); + private final List mirrorOptions = + Lang.translatedOptions("schematic.mirror", "none", "leftRight", "frontBack"); private final String positionLabel = Lang.translate("schematic.position"); private final String rotationLabel = Lang.translate("schematic.rotation"); private final String mirrorLabel = Lang.translate("schematic.mirror"); @@ -48,10 +50,11 @@ public class SchematicEditScreen extends AbstractSimiScreen { yInput = new TextFieldWidget(font, x + 115, y + 32, 32, 10, ""); zInput = new TextFieldWidget(font, x + 155, y + 32, 32, 10, ""); - if (handler.deployed) { - xInput.setText("" + handler.anchor.getX()); - yInput.setText("" + handler.anchor.getY()); - zInput.setText("" + handler.anchor.getZ()); + BlockPos anchor = handler.getTransformation().getAnchor(); + if (handler.isDeployed()) { + xInput.setText("" + anchor.getX()); + yInput.setText("" + anchor.getY()); + zInput.setText("" + anchor.getZ()); } else { BlockPos alt = minecraft.player.getPosition(); xInput.setText("" + alt.getX()); @@ -77,13 +80,14 @@ public class SchematicEditScreen extends AbstractSimiScreen { }); } + PlacementSettings settings = handler.getTransformation().toSettings(); Label labelR = new Label(x + 99, y + 52, "").withShadow(); rotationArea = new SelectionScrollInput(x + 96, y + 49, 94, 14).forOptions(rotationOptions).titled("Rotation") - .setState(handler.cachedSettings.getRotation().ordinal()).writingTo(labelR); + .setState(settings.getRotation().ordinal()).writingTo(labelR); Label labelM = new Label(x + 99, y + 72, "").withShadow(); mirrorArea = new SelectionScrollInput(x + 96, y + 69, 94, 14).forOptions(mirrorOptions).titled("Mirror") - .setState(handler.cachedSettings.getMirror().ordinal()).writingTo(labelM); + .setState(settings.getMirror().ordinal()).writingTo(labelM); Collections.addAll(widgets, xInput, yInput, zInput); Collections.addAll(widgets, labelR, labelM, rotationArea, mirrorArea); @@ -127,8 +131,8 @@ public class SchematicEditScreen extends AbstractSimiScreen { int y = guiTop; ScreenResources.SCHEMATIC.draw(this, x, y); - font.drawStringWithShadow(handler.cachedSchematicName, - x + 103 - font.getStringWidth(handler.cachedSchematicName) / 2, y + 10, 0xDDEEFF); + font.drawStringWithShadow(handler.getCurrentSchematicName(), + x + 103 - font.getStringWidth(handler.getCurrentSchematicName()) / 2, y + 10, 0xDDEEFF); font.drawString(positionLabel, x + 10, y + 32, ScreenResources.FONT_COLOR); font.drawString(rotationLabel, x + 10, y + 52, ScreenResources.FONT_COLOR); @@ -152,10 +156,22 @@ public class SchematicEditScreen extends AbstractSimiScreen { validCoords = false; } - if (validCoords) - handler.moveTo(newLocation); - handler.setRotation(Rotation.values()[rotationArea.getState()]); - handler.setMirror(Mirror.values()[mirrorArea.getState()]); + PlacementSettings settings = new PlacementSettings(); + settings.setRotation(Rotation.values()[rotationArea.getState()]); + settings.setMirror(Mirror.values()[mirrorArea.getState()]); + + if (validCoords && newLocation != null) { + ItemStack item = handler.getActiveSchematicItem(); + if (item != null) { + item.getTag().putBoolean("Deployed", true); + item.getTag().put("Anchor", NBTUtil.writeBlockPos(newLocation)); + } + + handler.getTransformation().init(newLocation, settings, handler.getBounds()); + handler.markDirty(); + handler.deploy(); + } + } } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java index 6a406a721..16b88fcde 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java @@ -1,19 +1,16 @@ package com.simibubi.create.modules.schematics.client; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.AllPackets; -import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.gui.ToolSelectionScreen; import com.simibubi.create.foundation.packet.NbtPacket; -import com.simibubi.create.foundation.type.Cuboid; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.TessellatorHelper; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.modules.schematics.SchematicWorld; import com.simibubi.create.modules.schematics.client.tools.Tools; import com.simibubi.create.modules.schematics.item.SchematicItem; @@ -26,79 +23,62 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; -import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.gen.feature.template.PlacementSettings; import net.minecraft.world.gen.feature.template.Template; public class SchematicHandler { - public Template cachedSchematic; - public String cachedSchematicName; - public PlacementSettings cachedSettings; + private String displayedSchematic; + private SchematicTransformation transformation; + private AxisAlignedBB bounds; // local space + private AABBOutline outline; + private boolean deployed; + private boolean active; + private Tools currentTool; - public BlockPos anchor; - public BlockPos size; - public boolean active; - public boolean deployed; - public int slot; - public ItemStack item; + private static final int SYNC_DELAY = 10; + private int syncCooldown; + private int activeHotbarSlot; + private ItemStack activeSchematicItem; - private final List mirrors = Arrays.asList("none", "leftRight", "frontBack"); - private final List rotations = Arrays.asList("none", "cw90", "cw180", "cw270"); - - public Tools currentTool; - public ToolSelectionScreen selectionScreen; - - public static final int SYNC_DELAY = 20; - public int syncCooldown; - - private BlueprintHotbarOverlay overlay; + private SchematicRenderer renderer; + private SchematicHotbarSlotOverlay overlay; + private ToolSelectionScreen selectionScreen; public SchematicHandler() { + overlay = new SchematicHotbarSlotOverlay(); + renderer = new SchematicRenderer(); currentTool = Tools.Deploy; - overlay = new BlueprintHotbarOverlay(); selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + transformation = new SchematicTransformation(); } public void tick() { ClientPlayerEntity player = Minecraft.getInstance().player; + if (activeSchematicItem != null && transformation != null) + transformation.tick(); + ItemStack stack = findBlueprintInHand(player); if (stack == null) { active = false; syncCooldown = 0; - if (item != null && itemLost(player)) { - slot = 0; - item = null; - CreateClient.schematicHologram.setActive(false); + if (activeSchematicItem != null && itemLost(player)) { + activeHotbarSlot = 0; + activeSchematicItem = null; + renderer.setActive(false); } return; } - // Newly equipped - if (!active || !stack.getTag().getString("File").equals(cachedSchematicName)) { - loadSettings(stack); - cachedSchematicName = stack.getTag().getString("File"); - active = true; - if (deployed) { - Tools toolBefore = currentTool; - selectionScreen = new ToolSelectionScreen(Tools.getTools(player.isCreative()), this::equip); - if (toolBefore != null) { - selectionScreen.setSelectedElement(toolBefore); - equip(toolBefore); - } - } else - selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); - sync(); - } - + if (!active || !stack.getTag().getString("File").equals(displayedSchematic)) + init(player, stack); if (!active) return; + renderer.tick(); if (syncCooldown > 0) syncCooldown--; if (syncCooldown == 1) @@ -108,22 +88,62 @@ public class SchematicHandler { currentTool.getTool().updateSelection(); } - public void render() { - if (!active) - return; - if (Minecraft.getInstance().player.isSneaking()) + private void init(ClientPlayerEntity player, ItemStack stack) { + loadSettings(stack); + displayedSchematic = stack.getTag().getString("File"); + active = true; + if (deployed) { + setupRenderer(); + Tools toolBefore = currentTool; + selectionScreen = new ToolSelectionScreen(Tools.getTools(player.isCreative()), this::equip); + if (toolBefore != null) { + selectionScreen.setSelectedElement(toolBefore); + equip(toolBefore); + } + } else + selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + } + + private void setupRenderer() { + Template schematic = SchematicItem.loadSchematic(activeSchematicItem); + if (schematic.getSize().equals(BlockPos.ZERO)) return; + SchematicWorld w = new SchematicWorld(BlockPos.ZERO, Minecraft.getInstance().world); + schematic.addBlocksToWorld(w, BlockPos.ZERO, new PlacementSettings()); + renderer.startHologram(w); + } + + public void render() { + boolean present = activeSchematicItem != null; + if (!active && !present) + return; + if (active) { + TessellatorHelper.prepareForDrawing(); + currentTool.getTool().renderTool(); + TessellatorHelper.cleanUpAfterDrawing(); + } + + GlStateManager.pushMatrix(); TessellatorHelper.prepareForDrawing(); - currentTool.getTool().renderTool(); + transformation.applyGLTransformations(); + renderer.render(); + GlStateManager.disableCull(); + + if (active) + currentTool.getTool().renderToolLocal(); + + GlStateManager.enableCull(); + GlStateManager.depthMask(true); TessellatorHelper.cleanUpAfterDrawing(); + GlStateManager.popMatrix(); } public void renderOverlay() { if (!active) return; - if (item != null) - overlay.renderOn(slot); + if (activeSchematicItem != null) + overlay.renderOn(activeHotbarSlot); currentTool.getTool().renderOverlay(); selectionScreen.renderPassive(Minecraft.getInstance().getRenderPartialTicks()); @@ -148,7 +168,6 @@ public class SchematicHandler { if (pressed && !selectionScreen.focused) selectionScreen.focused = true; - if (!pressed && selectionScreen.focused) { selectionScreen.focused = false; selectionScreen.onClose(); @@ -156,18 +175,15 @@ public class SchematicHandler { } public boolean mouseScrolled(double delta) { - if (!active) - return false; - if (Minecraft.getInstance().player.isSneaking()) + if (!active || Minecraft.getInstance().player.isSneaking()) return false; + if (selectionScreen.focused) { selectionScreen.cycle((int) delta); return true; } - if (AllKeys.ACTIVATE_TOOL.isPressed()) { + if (AllKeys.ACTIVATE_TOOL.isPressed()) return currentTool.getTool().handleMouseWheel(delta); - } - return false; } @@ -178,16 +194,16 @@ public class SchematicHandler { if (!stack.hasTag()) return null; - item = stack; - slot = player.inventory.currentItem; + activeSchematicItem = stack; + activeHotbarSlot = player.inventory.currentItem; return stack; } private boolean itemLost(PlayerEntity player) { for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { - if (!player.inventory.getStackInSlot(i).isItemEqual(item)) + if (!player.inventory.getStackInSlot(i).isItemEqual(activeSchematicItem)) continue; - if (!ItemStack.areItemStackTagsEqual(player.inventory.getStackInSlot(i), item)) + if (!ItemStack.areItemStackTagsEqual(player.inventory.getStackInSlot(i), activeSchematicItem)) continue; return false; } @@ -196,25 +212,20 @@ public class SchematicHandler { public void markDirty() { syncCooldown = SYNC_DELAY; - CreateClient.schematicHologram.setActive(false); } public void sync() { - message(Lang.translate("schematics.synchronizing")); - AllPackets.channel.sendToServer(new NbtPacket(item, slot)); + if (activeSchematicItem == null) + return; - if (deployed) { - Template schematic = SchematicItem.getSchematic(item); + PlacementSettings settings = transformation.toSettings(); + CompoundNBT tag = activeSchematicItem.getTag(); + tag.putBoolean("Deployed", deployed); + tag.put("Anchor", NBTUtil.writeBlockPos(transformation.getAnchor())); + tag.putString("Rotation", settings.getRotation().name()); + tag.putString("Mirror", settings.getMirror().name()); - if (schematic.getSize().equals(BlockPos.ZERO)) - return; - - SchematicWorld w = new SchematicWorld(new HashMap<>(), new Cuboid(), anchor, Minecraft.getInstance().world); - PlacementSettings settings = cachedSettings.copy(); - settings.setBoundingBox(null); - schematic.addBlocksToWorld(w, anchor, settings); - CreateClient.schematicHologram.startHologram(w); - } + AllPackets.channel.sendToServer(new NbtPacket(activeSchematicItem, activeHotbarSlot)); } public void equip(Tools tool) { @@ -224,149 +235,66 @@ public class SchematicHandler { public void loadSettings(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - cachedSettings = new PlacementSettings(); - cachedSettings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); - cachedSettings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); + BlockPos anchor = BlockPos.ZERO; + PlacementSettings settings = SchematicItem.getSettings(blueprint); + transformation = new SchematicTransformation(); deployed = tag.getBoolean("Deployed"); if (deployed) anchor = NBTUtil.readBlockPos(tag.getCompound("Anchor")); + BlockPos size = NBTUtil.readBlockPos(tag.getCompound("Bounds")); - size = NBTUtil.readBlockPos(tag.getCompound("Bounds")); + bounds = new AxisAlignedBB(BlockPos.ZERO, size); + outline = new AABBOutline(bounds); + outline.disableCull = true; + transformation.init(anchor, settings, bounds); } - public void flip(Axis axis) { - - Rotation r = cachedSettings.getRotation(); - boolean rotationAt90s = r == Rotation.CLOCKWISE_90 || r == Rotation.COUNTERCLOCKWISE_90; - Mirror mirror = axis == Axis.Z ^ rotationAt90s ? Mirror.FRONT_BACK : Mirror.LEFT_RIGHT; - - BlockPos coordModifier = new BlockPos((r == Rotation.NONE || r == Rotation.COUNTERCLOCKWISE_90) ? 1 : -1, 0, - (r == Rotation.NONE || r == Rotation.CLOCKWISE_90) ? 1 : -1); - BlockPos anchorOffset = axis == Axis.Z - ? new BlockPos(((rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getX(), 0, 0) - : new BlockPos(0, 0, ((!rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getZ()); - - Mirror m = cachedSettings.getMirror(); - - if (m == Mirror.NONE) { - cachedSettings.setMirror(mirror); - anchor = anchor.add(anchorOffset); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal()))); - - } else if (m == mirror) { - cachedSettings.setMirror(Mirror.NONE); - anchor = anchor.subtract(anchorOffset); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal()))); - - } else if (m != mirror) { - cachedSettings.setMirror(Mirror.NONE); - anchor = anchor.add(anchorOffset); - cachedSettings.setRotation(r.add(Rotation.CLOCKWISE_180)); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal())) + ", " - + Lang.translate("schematic.rotation") + ": " - + Lang.translate("schematic.rotation." + rotations.get(cachedSettings.getRotation().ordinal()))); + public void deploy() { + if (!deployed) { + List tools = Tools.getTools(Minecraft.getInstance().player.isCreative()); + selectionScreen = new ToolSelectionScreen(tools, this::equip); } - - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - item.getTag().putString("Mirror", cachedSettings.getMirror().name()); - item.getTag().putString("Rotation", r.name()); - - markDirty(); - } - - public void message(String msg) { - Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(msg), true); - } - - public void rotate(Rotation rotation) { - Rotation r = cachedSettings.getRotation(); - BlockPos center = centerOfSchematic(); - cachedSettings.setRotation(r.add(rotation)); - BlockPos diff = center.subtract(anchor); - BlockPos move = diff.subtract(diff.rotate(rotation)); - anchor = anchor.add(move); - - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - item.getTag().putString("Rotation", cachedSettings.getRotation().name()); - - message(Lang.translate("schematic.rotation") + ": " - + Lang.translate("schematic.rotation." + rotations.get(cachedSettings.getRotation().ordinal()))); - - markDirty(); - } - - public void setMirror(Mirror mirror) { - cachedSettings.setMirror(mirror); - item.getTag().putString("Mirror", cachedSettings.getMirror().name()); - markDirty(); - } - - public void setRotation(Rotation rotation) { - cachedSettings.setRotation(rotation); - item.getTag().putString("Rotation", cachedSettings.getRotation().name()); - markDirty(); - } - - public void moveTo(BlockPos anchor) { - if (!deployed) - selectionScreen = new ToolSelectionScreen(Tools.getTools(Minecraft.getInstance().player.isCreative()), - this::equip); - deployed = true; - this.anchor = anchor; - item.getTag().putBoolean("Deployed", true); - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - markDirty(); + setupRenderer(); + } + + public String getCurrentSchematicName() { + return displayedSchematic != null ? displayedSchematic : "-"; } public void printInstantly() { - AllPackets.channel.sendToServer(new SchematicPlacePacket(item.copy())); - CompoundNBT nbt = item.getTag(); + AllPackets.channel.sendToServer(new SchematicPlacePacket(activeSchematicItem.copy())); + CompoundNBT nbt = activeSchematicItem.getTag(); nbt.putBoolean("Deployed", false); - item.setTag(nbt); - CreateClient.schematicHologram.setActive(false); + activeSchematicItem.setTag(nbt); + renderer.setActive(false); active = false; + markDirty(); } - public BlockPos getTransformedSize() { - BlockPos flipped = size; - if (cachedSettings.getMirror() == Mirror.FRONT_BACK) - flipped = new BlockPos(-flipped.getX(), flipped.getY(), flipped.getZ()); - if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) - flipped = new BlockPos(flipped.getX(), flipped.getY(), -flipped.getZ()); - - BlockPos rotate = flipped.rotate(cachedSettings.getRotation()); - return rotate; + public AABBOutline getOutline() { + return outline; } - public BlockPos getTransformedAnchor() { - BlockPos anchor = this.anchor; - Rotation r = cachedSettings.getRotation(); - - BlockPos flipOffset = BlockPos.ZERO; - if (cachedSettings.getMirror() == Mirror.FRONT_BACK) - flipOffset = new BlockPos(1, 0, 0); - if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) - flipOffset = new BlockPos(0, 0, 1); - - flipOffset = flipOffset.rotate(r); - anchor = anchor.add(flipOffset); - - if (r == Rotation.CLOCKWISE_90 || r == Rotation.CLOCKWISE_180) - anchor = anchor.add(1, 0, 0); - if (r == Rotation.COUNTERCLOCKWISE_90 || r == Rotation.CLOCKWISE_180) - anchor = anchor.add(0, 0, 1); - return anchor; + public boolean isActive() { + return active; } - public BlockPos centerOfSchematic() { - BlockPos size = getTransformedSize(); - BlockPos center = new BlockPos(size.getX() / 2, 0, size.getZ() / 2); - return anchor.add(center); + public AxisAlignedBB getBounds() { + return bounds; + } + + public SchematicTransformation getTransformation() { + return transformation; + } + + public boolean isDeployed() { + return deployed; + } + + public ItemStack getActiveSchematicItem() { + return activeSchematicItem; } } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java deleted file mode 100644 index d0b973cdc..000000000 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.simibubi.create.modules.schematics.client; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; - -import org.lwjgl.opengl.GL11; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.simibubi.create.foundation.type.Cuboid; -import com.simibubi.create.modules.schematics.SchematicWorld; - -import net.minecraft.block.BedBlock; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.RegionRenderCacheBuilder; -import net.minecraft.client.renderer.texture.AtlasTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.client.renderer.vertex.VertexFormatElement; -import net.minecraft.client.renderer.vertex.VertexFormatElement.Usage; -import net.minecraft.entity.Entity; -import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.gen.feature.template.PlacementSettings; -import net.minecraft.world.gen.feature.template.Template; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; - -public class SchematicHologram { - - private final RegionRenderCacheBuilder bufferCache = new RegionRenderCacheBuilder(); - private final boolean[] usedBlockRenderLayers = new boolean[BlockRenderLayer.values().length]; - private final boolean[] startedBufferBuilders = new boolean[BlockRenderLayer.values().length]; - private boolean active; - private boolean changed; - private SchematicWorld schematic; - private BlockPos anchor; - - public SchematicHologram() { - changed = false; - } - - public void startHologram(Template schematic, BlockPos anchor) { - SchematicWorld world = new SchematicWorld(new HashMap<>(), new Cuboid(BlockPos.ZERO, BlockPos.ZERO), anchor, - Minecraft.getInstance().world); - schematic.addBlocksToWorld(world, anchor, new PlacementSettings()); - startHologram(world); - } - - public void startHologram(SchematicWorld world) { - this.anchor = world.anchor; - this.schematic = world; - this.active = true; - this.changed = true; - } - - public void setActive(boolean active) { - this.active = active; - } - - public void update() { - changed = true; - } - - public void tick() { - if (!active) - return; - Minecraft minecraft = Minecraft.getInstance(); - if (minecraft.world == null) - return; - if (minecraft.player == null) - return; - if (changed) { - redraw(minecraft); - changed = false; - } - } - - private void redraw(Minecraft minecraft) { - Arrays.fill(usedBlockRenderLayers, false); - Arrays.fill(startedBufferBuilders, false); - - final SchematicWorld blockAccess = schematic; - final BlockRendererDispatcher blockRendererDispatcher = minecraft.getBlockRendererDispatcher(); - - List blockstates = new LinkedList<>(); - - for (BlockPos localPos : BlockPos.getAllInBoxMutable(blockAccess.getBounds().getOrigin(), - blockAccess.getBounds().getOrigin().add(blockAccess.getBounds().getSize()))) { - BlockPos pos = localPos.add(anchor); - BlockState state = blockAccess.getBlockState(pos); - for (BlockRenderLayer blockRenderLayer : BlockRenderLayer.values()) { - if (!state.getBlock().canRenderInLayer(state, blockRenderLayer)) { - continue; - } - ForgeHooksClient.setRenderLayer(blockRenderLayer); - final int blockRenderLayerId = blockRenderLayer.ordinal(); - final BufferBuilder bufferBuilder = bufferCache.getBuilder(blockRenderLayerId); - if (!startedBufferBuilders[blockRenderLayerId]) { - startedBufferBuilders[blockRenderLayerId] = true; - // Copied from RenderChunk - { - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); - } - } - // OptiFine Shaders compatibility - // if (Config.isShaders()) SVertexBuilder.pushEntity(state, pos, - // blockAccess, bufferBuilder); - - // Block transformations - if (state.getBlock() instanceof BedBlock) { - state = Blocks.QUARTZ_SLAB.getDefaultState(); - } - - usedBlockRenderLayers[blockRenderLayerId] |= blockRendererDispatcher.renderBlock(state, pos, - blockAccess, bufferBuilder, minecraft.world.rand, EmptyModelData.INSTANCE); - blockstates.add(state); - // if (Config.isShaders()) - // SVertexBuilder.popEntity(bufferBuilder); - } - ForgeHooksClient.setRenderLayer(null); - } - - // finishDrawing - for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) { - if (!startedBufferBuilders[blockRenderLayerId]) { - continue; - } - bufferCache.getBuilder(blockRenderLayerId).finishDrawing(); - } - } - - public void render() { - if (active) { - final Entity entity = Minecraft.getInstance().getRenderViewEntity(); - - if (entity == null) { - return; - } - - ActiveRenderInfo renderInfo = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); - Vec3d view = renderInfo.getProjectedView(); - double renderPosX = view.x; - double renderPosY = view.y; - double renderPosZ = view.z; - - GlStateManager.enableAlphaTest(); - GlStateManager.enableBlend(); - Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); - - for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) { - if (!usedBlockRenderLayers[blockRenderLayerId]) { - continue; - } - final BufferBuilder bufferBuilder = bufferCache.getBuilder(blockRenderLayerId); - GlStateManager.pushMatrix(); - GlStateManager.translated(-renderPosX, -renderPosY, -renderPosZ); - drawBuffer(bufferBuilder); - GlStateManager.popMatrix(); - } - GlStateManager.disableBlend(); - } - } - - // Coppied from the Tesselator's vboUploader - Draw everything but don't - // reset the buffer - private static void drawBuffer(final BufferBuilder bufferBuilder) { - if (bufferBuilder.getVertexCount() > 0) { - - VertexFormat vertexformat = bufferBuilder.getVertexFormat(); - int size = vertexformat.getSize(); - ByteBuffer bytebuffer = bufferBuilder.getByteBuffer(); - List list = vertexformat.getElements(); - - for (int index = 0; index < list.size(); ++index) { - VertexFormatElement vertexformatelement = list.get(index); - Usage usage = vertexformatelement.getUsage(); - bytebuffer.position(vertexformat.getOffset(index)); - usage.preDraw(vertexformat, index, size, bytebuffer); - } - - GlStateManager.drawArrays(bufferBuilder.getDrawMode(), 0, bufferBuilder.getVertexCount()); - - for (int index = 0; index < list.size(); ++index) { - VertexFormatElement vertexformatelement = list.get(index); - Usage usage = vertexformatelement.getUsage(); - usage.postDraw(vertexformat, index, size, bytebuffer); - } - } - } - -} diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java similarity index 90% rename from src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java rename to src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java index 125d09bd1..ccd84926a 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java @@ -7,7 +7,7 @@ import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; -public class BlueprintHotbarOverlay extends AbstractGui { +public class SchematicHotbarSlotOverlay extends AbstractGui { public void renderOn(int slot) { MainWindow mainWindow = Minecraft.getInstance().mainWindow; diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java new file mode 100644 index 000000000..04c81c186 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java @@ -0,0 +1,166 @@ +package com.simibubi.create.modules.schematics.client; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; +import com.simibubi.create.foundation.utility.render.StructureRenderer; +import com.simibubi.create.modules.schematics.SchematicWorld; + +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.RegionRenderCacheBuilder; +import net.minecraft.client.renderer.texture.AtlasTexture; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import net.minecraft.client.renderer.vertex.VertexFormatElement.Usage; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; + +public class SchematicRenderer { + + private final RegionRenderCacheBuilder bufferCache = new RegionRenderCacheBuilder(); + private final boolean[] usedBlockRenderLayers = new boolean[BlockRenderLayer.values().length]; + private final boolean[] startedBufferBuilders = new boolean[BlockRenderLayer.values().length]; + private boolean active; + private boolean changed; + private SchematicWorld schematic; + private AABBOutline outline; + private BlockPos anchor; + + public SchematicRenderer() { + changed = false; + } + + public void startHologram(SchematicWorld world) { + this.anchor = world.anchor; + this.schematic = world; + this.active = true; + this.changed = true; + } + + public void setActive(boolean active) { + this.active = active; + } + + public void update() { + changed = true; + } + + public void tick() { + if (!active) + return; + Minecraft mc = Minecraft.getInstance(); + if (mc.world == null || mc.player == null || !changed) + return; + + redraw(mc); + changed = false; + } + + public void render() { + if (!active) + return; + + GlStateManager.disableCull(); + GlStateManager.enableAlphaTest(); + GlStateManager.depthMask(true); + Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); + + for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) + if (usedBlockRenderLayers[blockRenderLayerId]) + drawBuffer(bufferCache.getBuilder(blockRenderLayerId)); + + GlStateManager.pushMatrix(); + Vec3d position = new Vec3d(anchor); + Vec3d rotation = Vec3d.ZERO; + StructureRenderer.renderTileEntities(schematic, position, rotation, schematic.getTileEntities()); + GlStateManager.popMatrix(); + } + + private void redraw(Minecraft minecraft) { + Arrays.fill(usedBlockRenderLayers, false); + Arrays.fill(startedBufferBuilders, false); + + SchematicWorld blockAccess = schematic; + blockAccess.renderMode = true; + BlockRendererDispatcher blockRendererDispatcher = minecraft.getBlockRendererDispatcher(); + List blockstates = new LinkedList<>(); + BlockPos min = blockAccess.getBounds().getOrigin(); + BlockPos max = min.add(blockAccess.getBounds().getSize()); + outline = new AABBOutline(new AxisAlignedBB(min, max)); + outline.setTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED); + + for (BlockPos localPos : BlockPos.getAllInBoxMutable(min, max)) { + BlockPos pos = localPos.add(anchor); + BlockState state = blockAccess.getBlockState(pos); + + for (BlockRenderLayer blockRenderLayer : BlockRenderLayer.values()) { + if (!state.getBlock().canRenderInLayer(state, blockRenderLayer)) + continue; + ForgeHooksClient.setRenderLayer(blockRenderLayer); + + final int blockRenderLayerId = blockRenderLayer.ordinal(); + final BufferBuilder bufferBuilder = bufferCache.getBuilder(blockRenderLayerId); + if (!startedBufferBuilders[blockRenderLayerId]) { + startedBufferBuilders[blockRenderLayerId] = true; + bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); + } + + usedBlockRenderLayers[blockRenderLayerId] |= blockRendererDispatcher.renderBlock(state, pos, + blockAccess, bufferBuilder, minecraft.world.rand, EmptyModelData.INSTANCE); + blockstates.add(state); + } + ForgeHooksClient.setRenderLayer(null); + } + + // finishDrawing + blockAccess.renderMode = false; + for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) { + if (!startedBufferBuilders[blockRenderLayerId]) + continue; + bufferCache.getBuilder(blockRenderLayerId).finishDrawing(); + } + } + + // Coppied from the Tesselator's vboUploader - Draw everything but don't + // reset the buffer + private static void drawBuffer(final BufferBuilder bufferBuilder) { + if (bufferBuilder.getVertexCount() <= 0) + return; + + VertexFormat vertexformat = bufferBuilder.getVertexFormat(); + int size = vertexformat.getSize(); + ByteBuffer bytebuffer = bufferBuilder.getByteBuffer(); + List list = vertexformat.getElements(); + + for (int index = 0; index < list.size(); ++index) { + VertexFormatElement vertexformatelement = list.get(index); + Usage usage = vertexformatelement.getUsage(); + bytebuffer.position(vertexformat.getOffset(index)); + usage.preDraw(vertexformat, index, size, bytebuffer); + } + + GlStateManager.drawArrays(bufferBuilder.getDrawMode(), 0, bufferBuilder.getVertexCount()); + + for (int index = 0; index < list.size(); ++index) { + VertexFormatElement vertexformatelement = list.get(index); + Usage usage = vertexformatelement.getUsage(); + usage.postDraw(vertexformat, index, size, bytebuffer); + } + } + +} diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java new file mode 100644 index 000000000..008b4c8ee --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java @@ -0,0 +1,208 @@ +package com.simibubi.create.modules.schematics.client; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingAngle; +import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.gen.feature.template.PlacementSettings; + +public class SchematicTransformation { + + private InterpolatedChasingValue x, y, z, scaleFrontBack, scaleLeftRight; + private InterpolatedChasingAngle rotation; + private double xOrigin; + private double zOrigin; + + public SchematicTransformation() { + x = new InterpolatedChasingValue(); + y = new InterpolatedChasingValue(); + z = new InterpolatedChasingValue(); + scaleFrontBack = new InterpolatedChasingValue(); + scaleLeftRight = new InterpolatedChasingValue(); + rotation = new InterpolatedChasingAngle(); + } + + public void init(BlockPos anchor, PlacementSettings settings, AxisAlignedBB bounds) { + int leftRight = settings.getMirror() == Mirror.LEFT_RIGHT ? -1 : 1; + int frontBack = settings.getMirror() == Mirror.FRONT_BACK ? -1 : 1; + scaleFrontBack.start(frontBack); + scaleLeftRight.start(leftRight); + xOrigin = bounds.getXSize() / 2f; + zOrigin = bounds.getZSize() / 2f; + + int r = -(settings.getRotation().ordinal() * 90); + rotation.start(r); + + Vec3d vec = fromAnchor(anchor); + x.start((float) vec.x); + y.start((float) vec.y); + z.start((float) vec.z); + } + + public void applyGLTransformations() { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + + // Translation + GlStateManager.translated(x.get(pt), y.get(pt), z.get(pt)); + + Vec3d rotationOffset = getRotationOffset(true); + + // Rotation & Mirror + GlStateManager.translated(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); + GlStateManager.rotated(rotation.get(pt), 0, 1, 0); + GlStateManager.translated(-rotationOffset.x, 0, -rotationOffset.z); + GlStateManager.scaled(scaleFrontBack.get(pt), 1, scaleLeftRight.get(pt)); + GlStateManager.translated(-xOrigin, 0, -zOrigin); + + } + + public Vec3d getRotationOffset(boolean ignoreMirrors) { + Vec3d rotationOffset = Vec3d.ZERO; + if ((int) (zOrigin * 2) % 2 != (int) (xOrigin * 2) % 2) { + boolean xGreaterZ = xOrigin > zOrigin; + float xIn = (xGreaterZ ? 0 : .5f); + float zIn = (!xGreaterZ ? 0 : .5f); + if (!ignoreMirrors) { + xIn *= getMirrorModifier(Axis.X); + zIn *= getMirrorModifier(Axis.Z); + } + rotationOffset = new Vec3d(xIn, 0, zIn); + } + return rotationOffset; + } + + public Vec3d toLocalSpace(Vec3d vec) { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + Vec3d rotationOffset = getRotationOffset(true); + + vec = vec.subtract(x.get(pt), y.get(pt), z.get(pt)); + vec = vec.subtract(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); + vec = VecHelper.rotate(vec, -rotation.get(pt), Axis.Y); + vec = vec.add(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.get(pt), 1, scaleLeftRight.get(pt)); + vec = vec.add(xOrigin, 0, zOrigin); + + return vec; + } + + public PlacementSettings toSettings() { + PlacementSettings settings = new PlacementSettings(); + + int i = (int) rotation.getTarget(); + + boolean mirrorlr = scaleLeftRight.getTarget() < 0; + boolean mirrorfb = scaleFrontBack.getTarget() < 0; + if (mirrorlr && mirrorfb) { + mirrorlr = mirrorfb = false; + i += 180; + } + i = i % 360; + if (i < 0) + i += 360; + + Rotation rotation = Rotation.NONE; + switch (i) { + case 90: + rotation = Rotation.COUNTERCLOCKWISE_90; + break; + case 180: + rotation = Rotation.CLOCKWISE_180; + break; + case 270: + rotation = Rotation.CLOCKWISE_90; + break; + default: + } + + settings.setRotation(rotation); + if (mirrorfb) + settings.setMirror(Mirror.FRONT_BACK); + if (mirrorlr) + settings.setMirror(Mirror.LEFT_RIGHT); + + return settings; + } + + public BlockPos getAnchor() { + Vec3d vec = Vec3d.ZERO.add(.5, 0, .5); + Vec3d rotationOffset = getRotationOffset(false); + vec = vec.subtract(xOrigin, 0, zOrigin); + vec = vec.subtract(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.getTarget(), 1, scaleLeftRight.getTarget()); + vec = VecHelper.rotate(vec, rotation.getTarget(), Axis.Y); + vec = vec.add(xOrigin, 0, zOrigin); + + vec = vec.add(x.getTarget(), y.getTarget(), z.getTarget()); + return new BlockPos(vec.x, vec.y, vec.z); + } + + public Vec3d fromAnchor(BlockPos pos) { + Vec3d vec = Vec3d.ZERO.add(.5, 0, .5); + Vec3d rotationOffset = getRotationOffset(false); + vec = vec.subtract(xOrigin, 0, zOrigin); + vec = vec.subtract(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.getTarget(), 1, scaleLeftRight.getTarget()); + vec = VecHelper.rotate(vec, rotation.getTarget(), Axis.Y); + vec = vec.add(xOrigin, 0, zOrigin); + + return new Vec3d(pos.subtract(new BlockPos(vec.x, vec.y, vec.z))); + } + + public int getRotationTarget() { + return (int) rotation.getTarget(); + } + + public int getMirrorModifier(Axis axis) { + if (axis == Axis.Z) + return (int) scaleLeftRight.getTarget(); + return (int) scaleFrontBack.getTarget(); + } + + public float getCurrentRotation() { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + return rotation.get(pt); + } + + public void tick() { + x.tick(); + y.tick(); + z.tick(); + scaleLeftRight.tick(); + scaleFrontBack.tick(); + rotation.tick(); + } + + public void flip(Axis axis) { + if (axis == Axis.X) + scaleLeftRight.target(scaleLeftRight.getTarget() * -1); + if (axis == Axis.Z) + scaleFrontBack.target(scaleFrontBack.getTarget() * -1); + } + + public void rotate90(boolean clockwise) { + rotation.target(rotation.getTarget() + (clockwise ? -90 : 90)); + } + + public void move(float xIn, float yIn, float zIn) { + moveTo(x.getTarget() + xIn, y.getTarget() + yIn, z.getTarget() + zIn); + } + + public void moveTo(BlockPos pos) { + moveTo(pos.getX(), pos.getY(), pos.getZ()); + } + + public void moveTo(float xIn, float yIn, float zIn) { + x.target(xIn); + y.target(yIn); + z.target(zIn); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java index 306e79f02..417a0cf5e 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java @@ -2,11 +2,17 @@ package com.simibubi.create.modules.schematics.client.tools; import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTUtil; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.Vec3d; public class DeployTool extends PlacementToolBase { @@ -15,68 +21,78 @@ public class DeployTool extends PlacementToolBase { super.init(); selectionRange = -1; } - + @Override public void updateSelection() { - if (schematicHandler.active && selectionRange == -1) { - selectionRange = (int) schematicHandler.size.manhattanDistance(BlockPos.ZERO) / 2; + if (schematicHandler.isActive() && selectionRange == -1) { + selectionRange = (int) (schematicHandler.getBounds().getCenter().length() / 2); selectionRange = MathHelper.clamp(selectionRange, 1, 100); } selectIgnoreBlocks = AllKeys.ACTIVATE_TOOL.isPressed(); - super.updateSelection(); } - + @Override public void renderTool() { super.renderTool(); - - if (selectedPos == null) + + if (selectedPos == null) return; - - BlockPos size = schematicHandler.getTransformedSize(); - BlockPos min = selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f)); - BlockPos max = min.add(size.getX(), size.getY(), size.getZ()); - - if (schematicHandler.deployed) { - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - min = new BlockPos(bb.minX, bb.minY, bb.minZ); - max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - } - - GlStateManager.lineWidth(2); - GlStateManager.color4f(.5f, .8f, 1, 1); - GlStateManager.disableTexture(); - - WorldRenderer.drawBoundingBox(min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, - max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, .8f, .9f, 1, 1); - - GlStateManager.lineWidth(1); - GlStateManager.enableTexture(); - + + GlStateManager.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.enableBlend(); + float pt = Minecraft.getInstance().getRenderPartialTicks(); + double x = MathHelper.lerp(pt, lastChasingSelectedPos.x, chasingSelectedPos.x); + double y = MathHelper.lerp(pt, lastChasingSelectedPos.y, chasingSelectedPos.y); + double z = MathHelper.lerp(pt, lastChasingSelectedPos.z, chasingSelectedPos.z); + + SchematicTransformation transformation = schematicHandler.getTransformation(); + Vec3d center = schematicHandler.getBounds().getCenter(); + Vec3d offset = transformation.getRotationOffset(true); + + if (schematicHandler.getBounds().getXSize() % 2 == 1 || schematicHandler.getBounds().getZSize() % 2 == 1) + GlStateManager.translated(.5f, 0, .5f); + GlStateManager.translated(x, y, z); + GlStateManager.rotated(transformation.getCurrentRotation(), 0, 1, 0); + GlStateManager.translated(-offset.x, 0, -offset.z); + GlStateManager.translated(-(center.x), 0, -(center.z)); + + schematicHandler.getOutline().setTextures(AllSpecialTextures.CHECKERED, null); + schematicHandler.getOutline().render(Tessellator.getInstance().getBuffer()); + schematicHandler.getOutline().setTextures(null, null); + GlStateManager.popMatrix(); } - + @Override public boolean handleMouseWheel(double delta) { - + if (selectIgnoreBlocks) { selectionRange += delta; selectionRange = MathHelper.clamp(selectionRange, 1, 100); return true; } - + return super.handleMouseWheel(delta); } - + @Override public boolean handleRightClick() { if (selectedPos == null) return super.handleRightClick(); - - BlockPos size = schematicHandler.getTransformedSize(); - schematicHandler.moveTo(selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f))); - + Vec3d center = schematicHandler.getBounds().getCenter(); + BlockPos target = selectedPos.add(-((int) center.x), 0, -((int) center.z)); + + ItemStack item = schematicHandler.getActiveSchematicItem(); + if (item != null) { + item.getTag().putBoolean("Deployed", true); + item.getTag().put("Anchor", NBTUtil.writeBlockPos(target)); + } + + schematicHandler.getTransformation().moveTo(target); + schematicHandler.markDirty(); + schematicHandler.deploy(); return true; } - + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java index c404d4b58..2e9cba5ab 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java @@ -1,11 +1,28 @@ package com.simibubi.create.modules.schematics.client.tools; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; + public class FlipTool extends PlacementToolBase { @Override public void init() { super.init(); - renderSelectedFace = true; + renderSelectedFace = false; } @Override @@ -23,17 +40,69 @@ public class FlipTool extends PlacementToolBase { @Override public void updateSelection() { super.updateSelection(); - - if (!schematicSelected) - return; - - renderSelectedFace = selectedFace.getAxis().isHorizontal(); } private void mirror() { if (schematicSelected && selectedFace.getAxis().isHorizontal()) { - schematicHandler.flip(selectedFace.getAxis()); + schematicHandler.getTransformation().flip(selectedFace.getAxis()); + schematicHandler.markDirty(); } } + @Override + public void renderToolLocal() { + super.renderToolLocal(); + + if (!schematicSelected || !selectedFace.getAxis().isHorizontal()) + return; + + GlStateManager.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.enableBlend(); + + Direction facing = selectedFace.rotateY(); + Axis axis = facing.getAxis(); + Vec3d color = ColorHelper.getRGB(0x4d80e4); + AxisAlignedBB bounds = schematicHandler.getBounds(); + + Vec3d plane = VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec())); + plane = plane.mul(bounds.getXSize() / 2f + 1, bounds.getYSize() / 2f + 1, bounds.getZSize() / 2f + 1); + Vec3d center = bounds.getCenter(); + + Vec3d v1 = plane.add(center); + plane = plane.mul(-1, 1, -1); + Vec3d v2 = plane.add(center); + plane = plane.mul(1, -1, 1); + Vec3d v3 = plane.add(center); + plane = plane.mul(-1, 1, -1); + Vec3d v4 = plane.add(center); + + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + AABBOutline outline = schematicHandler.getOutline(); + AllSpecialTextures.BLANK.bind(); + outline.renderAACuboidLine(v1, v2, color, 1, buffer); + outline.renderAACuboidLine(v2, v3, color, 1, buffer); + outline.renderAACuboidLine(v3, v4, color, 1, buffer); + outline.renderAACuboidLine(v4, v1, color, 1, buffer); + + Tessellator.getInstance().draw(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + + GlStateManager.texParameter(GL11.GL_TEXTURE_2D, 10242, GL11.GL_REPEAT); + GlStateManager.texParameter(GL11.GL_TEXTURE_2D, 10243, GL11.GL_REPEAT); + GlStateManager.depthMask(false); + Vec3d uDiff = v2.subtract(v1); + Vec3d vDiff = v4.subtract(v1); + float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); + float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); + + GlStateManager.enableCull(); + AllSpecialTextures.HIGHLIGHT_CHECKERED.bind(); + outline.putQuadUV(v1, v2, v3, v4, 0, 0, maxU, maxV, color, 1, buffer); + outline.putQuadUV(v2, v1, v4, v3, 0, 0, maxU, maxV, color, 1, buffer); + Tessellator.getInstance().draw(); + GlStateManager.popMatrix(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java index dc86fa1c6..5c892b78b 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java @@ -10,6 +10,7 @@ public interface ISchematicTool { public void renderTool(); public void renderOverlay(); + public void renderToolLocal(); } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java index 80500ba89..116f2f81f 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java @@ -1,5 +1,11 @@ package com.simibubi.create.modules.schematics.client.tools; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; + +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.Vec3d; + public class MoveTool extends PlacementToolBase { @Override @@ -17,13 +23,19 @@ public class MoveTool extends PlacementToolBase { renderSelectedFace = selectedFace.getAxis().isHorizontal(); } - + @Override public boolean handleMouseWheel(double delta) { - if (schematicSelected && selectedFace.getAxis().isHorizontal()) { - schematicHandler.moveTo(delta < 0 ? schematicHandler.anchor.add(selectedFace.getDirectionVec()) - : schematicHandler.anchor.subtract(selectedFace.getDirectionVec())); - } + if (!schematicSelected || !selectedFace.getAxis().isHorizontal()) + return true; + + SchematicTransformation transformation = schematicHandler.getTransformation(); + Vec3d vec = new Vec3d(selectedFace.getDirectionVec()).scale(-Math.signum(delta)); + vec = vec.mul(transformation.getMirrorModifier(Axis.X), 1, transformation.getMirrorModifier(Axis.Z)); + vec = VecHelper.rotate(vec, transformation.getRotationTarget(), Axis.Y); + transformation.move((float) vec.x, 0, (float) vec.z); + schematicHandler.markDirty(); + return true; } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java index 3910a0a22..a0d583018 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java @@ -4,8 +4,9 @@ public class MoveVerticalTool extends PlacementToolBase { @Override public boolean handleMouseWheel(double delta) { - if (schematicHandler.deployed) { - schematicHandler.moveTo(schematicHandler.anchor.add(0, delta, 0)); + if (schematicHandler.isDeployed()) { + schematicHandler.getTransformation().move(0, (float) Math.signum(delta), 0); + schematicHandler.markDirty(); } return true; } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java index 171f132f0..91d2fc51f 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java @@ -1,13 +1,47 @@ package com.simibubi.create.modules.schematics.client.tools; -import net.minecraft.util.Rotation; +import org.lwjgl.opengl.GL11; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; public class RotateTool extends PlacementToolBase { @Override public boolean handleMouseWheel(double delta) { - schematicHandler.rotate(delta > 0 ? Rotation.CLOCKWISE_90 : Rotation.COUNTERCLOCKWISE_90); + schematicHandler.getTransformation().rotate90(delta > 0); + schematicHandler.markDirty(); return true; } + @Override + public void renderToolLocal() { + super.renderToolLocal(); + + GlStateManager.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.enableBlend(); + + Vec3d color = ColorHelper.getRGB(0x4d80e4); + AxisAlignedBB bounds = schematicHandler.getBounds(); + double height = bounds.getYSize() + Math.max(20, bounds.getYSize()); + + Vec3d center = bounds.getCenter().add(schematicHandler.getTransformation().getRotationOffset(false)); + Vec3d start = center.subtract(0, height / 2, 0); + Vec3d end = center.add(0, height / 2, 0); + + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); + buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + schematicHandler.getOutline().renderAACuboidLine(start, end, color, 1, buffer); + Tessellator.getInstance().draw(); + GlStateManager.popMatrix(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java index 9c7d150c5..80ff83752 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java @@ -1,22 +1,27 @@ package com.simibubi.create.modules.schematics.client.tools; +import java.util.Arrays; +import java.util.List; + import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.modules.schematics.client.SchematicHandler; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.item.ItemUseContext; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.util.Direction; -import net.minecraft.util.Hand; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.MutableBoundingBox; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; @@ -24,13 +29,18 @@ public abstract class SchematicToolBase implements ISchematicTool { protected SchematicHandler schematicHandler; - public BlockPos selectedPos; - public boolean selectIgnoreBlocks; - public int selectionRange; + protected BlockPos selectedPos; + protected Vec3d chasingSelectedPos; + protected Vec3d lastChasingSelectedPos; - public boolean schematicSelected; - public boolean renderSelectedFace; - public Direction selectedFace; + protected boolean selectIgnoreBlocks; + protected int selectionRange; + protected boolean schematicSelected; + protected boolean renderSelectedFace; + protected Direction selectedFace; + + protected final List mirrors = Arrays.asList("none", "leftRight", "frontBack"); + protected final List rotations = Arrays.asList("none", "cw90", "cw180", "cw270"); @Override public void init() { @@ -38,86 +48,95 @@ public abstract class SchematicToolBase implements ISchematicTool { selectedPos = null; selectedFace = null; schematicSelected = false; + chasingSelectedPos = Vec3d.ZERO; + lastChasingSelectedPos = Vec3d.ZERO; } @Override public void updateSelection() { + updateTargetPos(); + + if (selectedPos == null) + return; + lastChasingSelectedPos = chasingSelectedPos; + Vec3d target = new Vec3d(selectedPos); + if (target.distanceTo(chasingSelectedPos) < 1 / 512f) { + chasingSelectedPos = target; + return; + } + + chasingSelectedPos = chasingSelectedPos.add(target.subtract(chasingSelectedPos).scale(1 / 2f)); + } + + public void updateTargetPos() { ClientPlayerEntity player = Minecraft.getInstance().player; // Select Blueprint - if (schematicHandler.deployed) { - BlockPos min = schematicHandler.getTransformedAnchor(); - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - PredicateTraceResult result = RaycastHelper.rayTraceUntil(player, 70, - pos -> bb.isVecInside(pos)); + if (schematicHandler.isDeployed()) { + SchematicTransformation transformation = schematicHandler.getTransformation(); + AxisAlignedBB localBounds = schematicHandler.getBounds(); + + Vec3d traceOrigin = RaycastHelper.getTraceOrigin(player); + Vec3d start = transformation.toLocalSpace(traceOrigin); + Vec3d end = transformation.toLocalSpace(RaycastHelper.getTraceTarget(player, 70, traceOrigin)); + PredicateTraceResult result = + RaycastHelper.rayTraceUntil(start, end, pos -> localBounds.contains(VecHelper.getCenterOf(pos))); + schematicSelected = !result.missed(); selectedFace = schematicSelected ? result.getFacing() : null; } + boolean snap = this.selectedPos == null; + // Select location at distance if (selectIgnoreBlocks) { - selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) - .add(player.getLookVec().scale(selectionRange))); + float pt = Minecraft.getInstance().getRenderPartialTicks(); + selectedPos = new BlockPos(player.getEyePosition(pt).add(player.getLookVec().scale(selectionRange))); + if (snap) + lastChasingSelectedPos = chasingSelectedPos = new Vec3d(selectedPos); return; } // Select targeted Block + selectedPos = null; BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); - if (trace != null && trace.getType() == Type.BLOCK) { + if (trace == null || trace.getType() != Type.BLOCK) + return; - BlockPos hit = new BlockPos(trace.getHitVec()); - boolean replaceable = player.world.getBlockState(hit) - .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); - if (trace.getFace().getAxis().isVertical() && !replaceable) - hit = hit.offset(trace.getFace()); - - selectedPos = hit; - } else { - selectedPos = null; - } + BlockPos hit = new BlockPos(trace.getHitVec()); + boolean replaceable = player.world.getBlockState(hit).getMaterial().isReplaceable(); + if (trace.getFace().getAxis().isVertical() && !replaceable) + hit = hit.offset(trace.getFace()); + selectedPos = hit; + if (snap) + lastChasingSelectedPos = chasingSelectedPos = new Vec3d(selectedPos); } @Override - public void renderTool() { - - if (schematicHandler.deployed) { - GlStateManager.lineWidth(2); - GlStateManager.color4f(1, 1, 1, 1); - GlStateManager.disableTexture(); - - BlockPos min = schematicHandler.getTransformedAnchor(); - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - - WorldRenderer.drawBoundingBox(min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, - max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, 1, 1, 1, 1); - - if (schematicSelected && renderSelectedFace && AllKeys.ACTIVATE_TOOL.isPressed()) { - Vec3d vec = new Vec3d(selectedFace.getDirectionVec()); - Vec3d center = new Vec3d(min.add(max)).scale(1 / 2f); - Vec3d radii = new Vec3d(max.subtract(min)).scale(1 / 2f); - - Vec3d onFaceOffset = new Vec3d(1 - Math.abs(vec.x), 1 - Math.abs(vec.y), 1 - Math.abs(vec.z)) - .mul(radii); - Vec3d faceMin = center.add(vec.mul(radii).add(onFaceOffset)).add(vec.scale(1/8f)); - Vec3d faceMax = center.add(vec.mul(radii).subtract(onFaceOffset)).add(vec.scale(1/8f)); - - GlStateManager.lineWidth(6); - WorldRenderer.drawBoundingBox(faceMin.getX(), faceMin.getY() + 1 / 16d, faceMin.getZ(), faceMax.getX(), - faceMax.getY() + 1 / 8d, faceMax.getZ(), .6f, .7f, 1, 1); - } - - GlStateManager.lineWidth(1); - GlStateManager.enableTexture(); + public void renderToolLocal() { + if (!schematicHandler.isDeployed()) + return; + AABBOutline outline = schematicHandler.getOutline(); + if (renderSelectedFace) { + schematicHandler.getOutline().setTextures(null, + AllKeys.ctrlDown() ? AllSpecialTextures.HIGHLIGHT_CHECKERED : AllSpecialTextures.CHECKERED); + outline.highlightFace(selectedFace); } + RenderHelper.disableStandardItemLighting(); + GlStateManager.pushMatrix(); + GlStateManager.enableBlend(); + outline.render(Tessellator.getInstance().getBuffer()); + GlStateManager.popMatrix(); + outline.setTextures(null, null); + } @Override - public void renderOverlay() { + public void renderTool() {} - } + @Override + public void renderOverlay() {} } diff --git a/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java b/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java index fe23c977e..c53bc74fa 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java +++ b/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java @@ -75,22 +75,20 @@ public class SchematicItem extends Item { public static void writeSize(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - Template t = getSchematic(blueprint); + Template t = loadSchematic(blueprint); tag.put("Bounds", NBTUtil.writeBlockPos(t.getSize())); blueprint.setTag(tag); } public static PlacementSettings getSettings(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - PlacementSettings settings = new PlacementSettings(); settings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); settings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); - return settings; } - public static Template getSchematic(ItemStack blueprint) { + public static Template loadSchematic(ItemStack blueprint) { Template t = new Template(); String owner = blueprint.getTag().getString("Owner"); String schematic = blueprint.getTag().getString("File"); @@ -120,14 +118,25 @@ public class SchematicItem extends Item { @Override public ActionResultType onItemUse(ItemUseContext context) { - if (context.isPlacerSneaking() && context.getHand() == Hand.MAIN_HAND) { - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - displayBlueprintScreen(); - }); - return ActionResultType.SUCCESS; - } + if (!onItemUse(context.getPlayer(), context.getHand())) + return super.onItemUse(context); + return ActionResultType.SUCCESS; + } - return super.onItemUse(context); + @Override + public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { + if (!onItemUse(playerIn, handIn)) + return super.onItemRightClick(worldIn, playerIn, handIn); + return new ActionResult(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn)); + } + + private boolean onItemUse(PlayerEntity player, Hand hand) { + if (!player.isSneaking() || hand != Hand.MAIN_HAND) + return false; + if (!player.getHeldItem(hand).hasTag()) + return false; + DistExecutor.runWhenOn(Dist.CLIENT, () -> this::displayBlueprintScreen); + return true; } @OnlyIn(value = Dist.CLIENT) @@ -135,17 +144,4 @@ public class SchematicItem extends Item { ScreenOpener.open(new SchematicEditScreen()); } - @Override - public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { - if (playerIn.isSneaking() && handIn == Hand.MAIN_HAND) { - if (playerIn.getHeldItem(handIn).hasTag()) - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - displayBlueprintScreen(); - }); - return new ActionResult(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn)); - } - - return super.onItemRightClick(worldIn, playerIn, handIn); - } - } diff --git a/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java b/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java index c58b5212d..82db762ef 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java +++ b/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java @@ -31,7 +31,7 @@ public class SchematicPlacePacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); - Template t = SchematicItem.getSchematic(stack); + Template t = SchematicItem.loadSchematic(stack); t.addBlocksToWorld(player.getServerWorld(), NBTUtil.readBlockPos(stack.getTag().getCompound("Anchor")), SchematicItem.getSettings(stack)); }); diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index 3336eb56a..b8b7668f5 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -881,8 +881,8 @@ "block.create.mechanical_press.tooltip.behaviour1": "_Starts_ to compress items dropped below it.", "block.create.mechanical_press.tooltip.condition2": "When Above a Mechanical Belt", "block.create.mechanical_press.tooltip.behaviour2": "_Automatically_ compresses bypassing items on the Belt.", - "block.create.mechanical_mixer.tooltip.condition3": "When above Basin", - "block.create.mechanical_mixer.tooltip.behaviour3": "Starts to _compact_ _items_ in the basin whenever all necessary ingredients are present.", + "block.create.mechanical_press.tooltip.condition3": "When above Basin", + "block.create.mechanical_press.tooltip.behaviour3": "Starts to _compact_ _items_ in the basin whenever all necessary ingredients are present.", "block.create.basin.tooltip": "BASIN", "block.create.basin.tooltip.summary": "A handy _item_ _container_ used in processing with the _Mechanical_ _Mixer_ and the _Mechanical_ _Press_. Supports _Redstone_ _Comparators_.", diff --git a/src/main/resources/assets/create/textures/gui/background.png b/src/main/resources/assets/create/textures/gui/background.png index de5cde99c1d332042bf2e8cd04f2526ee8a06e32..e51ac31894d4afc471b974dfd8ceae2457361b8e 100644 GIT binary patch delta 98 zcmdnYIE`_F3KwH>kh>GZx^prwCn`$&?q*=%+s%0V#}zXM1_o_U7sn6_|70HRo41i@#Yc;mI6kIgTe~DWM4fTtXnV delta 129 zcmbQnxS4T+%0xqn@;wX;e0vzD?kVzQU|^6aag8Vm&QB{TPb^AhC`ioAE78kKEm1Jh zGt@KgRr#9^RAcDr;uvD#pUiPO{=LX8Kbw;c?tI#w^3o4DG+5ks9ARI{)?qU7NrsJr h_X8pIK<5l=2B{gI0ifaT516C3fsR)XSAbWs-3RH-sniN?jXb>I1pcohy z1Gs@8OAN@O35#W`(10VdX@cy;u*3*q$uijKkG9k4%>17p@4WZD``vr)`QE+fzH7&i z*{dV;5C8!6LkZ^=}!ieD_~Xd{-gT=VA0iN0k9Rk z<~s*3G5{L2pB6-`&gvxqYIcVX?01dun|j+pa_w2)BDNS_&(kHsHy2hUT(wd!!TGw5 zIu&LiULAJ3k&$1#>+ZqEr$tvQOE$44ijuY#Z`$H)x9Vt-ySvVf%?Iv>H#j;tLNaZ4 zlNv}ChP-MXdEBoKPT$D1VXjwlbA=;0!)iSzM3SdG%<%f)={GfO-7LzysBdFQ`oDC@4bD9OSzH0neC2pL6d37Tn}2^ z87wr0Hn+AqluKwAunWeD)@Iq*?F)?x`Es^K+Bb~v3i{z{YLF&4n|kXbx0UT) zTSl}|MRet!Gux|SnFPLNn?3k(V|HZ|=gw5WS2EpdACm^}{0y3>{wzkoDK=v!%#I|z zBqz!2TH-BNq6{TP@TSj-chc;g#+dk#_lChpu+13s*T0Z5iB=HZ;y!c{Ke8Al zUFVF|W42UYD|>e@R$lxfNv0V2Sad4oI$M=$*;}>NDm!Dw3*WS3fLk_om40Pbpj_NU zQ0_@x4b3}hI*nl`aAFwJ`F`tkoyDYIe6+0aE?hxPXcGFA$AZ>WJ=fz7cG!<%@U1qa zGpNdxd4)*~a*LK%`ii@nTl!RRdLx9-D!kk|x)W)5Y+q)kjdHQ1MQm>yFF|k9L zhxU#R6l&?76oK0e_{$4p^pHv+m7Z20xp|b6aXYa|h$g{b_MKL#FI(UarX|dfkx-A~ z?mMu$$I#h}0Rj6>fpp_&^CG8CD5x2&67~L(->pb3pXed{V7pm3Ucw-v z7wMY&WQrRTyq#hW*36qcpOU%5TY`+x8qEEvsMq^z8VtX{2!UIDM&1|`wVUQ!S4T_> z zv6C$DL2OeF$~=^>BgrpIr8jqnpxXO{+cS!s3ENS5#Q`CkXju8I!@{^gI6ldO z4UjHW50uQ!lm{vgzlJtwpUs8ECtQ_}mhU;CVR2$(`;kQRxe7j^%623=j%(07^NKed z?j1&CkCA8=of+x_(aW}R`ML>RqL^(*7$S7~7WQkV7jt1@>AB`X?Y%odUV%Q;zuO7A z2xX>(i!%J8!#pywe9v**rVP2>C3H?nlZx?skF)rSugjn^l`gFxvtZY5*H14_ z4Uv+%5myTdj%Ap=aYK35!Q-qGBOP#qb);+*Zwv4MX7?X5)oMpHTIgtJZZgY zWHSfzWPgdTnTRzp6Y77NQzm_eiXnUmN1RfM*KKs3`$Y>1Lvs$Z`3)UX?kYu=ZF z?G&9{d+^DEe0T2@EjZO0TOtL1eq+HpjYB@N=Ru1xrX$3rQAuAE+p%0)>hiFU(Vr!K ztu4BVf4H-(nvijwcCDIX);nYt#tw3;b9-$Sp1P!&YN`*y z#CPlb=&N@S!VyHbIN5X3UB%y7NRDHy*k&F8iX{|i9t5Bf4sg0FbI$~TfK|Xa835Yn zfNK74jg=UnAct-WSu@s8Chpn}aGnGFwL1^VNrt^TbM2W=PxC{bZT8%t1&kj}kq}w) zjLVT1c-CrKxKCHf7%=86I3sbt3oX101vHjwJz8iJ$n`1&!ormVL=bcO(y{C+yv9Y zZTA#&P?v7?(4-a0uLOA%Y7L3c=q^<0p$&&8nS-K zzI5`13D6rpgZo*S;f%{rR3i#dum5ZLJbFhyGZlfjTrgkGn6)(iBg!9C*bE{WMZW+G z+i9^fv5+1%ksnT@`_U#QCSte)ue0+wy5Gll1E_c34=kGv|BD*^(*pjTu}*gt-mp&h z9&29q0zely0PNNKAKKw}(f;rGo96k0xBd?bwIbdreV1X&O-4^}E5B@T$nMyIQd|E^ F{{RP?^eX@W literal 2795 zcmeHJdpH!@7T+@llR>hx zsj29x007hu?BC-F07Slp0JxGIPMmub{6&iP+~*9QbQ?^|1z5jC~ed-Zt@?o!qZ@q@t z819^zai%NcNOQ+YtJ)vj%JX)-$!zfLb#tr9oO_#bA7*hAT~eSU4ZPNO)78zZ%=*x_ zy!N2aVuuiSo0cM*=A!Ene?5Z~Rt*~}qMSfKCug1CInmLwzM-#ImP z-!SpMP$gT&-KJ2?KRqlzKRa0MwB#;6H`#f+{F6JTWayBzL*n}2El$d5anxHB#B1LN zB8J;30>Ne=hG9`2Fq>H9MY*lL0y;p0Y&0FqG>)b~PzV?n9;ZaEM}ggM1@{k6%8#|-bPb^@ zh~EV+7jgDdJL8qermsj=Z<1KDR3oS7lDqhorhWlWs>BuYIQHU9Bq?@A=bnYqYwCKU zl}A{3_~RLbty!JBR`Rpp;Nbg;_l~g@xR~Cm{=H3!vRVt`vY&vm`ZpQ(MXm$vT5_O$j1I!((YXL1i4WyNSP}T zH7e*Lk(|LbSF^KSoF+5boLQPY#-hd}K2W-7h?Z%+*XEA5=lNskVg5}?4yI;idwD~G z)xyF+Fg}7K7 z=MHv>pZ;v<30h$o&yBQZR9a5Skp0b1!lIHMzBoy;G*PpYC^RC3)X0$#Kx4z$O+F!-ui^z-G!0;EdF2*UXvA?daN$&lyT!xyA&s) z0V7BD!@279a59Afl#e-{8nF#(OFWmyW0dKrgK>eadR5O&Txh3bHg=qw4E%NhRWtiZ3(s};Rjen%~NC(oD3;2S;notvY zQP%Deco2N{^Pz+uJYH7g6QQ7)Wmm!~T?k35&hT$DKT4fMh4U6=zYX}qc5=5bGmm4N(hNw@TQ>_oDrZto$jA)a_at&){Xd@SNtD}+r9W~Rq z(vJhr#IlD}{1C)Gi5DCvvUe;WIy@r8vDE2vu8hz=7eq4dxHVtBc}_a3mo%`$SNkH2 z26Stj?G>J0S~`RZK-}JX5M&6QFaCbW-Q8tOBB@^s!=62Br3X=rj*ezNG9ZhTkmRB= zLv*DfwD%PU+FVSwW`XB(X{37n{9&p1k5HI;C1&+Q2vfvlh#i9(MTR{9jO#%_iY7qo z{wYv%0IMS2zozzE_ES!gDilD9+N@vlroPp;I-IL6lb!zCkk*Zxe6AV-)R`%cmi0`m z`eX}5phEyw1VFZ=KrC}w>${Y*4AEaqu7-flLMw{}DMKCAstz<-w}VOME!uKHg~F9D zu|KMkxj?xZJ1!F3TJCt1kcyI6!p@66Z;UP}P9R9!Q2z6{UjK4A_!e z-QM0FdXGw7x(H0o&0RJWU?U^V^=>H8w*&ORJ9QLG9TGl{hrIVf-wBr2c73ep*3&Yv zV$fqaE;B@)CltUpd;=5yZZtPWZRX-xBS%Ek;?xmj3CMV~IK?bvPtU>WbM{~)VQKEu zL-bh#rzCqHAQODp4C;nd=wod;2}tNXJ}}VeM19;fP-OikjqK*;#=M4o;;>I9JTA`! z9SOPq0lD+sM!nnHW83W!!_c5hUn*Cy7E+bO!v^rM7LJGRU{U2GF^#Y z9tLqRY%EbvL&HUWxn!b%PL4tVRKJ{ntKWF|4rls%9;l6Z=@P@&DzBj`!E$jh@YUyk z0nr<45J&Xpj@*zxQ5T9W?%uicA%B+2VzJmi<>pUMPqSIFt>*#xQZnFY|2I9~S^BFm zW})=*VjD)avTjuJ8bCz}kiXa$f4Y(W@9=&21f>esL}=}}p0VQTB>$j-1AE=~JaNV* F{~P@hm8t*$ diff --git a/src/main/resources/assets/create/textures/item/blueprint_and_quill.png b/src/main/resources/assets/create/textures/item/blueprint_and_quill.png index dd13e81665dc9b5c48a9b8ff019af80018acebc2..dc2f06e0aa921e8de1a74b040418bd1b4d12dfd0 100644 GIT binary patch delta 469 zcmV;`0V@9R0)_;TBnkm@Qb$4nuFf3kks%v@!2kdb!2!6DYwZ940h>ugK~y+Tt&+b> zLQxdQ&#T0KiqKQBpdosb@Ia%bh8l%81RB)TmN+=sZs8x`EH#8%Z8j9{(V~n-w*y^zDeZ*K+IdcZifx>D*<9`|5HStg`LBJOwT>O00000 LNkvXXu0mjfs4&qz delta 320 zcmV-G0l)r+1n>foB#|)~f5HF&4#EKyC`y0;000U#9G-OMM0yGD2lXzpKZke@L-bLtLYVpwGxJ52S|4fvkU^}N)n?!VNZKoO^_|3K zVQmZ+n|Q!Xm^LYjHlpYtqs1mmg0n1>jlWPpdp%7+?8lYA6s#BjXcow?JnsW=9dXyn SOcV_O0000>SJtJX|bb4AKaqFJAqCp&2Uxxn%x^7yl1m`uhLY z(?4LkYWl7J+Aa(k@Hobo=)eGG2uveMnqdHB2(re(3K$pwK_aM;1rRq+00000NkvXX Hu0mjf6rqDJ delta 252 zcmV5cPbuUQH8!tdw5Md`BK?{*E*N0000CVzZmPG1TL9!SA!ZXrP3_&pfHjgsmlrW!sIpmV9g*y3$tq(Oss7g82>ObuuH2laQ_u;0J{LDSw)GL;oYnI zU;{y#K>+3=Sa{sI_nDz5pn+jyW*@_CjvaM~SOGa{{)QL-L1B7)0PlME8Jqnva_^6#F%9n5T!v%0-vA(0W~=R4YHhzgsXe|foSS_k>Cr1aF) zdT&5xVQz=J)j`^>Kb0^B0$_WzItTzvkktVI#6<|9#q#U`%IPNfFGNEI05EIw@7Dl$ zm&+r%9l&XPFc1WQ-UE}tWKP%UbL;?=Lge&1DggT`rXt7&0O1b7qOm31j= qiy@Ymu7fG@J&fu#8tTMp3gH7eBbhkYw>dlj0000YbIfu vU?9QZ#m*aGruRX_E17k1qXiF7LIMMW@=o@DN!7nW_A_|8`njxgN@xNA0Rt#Z literal 0 HcmV?d00001