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
|
@ -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"),
|
||||
|
||||
;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -7,12 +7,16 @@ 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;
|
||||
return this;
|
||||
|
@ -23,4 +27,14 @@ public class InterpolatedChasingValue extends InterpolatedValue {
|
|||
return this;
|
||||
}
|
||||
|
||||
public InterpolatedChasingValue start(float value) {
|
||||
lastValue = this.value = value;
|
||||
target(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<BlockPos> predicate) {
|
||||
public static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate<BlockPos> 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))
|
||||
|
|
|
@ -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<BlockState> 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<? extends PlayerEntity> 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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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<O extends Outline> 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 <O extends Outline> OutlineParticle<O> 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<O> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<TileEntity> 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<TileEntity> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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<Outline> particle;
|
||||
ChassisTileEntity te;
|
||||
int timer;
|
||||
|
||||
|
|
|
@ -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> CONTRAPTION = new Compartment<>();
|
||||
protected static PlacementSimulationWorld renderWorld;
|
||||
protected static LightingWorld lightingWorld;
|
||||
|
||||
public static void render(World world, Contraption c, Consumer<SuperByteBuffer> 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<TileEntity> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<BlockPos, BlockState> blocks;
|
||||
private Map<BlockPos, TileEntity> tileEntities;
|
||||
private Cuboid bounds;
|
||||
public BlockPos anchor;
|
||||
public boolean renderMode;
|
||||
|
||||
public SchematicWorld(Map<BlockPos, BlockState> 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<TileEntity> getTileEntities() {
|
||||
return tileEntities.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ChasingAABBOutline> particle;
|
||||
|
||||
public boolean mouseScrolled(double delta) {
|
||||
if (!isActive())
|
||||
|
@ -65,9 +58,14 @@ 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);
|
||||
if (selectedFace == null)
|
||||
return true;
|
||||
|
||||
AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos);
|
||||
Vec3i vec = selectedFace.getDirectionVec();
|
||||
Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
|
||||
if (bb.contains(projectedView))
|
||||
delta *= -1;
|
||||
|
||||
int x = (int) (vec.getX() * delta);
|
||||
int y = (int) (vec.getY() * delta);
|
||||
|
@ -75,17 +73,17 @@ public class SchematicAndQuillHandler {
|
|||
|
||||
AxisDirection axisDirection = selectedFace.getAxisDirection();
|
||||
if (axisDirection == AxisDirection.NEGATIVE)
|
||||
bb.offset(-x, -y, -z);
|
||||
bb = bb.offset(-x, -y, -z);
|
||||
|
||||
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);
|
||||
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", bb.getXSize(),
|
||||
bb.getYSize(), bb.getZSize());
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -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<String> rotationOptions = Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180",
|
||||
"cw270");
|
||||
private final List<String> mirrorOptions = Lang.translatedOptions("schematic.mirror", "none", "leftRight",
|
||||
"frontBack");
|
||||
private final List<String> rotationOptions =
|
||||
Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", "cw270");
|
||||
private final List<String> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String> mirrors = Arrays.asList("none", "leftRight", "frontBack");
|
||||
private final List<String> 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();
|
||||
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 (deployed) {
|
||||
Template schematic = SchematicItem.getSchematic(item);
|
||||
|
||||
if (schematic.getSize().equals(BlockPos.ZERO))
|
||||
if (activeSchematicItem == null)
|
||||
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);
|
||||
}
|
||||
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());
|
||||
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<BlockState> 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<VertexFormatElement> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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<BlockState> 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<VertexFormatElement> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
@ -18,12 +24,11 @@ public class DeployTool extends PlacementToolBase {
|
|||
|
||||
@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();
|
||||
}
|
||||
|
||||
|
@ -34,26 +39,29 @@ public class DeployTool extends PlacementToolBase {
|
|||
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());
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
SchematicTransformation transformation = schematicHandler.getTransformation();
|
||||
Vec3d center = schematicHandler.getBounds().getCenter();
|
||||
Vec3d offset = transformation.getRotationOffset(true);
|
||||
|
||||
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();
|
||||
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
|
||||
|
@ -72,10 +80,18 @@ public class DeployTool extends PlacementToolBase {
|
|||
public boolean handleRightClick() {
|
||||
if (selectedPos == null)
|
||||
return super.handleRightClick();
|
||||
Vec3d center = schematicHandler.getBounds().getCenter();
|
||||
BlockPos target = selectedPos.add(-((int) center.x), 0, -((int) center.z));
|
||||
|
||||
BlockPos size = schematicHandler.getTransformedSize();
|
||||
schematicHandler.moveTo(selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f)));
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ public interface ISchematicTool {
|
|||
|
||||
public void renderTool();
|
||||
public void renderOverlay();
|
||||
public void renderToolLocal();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -20,10 +26,16 @@ public class MoveTool extends PlacementToolBase {
|
|||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<String> mirrors = Arrays.asList("none", "leftRight", "frontBack");
|
||||
protected final List<String> 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)));
|
||||
boolean replaceable = player.world.getBlockState(hit).getMaterial().isReplaceable();
|
||||
if (trace.getFace().getAxis().isVertical() && !replaceable)
|
||||
hit = hit.offset(trace.getFace());
|
||||
|
||||
selectedPos = hit;
|
||||
} else {
|
||||
selectedPos = null;
|
||||
}
|
||||
if (snap)
|
||||
lastChasingSelectedPos = chasingSelectedPos = new Vec3d(selectedPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTool() {
|
||||
public void renderToolLocal() {
|
||||
if (!schematicHandler.isDeployed())
|
||||
return;
|
||||
|
||||
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);
|
||||
AABBOutline outline = schematicHandler.getOutline();
|
||||
if (renderSelectedFace) {
|
||||
schematicHandler.getOutline().setTextures(null,
|
||||
AllKeys.ctrlDown() ? AllSpecialTextures.HIGHLIGHT_CHECKERED : AllSpecialTextures.CHECKERED);
|
||||
outline.highlightFace(selectedFace);
|
||||
}
|
||||
|
||||
GlStateManager.lineWidth(1);
|
||||
GlStateManager.enableTexture();
|
||||
|
||||
}
|
||||
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() {}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
if (!onItemUse(context.getPlayer(), context.getHand()))
|
||||
return super.onItemUse(context);
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
return super.onItemUse(context);
|
||||
@Override
|
||||
public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
|
||||
if (!onItemUse(playerIn, handIn))
|
||||
return super.onItemRightClick(worldIn, playerIn, handIn);
|
||||
return new ActionResult<ItemStack>(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<ItemStack> 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<ItemStack>(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn));
|
||||
}
|
||||
|
||||
return super.onItemRightClick(worldIn, playerIn, handIn);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public class SchematicPlacePacket extends SimplePacketBase {
|
|||
public void handle(Supplier<Context> 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));
|
||||
});
|
||||
|
|
|
@ -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_.",
|
||||
|
|
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 150 B |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 518 B |
Before Width: | Height: | Size: 317 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 436 B |
After Width: | Height: | Size: 156 B |
After Width: | Height: | Size: 156 B |