Jank Control
- More blocks now support the new belt system - Fixed the extractor models - Prepared the funnel model for filtering - Items now look 80% better on belts
This commit is contained in:
parent
25cac1fe8e
commit
e5c78fbd04
25 changed files with 1312 additions and 996 deletions
|
@ -0,0 +1,94 @@
|
|||
package com.simibubi.create.foundation.utility;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IWorldReader;
|
||||
|
||||
/**
|
||||
* Stolen from EntityRenderer
|
||||
*/
|
||||
public class IndependentShadowRenderer {
|
||||
|
||||
private static final ResourceLocation SHADOW_TEXTURES = new ResourceLocation("textures/misc/shadow.png");
|
||||
|
||||
public static void renderShadow(double x, double y, double z, float shadowAlpha, float size) {
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.enableAlphaTest();
|
||||
GlStateManager.blendFunc(GlStateManager.SourceFactor.DST_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
Minecraft.getInstance().getTextureManager().bindTexture(SHADOW_TEXTURES);
|
||||
IWorldReader iworldreader = Minecraft.getInstance().world;
|
||||
GlStateManager.depthMask(false);
|
||||
int i = MathHelper.floor(x - size);
|
||||
int j = MathHelper.floor(x + size);
|
||||
int k = MathHelper.floor(y - size);
|
||||
int l = MathHelper.floor(y);
|
||||
int i1 = MathHelper.floor(z - size);
|
||||
int j1 = MathHelper.floor(z + size);
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder bufferbuilder = tessellator.getBuffer();
|
||||
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
|
||||
|
||||
for (BlockPos blockpos : BlockPos.getAllInBoxMutable(new BlockPos(i, k, i1), new BlockPos(j, l, j1))) {
|
||||
BlockPos blockpos1 = blockpos.down();
|
||||
BlockState blockstate = iworldreader.getBlockState(blockpos1);
|
||||
if (blockstate.getRenderType() != BlockRenderType.INVISIBLE && iworldreader.getLight(blockpos) > 3) {
|
||||
func_217759_a(blockstate, iworldreader, blockpos1, 0, 0, 0, blockpos, shadowAlpha, size, -x, -y, -z);
|
||||
}
|
||||
}
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.depthMask(true);
|
||||
}
|
||||
|
||||
private static void func_217759_a(BlockState p_217759_1_, IWorldReader p_217759_2_, BlockPos p_217759_3_,
|
||||
double p_217759_4_, double p_217759_6_, double p_217759_8_, BlockPos p_217759_10_, float p_217759_11_,
|
||||
float p_217759_12_, double p_217759_13_, double p_217759_15_, double p_217759_17_) {
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
VoxelShape voxelshape = p_217759_1_.getShape(world, p_217759_10_.down());
|
||||
if (!voxelshape.isEmpty()) {
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder bufferbuilder = tessellator.getBuffer();
|
||||
double d0 = ((double) p_217759_11_ - (p_217759_6_ - ((double) p_217759_10_.getY() + p_217759_15_)) / 2.0D)
|
||||
* 0.5D * (double) world.getBrightness(p_217759_10_);
|
||||
if (!(d0 < 0.0D)) {
|
||||
if (d0 > 1.0D) {
|
||||
d0 = 1.0D;
|
||||
}
|
||||
|
||||
AxisAlignedBB axisalignedbb = voxelshape.getBoundingBox();
|
||||
double d1 = (double) p_217759_10_.getX() + axisalignedbb.minX + p_217759_13_;
|
||||
double d2 = (double) p_217759_10_.getX() + axisalignedbb.maxX + p_217759_13_;
|
||||
double d3 = (double) p_217759_10_.getY() + axisalignedbb.minY + p_217759_15_ + 0.015625D;
|
||||
double d4 = (double) p_217759_10_.getZ() + axisalignedbb.minZ + p_217759_17_;
|
||||
double d5 = (double) p_217759_10_.getZ() + axisalignedbb.maxZ + p_217759_17_;
|
||||
float f = (float) ((p_217759_4_ - d1) / 2.0D / (double) p_217759_12_ + 0.5D);
|
||||
float f1 = (float) ((p_217759_4_ - d2) / 2.0D / (double) p_217759_12_ + 0.5D);
|
||||
float f2 = (float) ((p_217759_8_ - d4) / 2.0D / (double) p_217759_12_ + 0.5D);
|
||||
float f3 = (float) ((p_217759_8_ - d5) / 2.0D / (double) p_217759_12_ + 0.5D);
|
||||
bufferbuilder.pos(d1, d3, d4).tex((double) f, (double) f2).color(1.0F, 1.0F, 1.0F, (float) d0)
|
||||
.endVertex();
|
||||
bufferbuilder.pos(d1, d3, d5).tex((double) f, (double) f3).color(1.0F, 1.0F, 1.0F, (float) d0)
|
||||
.endVertex();
|
||||
bufferbuilder.pos(d2, d3, d5).tex((double) f1, (double) f3).color(1.0F, 1.0F, 1.0F, (float) d0)
|
||||
.endVertex();
|
||||
bufferbuilder.pos(d2, d3, d4).tex((double) f1, (double) f2).color(1.0F, 1.0F, 1.0F, (float) d0)
|
||||
.endVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,24 +16,23 @@ import net.minecraft.util.math.Vec3d;
|
|||
|
||||
public class TessellatorHelper {
|
||||
|
||||
public static final float fontScale = 1/512f;
|
||||
public static final float fontScale = 1 / 512f;
|
||||
|
||||
public static void prepareForDrawing() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushLightingAttributes();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.enableAlphaTest();
|
||||
GlStateManager.color4f(1, 1, 1, 1);
|
||||
public static void prepareForDrawing() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushLightingAttributes();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.enableAlphaTest();
|
||||
GlStateManager.color4f(1, 1, 1, 1);
|
||||
|
||||
ActiveRenderInfo renderInfo = mc.gameRenderer.getActiveRenderInfo();
|
||||
Vec3d view = renderInfo.getProjectedView();
|
||||
GlStateManager.translated(-view.x, -view.y, -view.z);
|
||||
}
|
||||
|
||||
ActiveRenderInfo renderInfo = mc.gameRenderer.getActiveRenderInfo();
|
||||
Vec3d view = renderInfo.getProjectedView();
|
||||
GlStateManager.translated(-view.x, -view.y, -view.z);
|
||||
}
|
||||
|
||||
public static void prepareFastRender() {
|
||||
Minecraft.getInstance().textureManager
|
||||
.bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE);
|
||||
Minecraft.getInstance().textureManager.bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE);
|
||||
net.minecraft.client.renderer.RenderHelper.disableStandardItemLighting();
|
||||
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.enableBlend();
|
||||
|
@ -43,35 +42,35 @@ public class TessellatorHelper {
|
|||
GlStateManager.shadeModel(GL11.GL_SMOOTH);
|
||||
else
|
||||
GlStateManager.shadeModel(GL11.GL_FLAT);
|
||||
|
||||
|
||||
GlStateManager.color3f(1, 1, 1);
|
||||
}
|
||||
|
||||
public static void begin() {
|
||||
begin(DefaultVertexFormats.POSITION_TEX);
|
||||
}
|
||||
|
||||
public static void begin(VertexFormat format) {
|
||||
Tessellator.getInstance().getBuffer().begin(GL11.GL_QUADS, format);
|
||||
}
|
||||
public static void begin() {
|
||||
begin(DefaultVertexFormats.POSITION_TEX);
|
||||
}
|
||||
|
||||
public static void draw() {
|
||||
Tessellator.getInstance().draw();
|
||||
}
|
||||
public static void begin(VertexFormat format) {
|
||||
Tessellator.getInstance().getBuffer().begin(GL11.GL_QUADS, format);
|
||||
}
|
||||
|
||||
public static void cleanUpAfterDrawing() {
|
||||
GlStateManager.disableAlphaTest();
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popAttributes();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
public static void draw() {
|
||||
Tessellator.getInstance().draw();
|
||||
}
|
||||
|
||||
public static void cleanUpAfterDrawing() {
|
||||
GlStateManager.disableAlphaTest();
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popAttributes();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
public static void drawString(String str, float x, float y, float z, boolean scalesUp, boolean hasDepth) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
float pitch = mc.getRenderManager().playerViewX;
|
||||
float yaw = mc.getRenderManager().playerViewY;
|
||||
boolean isThirdPersonFrontal = mc.gameSettings.thirdPersonView == 2;
|
||||
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.pushLightingAttributes();
|
||||
GlStateManager.translatef(x, y, z);
|
||||
|
@ -82,9 +81,9 @@ public class TessellatorHelper {
|
|||
GlStateManager.disableLighting();
|
||||
if (!hasDepth) {
|
||||
GlStateManager.depthMask(false);
|
||||
GlStateManager.disableDepthTest();
|
||||
GlStateManager.disableDepthTest();
|
||||
}
|
||||
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA,
|
||||
GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE,
|
||||
|
@ -98,21 +97,21 @@ public class TessellatorHelper {
|
|||
bufferbuilder.pos((double) (-i - 3), (double) (10), 0.0D).color(1F, 1F, 1F, .5F).endVertex();
|
||||
bufferbuilder.pos((double) (i + 3), (double) (10), 0.0D).color(1F, 1F, 1F, .5F).endVertex();
|
||||
bufferbuilder.pos((double) (i + 3), (double) (-3), 0.0D).color(1F, 1F, 1F, .5F).endVertex();
|
||||
|
||||
|
||||
if (scalesUp) {
|
||||
double distance = mc.player.getEyePosition(mc.getRenderPartialTicks()).squareDistanceTo(x, y, z);
|
||||
double scale = distance * fontScale;
|
||||
GlStateManager.scaled(2 + scale, 2 + scale, 2 + scale);
|
||||
GlStateManager.scaled(2 + scale, 2 + scale, 2 + scale);
|
||||
}
|
||||
tessellator.draw();
|
||||
GlStateManager.enableTexture();
|
||||
if (hasDepth) {
|
||||
GlStateManager.translatef(0, 0, -0.125f);
|
||||
}
|
||||
|
||||
|
||||
mc.fontRenderer.drawString(str, -mc.fontRenderer.getStringWidth(str) / 2, 0, 0);
|
||||
GlStateManager.enableDepthTest();
|
||||
|
||||
|
||||
GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.depthMask(true);
|
||||
GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA,
|
||||
|
@ -121,118 +120,124 @@ public class TessellatorHelper {
|
|||
GlStateManager.popMatrix();
|
||||
GlStateManager.popAttributes();
|
||||
}
|
||||
|
||||
public static void cube(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale,
|
||||
boolean scaleVertical, boolean doubleFaces) {
|
||||
TessellatorHelper.walls(bufferBuilder, pos, size, scale, scaleVertical, doubleFaces);
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
|
||||
if (doubleFaces) {
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true, scaleVertical, false);
|
||||
} else {
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true, scaleVertical, false, false);
|
||||
}
|
||||
}
|
||||
public static void cube(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale,
|
||||
boolean scaleVertical, boolean doubleFaces) {
|
||||
TessellatorHelper.walls(bufferBuilder, pos, size, scale, scaleVertical, doubleFaces);
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
|
||||
public static void walls(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale,
|
||||
boolean scaleVertical, boolean doubleFaces) {
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
if (doubleFaces) {
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true,
|
||||
scaleVertical, false);
|
||||
} else {
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, 0, l), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).up(h), new BlockPos(-w, 0, l), scale, true, scaleVertical,
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (doubleFaces) {
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false);
|
||||
} else {
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false, false);
|
||||
}
|
||||
}
|
||||
public static void walls(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double scale,
|
||||
boolean scaleVertical, boolean doubleFaces) {
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
|
||||
public static void doubleFace(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift,
|
||||
boolean stretch, boolean shiftVertical, boolean mirrorTexture) {
|
||||
TessellatorHelper.face(bufferBuilder, pos, size, shift, stretch, shiftVertical, false, mirrorTexture);
|
||||
TessellatorHelper.face(bufferBuilder, pos.add(size.getX(), 0, (size.getY() == 0) ? 0 : size.getZ()),
|
||||
new BlockPos(-size.getX(), size.getY(), (size.getY() == 0) ? size.getZ() : -size.getZ()), -shift,
|
||||
stretch, shiftVertical, true, mirrorTexture);
|
||||
}
|
||||
if (doubleFaces) {
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true,
|
||||
scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true,
|
||||
scaleVertical, false);
|
||||
TessellatorHelper.doubleFace(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false);
|
||||
} else {
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(w, h, 0), scale, true, scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(0, h, -l), scale, true,
|
||||
scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos.east(w).south(l), new BlockPos(-w, h, 0), scale, true,
|
||||
scaleVertical, false, false);
|
||||
TessellatorHelper.face(bufferBuilder, pos, new BlockPos(0, h, l), scale, true, scaleVertical, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void face(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift, boolean stretch,
|
||||
boolean shiftVertical, boolean shiftBackwards, boolean mirrorTexture) {
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
if (shiftBackwards)
|
||||
shift = -shift;
|
||||
public static void doubleFace(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift,
|
||||
boolean stretch, boolean shiftVertical, boolean mirrorTexture) {
|
||||
TessellatorHelper.face(bufferBuilder, pos, size, shift, stretch, shiftVertical, false, mirrorTexture);
|
||||
TessellatorHelper.face(bufferBuilder, pos.add(size.getX(), 0, (size.getY() == 0) ? 0 : size.getZ()),
|
||||
new BlockPos(-size.getX(), size.getY(), (size.getY() == 0) ? size.getZ() : -size.getZ()), -shift,
|
||||
stretch, shiftVertical, true, mirrorTexture);
|
||||
}
|
||||
|
||||
if (w == 0) { // YZ plane -> H has to be positive
|
||||
public static void face(BufferBuilder bufferBuilder, BlockPos pos, BlockPos size, double shift, boolean stretch,
|
||||
boolean shiftVertical, boolean shiftBackwards, boolean mirrorTexture) {
|
||||
int w = size.getX();
|
||||
int h = size.getY();
|
||||
int l = size.getZ();
|
||||
if (shiftBackwards)
|
||||
shift = -shift;
|
||||
|
||||
double xs = (l < 0) ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
xs = -xs;
|
||||
double ys1 = shiftVertical ? shift : 0;
|
||||
double zs1 = l < 0 ? -shift : shift;
|
||||
if (!stretch && (l > 0 ^ mirrorTexture))
|
||||
zs1 = -zs1;
|
||||
double ys2 = stretch ? -ys1 : ys1;
|
||||
double zs2 = stretch ? -zs1 : zs1;
|
||||
double u1 = (mirrorTexture) ? l : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : l;
|
||||
if (w == 0) { // YZ plane -> H has to be positive
|
||||
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs1), pos.south(l), u2, h);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs1), pos.south(l).up(h), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs2), pos.up(h), u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs2), pos, u1, h);
|
||||
double xs = (l < 0) ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
xs = -xs;
|
||||
double ys1 = shiftVertical ? shift : 0;
|
||||
double zs1 = l < 0 ? -shift : shift;
|
||||
if (!stretch && (l > 0 ^ mirrorTexture))
|
||||
zs1 = -zs1;
|
||||
double ys2 = stretch ? -ys1 : ys1;
|
||||
double zs2 = stretch ? -zs1 : zs1;
|
||||
double u1 = (mirrorTexture) ? l : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : l;
|
||||
|
||||
} else if (h == 0) { // XZ plane -> L has to be positive
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs1), pos.south(l), u2, h);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs1), pos.south(l).up(h), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys1, zs2), pos.up(h), u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs, ys2, zs2), pos, u1, h);
|
||||
|
||||
double ys = w < 0 ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
ys = -ys;
|
||||
double xs1 = w < 0 ? -shift : shift;
|
||||
double zs1 = shift;
|
||||
double xs2 = stretch ? -xs1 : xs1;
|
||||
double zs2 = stretch ? -zs1 : zs1;
|
||||
double u1 = (mirrorTexture) ? w : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : w;
|
||||
} else if (h == 0) { // XZ plane -> L has to be positive
|
||||
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs1), pos.south(l), u1, l);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs2), pos, u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs2), pos.east(w), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs1), pos.east(w).south(l), u2, l);
|
||||
double ys = w < 0 ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
ys = -ys;
|
||||
double xs1 = w < 0 ? -shift : shift;
|
||||
double zs1 = shift;
|
||||
double xs2 = stretch ? -xs1 : xs1;
|
||||
double zs2 = stretch ? -zs1 : zs1;
|
||||
double u1 = (mirrorTexture) ? w : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : w;
|
||||
|
||||
} else if (l == 0) { // XY plane -> H has to be positive
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs1), pos.south(l), u1, l);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys, zs2), pos, u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs2), pos.east(w), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys, zs1), pos.east(w).south(l), u2, l);
|
||||
|
||||
double zs = w < 0 ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
zs = -zs;
|
||||
double ys1 = shiftVertical ? shift : 0;
|
||||
double xs1 = w < 0 ? -shift : shift;
|
||||
if (!stretch && (w > 0 ^ mirrorTexture))
|
||||
xs1 = -xs1;
|
||||
double ys2 = stretch ? -ys1 : ys1;
|
||||
double xs2 = stretch ? -xs1 : xs1;
|
||||
double u1 = (mirrorTexture) ? w : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : w;
|
||||
} else if (l == 0) { // XY plane -> H has to be positive
|
||||
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys2, zs), pos, u1, h);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys1, zs), pos.up(h), u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys1, zs), pos.east(w).up(h), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys2, zs), pos.east(w), u2, h);
|
||||
double zs = w < 0 ? shift : -shift;
|
||||
if (shiftBackwards)
|
||||
zs = -zs;
|
||||
double ys1 = shiftVertical ? shift : 0;
|
||||
double xs1 = w < 0 ? -shift : shift;
|
||||
if (!stretch && (w > 0 ^ mirrorTexture))
|
||||
xs1 = -xs1;
|
||||
double ys2 = stretch ? -ys1 : ys1;
|
||||
double xs2 = stretch ? -xs1 : xs1;
|
||||
double u1 = (mirrorTexture) ? w : 0;
|
||||
double u2 = (mirrorTexture) ? 0 : w;
|
||||
|
||||
}
|
||||
}
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys2, zs), pos, u1, h);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs2, ys1, zs), pos.up(h), u1, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys1, zs), pos.east(w).up(h), u2, 0);
|
||||
TessellatorHelper.posTexShift(bufferBuilder, new Vec3d(xs1, ys2, zs), pos.east(w), u2, h);
|
||||
|
||||
private static void posTexShift(BufferBuilder bufferBuilder, Vec3d shift, BlockPos pos, double u, double v) {
|
||||
bufferBuilder.pos(shift.x + pos.getX(), shift.y + pos.getY(), shift.z + pos.getZ()).tex(u, v).endVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void posTexShift(BufferBuilder bufferBuilder, Vec3d shift, BlockPos pos, double u, double v) {
|
||||
bufferBuilder.pos(shift.x + pos.getX(), shift.y + pos.getY(), shift.z + pos.getZ()).tex(u, v).endVertex();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
|
|||
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionRenderer;
|
||||
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalBearingTileEntityRenderer;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.FastItemRenderer;
|
||||
|
||||
import net.minecraft.client.resources.ReloadListener;
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
|
@ -23,7 +22,6 @@ public class CachedBufferReloader extends ReloadListener<String> {
|
|||
ContraptionRenderer.invalidateCache();
|
||||
MechanicalBearingTileEntityRenderer.invalidateCache();
|
||||
ColoredIndicatorRenderer.invalidateCache();
|
||||
FastItemRenderer.invalidateCache();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.simibubi.create.modules.contraptions;
|
|||
|
||||
import static com.simibubi.create.AllBlocks.BELT;
|
||||
import static com.simibubi.create.AllBlocks.COGWHEEL;
|
||||
import static com.simibubi.create.AllBlocks.ENCASED_FAN;
|
||||
import static com.simibubi.create.AllBlocks.LARGE_COGWHEEL;
|
||||
import static com.simibubi.create.CreateConfig.parameters;
|
||||
import static net.minecraft.state.properties.BlockStateProperties.AXIS;
|
||||
|
|
|
@ -7,21 +7,22 @@ import java.util.Optional;
|
|||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.block.IRenderUtilityBlock;
|
||||
import com.simibubi.create.foundation.block.IWithTileEntity;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.block.SyncedTileEntity;
|
||||
import com.simibubi.create.foundation.utility.ItemHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.HorizontalBlock;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.StateContainer.Builder;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
|
@ -99,8 +100,8 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> getPotentialAttachmentLocations(BeltTileEntity te) {
|
||||
return Arrays.asList(te.getPos().up(2));
|
||||
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
|
||||
return Arrays.asList(pos.up(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,15 +113,35 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<BlockPos> getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state) {
|
||||
BlockState blockState = world.getBlockState(pos.down(2));
|
||||
if (!AllBlocks.BELT.typeOf(blockState) || blockState.get(BeltBlock.SLOPE) != Slope.HORIZONTAL)
|
||||
return Optional.empty();
|
||||
return Optional.of(pos.down(2));
|
||||
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
|
||||
return pos.down(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
|
||||
public boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos,
|
||||
BlockState attachmentState, BlockState beltState) {
|
||||
return AllBlocks.BELT.typeOf(beltState) && beltState.get(BeltBlock.SLOPE) == Slope.HORIZONTAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
MechanicalPressTileEntity pressTe = (MechanicalPressTileEntity) te.getWorld()
|
||||
.getTileEntity(state.attachmentPos);
|
||||
|
||||
if (pressTe == null || pressTe.getSpeed() == 0)
|
||||
return false;
|
||||
if (pressTe.running)
|
||||
return false;
|
||||
if (!pressTe.getRecipe(transported.stack).isPresent())
|
||||
return false;
|
||||
|
||||
state.processingDuration = 1;
|
||||
pressTe.start(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processItem(BeltTileEntity te, TransportedItemStack transportedStack, BeltAttachmentState state) {
|
||||
MechanicalPressTileEntity pressTe = (MechanicalPressTileEntity) te.getWorld()
|
||||
.getTileEntity(state.attachmentPos);
|
||||
|
||||
|
@ -128,42 +149,23 @@ public class MechanicalPressBlock extends HorizontalKineticBlock
|
|||
if (pressTe == null || pressTe.getSpeed() == 0)
|
||||
return false;
|
||||
|
||||
// Not an Item
|
||||
if (!(entity instanceof ItemEntity))
|
||||
return false;
|
||||
|
||||
// Running
|
||||
if (pressTe.running) {
|
||||
double distanceTo = entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos()));
|
||||
if (distanceTo < .32f)
|
||||
return true;
|
||||
if (distanceTo < .4f) {
|
||||
entity.setPosition(te.getPos().getX() + .5f, entity.posY, te.getPos().getZ() + .5f);
|
||||
return true;
|
||||
if (pressTe.runningTicks == 30) {
|
||||
Optional<PressingRecipe> recipe = pressTe.getRecipe(transportedStack.stack);
|
||||
if (!recipe.isPresent())
|
||||
return false;
|
||||
ItemStack out = recipe.get().getRecipeOutput().copy();
|
||||
List<ItemStack> multipliedOutput = ItemHelper.multipliedOutput(transportedStack.stack, out);
|
||||
if (multipliedOutput.isEmpty())
|
||||
transportedStack.stack = ItemStack.EMPTY;
|
||||
transportedStack.stack = multipliedOutput.get(0);
|
||||
|
||||
TileEntity controllerTE = te.getWorld().getTileEntity(te.getController());
|
||||
if (controllerTE != null && controllerTE instanceof BeltTileEntity)
|
||||
((SyncedTileEntity) controllerTE).sendData();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start process
|
||||
if (state.processingEntity != entity) {
|
||||
state.processingEntity = entity;
|
||||
if (!pressTe.getRecipe((ItemEntity) entity).isPresent()) {
|
||||
state.processingDuration = -1;
|
||||
} else {
|
||||
state.processingDuration = 1;
|
||||
pressTe.start(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Already processed
|
||||
if (state.processingDuration == -1)
|
||||
return false;
|
||||
|
||||
// Just Finished
|
||||
if (pressTe.finished) {
|
||||
state.processingDuration = -1;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -6,13 +6,17 @@ import com.simibubi.create.AllRecipes;
|
|||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.logistics.InWorldProcessing;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
@ -85,31 +89,45 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
if (runningTicks == 30) {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(beltMode ? 2 : 1));
|
||||
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) {
|
||||
if (!(entity instanceof ItemEntity))
|
||||
continue;
|
||||
ItemEntity itemEntity = (ItemEntity) entity;
|
||||
|
||||
if (world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .25f).mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, itemEntity.getItem()), entity.posX,
|
||||
entity.posY, entity.posZ, motion.x, motion.y, motion.z);
|
||||
if (!beltMode) {
|
||||
AxisAlignedBB bb = new AxisAlignedBB(pos.down(beltMode ? 2 : 1));
|
||||
for (Entity entity : world.getEntitiesWithinAABBExcludingEntity(null, bb)) {
|
||||
if (!(entity instanceof ItemEntity))
|
||||
continue;
|
||||
|
||||
ItemEntity itemEntity = (ItemEntity) entity;
|
||||
makeParticleEffect(entity.getPositionVec(), itemEntity.getItem());
|
||||
|
||||
if (!world.isRemote) {
|
||||
Optional<PressingRecipe> recipe = getRecipe(itemEntity.getItem());
|
||||
if (recipe.isPresent())
|
||||
InWorldProcessing.applyRecipeOn(itemEntity, recipe.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (beltMode && world.isRemote) {
|
||||
TileEntity te = world.getTileEntity(pos.down(2));
|
||||
if (te != null && te instanceof BeltTileEntity) {
|
||||
BeltTileEntity beltTE = (BeltTileEntity) te;
|
||||
TileEntity controller = world.getTileEntity(beltTE.getController());
|
||||
if (controller != null && controller instanceof BeltTileEntity) {
|
||||
TransportedItemStack stackAtOffset = ((BeltTileEntity) controller).getInventory()
|
||||
.getStackAtOffset(beltTE.index);
|
||||
if (stackAtOffset != null)
|
||||
makeParticleEffect(VecHelper.getCenterOf(pos.down(2)).add(0, 5 / 16f, 0),
|
||||
stackAtOffset.stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.isRemote) {
|
||||
Optional<PressingRecipe> recipe = getRecipe(itemEntity);
|
||||
if (recipe.isPresent())
|
||||
InWorldProcessing.applyRecipeOn(itemEntity, recipe.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.isRemote) {
|
||||
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_BREAK, SoundCategory.BLOCKS, .5f, 1f);
|
||||
world.playSound(null, getPos(), SoundEvents.BLOCK_ANVIL_LAND, SoundCategory.BLOCKS, .125f, 1f);
|
||||
|
@ -128,8 +146,18 @@ public class MechanicalPressTileEntity extends KineticTileEntity {
|
|||
runningTicks++;
|
||||
}
|
||||
|
||||
public Optional<PressingRecipe> getRecipe(ItemEntity itemEntity) {
|
||||
pressingInv.setInventorySlotContents(0, itemEntity.getItem());
|
||||
public void makeParticleEffect(Vec3d pos, ItemStack stack) {
|
||||
if (world.isRemote) {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .25f).mul(1, 0, 1);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), pos.x, pos.y, pos.z, motion.x,
|
||||
motion.y, motion.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<PressingRecipe> getRecipe(ItemStack item) {
|
||||
pressingInv.setInventorySlotContents(0, item);
|
||||
Optional<PressingRecipe> recipe = world.getRecipeManager().getRecipe(AllRecipes.Types.PRESSING, pressingInv,
|
||||
world);
|
||||
return recipe;
|
||||
|
|
|
@ -4,10 +4,11 @@ import net.minecraft.inventory.ItemStackHelper;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.wrapper.RecipeWrapper;
|
||||
|
||||
public class ProcessingInventory extends RecipeWrapper {
|
||||
public class ProcessingInventory extends RecipeWrapper implements IItemHandler {
|
||||
protected int remainingTime;
|
||||
protected int recipeDuration;
|
||||
protected boolean appliedRecipe;
|
||||
|
@ -50,8 +51,40 @@ public class ProcessingInventory extends RecipeWrapper {
|
|||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInventoryStackLimit() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
public ItemStackHandler getItems() {
|
||||
return (ItemStackHandler) inv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlots() {
|
||||
return 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) {
|
||||
if (!isItemValid(slot, stack))
|
||||
return stack;
|
||||
return inv.insertItem(slot, stack, simulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, ItemStack stack) {
|
||||
return slot == 0 && isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,10 +7,12 @@ import java.util.List;
|
|||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllRecipes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.logistics.block.IHaveFilter;
|
||||
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
|
@ -24,15 +26,23 @@ import net.minecraft.particles.BlockParticleData;
|
|||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
import net.minecraft.particles.ParticleTypes;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
||||
|
||||
public ProcessingInventory inventory;
|
||||
private int recipeIndex;
|
||||
private ItemStack filter;
|
||||
private LazyOptional<IItemHandler> invProvider = LazyOptional.empty();
|
||||
|
||||
public SawTileEntity() {
|
||||
super(AllTileEntities.SAW.type);
|
||||
|
@ -40,6 +50,7 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
inventory.remainingTime = -1;
|
||||
filter = ItemStack.EMPTY;
|
||||
recipeIndex = 0;
|
||||
invProvider = LazyOptional.of(() -> inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,12 +89,17 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
return;
|
||||
if (getSpeed() == 0)
|
||||
return;
|
||||
if (inventory.remainingTime == -1)
|
||||
if (inventory.remainingTime == -1) {
|
||||
if (!inventory.isEmpty() && !inventory.appliedRecipe)
|
||||
start();
|
||||
return;
|
||||
}
|
||||
|
||||
float processingSpeed = MathHelper.clamp(Math.abs(getSpeed()) / 32, 1, 128);
|
||||
inventory.remainingTime -= processingSpeed;
|
||||
spawnParticles(inventory.getStackInSlot(0));
|
||||
|
||||
if (inventory.remainingTime > 0)
|
||||
spawnParticles(inventory.getStackInSlot(0));
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
@ -95,10 +111,69 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
return;
|
||||
}
|
||||
|
||||
Vec3d outPos = VecHelper.getCenterOf(pos).add(getItemMovementVec().scale(.5f).add(0, .5, 0));
|
||||
Vec3d outMotion = getItemMovementVec().scale(.0625).add(0, .125, 0);
|
||||
Vec3d itemMovement = getItemMovementVec();
|
||||
Direction itemMovementFacing = Direction.getFacingFromVector(itemMovement.x, itemMovement.y, itemMovement.z);
|
||||
Vec3d outPos = VecHelper.getCenterOf(pos).add(itemMovement.scale(.5f).add(0, .5, 0));
|
||||
Vec3d outMotion = itemMovement.scale(.0625).add(0, .125, 0);
|
||||
|
||||
if (inventory.remainingTime <= 0) {
|
||||
|
||||
// Try moving items onto the belt
|
||||
BlockPos nextPos = pos.add(itemMovement.x, itemMovement.y, itemMovement.z);
|
||||
if (AllBlocks.BELT.typeOf(world.getBlockState(nextPos))) {
|
||||
TileEntity te = world.getTileEntity(nextPos);
|
||||
if (te != null && te instanceof BeltTileEntity) {
|
||||
for (int slot = 0; slot < inventory.getSizeInventory(); slot++) {
|
||||
ItemStack stack = inventory.getStackInSlot(slot);
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
|
||||
if (itemMovementFacing.getAxis() == Axis.Z)
|
||||
itemMovementFacing = itemMovementFacing.getOpposite();
|
||||
if (((BeltTileEntity) te).tryInsertingFromSide(itemMovementFacing, stack, false))
|
||||
inventory.setInventorySlotContents(slot, ItemStack.EMPTY);
|
||||
else {
|
||||
inventory.remainingTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.clear();
|
||||
inventory.remainingTime = -1;
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
|
||||
// Try moving items onto next saw
|
||||
if (AllBlocks.SAW.typeOf(world.getBlockState(nextPos))) {
|
||||
TileEntity te = world.getTileEntity(nextPos);
|
||||
if (te != null && te instanceof SawTileEntity) {
|
||||
SawTileEntity sawTileEntity = (SawTileEntity) te;
|
||||
Vec3d otherMovement = sawTileEntity.getItemMovementVec();
|
||||
if (Direction.getFacingFromVector(otherMovement.x, otherMovement.y,
|
||||
otherMovement.z) != itemMovementFacing.getOpposite()) {
|
||||
for (int slot = 0; slot < inventory.getSizeInventory(); slot++) {
|
||||
ItemStack stack = inventory.getStackInSlot(slot);
|
||||
if (stack.isEmpty())
|
||||
continue;
|
||||
|
||||
ProcessingInventory sawInv = sawTileEntity.inventory;
|
||||
if (sawInv.isEmpty()) {
|
||||
sawInv.insertItem(0, stack, false);
|
||||
inventory.setInventorySlotContents(slot, ItemStack.EMPTY);
|
||||
|
||||
} else {
|
||||
inventory.remainingTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
inventory.clear();
|
||||
inventory.remainingTime = -1;
|
||||
sendData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eject Items
|
||||
for (int slot = 0; slot < inventory.getSizeInventory(); slot++) {
|
||||
ItemStack stack = inventory.getStackInSlot(slot);
|
||||
if (stack.isEmpty())
|
||||
|
@ -108,6 +183,7 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
world.addEntity(entityIn);
|
||||
}
|
||||
inventory.clear();
|
||||
world.updateComparatorOutputLevel(pos, getBlockState().getBlock());
|
||||
inventory.remainingTime = -1;
|
||||
sendData();
|
||||
return;
|
||||
|
@ -116,6 +192,19 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
invProvider.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
|
||||
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
return invProvider.cast();
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
protected void spawnParticles(ItemStack stack) {
|
||||
if (stack == null || stack.isEmpty())
|
||||
return;
|
||||
|
@ -198,6 +287,17 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
|
||||
inventory.clear();
|
||||
inventory.setInventorySlotContents(0, entity.getItem().copy());
|
||||
entity.remove();
|
||||
start();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!canProcess())
|
||||
return;
|
||||
if (inventory.isEmpty())
|
||||
return;
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
List<IRecipe<?>> recipes = getRecipes();
|
||||
boolean valid = !recipes.isEmpty();
|
||||
|
@ -206,7 +306,6 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
if (recipes.isEmpty()) {
|
||||
inventory.remainingTime = inventory.recipeDuration = 10;
|
||||
inventory.appliedRecipe = false;
|
||||
entity.remove();
|
||||
sendData();
|
||||
return;
|
||||
}
|
||||
|
@ -222,11 +321,9 @@ public class SawTileEntity extends KineticTileEntity implements IHaveFilter {
|
|||
time = ((CuttingRecipe) recipe).getProcessingDuration();
|
||||
}
|
||||
|
||||
inventory.remainingTime = time * Math.max(1, (entity.getItem().getCount() / 5));
|
||||
inventory.remainingTime = time * Math.max(1, (inventory.getStackInSlot(0).getCount() / 5));
|
||||
inventory.recipeDuration = inventory.remainingTime;
|
||||
inventory.appliedRecipe = false;
|
||||
entity.remove();
|
||||
|
||||
sendData();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,16 +24,17 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class SawTileEntityRenderer extends TileEntityRenderer<SawTileEntity> {
|
||||
|
||||
FilteredTileEntityRenderer filterRenderer;
|
||||
|
||||
|
||||
public SawTileEntityRenderer() {
|
||||
filterRenderer = new FilteredTileEntityRenderer();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render(SawTileEntity te, double x, double y, double z, float partialTicks, int destroyStage) {
|
||||
super.render(te, x, y, z, partialTicks, destroyStage);
|
||||
|
@ -43,9 +44,11 @@ public class SawTileEntityRenderer extends TileEntityRenderer<SawTileEntity> {
|
|||
boolean alongZ = !te.getBlockState().get(SawBlock.AXIS_ALONG_FIRST_COORDINATE);
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
float offset = te.inventory.recipeDuration != 0
|
||||
? (float) (te.inventory.remainingTime) / te.inventory.recipeDuration
|
||||
: 0;
|
||||
boolean moving = te.inventory.recipeDuration != 0;
|
||||
float offset = moving ? (float) (te.inventory.remainingTime) / te.inventory.recipeDuration : 0;
|
||||
if (moving)
|
||||
offset = MathHelper.clamp(offset + (-partialTicks + .5f) / te.inventory.recipeDuration, 0, 1);
|
||||
|
||||
if (te.getSpeed() == 0)
|
||||
offset = .5f;
|
||||
if (te.getSpeed() < 0 ^ alongZ)
|
||||
|
@ -69,7 +72,7 @@ public class SawTileEntityRenderer extends TileEntityRenderer<SawTileEntity> {
|
|||
|
||||
// Filter
|
||||
filterRenderer.render(te, x, y, z, partialTicks, destroyStage);
|
||||
|
||||
|
||||
// Kinetic renders
|
||||
final BlockState state = getRenderedBlockState(te);
|
||||
KineticTileEntityRenderer.cacheIfMissing(state, getWorld(), BlockModelSpinner::new);
|
||||
|
|
|
@ -2,11 +2,11 @@ package com.simibubi.create.modules.contraptions.relays.belt;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -14,6 +14,7 @@ import net.minecraft.nbt.CompoundNBT;
|
|||
import net.minecraft.nbt.INBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -33,32 +34,52 @@ public enum AllBeltAttachments {
|
|||
}
|
||||
|
||||
public interface IBeltAttachment {
|
||||
public List<BlockPos> getPotentialAttachmentLocations(BeltTileEntity te);
|
||||
|
||||
public Optional<BlockPos> getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state);
|
||||
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState);
|
||||
|
||||
public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state);
|
||||
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state);
|
||||
|
||||
default boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos, BlockState attachmentState,
|
||||
BlockState beltState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void onAttachmentPlaced(IWorld world, BlockPos pos, BlockState state) {
|
||||
Optional<BlockPos> beltPos = getValidBeltPositionFor(world, pos, state);
|
||||
if (!beltPos.isPresent())
|
||||
BlockPos beltPos = getBeltPositionForAttachment(world, pos, state);
|
||||
TileEntity te = world.getTileEntity(beltPos);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return;
|
||||
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(beltPos.get());
|
||||
if (te == null)
|
||||
BeltTileEntity belt = (BeltTileEntity) te;
|
||||
if (!isAttachedCorrectly(world, pos, belt.getPos(), state, belt.getBlockState()))
|
||||
return;
|
||||
te.attachmentTracker.addAttachment(world, pos);
|
||||
te.sendData();
|
||||
belt.attachmentTracker.addAttachment(world, pos);
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
|
||||
default void onAttachmentRemoved(IWorld world, BlockPos pos, BlockState state) {
|
||||
Optional<BlockPos> beltPos = getValidBeltPositionFor(world, pos, state);
|
||||
if (!beltPos.isPresent())
|
||||
BlockPos beltPos = getBeltPositionForAttachment(world, pos, state);
|
||||
TileEntity te = world.getTileEntity(beltPos);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return;
|
||||
BeltTileEntity te = (BeltTileEntity) world.getTileEntity(beltPos.get());
|
||||
if (te == null)
|
||||
BeltTileEntity belt = (BeltTileEntity) te;
|
||||
if (!isAttachedCorrectly(world, pos, belt.getPos(), state, belt.getBlockState()))
|
||||
return;
|
||||
te.attachmentTracker.removeAttachment(pos);
|
||||
te.sendData();
|
||||
belt.attachmentTracker.removeAttachment(pos);
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +88,7 @@ public enum AllBeltAttachments {
|
|||
public BlockPos attachmentPos;
|
||||
public int processingDuration;
|
||||
public Entity processingEntity;
|
||||
public TransportedItemStack processingStack;
|
||||
|
||||
public BeltAttachmentState(IBeltAttachment attachment, BlockPos attachmentPos) {
|
||||
this.attachment = attachment;
|
||||
|
@ -86,19 +108,25 @@ public enum AllBeltAttachments {
|
|||
|
||||
public void findAttachments(BeltTileEntity belt) {
|
||||
for (AllBeltAttachments ba : AllBeltAttachments.values()) {
|
||||
List<BlockPos> attachmentPositions = ba.attachment.getPotentialAttachmentLocations(belt);
|
||||
World world = belt.getWorld();
|
||||
BlockPos beltPos = belt.getPos();
|
||||
BlockState beltState = belt.getBlockState();
|
||||
List<BlockPos> attachmentPositions = ba.attachment.getPotentialAttachmentPositions(world, beltPos,
|
||||
beltState);
|
||||
|
||||
for (BlockPos potentialPos : attachmentPositions) {
|
||||
if (!world.isBlockPresent(potentialPos))
|
||||
continue;
|
||||
BlockState state = world.getBlockState(potentialPos);
|
||||
if (!(state.getBlock() instanceof IBeltAttachment))
|
||||
if (!(state.getBlock() instanceof IBeltAttachment))
|
||||
continue;
|
||||
Optional<BlockPos> validBeltPos = ((IBeltAttachment) state.getBlock()).getValidBeltPositionFor(world, potentialPos, state);
|
||||
if (!validBeltPos.isPresent())
|
||||
IBeltAttachment attachment = (IBeltAttachment) state.getBlock();
|
||||
if (!attachment.getBeltPositionForAttachment(world, potentialPos, state).equals(beltPos))
|
||||
continue;
|
||||
if (validBeltPos.get().equals(belt.getPos()))
|
||||
addAttachment(world, potentialPos);
|
||||
if (!attachment.isAttachedCorrectly(world, potentialPos, beltPos, state, beltState))
|
||||
continue;
|
||||
|
||||
addAttachment(world, potentialPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.simibubi.create.foundation.block.IWithTileEntity;
|
|||
import com.simibubi.create.foundation.block.IWithoutBlockItem;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.modules.contraptions.base.HorizontalKineticBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
@ -38,7 +39,7 @@ import net.minecraft.world.IBlockReader;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.Tags;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockItem, IWithTileEntity<BeltTileEntity> {
|
||||
|
||||
|
@ -99,10 +100,14 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
if (entityIn instanceof ItemEntity && entityIn.isAlive()) {
|
||||
if (worldIn.isRemote)
|
||||
return;
|
||||
if (entityIn.getMotion().y > 0)
|
||||
return;
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
ItemEntity itemEntity = (ItemEntity) entityIn;
|
||||
ItemStack remainder = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
|
||||
.orElseGet(() -> new ItemStackHandler(0)).insertItem(0, itemEntity.getItem().copy(), false);
|
||||
IItemHandler handler = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).orElse(null);
|
||||
if (handler == null)
|
||||
return;
|
||||
ItemStack remainder = handler.insertItem(0, itemEntity.getItem().copy(), false);
|
||||
if (remainder.isEmpty())
|
||||
itemEntity.remove();
|
||||
});
|
||||
|
@ -133,19 +138,42 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
if (player.isSneaking() || !player.isAllowEdit())
|
||||
return false;
|
||||
ItemStack heldItem = player.getHeldItem(handIn);
|
||||
if (!Tags.Items.DYES.contains(heldItem.getItem()))
|
||||
return false;
|
||||
if (worldIn.isRemote)
|
||||
boolean isShaft = heldItem.getItem() == AllBlocks.SHAFT.get().asItem();
|
||||
boolean isDye = Tags.Items.DYES.contains(heldItem.getItem());
|
||||
|
||||
if (isShaft) {
|
||||
TileEntity te = worldIn.getTileEntity(pos);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return false;
|
||||
BeltTileEntity belt = (BeltTileEntity) te;
|
||||
if (belt.hasPulley())
|
||||
return false;
|
||||
if (worldIn.isRemote)
|
||||
return true;
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
belt.hasPulley = true;
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
belt.attachKinetics();
|
||||
return true;
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
DyeColor dyeColor = DyeColor.getColor(heldItem);
|
||||
if (dyeColor == null)
|
||||
return;
|
||||
te.applyColor(dyeColor);
|
||||
});
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isDye) {
|
||||
if (worldIn.isRemote)
|
||||
return true;
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
DyeColor dyeColor = DyeColor.getColor(heldItem);
|
||||
if (dyeColor == null)
|
||||
return;
|
||||
te.applyColor(dyeColor);
|
||||
});
|
||||
if (!player.isCreative())
|
||||
heldItem.shrink(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -177,8 +205,15 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
@Override
|
||||
public void onBlockHarvested(World worldIn, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||
withTileEntityDo(worldIn, pos, te -> {
|
||||
if (te.hasPulley())
|
||||
if (worldIn.isRemote)
|
||||
return;
|
||||
if (te.hasPulley() && (player == null || !player.isCreative()))
|
||||
Block.spawnDrops(AllBlocks.SHAFT.get().getDefaultState(), worldIn, pos);
|
||||
if (te.isController()) {
|
||||
BeltInventory inv = te.getInventory();
|
||||
for (TransportedItemStack stack : inv.items)
|
||||
inv.eject(stack);
|
||||
}
|
||||
});
|
||||
super.onBlockHarvested(worldIn, pos, state, player);
|
||||
}
|
||||
|
@ -211,16 +246,20 @@ public class BeltBlock extends HorizontalKineticBlock implements IWithoutBlockIt
|
|||
break;
|
||||
|
||||
BeltTileEntity te = (BeltTileEntity) worldIn.getTileEntity(toDestroy);
|
||||
boolean hasPulley = te.hasPulley();
|
||||
if (te.isController()) {
|
||||
BeltInventory inv = te.getInventory();
|
||||
for (TransportedItemStack stack : inv.items)
|
||||
inv.eject(stack);
|
||||
}
|
||||
|
||||
te.setSource(null);
|
||||
te.remove();
|
||||
|
||||
if (hasPulley) {
|
||||
if (te.hasPulley())
|
||||
worldIn.setBlockState(toDestroy, AllBlocks.SHAFT.get().getDefaultState()
|
||||
.with(BlockStateProperties.AXIS, getRotationAxis(destroyedBlock)), 3);
|
||||
} else {
|
||||
else
|
||||
worldIn.destroyBlock(toDestroy, false);
|
||||
}
|
||||
|
||||
if (destroyedBlock.get(PART) == Part.END)
|
||||
break;
|
||||
|
|
|
@ -4,9 +4,11 @@ import java.util.Collections;
|
|||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -21,7 +23,10 @@ import net.minecraft.util.math.Vec3d;
|
|||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
|
||||
public class BeltInventory {
|
||||
|
||||
|
@ -36,7 +41,7 @@ public class BeltInventory {
|
|||
}
|
||||
|
||||
public void tick() {
|
||||
|
||||
|
||||
// Reverse item collection if belt just reversed
|
||||
if (beltMovementPositive != movingPositive()) {
|
||||
beltMovementPositive = movingPositive();
|
||||
|
@ -49,12 +54,15 @@ public class BeltInventory {
|
|||
TransportedItemStack stackInFront = null;
|
||||
TransportedItemStack current = null;
|
||||
Iterator<TransportedItemStack> iterator = items.iterator();
|
||||
float beltSpeed = belt.getBeltMovementSpeed();
|
||||
|
||||
float beltSpeed = belt.getDirectionAwareBeltMovementSpeed();
|
||||
float spacing = 1;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Items: while (iterator.hasNext()) {
|
||||
stackInFront = current;
|
||||
current = iterator.next();
|
||||
current.prevBeltPosition = current.beltPosition;
|
||||
current.prevSideOffset = current.sideOffset;
|
||||
|
||||
if (current.stack.isEmpty()) {
|
||||
iterator.remove();
|
||||
|
@ -64,6 +72,11 @@ public class BeltInventory {
|
|||
|
||||
float movement = beltSpeed;
|
||||
|
||||
// Don't move if locked
|
||||
boolean onClient = belt.getWorld().isRemote;
|
||||
if (onClient && current.locked)
|
||||
continue;
|
||||
|
||||
// Don't move if other items are waiting in front
|
||||
float currentPos = current.beltPosition;
|
||||
if (stackInFront != null) {
|
||||
|
@ -74,18 +87,60 @@ public class BeltInventory {
|
|||
: Math.max(movement, diff + spacing);
|
||||
}
|
||||
|
||||
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
|
||||
float limitedMovement = beltMovementPositive ? Math.min(movement, diffToEnd)
|
||||
: Math.max(movement, diffToEnd);
|
||||
|
||||
// Determine current segment
|
||||
int segmentBefore = (int) currentPos;
|
||||
float min = segmentBefore + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = segmentBefore + .5f + (SEGMENT_WINDOW / 2);
|
||||
if (currentPos < min || currentPos > max)
|
||||
segmentBefore = -1;
|
||||
|
||||
current.beltPosition += limitedMovement;
|
||||
// Don't move beyond the edge
|
||||
float diffToEnd = beltMovementPositive ? belt.beltLength - currentPos : -currentPos;
|
||||
float limitedMovement = beltMovementPositive ? Math.min(movement, diffToEnd)
|
||||
: Math.max(movement, diffToEnd);
|
||||
|
||||
if (!onClient) {
|
||||
// Don't move if belt attachments want to continue processing
|
||||
if (segmentBefore != -1 && current.locked) {
|
||||
BeltTileEntity beltSegment = getBeltSegment(segmentBefore);
|
||||
if (beltSegment != null) {
|
||||
|
||||
current.locked = false;
|
||||
for (BeltAttachmentState attachmentState : beltSegment.attachmentTracker.attachments) {
|
||||
if (attachmentState.attachment.processItem(beltSegment, current, attachmentState))
|
||||
current.locked = true;
|
||||
}
|
||||
if (!current.locked || current.stack.isEmpty())
|
||||
belt.sendData();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// See if any new belt processing catches the item
|
||||
int upcomingSegment = (int) (current.beltPosition + (beltMovementPositive ? .5f : -.5f));
|
||||
for (int segment = upcomingSegment; beltMovementPositive
|
||||
? segment <= current.beltPosition + limitedMovement
|
||||
: segment >= current.beltPosition + limitedMovement; segment += beltMovementPositive ? 1 : -1) {
|
||||
BeltTileEntity beltSegment = getBeltSegment(segmentBefore);
|
||||
if (beltSegment == null)
|
||||
break;
|
||||
for (BeltAttachmentState attachmentState : beltSegment.attachmentTracker.attachments) {
|
||||
if (attachmentState.attachment.startProcessingItem(beltSegment, current, attachmentState)) {
|
||||
current.beltPosition += (segment + .5f) - current.beltPosition;
|
||||
current.locked = true;
|
||||
belt.sendData();
|
||||
continue Items;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Movement
|
||||
current.beltPosition += limitedMovement;
|
||||
current.sideOffset += (current.getTargetSideOffset() - current.sideOffset) * Math.abs(limitedMovement) * 2f;
|
||||
currentPos = current.beltPosition;
|
||||
|
||||
// Determine segment after movement
|
||||
int segmentAfter = (int) currentPos;
|
||||
min = segmentAfter + .5f - (SEGMENT_WINDOW / 2);
|
||||
max = segmentAfter + .5f + (SEGMENT_WINDOW / 2);
|
||||
|
@ -113,12 +168,38 @@ public class BeltInventory {
|
|||
BlockState state = world.getBlockState(nextPosition);
|
||||
Direction movementFacing = belt.getMovementFacing();
|
||||
|
||||
// next block is a basin or a saw
|
||||
if (AllBlocks.BASIN.typeOf(state) || AllBlocks.SAW.typeOf(state)) {
|
||||
TileEntity te = world.getTileEntity(nextPosition);
|
||||
if (te != null) {
|
||||
LazyOptional<IItemHandler> optional = te
|
||||
.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, Direction.UP);
|
||||
if (optional.isPresent()) {
|
||||
IItemHandler itemHandler = optional.orElse(null);
|
||||
ItemStack remainder = ItemHandlerHelper.insertItemStacked(itemHandler, current.stack.copy(),
|
||||
false);
|
||||
if (remainder.equals(current.stack, false))
|
||||
continue;
|
||||
|
||||
current.stack = remainder;
|
||||
if (remainder.isEmpty()) {
|
||||
iterator.remove();
|
||||
current = null;
|
||||
}
|
||||
|
||||
belt.sendData();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// next block is not a belt
|
||||
if (!AllBlocks.BELT.typeOf(state)) {
|
||||
if (!Block.hasSolidSide(state, world, nextPosition, movementFacing.getOpposite())) {
|
||||
eject(current);
|
||||
iterator.remove();
|
||||
current = null;
|
||||
belt.sendData();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -135,25 +216,12 @@ public class BeltInventory {
|
|||
continue;
|
||||
|
||||
// Inserting into other belt
|
||||
BlockPos controller = nextBelt.getController();
|
||||
if (!world.isBlockPresent(controller))
|
||||
continue;
|
||||
te = world.getTileEntity(controller);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
continue;
|
||||
BeltTileEntity nextBeltController = (BeltTileEntity) te;
|
||||
BeltInventory nextInventory = nextBeltController.getInventory();
|
||||
if (nextBelt.tryInsertingFromSide(movementFacing, current, false)) {
|
||||
iterator.remove();
|
||||
current = null;
|
||||
belt.sendData();
|
||||
}
|
||||
|
||||
if (!nextInventory.canInsertAt(nextBelt.index))
|
||||
continue;
|
||||
|
||||
current.beltPosition = nextBelt.index + .5f;
|
||||
current.insertedAt = nextBelt.index;
|
||||
nextInventory.insert(current);
|
||||
iterator.remove();
|
||||
current = null;
|
||||
belt.sendData();
|
||||
nextBeltController.sendData();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -164,10 +232,23 @@ public class BeltInventory {
|
|||
public ItemStack stack;
|
||||
public float beltPosition;
|
||||
public float sideOffset;
|
||||
public int angle;
|
||||
public int insertedAt;
|
||||
public Direction insertedFrom;
|
||||
public boolean locked;
|
||||
|
||||
public float prevBeltPosition;
|
||||
public float prevSideOffset;
|
||||
|
||||
public TransportedItemStack(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
angle = new Random().nextInt(360);
|
||||
sideOffset = prevSideOffset = getTargetSideOffset();
|
||||
insertedFrom = Direction.UP;
|
||||
}
|
||||
|
||||
public float getTargetSideOffset() {
|
||||
return (angle - 180) / (360 * 3f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,22 +260,36 @@ public class BeltInventory {
|
|||
CompoundNBT nbt = new CompoundNBT();
|
||||
nbt.put("Item", stack.serializeNBT());
|
||||
nbt.putFloat("Pos", beltPosition);
|
||||
nbt.putFloat("PrevPos", prevBeltPosition);
|
||||
nbt.putFloat("Offset", sideOffset);
|
||||
nbt.putFloat("PrevOffset", prevSideOffset);
|
||||
nbt.putInt("InSegment", insertedAt);
|
||||
nbt.putInt("Angle", angle);
|
||||
nbt.putInt("InDirection", insertedFrom.getIndex());
|
||||
nbt.putBoolean("Locked", locked);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public static TransportedItemStack read(CompoundNBT nbt) {
|
||||
TransportedItemStack stack = new TransportedItemStack(ItemStack.read(nbt.getCompound("Item")));
|
||||
stack.beltPosition = nbt.getFloat("Pos");
|
||||
stack.prevBeltPosition = nbt.getFloat("PrevPos");
|
||||
stack.sideOffset = nbt.getFloat("Offset");
|
||||
stack.prevSideOffset = nbt.getFloat("PrevOffset");
|
||||
stack.insertedAt = nbt.getInt("InSegment");
|
||||
stack.angle = nbt.getInt("Angle");
|
||||
stack.insertedFrom = Direction.byIndex(nbt.getInt("InDirection"));
|
||||
stack.locked = nbt.getBoolean("Locked");
|
||||
return stack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean canInsertAt(int segment) {
|
||||
return canInsertFrom(segment, Direction.UP);
|
||||
}
|
||||
|
||||
public boolean canInsertFrom(int segment, Direction side) {
|
||||
float min = segment + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = segment + .5f + (SEGMENT_WINDOW / 2);
|
||||
|
||||
|
@ -211,7 +306,8 @@ public class BeltInventory {
|
|||
|
||||
// Items on the belt get prioritized if the previous item was inserted on the
|
||||
// same segment
|
||||
if (stack.insertedAt == segment && currentPos <= segment + 1)
|
||||
if (stack.insertedAt == segment && stack.insertedFrom == side
|
||||
&& (beltMovementPositive ? currentPos <= segment + 1.5 : currentPos - 1.5 >= segment))
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -219,20 +315,23 @@ public class BeltInventory {
|
|||
}
|
||||
|
||||
protected void insert(TransportedItemStack newStack) {
|
||||
int index = 0;
|
||||
if (items.isEmpty())
|
||||
items.add(newStack);
|
||||
for (TransportedItemStack stack : items) {
|
||||
if (stack.compareTo(newStack) > 0 == beltMovementPositive)
|
||||
break;
|
||||
index++;
|
||||
else {
|
||||
int index = 0;
|
||||
for (TransportedItemStack stack : items) {
|
||||
if (stack.compareTo(newStack) > 0 == beltMovementPositive)
|
||||
break;
|
||||
index++;
|
||||
}
|
||||
items.add(index, newStack);
|
||||
}
|
||||
items.add(index, newStack);
|
||||
|
||||
belt.markDirty();
|
||||
belt.sendData();
|
||||
}
|
||||
|
||||
protected TransportedItemStack getStackAtOffset(int offset) {
|
||||
public TransportedItemStack getStackAtOffset(int offset) {
|
||||
float min = offset + .5f - (SEGMENT_WINDOW / 2);
|
||||
float max = offset + .5f + (SEGMENT_WINDOW / 2);
|
||||
for (TransportedItemStack stack : items) {
|
||||
|
@ -260,28 +359,40 @@ public class BeltInventory {
|
|||
return nbt;
|
||||
}
|
||||
|
||||
private void eject(TransportedItemStack stack) {
|
||||
public void eject(TransportedItemStack stack) {
|
||||
ItemStack ejected = stack.stack;
|
||||
Vec3d outPos = getVectorForOffset(stack.beltPosition);
|
||||
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y, outPos.z, ejected);
|
||||
entity.setMotion(new Vec3d(belt.getBeltChainDirection()).scale(Math.abs(belt.getBeltMovementSpeed())));
|
||||
Vec3d outMotion = new Vec3d(belt.getBeltChainDirection()).scale(Math.abs(belt.getBeltMovementSpeed())).add(0,
|
||||
1 / 8f, 0);
|
||||
outPos.add(outMotion.normalize());
|
||||
ItemEntity entity = new ItemEntity(belt.getWorld(), outPos.x, outPos.y + 6 / 16f, outPos.z, ejected);
|
||||
entity.setMotion(outMotion);
|
||||
entity.velocityChanged = true;
|
||||
belt.getWorld().addEntity(entity);
|
||||
}
|
||||
|
||||
private Vec3d getVectorForOffset(float offset) {
|
||||
Vec3d vec = VecHelper.getCenterOf(belt.getPos());
|
||||
vec.add(new Vec3d(belt.getBeltChainDirection()).scale(offset));
|
||||
vec = vec.add(new Vec3d(belt.getBeltFacing().getDirectionVec()).scale(offset - .5f));
|
||||
return vec;
|
||||
}
|
||||
|
||||
private BeltTileEntity getBeltSegment(int segment) {
|
||||
BlockPos pos = getPositionForOffset(segment);
|
||||
TileEntity te = belt.getWorld().getTileEntity(pos);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return null;
|
||||
return (BeltTileEntity) te;
|
||||
}
|
||||
|
||||
private BlockPos getPositionForOffset(int offset) {
|
||||
BlockPos pos = belt.getPos();
|
||||
Vec3i vec = belt.getBeltChainDirection();
|
||||
Vec3i vec = belt.getBeltFacing().getDirectionVec();
|
||||
return pos.add(offset * vec.getX(), offset * vec.getY(), offset * vec.getZ());
|
||||
}
|
||||
|
||||
private boolean movingPositive() {
|
||||
return belt.getBeltMovementSpeed() > 0;
|
||||
return belt.getDirectionAwareBeltMovementSpeed() > 0;
|
||||
}
|
||||
|
||||
public class ItemHandlerSegment implements IItemHandler {
|
||||
|
@ -311,6 +422,7 @@ public class BeltInventory {
|
|||
TransportedItemStack newStack = new TransportedItemStack(stack);
|
||||
newStack.insertedAt = offset;
|
||||
newStack.beltPosition = offset + .5f;
|
||||
newStack.prevBeltPosition = newStack.beltPosition;
|
||||
insert(newStack);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
|
|
|
@ -93,7 +93,7 @@ public class BeltMovementHandler {
|
|||
|
||||
// Attachment pauses movement
|
||||
for (BeltAttachmentState state : belt.attachmentTracker.attachments) {
|
||||
if (state.attachment.handleEntity(belt, entityIn, state)) {
|
||||
if (state.attachment.processEntity(belt, entityIn, state)) {
|
||||
info.ticksSinceLastCollision--;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@ import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
|||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.Tracker;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Part;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltMovementHandler.TransportedEntityInfo;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.item.DyeColor;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
|
@ -197,6 +199,13 @@ public class BeltTileEntity extends KineticTileEntity {
|
|||
return getSpeed() / 1600f;
|
||||
}
|
||||
|
||||
public float getDirectionAwareBeltMovementSpeed() {
|
||||
int offset = getBeltFacing().getAxisDirection().getOffset();
|
||||
if (getBeltFacing().getAxis() == Axis.X)
|
||||
offset *= -1;
|
||||
return getSpeed() / 1600f * offset;
|
||||
}
|
||||
|
||||
public boolean hasPulley() {
|
||||
if (!AllBlocks.BELT.typeOf(getBlockState()))
|
||||
return false;
|
||||
|
@ -270,4 +279,44 @@ public class BeltTileEntity extends KineticTileEntity {
|
|||
return inventory;
|
||||
}
|
||||
|
||||
public boolean tryInsertingFromSide(Direction side, ItemStack stack, boolean simulate) {
|
||||
return tryInsertingFromSide(side, new TransportedItemStack(stack), simulate);
|
||||
}
|
||||
|
||||
public boolean tryInsertingFromSide(Direction side, TransportedItemStack transportedStack, boolean simulate) {
|
||||
BlockPos controller = getController();
|
||||
if (!world.isBlockPresent(controller))
|
||||
return false;
|
||||
TileEntity te = world.getTileEntity(controller);
|
||||
if (te == null || !(te instanceof BeltTileEntity))
|
||||
return false;
|
||||
BeltTileEntity nextBeltController = (BeltTileEntity) te;
|
||||
BeltInventory nextInventory = nextBeltController.getInventory();
|
||||
|
||||
if (!nextInventory.canInsertFrom(index, side))
|
||||
return false;
|
||||
if (simulate)
|
||||
return true;
|
||||
|
||||
transportedStack.beltPosition = index + .5f;
|
||||
|
||||
Direction movementFacing = getMovementFacing();
|
||||
if (!side.getAxis().isVertical()) {
|
||||
if (movementFacing != side)
|
||||
transportedStack.sideOffset = side.getAxisDirection().getOffset() * .35f;
|
||||
else
|
||||
transportedStack.beltPosition = getDirectionAwareBeltMovementSpeed() > 0 ? index : index + 1;
|
||||
if (side.getAxis() == Axis.X ^ movementFacing.getAxis() == Axis.X)
|
||||
transportedStack.sideOffset *= -1;
|
||||
}
|
||||
|
||||
transportedStack.prevSideOffset = transportedStack.sideOffset;
|
||||
transportedStack.insertedAt = index;
|
||||
transportedStack.insertedFrom = side;
|
||||
transportedStack.prevBeltPosition = transportedStack.beltPosition;
|
||||
nextInventory.insert(transportedStack);
|
||||
nextBeltController.sendData();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.modules.contraptions.relays.belt;
|
|||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.utility.IndependentShadowRenderer;
|
||||
import com.simibubi.create.foundation.utility.TessellatorHelper;
|
||||
import com.simibubi.create.modules.contraptions.base.IRotate;
|
||||
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
|
||||
|
@ -12,6 +13,8 @@ import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.Transp
|
|||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
||||
|
@ -19,6 +22,7 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
|||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
|
@ -28,27 +32,66 @@ public class BeltTileEntityRenderer extends TileEntityRenderer<BeltTileEntity> {
|
|||
@Override
|
||||
public void render(BeltTileEntity te, double x, double y, double z, float partialTicks, int destroyStage) {
|
||||
super.render(te, x, y, z, partialTicks, destroyStage);
|
||||
if (te.isController()) {
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translated(x + .5, y + 13 / 16f + .25, z + .5);
|
||||
|
||||
for (TransportedItemStack transported : te.getInventory().items) {
|
||||
GlStateManager.pushMatrix();
|
||||
Vec3i direction = te.getBeltChainDirection();
|
||||
float offset = transported.beltPosition;
|
||||
Vec3d offsetVec = new Vec3d(direction).scale(offset);
|
||||
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
|
||||
Minecraft.getInstance().getItemRenderer().renderItem(transported.stack, TransformType.FIXED);
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
TessellatorHelper.prepareFastRender();
|
||||
TessellatorHelper.begin(DefaultVertexFormats.BLOCK);
|
||||
renderTileEntityFast(te, x, y, z, partialTicks, destroyStage, Tessellator.getInstance().getBuffer());
|
||||
TessellatorHelper.draw();
|
||||
|
||||
if (te.isController()) {
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
Vec3i directionVec = te.getBeltFacing().getDirectionVec();
|
||||
Vec3d beltStartOffset = new Vec3d(directionVec).scale(-.5).add(.5, 13 / 16f + .125f, .5);
|
||||
GlStateManager.translated(x + beltStartOffset.x, y + beltStartOffset.y, z + beltStartOffset.z);
|
||||
|
||||
for (TransportedItemStack transported : te.getInventory().items) {
|
||||
GlStateManager.pushMatrix();
|
||||
float offset = MathHelper.lerp(partialTicks, transported.prevBeltPosition, transported.beltPosition);
|
||||
|
||||
float sideOffset = MathHelper.lerp(partialTicks, transported.prevSideOffset, transported.sideOffset);
|
||||
Vec3d offsetVec = new Vec3d(directionVec).scale(offset);
|
||||
GlStateManager.translated(offsetVec.x, offsetVec.y, offsetVec.z);
|
||||
|
||||
boolean alongX = te.getBeltFacing().rotateY().getAxis() == Axis.X;
|
||||
if (!alongX)
|
||||
sideOffset *= -1;
|
||||
GlStateManager.translated(alongX ? sideOffset : 0, 0, alongX ? 0 : sideOffset);
|
||||
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
boolean blockItem = itemRenderer.getModelWithOverrides(transported.stack).isGui3d();
|
||||
if (Minecraft.getInstance().gameSettings.fancyGraphics) {
|
||||
Vec3d shadowPos = new Vec3d(te.getPos()).add(beltStartOffset.scale(1).add(offsetVec)
|
||||
.add(alongX ? sideOffset : 0, .39, alongX ? 0 : sideOffset));
|
||||
IndependentShadowRenderer.renderShadow(shadowPos.x, shadowPos.y, shadowPos.z, .75f,
|
||||
blockItem ? .2f : .2f);
|
||||
}
|
||||
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
|
||||
int count = (int) (MathHelper.log2((int) (transported.stack.getCount()))) / 2;
|
||||
for (int i = 0; i <= count; i++) {
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.rotated(transported.angle, 0, 1, 0);
|
||||
if (!blockItem) {
|
||||
GlStateManager.translated(0, -.09375, 0);
|
||||
GlStateManager.rotated(90, 1, 0, 0);
|
||||
}
|
||||
|
||||
GlStateManager.scaled(.5, .5, .5);
|
||||
itemRenderer.renderItem(transported.stack, TransformType.FIXED);
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.rotated(10, 0, 1, 0);
|
||||
GlStateManager.translated(0, 1/16d, 0);
|
||||
}
|
||||
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
package com.simibubi.create.modules.contraptions.relays.belt;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.simibubi.create.foundation.utility.BufferManipulator;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.model.data.EmptyModelData;
|
||||
|
||||
public class FastItemRenderer extends BufferManipulator {
|
||||
|
||||
public FastItemRenderer(ByteBuffer original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
public ByteBuffer getTranslatedAndRotated(World world, float x, float y, float z, float yaw, float pitch) {
|
||||
original.rewind();
|
||||
mutable.rewind();
|
||||
|
||||
float cosYaw = MathHelper.cos(yaw);
|
||||
float sinYaw = MathHelper.sin(yaw);
|
||||
float cosPitch = MathHelper.cos(pitch);
|
||||
float sinPitch = MathHelper.sin(pitch);
|
||||
|
||||
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
|
||||
float xL = getX(original, vertex); // - (float) rotationOffset.x;
|
||||
float yL = getY(original, vertex); // - (float) rotationOffset.y;
|
||||
float zL = getZ(original, vertex); // - (float) rotationOffset.z;
|
||||
|
||||
float xL2 = rotateX(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
float yL2 = rotateY(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
float zL2 = rotateZ(xL, yL, zL, sinPitch, cosPitch, Axis.X);
|
||||
//
|
||||
xL = rotateX(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
yL = rotateY(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
zL = rotateZ(xL2, yL2, zL2, sinYaw, cosYaw, Axis.Y);
|
||||
|
||||
float xPos = xL + x; // + (float) (offset.x + rotationOffset.x);
|
||||
float yPos = yL + y; // + (float) (offset.y + rotationOffset.y);
|
||||
float zPos = zL + z; // + (float) (offset.z + rotationOffset.z);
|
||||
putPos(mutable, vertex, xPos, yPos, zPos);
|
||||
BlockPos pos = new BlockPos(xPos + .5f, yPos + .5f, zPos + .5f);
|
||||
putLight(mutable, vertex, world.getCombinedLight(pos, 15));
|
||||
}
|
||||
|
||||
return mutable;
|
||||
}
|
||||
|
||||
protected static Cache<Item, FastItemRenderer> cachedItems;
|
||||
|
||||
public static void renderItem(BufferBuilder buffer, World world, ItemStack stack, float x, float y, float z,
|
||||
float yaw, float pitch) {
|
||||
if (stack.isEmpty())
|
||||
return;
|
||||
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
IBakedModel model = itemRenderer.getModelWithOverrides(stack);
|
||||
|
||||
if (model.isBuiltInRenderer()) {
|
||||
renderItemIntoBuffer(stack, itemRenderer, model, 0, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
cacheIfMissing(stack);
|
||||
FastItemRenderer renderer = cachedItems.getIfPresent(stack.getItem());
|
||||
if (renderer == null)
|
||||
return;
|
||||
buffer.putBulkData(renderer.getTranslatedAndRotated(world, x, y +1, z, yaw, pitch));
|
||||
}
|
||||
|
||||
protected static void cacheIfMissing(ItemStack stack) {
|
||||
if (cachedItems == null)
|
||||
cachedItems = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.SECONDS).build();
|
||||
if (cachedItems.getIfPresent(stack.getItem()) != null)
|
||||
return;
|
||||
|
||||
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
IBakedModel model = itemRenderer.getModelWithOverrides(stack);
|
||||
|
||||
int color = 0;
|
||||
BufferBuilder bufferbuilder = new BufferBuilder(0);
|
||||
bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
|
||||
renderItemIntoBuffer(stack, itemRenderer, model, color, bufferbuilder);
|
||||
bufferbuilder.finishDrawing();
|
||||
cachedItems.put(stack.getItem(), new FastItemRenderer(bufferbuilder.getByteBuffer()));
|
||||
}
|
||||
|
||||
protected static void renderItemIntoBuffer(ItemStack stack, ItemRenderer itemRenderer, IBakedModel model, int color,
|
||||
BufferBuilder bufferbuilder) {
|
||||
Random random = new Random(42L);
|
||||
for (Direction direction : Direction.values())
|
||||
itemRenderer.renderQuads(bufferbuilder, model.getQuads(null, direction, random, EmptyModelData.INSTANCE),
|
||||
color, stack);
|
||||
itemRenderer.renderQuads(bufferbuilder, model.getQuads(null, null, random, EmptyModelData.INSTANCE), color,
|
||||
stack);
|
||||
}
|
||||
|
||||
public static void invalidateCache() {
|
||||
if (cachedItems != null)
|
||||
cachedItems.invalidateAll();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,8 +2,10 @@ package com.simibubi.create.modules.logistics.block;
|
|||
|
||||
import static net.minecraft.state.properties.BlockStateProperties.HORIZONTAL_FACING;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.CreateConfig;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.logistics.item.CardboardBoxItem;
|
||||
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
|
||||
|
||||
|
@ -11,10 +13,12 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.ITickableTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
@ -126,6 +130,8 @@ public interface IExtractor extends ITickableTileEntity, IInventoryManipulator {
|
|||
IItemHandler inv = getInventory().orElse(null);
|
||||
ItemStack extracting = ItemStack.EMPTY;
|
||||
ItemStack filterItem = (this instanceof IHaveFilter) ? ((IHaveFilter) this).getFilter() : ItemStack.EMPTY;
|
||||
World world = getWorld();
|
||||
BlockPos pos = getPos();
|
||||
int extractionCount = filterItem.isEmpty() ? CreateConfig.parameters.extractorAmount.get()
|
||||
: filterItem.getCount();
|
||||
boolean checkHasEnoughItems = !filterItem.isEmpty();
|
||||
|
@ -171,18 +177,26 @@ public interface IExtractor extends ITickableTileEntity, IInventoryManipulator {
|
|||
break Extraction;
|
||||
} while (true);
|
||||
|
||||
if (AllBlocks.BELT.typeOf(world.getBlockState(pos.down()))) {
|
||||
TileEntity te = world.getTileEntity(pos.down());
|
||||
if (te != null && te instanceof BeltTileEntity && !extracting.isEmpty()) {
|
||||
if (((BeltTileEntity) te).tryInsertingFromSide(Direction.UP, extracting.copy(), simulate))
|
||||
return extracting;
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!simulate && hasEnoughItems) {
|
||||
World world = getWorld();
|
||||
Vec3d pos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0);
|
||||
Vec3d entityPos = VecHelper.getCenterOf(getPos()).add(0, -0.5f, 0);
|
||||
Entity entityIn = null;
|
||||
|
||||
if (extracting.getItem() instanceof CardboardBoxItem) {
|
||||
Direction face = getWorld().getBlockState(getPos()).get(HORIZONTAL_FACING).getOpposite();
|
||||
entityIn = new CardboardBoxEntity(world, pos, extracting, face);
|
||||
entityIn = new CardboardBoxEntity(world, entityPos, extracting, face);
|
||||
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .25f, .05f);
|
||||
|
||||
} else {
|
||||
entityIn = new ItemEntity(world, pos.x, pos.y, pos.z, extracting);
|
||||
entityIn = new ItemEntity(world, entityPos.x, entityPos.y, entityPos.z, extracting);
|
||||
entityIn.setMotion(Vec3d.ZERO);
|
||||
world.playSound(null, getPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.BLOCKS, .125f, .1f);
|
||||
}
|
||||
|
|
|
@ -2,31 +2,24 @@ package com.simibubi.create.modules.logistics.block.belts;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.foundation.block.IWithTileEntity;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.BeltAttachmentState;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.AllBeltAttachments.IBeltAttachment;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.TransportedItemStack;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity;
|
||||
import com.simibubi.create.modules.logistics.block.IInventoryManipulator;
|
||||
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.HorizontalBlock;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.StateContainer.Builder;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
|
@ -49,7 +42,7 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
|
|||
public boolean hasTileEntity(BlockState state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
|
||||
boolean isMoving) {
|
||||
|
@ -79,7 +72,7 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
|
|||
BlockState neighbour = worldIn.getBlockState(neighbourPos);
|
||||
return !neighbour.getShape(worldIn, pos).isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockItemUseContext context) {
|
||||
BlockState state = getDefaultState();
|
||||
|
@ -138,33 +131,32 @@ public class BeltFunnelBlock extends HorizontalBlock implements IBeltAttachment,
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> getPotentialAttachmentLocations(BeltTileEntity te) {
|
||||
return Arrays.asList(te.getPos().up());
|
||||
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
|
||||
return Arrays.asList(pos.up());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BlockPos> getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state) {
|
||||
BlockPos validPos = pos.down();
|
||||
BlockState blockState = world.getBlockState(validPos);
|
||||
if (!AllBlocks.BELT.typeOf(blockState)
|
||||
|| blockState.get(HORIZONTAL_FACING).getAxis() != state.get(HORIZONTAL_FACING).getAxis())
|
||||
return Optional.empty();
|
||||
return Optional.of(validPos);
|
||||
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
|
||||
return pos.down();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
|
||||
boolean isItem = entity instanceof ItemEntity;
|
||||
if (!isItem && !(entity instanceof CardboardBoxEntity))
|
||||
return false;
|
||||
boolean slope = te.getBlockState().get(BeltBlock.SLOPE) != Slope.HORIZONTAL;
|
||||
if (isItem && entity.getPositionVec().distanceTo(VecHelper.getCenterOf(te.getPos())) > (slope ? .6f : .4f))
|
||||
return false;
|
||||
entity.setMotion(Vec3d.ZERO);
|
||||
withTileEntityDo(te.getWorld(), state.attachmentPos, funnelTE -> {
|
||||
funnelTE.tryToInsert(entity);
|
||||
});
|
||||
public boolean startProcessingItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
return process(te, transported, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processItem(BeltTileEntity te, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
return process(te, transported, state);
|
||||
}
|
||||
|
||||
public boolean process(BeltTileEntity belt, TransportedItemStack transported, BeltAttachmentState state) {
|
||||
TileEntity te = belt.getWorld().getTileEntity(state.attachmentPos);
|
||||
if (te == null || !(te instanceof BeltFunnelTileEntity))
|
||||
return false;
|
||||
BeltFunnelTileEntity funnel = (BeltFunnelTileEntity) te;
|
||||
ItemStack stack = funnel.tryToInsert(transported.stack);
|
||||
transported.stack = stack;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,10 @@ package com.simibubi.create.modules.logistics.block.belts;
|
|||
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.foundation.block.SyncedTileEntity;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.modules.contraptions.relays.belt.BeltInventory.ItemHandlerSegment;
|
||||
import com.simibubi.create.modules.logistics.block.IInventoryManipulator;
|
||||
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.particles.ItemParticleData;
|
||||
|
@ -16,6 +15,7 @@ import net.minecraft.tileentity.ITickableTileEntity;
|
|||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
@ -27,6 +27,8 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
|
|||
protected boolean waitingForInventorySpace;
|
||||
private boolean initialize;
|
||||
|
||||
private ItemStack justEaten;
|
||||
|
||||
public BeltFunnelTileEntity() {
|
||||
super(AllTileEntities.BELT_FUNNEL.type);
|
||||
inventory = LazyOptional.empty();
|
||||
|
@ -38,22 +40,33 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
|
|||
super.read(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.putBoolean("Waiting", waitingForInventorySpace);
|
||||
return super.write(compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
initialize = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT writeToClient(CompoundNBT tag) {
|
||||
if (justEaten != null) {
|
||||
tag.put("Nom", justEaten.serializeNBT());
|
||||
justEaten = null;
|
||||
}
|
||||
return super.writeToClient(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readClientUpdate(CompoundNBT tag) {
|
||||
super.readClientUpdate(tag);
|
||||
if (!waitingForInventorySpace)
|
||||
neighborChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT compound) {
|
||||
compound.putBoolean("Waiting", waitingForInventorySpace);
|
||||
return super.write(compound);
|
||||
if (tag.contains("Nom"))
|
||||
justEaten = ItemStack.read(tag.getCompound("Nom"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,6 +85,10 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
|
|||
neighborChanged();
|
||||
initialize = false;
|
||||
}
|
||||
if (world.isRemote && justEaten != null) {
|
||||
spawnParticles(justEaten);
|
||||
justEaten = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,42 +104,34 @@ public class BeltFunnelTileEntity extends SyncedTileEntity implements ITickableT
|
|||
sendData();
|
||||
}
|
||||
|
||||
public void tryToInsert(Entity entity) {
|
||||
public ItemStack tryToInsert(ItemStack stack) {
|
||||
if (!inventory.isPresent())
|
||||
return;
|
||||
if (waitingForInventorySpace)
|
||||
return;
|
||||
|
||||
ItemStack stack = null;
|
||||
if (entity instanceof ItemEntity)
|
||||
stack = ((ItemEntity) entity).getItem().copy();
|
||||
if (entity instanceof CardboardBoxEntity)
|
||||
stack = ((CardboardBoxEntity) entity).getBox().copy();
|
||||
return stack;
|
||||
if (waitingForInventorySpace && !(inventory.orElse(null) instanceof ItemHandlerSegment))
|
||||
return stack;
|
||||
|
||||
IItemHandler inv = inventory.orElse(null);
|
||||
stack = ItemHandlerHelper.insertItemStacked(inv, stack, false);
|
||||
|
||||
if (stack.isEmpty()) {
|
||||
if (!world.isRemote) {
|
||||
entity.remove();
|
||||
ItemStack remainder = ItemHandlerHelper.insertItemStacked(inv, stack.copy(), false);
|
||||
|
||||
if (remainder.isEmpty()) {
|
||||
if (!world.isRemote)
|
||||
world.playSound(null, pos, SoundEvents.ENTITY_GENERIC_EAT, SoundCategory.BLOCKS, .125f, 1f);
|
||||
} else {
|
||||
Vec3i directionVec = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING).getDirectionVec();
|
||||
float xSpeed = directionVec.getX() * 1 / 8f;
|
||||
float zSpeed = directionVec.getZ() * 1 / 8f;
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), entity.posX,
|
||||
entity.posY, entity.posZ, xSpeed, 1 / 6f, zSpeed);
|
||||
}
|
||||
return;
|
||||
justEaten = stack;
|
||||
} else {
|
||||
waitingForInventorySpace = true;
|
||||
}
|
||||
|
||||
waitingForInventorySpace = true;
|
||||
sendData();
|
||||
return remainder;
|
||||
}
|
||||
|
||||
if (entity instanceof ItemEntity)
|
||||
if (!stack.equals(((ItemEntity) entity).getItem(), false))
|
||||
((ItemEntity) entity).setItem(stack);
|
||||
|
||||
public void spawnParticles(ItemStack stack) {
|
||||
Vec3i directionVec = getBlockState().get(BlockStateProperties.HORIZONTAL_FACING).getDirectionVec();
|
||||
float xSpeed = directionVec.getX() * 1 / 8f;
|
||||
float zSpeed = directionVec.getZ() * 1 / 8f;
|
||||
Vec3d vec = VecHelper.getCenterOf(pos);
|
||||
world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), vec.x, vec.y - 9 / 16f, vec.z, xSpeed,
|
||||
1 / 6f, zSpeed);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.simibubi.create.modules.logistics.block.belts;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
|
@ -129,16 +128,20 @@ public class EntityDetectorBlock extends HorizontalBlock
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> getPotentialAttachmentLocations(BeltTileEntity te) {
|
||||
Direction side = te.getBlockState().get(BeltBlock.HORIZONTAL_FACING).rotateY();
|
||||
return Arrays.asList(te.getPos().offset(side), te.getPos().offset(side.getOpposite()));
|
||||
public List<BlockPos> getPotentialAttachmentPositions(IWorld world, BlockPos pos, BlockState beltState) {
|
||||
Direction side = beltState.get(BeltBlock.HORIZONTAL_FACING).rotateY();
|
||||
return Arrays.asList(pos.offset(side), pos.offset(side.getOpposite()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BlockPos> getValidBeltPositionFor(IWorld world, BlockPos pos, BlockState state) {
|
||||
if (!state.get(BELT))
|
||||
return Optional.empty();
|
||||
return Optional.of(pos.offset(state.get(HORIZONTAL_FACING)));
|
||||
public BlockPos getBeltPositionForAttachment(IWorld world, BlockPos pos, BlockState state) {
|
||||
return pos.offset(state.get(HORIZONTAL_FACING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAttachedCorrectly(IWorld world, BlockPos attachmentPos, BlockPos beltPos, BlockState attachmentState,
|
||||
BlockState beltState) {
|
||||
return attachmentState.get(BELT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -178,11 +181,11 @@ public class EntityDetectorBlock extends HorizontalBlock
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean handleEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
|
||||
public boolean processEntity(BeltTileEntity te, Entity entity, BeltAttachmentState state) {
|
||||
|
||||
if (te.getWorld().isRemote)
|
||||
return false;
|
||||
|
||||
|
||||
if (state.processingEntity != entity) {
|
||||
state.processingEntity = entity;
|
||||
state.processingDuration = 0;
|
||||
|
|
|
@ -1,95 +1,140 @@
|
|||
{
|
||||
"__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)",
|
||||
"textures": {
|
||||
"particle": "create:block/belt_funnel",
|
||||
"belt_funnel": "create:block/belt_funnel",
|
||||
"brass_casing": "create:block/brass_casing"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [ 3, -4.1, -1 ],
|
||||
"to": [ 13, -3.1, 5 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#belt_funnel", "uv": [ 0, 11, 10, 12 ] },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 10, 11, 16, 12 ] },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 0, 11, 10, 12 ] },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 10, 11, 16, 12 ], "rotation": 180 },
|
||||
"up": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 13 ], "rotation": 90 },
|
||||
"down": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 12 ], "rotation": 90 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 3, 7, -1 ],
|
||||
"to": [ 13, 8, 5 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 1 ] },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 0, 0, 10, 1 ] },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 1 ], "rotation": 180 },
|
||||
"up": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 12 ], "rotation": 90 },
|
||||
"down": { "texture": "#belt_funnel", "uv": [ 10, 0, 16, 13 ], "rotation": 90 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 3, -3.1, -1 ],
|
||||
"to": [ 4, 7, 5 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 11.1 ] },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 10, 1, 16, 11 ] },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 11.1 ] },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 10, 1, 16, 11 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [ 4, -3.1, -1 ],
|
||||
"to": [ 12, 7, 4 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#brass_casing", "uv": [ 4, 3, 12, 13.1 ] },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 9, 3, 10, 9 ], "rotation": 90 },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 1, 1, 9, 11.1 ] },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 0, 2, 1, 8 ], "rotation": 90 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 4, 6, 0 ],
|
||||
"to": [ 12, 8, 4.8 ],
|
||||
"rotation": { "origin": [ 8, 8, 0 ], "axis": "x", "angle": -22.5 },
|
||||
"faces": {
|
||||
"north": { "texture": "#belt_funnel", "uv": [ 1, 7, 9, 9 ], "rotation": 180 },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 11, 4.6, 16, 6.6 ], "rotation": 180 },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 9, 2, 11, 10 ], "rotation": 90 },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 10, 5, 15, 7.4 ], "rotation": 180 },
|
||||
"up": { "texture": "#belt_funnel", "uv": [ 11, 2, 16, 9.4 ], "rotation": 90 },
|
||||
"down": { "texture": "#belt_funnel", "uv": [ 1, 8, 9, 12.8 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Ramp",
|
||||
"from": [ 4, -4, -8 ],
|
||||
"to": [ 12, 3, -1 ],
|
||||
"rotation": { "origin": [ 8, -4, -1 ], "axis": "x", "angle": 45.0 },
|
||||
"faces": {
|
||||
"north": { "texture": "#brass_casing", "uv": [ 4, 5, 12, 12 ] },
|
||||
"east": { "texture": "#brass_casing", "uv": [ 4, 9, 11, 16 ], "rotation": 90 },
|
||||
"west": { "texture": "#brass_casing", "uv": [ 5, 9, 12, 16 ], "rotation": 270 },
|
||||
"down": { "texture": "#brass_casing", "uv": [ 4, 0, 12, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 12, -3.1, -1 ],
|
||||
"to": [ 13, 7, 5 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#belt_funnel", "uv": [ 0, 1, 1, 11.1 ] },
|
||||
"east": { "texture": "#belt_funnel", "uv": [ 10, 1, 16, 11 ], "rotation": 180 },
|
||||
"south": { "texture": "#belt_funnel", "uv": [ 9, 1, 10, 11.1 ] },
|
||||
"west": { "texture": "#belt_funnel", "uv": [ 10, 1, 16, 11 ] }
|
||||
}
|
||||
}
|
||||
]
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"belt_funnel": "create:block/belt_funnel",
|
||||
"particle": "create:block/belt_funnel",
|
||||
"brass_casing": "create:block/brass_casing"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [3, -4.1, -1],
|
||||
"to": [13, -3.1, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 11, 10, 12], "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 11, 16, 12], "texture": "#belt_funnel"},
|
||||
"south": {"uv": [0, 11, 10, 12], "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 11, 16, 12], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"up": {"uv": [10, 0, 16, 13], "rotation": 90, "texture": "#belt_funnel"},
|
||||
"down": {"uv": [10, 1, 16, 11], "rotation": 90, "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [3, 7, -1],
|
||||
"to": [13, 8, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 10, 1], "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 0, 16, 1], "texture": "#belt_funnel"},
|
||||
"south": {"uv": [0, 0, 10, 1], "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 0, 16, 1], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"up": {"uv": [10, 1, 16, 11], "rotation": 90, "texture": "#belt_funnel"},
|
||||
"down": {"uv": [10, 0, 16, 13], "rotation": 90, "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [3, -3.1, -1],
|
||||
"to": [4, 7, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [9, 1, 10, 11.1], "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 1, 16, 11], "texture": "#belt_funnel"},
|
||||
"south": {"uv": [0, 1, 1, 11.1], "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 1, 16, 11], "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [4, -3.1, -1],
|
||||
"to": [12, 7, 4],
|
||||
"faces": {
|
||||
"north": {"uv": [4, 3, 12, 13.1], "texture": "#brass_casing"},
|
||||
"east": {"uv": [9, 3, 10, 9], "rotation": 90, "texture": "#belt_funnel"},
|
||||
"south": {"uv": [1, 1, 9, 11.1], "texture": "#belt_funnel"},
|
||||
"west": {"uv": [0, 2, 1, 8], "rotation": 90, "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [4, 9, -1],
|
||||
"to": [12, 10, 4.25],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 8, 0]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 12, 9, 13], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 5, 16, 6], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"south": {"uv": [9, 2, 11, 10], "rotation": 90, "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 5, 16, 6], "texture": "#belt_funnel"},
|
||||
"up": {"uv": [10, 2, 16, 10], "rotation": 90, "texture": "#belt_funnel"},
|
||||
"down": {"uv": [1, 8, 9, 12.8], "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [4, 7, -1],
|
||||
"to": [12, 9, 2.5],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 8, 0]},
|
||||
"faces": {
|
||||
"north": {"uv": [1, 11, 9, 13], "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 5, 14, 7], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 5, 14, 6], "texture": "#belt_funnel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Ramp",
|
||||
"from": [4, -4, -8],
|
||||
"to": [12, 3, -1],
|
||||
"rotation": {"angle": 45, "axis": "x", "origin": [8, -4, -1]},
|
||||
"faces": {
|
||||
"north": {"uv": [4, 5, 12, 12], "texture": "#brass_casing"},
|
||||
"east": {"uv": [4, 9, 11, 16], "rotation": 90, "texture": "#brass_casing"},
|
||||
"west": {"uv": [5, 9, 12, 16], "rotation": 270, "texture": "#brass_casing"},
|
||||
"down": {"uv": [4, 0, 12, 7], "texture": "#brass_casing"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [12, -3.1, -1],
|
||||
"to": [13, 7, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 1, 1, 11.1], "texture": "#belt_funnel"},
|
||||
"east": {"uv": [10, 1, 16, 11], "rotation": 180, "texture": "#belt_funnel"},
|
||||
"south": {"uv": [9, 1, 10, 11.1], "texture": "#belt_funnel"},
|
||||
"west": {"uv": [10, 1, 16, 11], "texture": "#belt_funnel"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [75, -149, 0],
|
||||
"translation": [-0.5, 3.25, 2.25],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [75, -149, 0],
|
||||
"translation": [-0.5, 3.25, 2.25],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [0, -55, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [0, -55, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"ground": {
|
||||
"translation": [0, 0, 2.25],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [30, 45, 0],
|
||||
"translation": [2.5, 1.75, 0],
|
||||
"scale": [0.625, 0.625, 0.625]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [0, 180, 0],
|
||||
"translation": [0, 3.5, -4.5],
|
||||
"scale": [0.5, 0.5, 0.5]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,75 +1,115 @@
|
|||
{
|
||||
"__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)",
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"extractor": "create:block/extractor",
|
||||
"textures": {
|
||||
"1": "create:block/brass_casing",
|
||||
"extractor": "create:block/extractor",
|
||||
"particle": "create:block/extractor"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [ 4, 2, -1 ],
|
||||
"to": [ 12, 3, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 7, 14, 8 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 4, 9, -1 ],
|
||||
"to": [ 12, 10, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 0, 14, 1 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 4, 3, -1 ],
|
||||
"to": [ 5, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 1, 7, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 11, 3, -1 ],
|
||||
"to": [ 12, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 13, 1, 14, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [ 5, 3, 3 ],
|
||||
"to": [ 11, 9, 4 ],
|
||||
"faces": {
|
||||
"south": { "texture": "#extractor", "uv": [ 7, 1, 13, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [ 5, 10, -0.6 ],
|
||||
"to": [ 11, 12, 4 ],
|
||||
"rotation": { "origin": [ 8, 11, -1 ], "axis": "x", "angle": 22.5 },
|
||||
"faces": {
|
||||
"north": { "texture": "#extractor", "uv": [ 13, 1, 15, 7 ], "rotation": 90 },
|
||||
"east": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 4, 1, 5, 7 ], "rotation": 270 },
|
||||
"west": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 9, 5, 15 ], "rotation": 90 }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [4, 2, -1],
|
||||
"to": [12, 3, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 7, 14, 8], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 0, 6, 1], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 7, 14, 8], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 0, 6, 1], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 0, 6, 8], "rotation": 90, "texture": "#extractor"},
|
||||
"down": {"uv": [0, 0, 6, 8], "rotation": 270, "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [4, 9, -1],
|
||||
"to": [12, 10, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 0, 14, 1], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 0, 6, 1], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 0, 14, 1], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 0, 6, 1], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 0, 6, 8], "rotation": 90, "texture": "#extractor"},
|
||||
"down": {"uv": [0, 0, 6, 8], "rotation": 270, "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [4, 3, -1],
|
||||
"to": [5, 9, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 14, 7], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 1, 6, 7], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 1, 7, 7], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 1, 6, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [11, 3, -1],
|
||||
"to": [12, 9, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 1, 7, 7], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 1, 6, 7], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [13, 1, 14, 7], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 1, 6, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [5, 3, 0],
|
||||
"to": [11, 9, 4],
|
||||
"faces": {
|
||||
"north": {"uv": [5, 5, 11, 11], "texture": "#1"},
|
||||
"south": {"uv": [7, 1, 13, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [5, 10, -0.6],
|
||||
"to": [11, 12, 4],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, -1]},
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 15, 7], "rotation": 90, "texture": "#extractor"},
|
||||
"east": {"uv": [0.1, 0, 4.7, 2], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [4, 1, 5, 7], "rotation": 270, "texture": "#extractor"},
|
||||
"west": {"uv": [0.1, 0, 4.7, 2], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 9, 5, 15], "rotation": 90, "texture": "#extractor"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_righthand": {
|
||||
"rotation": [75, -149, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [75, -149, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"firstperson_righthand": {
|
||||
"rotation": [0, -55, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"firstperson_lefthand": {
|
||||
"rotation": [0, -55, 0],
|
||||
"scale": [0.4, 0.4, 0.4]
|
||||
},
|
||||
"ground": {
|
||||
"translation": [0, 1, 1.25],
|
||||
"scale": [0.25, 0.25, 0.25]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [30, 45, 0],
|
||||
"translation": [2.5, -0.5, 0],
|
||||
"scale": [0.625, 0.625, 0.625]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [0, 180, 0],
|
||||
"translation": [0, 1.75, -4.5],
|
||||
"scale": [0.5, 0.5, 0.5]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,112 +1,118 @@
|
|||
{
|
||||
"__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)",
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"redstone_antenna": "create:block/redstone_antenna",
|
||||
"extractor": "create:block/extractor",
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "create:block/extractor",
|
||||
"textures": {
|
||||
"2": "create:block/brass_casing",
|
||||
"redstone_antenna": "create:block/redstone_antenna",
|
||||
"extractor": "create:block/extractor",
|
||||
"particle": "create:block/extractor"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [ 4, 2, -1 ],
|
||||
"to": [ 12, 3, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 7, 14, 8 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 4, 9, -1 ],
|
||||
"to": [ 12, 10, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 0, 14, 1 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 4, 3, -1 ],
|
||||
"to": [ 5, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 1, 7, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 11, 3, -1 ],
|
||||
"to": [ 12, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 13, 1, 14, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [ 5, 3, 3 ],
|
||||
"to": [ 11, 9, 4 ],
|
||||
"faces": {
|
||||
"south": { "texture": "#extractor", "uv": [ 7, 1, 13, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [ 5, 10, -0.6 ],
|
||||
"to": [ 11, 12, 4 ],
|
||||
"rotation": { "origin": [ 8, 11, -1 ], "axis": "x", "angle": 22.5 },
|
||||
"faces": {
|
||||
"north": { "texture": "#extractor", "uv": [ 13, 1, 15, 7 ], "rotation": 90 },
|
||||
"east": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 4, 1, 5, 7 ], "rotation": 270 },
|
||||
"west": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 9, 5, 15 ], "rotation": 90 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaX",
|
||||
"from": [ 11, 7, 2 ],
|
||||
"to": [ 14, 17, 3 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"south": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"down": { "texture": "#redstone_antenna", "uv": [ 0, 9, 3, 10 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaZ",
|
||||
"from": [ 12, 7, 1 ],
|
||||
"to": [ 13, 17, 4 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"west": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaTop",
|
||||
"from": [ 12, 15, 2 ],
|
||||
"to": [ 13, 16, 3 ],
|
||||
"faces": {
|
||||
"up": { "texture": "#redstone_antenna", "uv": [ 1, 1, 2, 2 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaDish",
|
||||
"from": [ 10, 13, 0 ],
|
||||
"to": [ 15, 13, 5 ],
|
||||
"faces": {
|
||||
"up": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] },
|
||||
"down": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [4, 2, -1],
|
||||
"to": [12, 3, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 7, 14, 8], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 0, 6, 1], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 7, 14, 8], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 0, 6, 1], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 0, 6, 8], "rotation": 90, "texture": "#extractor"},
|
||||
"down": {"uv": [0, 0, 6, 8], "rotation": 270, "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [4, 9, -1],
|
||||
"to": [12, 10, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 0, 14, 1], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 0, 6, 1], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 0, 14, 1], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 0, 6, 1], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 0, 6, 8], "rotation": 90, "texture": "#extractor"},
|
||||
"down": {"uv": [0, 0, 6, 8], "rotation": 270, "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [4, 3, -1],
|
||||
"to": [5, 9, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 14, 7], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 1, 6, 7], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [6, 1, 7, 7], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 1, 6, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [11, 3, -1],
|
||||
"to": [12, 9, 5],
|
||||
"faces": {
|
||||
"north": {"uv": [6, 1, 7, 7], "texture": "#extractor"},
|
||||
"east": {"uv": [0, 1, 6, 7], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [13, 1, 14, 7], "texture": "#extractor"},
|
||||
"west": {"uv": [0, 1, 6, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [5, 3, 0],
|
||||
"to": [11, 9, 4],
|
||||
"faces": {
|
||||
"north": {"uv": [5, 5, 11, 11], "texture": "#2"},
|
||||
"south": {"uv": [7, 1, 13, 7], "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [5, 10, -0.6],
|
||||
"to": [11, 12, 4],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, -1]},
|
||||
"faces": {
|
||||
"north": {"uv": [13, 1, 15, 7], "rotation": 90, "texture": "#extractor"},
|
||||
"east": {"uv": [0.1, 0, 4.7, 2], "rotation": 180, "texture": "#extractor"},
|
||||
"south": {"uv": [4, 1, 5, 7], "rotation": 270, "texture": "#extractor"},
|
||||
"west": {"uv": [0.1, 0, 4.7, 2], "texture": "#extractor"},
|
||||
"up": {"uv": [0, 9, 5, 15], "rotation": 90, "texture": "#extractor"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaX",
|
||||
"from": [11, 7, 2],
|
||||
"to": [14, 17, 3],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 3, 10], "texture": "#redstone_antenna"},
|
||||
"south": {"uv": [0, 0, 3, 10], "texture": "#redstone_antenna"},
|
||||
"down": {"uv": [0, 9, 3, 10], "texture": "#redstone_antenna"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaZ",
|
||||
"from": [12, 7, 1],
|
||||
"to": [13, 17, 4],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 0, 3, 10], "texture": "#redstone_antenna"},
|
||||
"west": {"uv": [0, 0, 3, 10], "texture": "#redstone_antenna"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaTop",
|
||||
"from": [12, 15, 2],
|
||||
"to": [13, 16, 3],
|
||||
"faces": {
|
||||
"up": {"uv": [1, 1, 2, 2], "texture": "#redstone_antenna"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaDish",
|
||||
"from": [10, 13, 0],
|
||||
"to": [15, 13, 5],
|
||||
"faces": {
|
||||
"up": {"uv": [4, 0, 9, 5], "texture": "#redstone_antenna"},
|
||||
"down": {"uv": [4, 0, 9, 5], "texture": "#redstone_antenna"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,86 +1,3 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"display": {
|
||||
"gui": {
|
||||
"rotation": [ 30, 45, 0 ],
|
||||
"translation": [ 0, 0, 0],
|
||||
"scale":[ 0.625, 0.625, 0.625 ]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [ 0, 180, 0 ],
|
||||
"translation": [ 0, 0, -3.5],
|
||||
"scale":[ 0.5, 0.5, 0.5 ]
|
||||
}
|
||||
},
|
||||
"textures": {
|
||||
"extractor": "create:block/extractor",
|
||||
"particle": "create:block/extractor"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [ 4, 2, -1 ],
|
||||
"to": [ 12, 3, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 7, 14, 8 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 4, 9, -1 ],
|
||||
"to": [ 12, 10, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 0, 14, 1 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 4, 3, -1 ],
|
||||
"to": [ 5, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 1, 7, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 11, 3, -1 ],
|
||||
"to": [ 12, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 13, 1, 14, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [ 5, 3, 3 ],
|
||||
"to": [ 11, 9, 4 ],
|
||||
"faces": {
|
||||
"south": { "texture": "#extractor", "uv": [ 7, 1, 13, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [ 5, 10, -0.6 ],
|
||||
"to": [ 11, 12, 4 ],
|
||||
"rotation": { "origin": [ 8, 11, -1 ], "axis": "x", "angle": 22.5 },
|
||||
"faces": {
|
||||
"north": { "texture": "#extractor", "uv": [ 13, 1, 15, 7 ], "rotation": 90 },
|
||||
"east": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 4, 1, 5, 7 ], "rotation": 270 },
|
||||
"west": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 9, 5, 15 ], "rotation": 90 }
|
||||
}
|
||||
}
|
||||
]
|
||||
"parent": "create:block/extractor"
|
||||
}
|
|
@ -1,123 +1,3 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"display": {
|
||||
"gui": {
|
||||
"rotation": [ 30, 45, 0 ],
|
||||
"translation": [ 0, 0, 0],
|
||||
"scale":[ 0.625, 0.625, 0.625 ]
|
||||
},
|
||||
"fixed": {
|
||||
"rotation": [ 0, 180, 0 ],
|
||||
"translation": [ 0, 0, -3.5],
|
||||
"scale":[ 0.5, 0.5, 0.5 ]
|
||||
}
|
||||
},
|
||||
"textures": {
|
||||
"redstone_antenna": "create:block/redstone_antenna",
|
||||
"extractor": "create:block/extractor",
|
||||
"particle": "create:block/extractor"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Bottom",
|
||||
"from": [ 4, 2, -1 ],
|
||||
"to": [ 12, 3, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 7, 14, 8 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top",
|
||||
"from": [ 4, 9, -1 ],
|
||||
"to": [ 12, 10, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 0, 14, 1 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 0, 6, 1 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 0, 6, 8 ], "rotation": 90 },
|
||||
"down": { "texture": "#extractor", "uv": [ 9, 0, 15, 8 ], "rotation": 270 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 4, 3, -1 ],
|
||||
"to": [ 5, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 6, 1, 7, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Side",
|
||||
"from": [ 11, 3, -1 ],
|
||||
"to": [ 12, 9, 5 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#extractor", "uv": [ 0, 1, 6, 7 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 13, 1, 14, 7 ] },
|
||||
"west": { "texture": "#extractor", "uv": [ 9, 1, 15, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Center",
|
||||
"from": [ 5, 3, 3 ],
|
||||
"to": [ 11, 9, 4 ],
|
||||
"faces": {
|
||||
"south": { "texture": "#extractor", "uv": [ 7, 1, 13, 7 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "FilterSpot",
|
||||
"from": [ 5, 10, -0.6 ],
|
||||
"to": [ 11, 12, 4 ],
|
||||
"rotation": { "origin": [ 8, 11, -1 ], "axis": "x", "angle": 22.5 },
|
||||
"faces": {
|
||||
"north": { "texture": "#extractor", "uv": [ 13, 1, 15, 7 ], "rotation": 90 },
|
||||
"east": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ], "rotation": 180 },
|
||||
"south": { "texture": "#extractor", "uv": [ 4, 1, 5, 7 ], "rotation": 270 },
|
||||
"west": { "texture": "#extractor", "uv": [ 0.1, 0, 4.7, 2 ] },
|
||||
"up": { "texture": "#extractor", "uv": [ 0, 9, 5, 15 ], "rotation": 90 }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaX",
|
||||
"from": [ 11, 7, 2 ],
|
||||
"to": [ 14, 17, 3 ],
|
||||
"faces": {
|
||||
"north": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"south": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"down": { "texture": "#redstone_antenna", "uv": [ 0, 9, 3, 10 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaZ",
|
||||
"from": [ 12, 7, 1 ],
|
||||
"to": [ 13, 17, 4 ],
|
||||
"faces": {
|
||||
"east": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] },
|
||||
"west": { "texture": "#redstone_antenna", "uv": [ 0, 0, 3, 10 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaTop",
|
||||
"from": [ 12, 15, 2 ],
|
||||
"to": [ 13, 16, 3 ],
|
||||
"faces": {
|
||||
"up": { "texture": "#redstone_antenna", "uv": [ 1, 1, 2, 2 ] }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AntennaDish",
|
||||
"from": [ 10, 13, 0 ],
|
||||
"to": [ 15, 13, 5 ],
|
||||
"faces": {
|
||||
"up": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] },
|
||||
"down": { "texture": "#redstone_antenna", "uv": [ 4, 0, 9, 5 ] }
|
||||
}
|
||||
}
|
||||
]
|
||||
"parent": "create:block/extractor_wireless"
|
||||
}
|
Loading…
Reference in a new issue