Cart Assembler and Agile Contraptions

- Started generalizing contraptions for other means of transportation
- Added mounted contraptions for minecarts
This commit is contained in:
simibubi 2019-10-27 14:15:39 +01:00
parent ee75468719
commit a391d74810
39 changed files with 1417 additions and 462 deletions

View file

@ -24,6 +24,8 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalP
import com.simibubi.create.modules.contraptions.receivers.constructs.PistonPoleBlock; import com.simibubi.create.modules.contraptions.receivers.constructs.PistonPoleBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.RotationChassisBlock; import com.simibubi.create.modules.contraptions.receivers.constructs.RotationChassisBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.TranslationChassisBlock; import com.simibubi.create.modules.contraptions.receivers.constructs.TranslationChassisBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.mounted.CartAssemblerBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.mounted.CartAssemblerBlock.MinecartAnchorBlock;
import com.simibubi.create.modules.contraptions.redstone.ContactBlock; import com.simibubi.create.modules.contraptions.redstone.ContactBlock;
import com.simibubi.create.modules.contraptions.relays.ClutchBlock; import com.simibubi.create.modules.contraptions.relays.ClutchBlock;
import com.simibubi.create.modules.contraptions.relays.CogWheelBlock; import com.simibubi.create.modules.contraptions.relays.CogWheelBlock;
@ -125,6 +127,8 @@ public enum AllBlocks {
SAW(new SawBlock()), SAW(new SawBlock()),
HARVESTER(new HarvesterBlock()), HARVESTER(new HarvesterBlock()),
HARVESTER_BLADE(new HarvesterBladeBlock()), HARVESTER_BLADE(new HarvesterBladeBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()),
__LOGISTICS__(), __LOGISTICS__(),
CONTACT(new ContactBlock()), CONTACT(new ContactBlock()),

View file

@ -2,6 +2,8 @@ package com.simibubi.create;
import java.util.function.Function; import java.util.function.Function;
import com.simibubi.create.modules.contraptions.receivers.constructs.mounted.ContraptionEntity;
import com.simibubi.create.modules.contraptions.receivers.constructs.mounted.ContraptionEntityRenderer;
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity; import com.simibubi.create.modules.logistics.transport.CardboardBoxEntity;
import com.simibubi.create.modules.logistics.transport.CardboardBoxEntityRenderer; import com.simibubi.create.modules.logistics.transport.CardboardBoxEntityRenderer;
@ -19,6 +21,7 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry;
public enum AllEntities { public enum AllEntities {
CARDBOARD_BOX(CardboardBoxEntity::new, 30, 3, CardboardBoxEntity::build), CARDBOARD_BOX(CardboardBoxEntity::new, 30, 3, CardboardBoxEntity::build),
CONTRAPTION(ContraptionEntity::new, 30, 3, ContraptionEntity::build),
; ;
@ -56,6 +59,7 @@ public enum AllEntities {
@OnlyIn(value = Dist.CLIENT) @OnlyIn(value = Dist.CLIENT)
public static void registerRenderers() { public static void registerRenderers() {
RenderingRegistry.registerEntityRenderingHandler(CardboardBoxEntity.class, CardboardBoxEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(CardboardBoxEntity.class, CardboardBoxEntityRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(ContraptionEntity.class, ContraptionEntityRenderer::new);
} }
} }

View file

@ -81,6 +81,8 @@ public enum AllItems {
PROPELLER(ingredient()), PROPELLER(ingredient()),
CRUSHED_IRON(ingredient()), CRUSHED_IRON(ingredient()),
CRUSHED_GOLD(ingredient()), CRUSHED_GOLD(ingredient()),
TIME_SCARF(ingredient()),
MOTION_SCARF(ingredient()),
__LOGISTICS__(), __LOGISTICS__(),
CARDBOARD_BOX_1616(new CardboardBoxItem(standardItemProperties())), CARDBOARD_BOX_1616(new CardboardBoxItem(standardItemProperties())),

View file

@ -5,10 +5,11 @@ import java.nio.ByteBuffer;
import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.MathHelper;
public abstract class BufferManipulator { public abstract class BufferManipulator {
protected static final int FORMAT_LENGTH = DefaultVertexFormats.BLOCK.getSize(); public static final int FORMAT_LENGTH = DefaultVertexFormats.BLOCK.getSize();
protected ByteBuffer original; protected ByteBuffer original;
protected ByteBuffer mutable; protected ByteBuffer mutable;
@ -23,66 +24,66 @@ public abstract class BufferManipulator {
mutable.rewind(); mutable.rewind();
} }
protected int vertexCount(ByteBuffer buffer) { protected static int vertexCount(ByteBuffer buffer) {
return buffer.limit() / FORMAT_LENGTH; return buffer.limit() / FORMAT_LENGTH;
} }
protected int getBufferPosition(int vertexIndex) { protected static int getBufferPosition(int vertexIndex) {
return vertexIndex * FORMAT_LENGTH; return vertexIndex * FORMAT_LENGTH;
} }
protected float getX(ByteBuffer buffer, int index) { protected static float getX(ByteBuffer buffer, int index) {
return buffer.getFloat(getBufferPosition(index)); return buffer.getFloat(getBufferPosition(index));
} }
protected float getY(ByteBuffer buffer, int index) { protected static float getY(ByteBuffer buffer, int index) {
return buffer.getFloat(getBufferPosition(index) + 4); return buffer.getFloat(getBufferPosition(index) + 4);
} }
protected float getZ(ByteBuffer buffer, int index) { protected static float getZ(ByteBuffer buffer, int index) {
return buffer.getFloat(getBufferPosition(index) + 8); return buffer.getFloat(getBufferPosition(index) + 8);
} }
protected byte getR(ByteBuffer buffer, int index) { protected static byte getR(ByteBuffer buffer, int index) {
return buffer.get(getBufferPosition(index) + 12); return buffer.get(getBufferPosition(index) + 12);
} }
protected byte getG(ByteBuffer buffer, int index) { protected static byte getG(ByteBuffer buffer, int index) {
return buffer.get(getBufferPosition(index) + 13); return buffer.get(getBufferPosition(index) + 13);
} }
protected byte getB(ByteBuffer buffer, int index) { protected static byte getB(ByteBuffer buffer, int index) {
return buffer.get(getBufferPosition(index) + 14); return buffer.get(getBufferPosition(index) + 14);
} }
protected byte getA(ByteBuffer buffer, int index) { protected static byte getA(ByteBuffer buffer, int index) {
return buffer.get(getBufferPosition(index) + 15); return buffer.get(getBufferPosition(index) + 15);
} }
protected void putPos(ByteBuffer buffer, int index, float x, float y, float z) { protected static void putPos(ByteBuffer buffer, int index, float x, float y, float z) {
int pos = getBufferPosition(index); int pos = getBufferPosition(index);
buffer.putFloat(pos, x); buffer.putFloat(pos, x);
buffer.putFloat(pos + 4, y); buffer.putFloat(pos + 4, y);
buffer.putFloat(pos + 8, z); buffer.putFloat(pos + 8, z);
} }
protected float rotateX(float x, float y, float z, float sin, float cos, Axis axis) { protected static float rotateX(float x, float y, float z, float sin, float cos, Axis axis) {
return axis == Axis.Y ? x * cos + z * sin : axis == Axis.Z ? x * cos - y * sin : x; return axis == Axis.Y ? x * cos + z * sin : axis == Axis.Z ? x * cos - y * sin : x;
} }
protected float rotateY(float x, float y, float z, float sin, float cos, Axis axis) { protected static float rotateY(float x, float y, float z, float sin, float cos, Axis axis) {
return axis == Axis.Y ? y : axis == Axis.Z ? y * cos + x * sin : y * cos - z * sin; return axis == Axis.Y ? y : axis == Axis.Z ? y * cos + x * sin : y * cos - z * sin;
} }
protected float rotateZ(float x, float y, float z, float sin, float cos, Axis axis) { protected static float rotateZ(float x, float y, float z, float sin, float cos, Axis axis) {
return axis == Axis.Y ? z * cos - x * sin : axis == Axis.Z ? z : z * cos + y * sin; return axis == Axis.Y ? z * cos - x * sin : axis == Axis.Z ? z : z * cos + y * sin;
} }
protected void putLight(ByteBuffer buffer, int index, int packedLight) { protected static void putLight(ByteBuffer buffer, int index, int packedLight) {
buffer.putInt(getBufferPosition(index) + 24, packedLight); buffer.putInt(getBufferPosition(index) + 24, packedLight);
} }
protected void putColor(ByteBuffer buffer, int index, byte r, byte g, byte b, byte a) { protected static void putColor(ByteBuffer buffer, int index, byte r, byte g, byte b, byte a) {
int bufferPosition = getBufferPosition(index); int bufferPosition = getBufferPosition(index);
buffer.put(bufferPosition + 12, r); buffer.put(bufferPosition + 12, r);
buffer.put(bufferPosition + 13, g); buffer.put(bufferPosition + 13, g);
@ -90,4 +91,35 @@ public abstract class BufferManipulator {
buffer.put(bufferPosition + 15, a); buffer.put(bufferPosition + 15, a);
} }
public static ByteBuffer remanipulateBuffer(ByteBuffer buffer, float x, float y, float z, float xOrigin,
float yOrigin, float zOrigin, float yaw, float pitch) {
buffer.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(buffer); vertex++) {
float xL = getX(buffer, vertex) - xOrigin;
float yL = getY(buffer, vertex) - yOrigin;
float zL = getZ(buffer, vertex) - zOrigin;
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 + xOrigin;
float yPos = yL + y + yOrigin;
float zPos = zL + z + zOrigin;
putPos(buffer, vertex, xPos, yPos, zPos);
}
return buffer;
}
} }

View file

@ -8,6 +8,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -30,6 +31,22 @@ public class TessellatorHelper {
GlStateManager.translated(-view.x, -view.y, -view.z); GlStateManager.translated(-view.x, -view.y, -view.z);
} }
public static void prepareFastRender() {
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();
GlStateManager.disableCull();
if (net.minecraft.client.Minecraft.isAmbientOcclusionEnabled())
GlStateManager.shadeModel(GL11.GL_SMOOTH);
else
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.color3f(1, 1, 1);
}
public static void begin() { public static void begin() {
begin(DefaultVertexFormats.POSITION_TEX); begin(DefaultVertexFormats.POSITION_TEX);
} }

View file

@ -2,6 +2,8 @@ package com.simibubi.create.foundation.utility;
import java.util.Random; import java.util.Random;
import net.minecraft.nbt.DoubleNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -36,4 +38,16 @@ public class VecHelper {
vec.z + (r.nextFloat() - .5f) * 2 * radius); vec.z + (r.nextFloat() - .5f) * 2 * radius);
} }
public static ListNBT writeNBT(Vec3d vec) {
ListNBT listnbt = new ListNBT();
listnbt.add(new DoubleNBT(vec.x));
listnbt.add(new DoubleNBT(vec.y));
listnbt.add(new DoubleNBT(vec.z));
return listnbt;
}
public static Vec3d readNBT(ListNBT list) {
return new Vec3d(list.getDouble(0), list.getDouble(1), list.getDouble(2));
}
} }

View file

@ -2,8 +2,8 @@ package com.simibubi.create.modules.contraptions;
import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer; import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; 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.receivers.constructs.MechanicalBearingTileEntityRenderer;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonTileEntityRenderer;
import net.minecraft.client.resources.ReloadListener; import net.minecraft.client.resources.ReloadListener;
import net.minecraft.profiler.IProfiler; import net.minecraft.profiler.IProfiler;
@ -19,7 +19,7 @@ public class CachedBufferReloader extends ReloadListener<String> {
@Override @Override
protected void apply(String splashList, IResourceManager resourceManagerIn, IProfiler profilerIn) { protected void apply(String splashList, IResourceManager resourceManagerIn, IProfiler profilerIn) {
KineticTileEntityRenderer.invalidateCache(); KineticTileEntityRenderer.invalidateCache();
MechanicalPistonTileEntityRenderer.invalidateCache(); ContraptionRenderer.invalidateCache();
MechanicalBearingTileEntityRenderer.invalidateCache(); MechanicalBearingTileEntityRenderer.invalidateCache();
ColoredIndicatorRenderer.invalidateCache(); ColoredIndicatorRenderer.invalidateCache();
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.receivers; package com.simibubi.create.modules.contraptions.receivers;
import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import com.simibubi.create.foundation.block.IRenderUtilityBlock; import com.simibubi.create.foundation.block.IRenderUtilityBlock;
@ -13,7 +14,6 @@ import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.DirectionalBlock; import net.minecraft.block.DirectionalBlock;
import net.minecraft.block.material.PushReaction; import net.minecraft.block.material.PushReaction;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.StateContainer.Builder;
@ -80,17 +80,17 @@ public class DrillBlock extends DirectionalKineticBlock
@Override @Override
@OnlyIn(value = Dist.CLIENT) @OnlyIn(value = Dist.CLIENT)
public void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) { public ByteBuffer renderInConstruct(MovementContext context) {
DrillTileEntityRenderer.renderInConstruct(context, x, y, z, buffer); return DrillTileEntityRenderer.renderInConstruct(context);
} }
@Override @Override
public void visitPosition(MovementContext context) { public void visitPosition(MovementContext context) {
Direction movement = context.getMovementDirection(); Direction movement = context.getMovementDirection();
BlockState block = context.state;
if (movement != block.get(FACING)) // BlockState block = context.state;
return; // if (movement == block.get(FACING).getOpposite())
// return;
World world = context.world; World world = context.world;
BlockPos pos = context.currentGridPos; BlockPos pos = context.currentGridPos;

View file

@ -2,6 +2,8 @@ package com.simibubi.create.modules.contraptions.receivers;
import static net.minecraft.state.properties.BlockStateProperties.FACING; import static net.minecraft.state.properties.BlockStateProperties.FACING;
import java.nio.ByteBuffer;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.base.IRotate; import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
@ -10,7 +12,6 @@ import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMoveme
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -27,7 +28,7 @@ public class DrillTileEntityRenderer extends KineticTileEntityRenderer {
return AllBlocks.DRILL_HEAD.get().getDefaultState().with(FACING, state.get(FACING)); return AllBlocks.DRILL_HEAD.get().getDefaultState().with(FACING, state.get(FACING));
} }
public static void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) { public static ByteBuffer renderInConstruct(MovementContext context) {
World world = context.world; World world = context.world;
BlockState state = context.state; BlockState state = context.state;
BlockPos pos = context.currentGridPos; BlockPos pos = context.currentGridPos;
@ -35,12 +36,13 @@ public class DrillTileEntityRenderer extends KineticTileEntityRenderer {
final BlockState renderedState = getRenderedBlockState(state); final BlockState renderedState = getRenderedBlockState(state);
cacheIfMissing(renderedState, world, BlockModelSpinner::new); cacheIfMissing(renderedState, world, BlockModelSpinner::new);
float speed = context.getMovementDirection() == state.get(FACING)? 100 : 0; float speed = (float) (context.getMovementDirection() == state.get(FACING) ? context.getAnimationSpeed() : 0);
Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state); Axis axis = ((IRotate) state.getBlock()).getRotationAxis(state);
float time = Animation.getWorldTime(Minecraft.getInstance().world, float time = Animation.getWorldTime(Minecraft.getInstance().world,
Minecraft.getInstance().getRenderPartialTicks()); Minecraft.getInstance().getRenderPartialTicks());
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI); float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);
renderFromCache(buffer, renderedState, world, (float) x, (float) y, (float) z, pos, axis, angle); return ((BlockModelSpinner) getBuffer(renderedState)).getTransformed(0, 0, 0, angle, axis,
world.getCombinedLight(pos, 0));
} }
} }

View file

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.receivers; package com.simibubi.create.modules.contraptions.receivers;
import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
@ -14,7 +15,6 @@ import net.minecraft.block.CropsBlock;
import net.minecraft.block.HorizontalBlock; import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.SugarCaneBlock; import net.minecraft.block.SugarCaneBlock;
import net.minecraft.block.material.PushReaction; import net.minecraft.block.material.PushReaction;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -74,8 +74,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
@Override @Override
@OnlyIn(value = Dist.CLIENT) @OnlyIn(value = Dist.CLIENT)
public void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) { public ByteBuffer renderInConstruct(MovementContext context) {
HarvesterTileEntityRenderer.renderInConstruct(context, x, y, z, buffer); return HarvesterTileEntityRenderer.renderInConstruct(context);
} }
@Override @Override

View file

@ -58,40 +58,42 @@ public class HarvesterTileEntityRenderer extends TileEntityRenderer<HarvesterTil
} }
public static void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) { public static ByteBuffer renderInConstruct(MovementContext context) {
World world = context.world; World world = context.world;
BlockState state = context.state; BlockState state = context.state;
BlockPos pos = context.currentGridPos; BlockPos pos = context.currentGridPos;
Direction facing = context.getMovementDirection(); Direction facing = context.getMovementDirection();
float speed = facing == state.get(HORIZONTAL_FACING) ? 100 * facing.getAxisDirection().getOffset() : 0; float speed = (float) (facing == state.get(HORIZONTAL_FACING)
? context.getAnimationSpeed() * facing.getAxisDirection().getOffset()
: 0);
if (facing.getAxis() == Axis.X) if (facing.getAxis() == Axis.X)
speed = -speed; speed = -speed;
float time = Animation.getWorldTime(Minecraft.getInstance().world, float time = Animation.getWorldTime(Minecraft.getInstance().world,
Minecraft.getInstance().getRenderPartialTicks()); Minecraft.getInstance().getRenderPartialTicks());
float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI); float angle = (float) (((time * speed) % 360) / 180 * (float) Math.PI);
render(world, state, pos, x, y, z, angle, buffer); return getVertexData(world, state, pos, 0, 0, 0, angle);
} }
@Override @Override
public void renderTileEntityFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks, public void renderTileEntityFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) { int destroyStage, BufferBuilder buffer) {
render(te.getWorld(), te.getBlockState(), te.getPos(), x, y, z, 0, buffer); buffer.putBulkData(getVertexData(te.getWorld(), te.getBlockState(), te.getPos(), x, y, z, 0));
} }
public static void render(World world, BlockState state, BlockPos pos, double x, double y, double z, float angle, public static ByteBuffer getVertexData(World world, BlockState state, BlockPos pos, double x, double y, double z,
BufferBuilder buffer) { float angle) {
if (!AllBlocks.HARVESTER.typeOf(state)) if (!AllBlocks.HARVESTER.typeOf(state))
return; return ByteBuffer.wrap(new byte[] {});
BlockState renderedState = AllBlocks.HARVESTER_BLADE.get().getDefaultState().with(HORIZONTAL_FACING, BlockState renderedState = AllBlocks.HARVESTER_BLADE.get().getDefaultState().with(HORIZONTAL_FACING,
state.get(HORIZONTAL_FACING)); state.get(HORIZONTAL_FACING));
KineticTileEntityRenderer.cacheIfMissing(renderedState, world, HarvesterRenderer::new); KineticTileEntityRenderer.cacheIfMissing(renderedState, world, HarvesterRenderer::new);
HarvesterRenderer renderer = (HarvesterRenderer) KineticTileEntityRenderer.getBuffer(renderedState); HarvesterRenderer renderer = (HarvesterRenderer) KineticTileEntityRenderer.getBuffer(renderedState);
buffer.putBulkData(renderer.getTransformed((float) x, (float) y, (float) z, angle, state.get(HORIZONTAL_FACING), ByteBuffer byteBuffer = renderer.getTransformed((float) x, (float) y, (float) z, angle,
state.getPackedLightmapCoords(world, pos))); state.get(HORIZONTAL_FACING), state.getPackedLightmapCoords(world, pos));
return byteBuffer;
} }
} }

View file

@ -1,8 +1,5 @@
package com.simibubi.create.modules.contraptions.receivers.constructs; package com.simibubi.create.modules.contraptions.receivers.constructs;
import static com.simibubi.create.AllBlocks.MECHANICAL_PISTON_HEAD;
import static com.simibubi.create.AllBlocks.PISTON_POLE;
import static com.simibubi.create.AllBlocks.STICKY_MECHANICAL_PISTON;
import static com.simibubi.create.CreateConfig.parameters; import static com.simibubi.create.CreateConfig.parameters;
import static net.minecraft.state.properties.BlockStateProperties.AXIS; import static net.minecraft.state.properties.BlockStateProperties.AXIS;
import static net.minecraft.state.properties.BlockStateProperties.FACING; import static net.minecraft.state.properties.BlockStateProperties.FACING;
@ -14,6 +11,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Function; import java.util.function.Function;
import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.MutablePair;
@ -22,7 +20,6 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateConfig; import com.simibubi.create.CreateConfig;
import com.simibubi.create.modules.contraptions.receivers.SawBlock; import com.simibubi.create.modules.contraptions.receivers.SawBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext; import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.PistonState;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.FallingBlock; import net.minecraft.block.FallingBlock;
@ -34,47 +31,66 @@ import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil; import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.PistonType;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class TranslationConstruct { public class Contraption {
protected Map<BlockPos, BlockInfo> blocks; protected Map<BlockPos, BlockInfo> blocks;
protected List<MutablePair<BlockInfo, MovementContext>> actors; protected List<MutablePair<BlockInfo, MovementContext>> actors;
protected AxisAlignedBB constructCollisionBox; protected AxisAlignedBB constructCollisionBox;
protected AxisAlignedBB pistonCollisionBox;
protected Set<BlockPos> cachedColliders; protected Set<BlockPos> cachedColliders;
protected Direction cachedColliderDirection; protected Direction cachedColliderDirection;
protected BlockPos anchor;
protected int extensionLength; public Contraption() {
protected int initialExtensionProgress;
protected Direction orientation;
public TranslationConstruct() {
blocks = new HashMap<>(); blocks = new HashMap<>();
actors = new ArrayList<>(); actors = new ArrayList<>();
} }
public static TranslationConstruct movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) { private static List<BlockInfo> getChassisClusterAt(World world, BlockPos pos) {
if (isFrozen()) List<BlockPos> search = new LinkedList<>();
Set<BlockPos> visited = new HashSet<>();
List<BlockInfo> chassis = new LinkedList<>();
BlockState anchorChassis = world.getBlockState(pos);
Axis axis = anchorChassis.get(AXIS);
search.add(pos);
while (!search.isEmpty()) {
if (chassis.size() > parameters.maxChassisForTranslation.get())
return null; return null;
TranslationConstruct construct = new TranslationConstruct();
construct.orientation = direction; BlockPos current = search.remove(0);
if (!construct.collectExtensions(world, pos, direction)) if (visited.contains(current))
continue;
if (!world.isAreaLoaded(current, 1))
return null; return null;
if (!construct.searchMovedStructure(world, pos.offset(direction, construct.initialExtensionProgress + 1),
retract ? direction.getOpposite() : direction)) BlockState state = world.getBlockState(current);
return null; if (!isChassis(state))
return construct; continue;
if (!TranslationChassisBlock.sameKind(anchorChassis, state))
continue;
if (state.get(AXIS) != axis)
continue;
visited.add(current);
chassis.add(new BlockInfo(current, world.getBlockState(current), getTileEntityNBT(world, current)));
for (Direction offset : Direction.values()) {
if (offset.getAxis() == axis)
continue;
search.add(current.offset(offset));
}
}
return chassis;
} }
public Set<BlockPos> getColliders(World world, Direction movementDirection) { public Set<BlockPos> getColliders(World world, Direction movementDirection) {
@ -101,86 +117,17 @@ public class TranslationConstruct {
return cachedColliders; return cachedColliders;
} }
private boolean collectExtensions(World world, BlockPos pos, Direction direction) { protected boolean searchMovedStructure(World world, BlockPos pos, Direction direction) {
List<BlockInfo> poles = new ArrayList<>();
BlockPos actualStart = pos;
BlockState nextBlock = world.getBlockState(actualStart.offset(direction));
int extensionsInFront = 0;
boolean sticky = STICKY_MECHANICAL_PISTON.typeOf(world.getBlockState(pos));
if (world.getBlockState(pos).get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) {
while (PISTON_POLE.typeOf(nextBlock) && nextBlock.get(FACING).getAxis() == direction.getAxis()
|| MECHANICAL_PISTON_HEAD.typeOf(nextBlock) && nextBlock.get(FACING) == direction) {
actualStart = actualStart.offset(direction);
poles.add(new BlockInfo(actualStart, nextBlock.with(FACING, direction), null));
extensionsInFront++;
nextBlock = world.getBlockState(actualStart.offset(direction));
if (extensionsInFront > parameters.maxPistonPoles.get())
return false;
}
}
if (extensionsInFront == 0)
poles.add(
new BlockInfo(pos,
MECHANICAL_PISTON_HEAD.get().getDefaultState().with(FACING, direction).with(
BlockStateProperties.PISTON_TYPE, sticky ? PistonType.STICKY : PistonType.DEFAULT),
null));
else
poles.add(new BlockInfo(pos, PISTON_POLE.get().getDefaultState().with(FACING, direction), null));
BlockPos end = pos;
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
int extensionsInBack = 0;
while (PISTON_POLE.typeOf(nextBlock)) {
end = end.offset(direction.getOpposite());
poles.add(new BlockInfo(end, nextBlock.with(FACING, direction), null));
extensionsInBack++;
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
if (extensionsInFront + extensionsInBack > parameters.maxPistonPoles.get())
return false;
}
extensionLength = extensionsInBack + extensionsInFront;
initialExtensionProgress = extensionsInFront;
pistonCollisionBox = new AxisAlignedBB(end.offset(direction, -extensionsInFront));
for (BlockInfo pole : poles) {
BlockPos polePos = pole.pos.offset(direction, -extensionsInFront);
blocks.put(polePos, new BlockInfo(polePos, pole.state, null));
pistonCollisionBox = pistonCollisionBox.union(new AxisAlignedBB(polePos));
}
return true;
}
private boolean searchMovedStructure(World world, BlockPos pos, Direction direction) {
List<BlockPos> frontier = new ArrayList<>(); List<BlockPos> frontier = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>(); Set<BlockPos> visited = new HashSet<>();
constructCollisionBox = new AxisAlignedBB(pos.offset(direction, initialExtensionProgress)); anchor = pos;
frontier.add(pos);
for (int offset = 1; offset <= parameters.maxChassisRange.get(); offset++) { if (constructCollisionBox == null)
BlockPos currentPos = pos.offset(direction, offset); constructCollisionBox = new AxisAlignedBB(pos);
if (!world.isAreaLoaded(currentPos, 1))
frontier.add(pos);
if (!addToInitialFrontier(world, pos, direction, frontier))
return false; return false;
if (!world.isBlockPresent(currentPos))
break;
BlockState state = world.getBlockState(currentPos);
if (state.getMaterial().isReplaceable())
break;
if (state.getCollisionShape(world, currentPos).isEmpty())
break;
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state) && state.get(FACING) == direction.getOpposite())
break;
if (!canPush(world, currentPos, direction))
return false;
frontier.add(currentPos);
}
for (int limit = 1000; limit > 0; limit--) { for (int limit = 1000; limit > 0; limit--) {
if (frontier.isEmpty()) if (frontier.isEmpty())
@ -192,6 +139,10 @@ public class TranslationConstruct {
return false; return false;
} }
protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
return true;
}
private boolean moveBlock(World world, BlockPos pos, Direction direction, List<BlockPos> frontier, private boolean moveBlock(World world, BlockPos pos, Direction direction, List<BlockPos> frontier,
Set<BlockPos> visited) { Set<BlockPos> visited) {
visited.add(pos); visited.add(pos);
@ -349,42 +300,8 @@ public class TranslationConstruct {
return true; return true;
} }
private static List<BlockInfo> getChassisClusterAt(World world, BlockPos pos) { private static boolean isChassis(BlockState state) {
List<BlockPos> search = new LinkedList<>(); return TranslationChassisBlock.isChassis(state);
Set<BlockPos> visited = new HashSet<>();
List<BlockInfo> chassis = new LinkedList<>();
BlockState anchorChassis = world.getBlockState(pos);
Axis axis = anchorChassis.get(AXIS);
search.add(pos);
while (!search.isEmpty()) {
if (chassis.size() > parameters.maxChassisForTranslation.get())
return null;
BlockPos current = search.remove(0);
if (visited.contains(current))
continue;
if (!world.isAreaLoaded(current, 1))
return null;
BlockState state = world.getBlockState(current);
if (!isChassis(state))
continue;
if (!TranslationChassisBlock.sameKind(anchorChassis, state))
continue;
if (state.get(AXIS) != axis)
continue;
visited.add(current);
chassis.add(capture(world, current));
for (Direction offset : Direction.values()) {
if (offset.getAxis() == axis)
continue;
search.add(current.offset(offset));
}
}
return chassis;
} }
private boolean notSupportive(World world, BlockPos pos, Direction facing) { private boolean notSupportive(World world, BlockPos pos, Direction facing) {
@ -396,11 +313,7 @@ public class TranslationConstruct {
return false; return false;
} }
private static boolean isChassis(BlockState state) { protected static boolean canPush(World world, BlockPos pos, Direction direction) {
return TranslationChassisBlock.isChassis(state);
}
private static boolean canPush(World world, BlockPos pos, Direction direction) {
BlockState blockState = world.getBlockState(pos); BlockState blockState = world.getBlockState(pos);
if (isChassis(blockState)) if (isChassis(blockState))
return true; return true;
@ -409,19 +322,15 @@ public class TranslationConstruct {
return PistonBlock.canPush(blockState, world, pos, direction, true, direction); return PistonBlock.canPush(blockState, world, pos, direction, true, direction);
} }
private void add(BlockPos pos, BlockInfo block) { protected BlockInfo capture(World world, BlockPos pos) {
BlockPos localPos = pos.offset(orientation, -initialExtensionProgress);
BlockInfo blockInfo = new BlockInfo(localPos, block.state, block.nbt);
blocks.put(localPos, blockInfo);
if (block.state.getBlock() instanceof IHaveMovementBehavior)
actors.add(MutablePair.of(blockInfo, null));
constructCollisionBox = constructCollisionBox.union(new AxisAlignedBB(localPos));
}
private static BlockInfo capture(World world, BlockPos pos) {
BlockState blockstate = world.getBlockState(pos); BlockState blockstate = world.getBlockState(pos);
if (AllBlocks.SAW.typeOf(blockstate)) if (AllBlocks.SAW.typeOf(blockstate))
blockstate = blockstate.with(SawBlock.RUNNING, true); blockstate = blockstate.with(SawBlock.RUNNING, true);
CompoundNBT compoundnbt = getTileEntityNBT(world, pos);
return new BlockInfo(pos, blockstate, compoundnbt);
}
public static CompoundNBT getTileEntityNBT(World world, BlockPos pos) {
TileEntity tileentity = world.getTileEntity(pos); TileEntity tileentity = world.getTileEntity(pos);
CompoundNBT compoundnbt = null; CompoundNBT compoundnbt = null;
if (tileentity != null) { if (tileentity != null) {
@ -430,17 +339,43 @@ public class TranslationConstruct {
compoundnbt.remove("y"); compoundnbt.remove("y");
compoundnbt.remove("z"); compoundnbt.remove("z");
} }
return new BlockInfo(pos, blockstate, compoundnbt); return compoundnbt;
}
protected void add(BlockPos pos, BlockInfo block) {
BlockInfo blockInfo = new BlockInfo(pos, block.state, block.nbt);
blocks.put(pos, blockInfo);
if (block.state.getBlock() instanceof IHaveMovementBehavior)
getActors().add(MutablePair.of(blockInfo, null));
constructCollisionBox = constructCollisionBox.union(new AxisAlignedBB(pos));
}
public void readNBT(CompoundNBT nbt) {
nbt.getList("Blocks", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
NBTUtil.readBlockState(comp.getCompound("Block")),
comp.contains("Data") ? comp.getCompound("Data") : null);
blocks.put(info.pos, info);
});
nbt.getList("Actors", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos")));
MovementContext context = MovementContext.readNBT(comp);
getActors().add(MutablePair.of(info, context));
});
if (nbt.contains("BoundsFront"))
constructCollisionBox = readAABB(nbt.getList("BoundsFront", 5));
anchor = NBTUtil.readBlockPos(nbt.getCompound("Anchor"));
} }
public AxisAlignedBB getCollisionBoxFront() { public AxisAlignedBB getCollisionBoxFront() {
return constructCollisionBox; return constructCollisionBox;
} }
public AxisAlignedBB getCollisionBoxBack() {
return pistonCollisionBox;
}
public CompoundNBT writeNBT() { public CompoundNBT writeNBT() {
CompoundNBT nbt = new CompoundNBT(); CompoundNBT nbt = new CompoundNBT();
ListNBT blocks = new ListNBT(); ListNBT blocks = new ListNBT();
@ -453,18 +388,21 @@ public class TranslationConstruct {
blocks.add(c); blocks.add(c);
} }
ListNBT actorsNBT = new ListNBT();
for (MutablePair<BlockInfo, MovementContext> actor : getActors()) {
CompoundNBT compound = new CompoundNBT();
compound.put("Pos", NBTUtil.writeBlockPos(actor.left.pos));
actor.right.writeToNBT(compound);
actorsNBT.add(compound);
}
nbt.put("Actors", actorsNBT);
if (constructCollisionBox != null) { if (constructCollisionBox != null) {
ListNBT bb = writeAABB(constructCollisionBox); ListNBT bb = writeAABB(constructCollisionBox);
nbt.put("BoundsFront", bb); nbt.put("BoundsFront", bb);
} }
if (pistonCollisionBox != null) {
ListNBT bb = writeAABB(pistonCollisionBox);
nbt.put("BoundsBack", bb);
}
nbt.put("Blocks", blocks); nbt.put("Blocks", blocks);
nbt.putInt("ExtensionLength", extensionLength); nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
return nbt; return nbt;
} }
@ -487,32 +425,38 @@ public class TranslationConstruct {
} }
public static TranslationConstruct fromNBT(CompoundNBT nbt) {
TranslationConstruct construct = new TranslationConstruct();
nbt.getList("Blocks", 10).forEach(c -> {
CompoundNBT comp = (CompoundNBT) c;
BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")),
NBTUtil.readBlockState(comp.getCompound("Block")),
comp.contains("Data") ? comp.getCompound("Data") : null);
construct.blocks.put(info.pos, info);
});
construct.extensionLength = nbt.getInt("ExtensionLength");
if (nbt.contains("BoundsFront"))
construct.constructCollisionBox = construct.readAABB(nbt.getList("BoundsFront", 5));
if (nbt.contains("BoundsBack"))
construct.pistonCollisionBox = construct.readAABB(nbt.getList("BoundsBack", 5));
// Find blocks with special movement behaviour
construct.blocks.values().forEach(block -> {
if (block.state.getBlock() instanceof IHaveMovementBehavior)
construct.actors.add(MutablePair.of(block, null));
});
return construct;
}
public static boolean isFrozen() { public static boolean isFrozen() {
return CreateConfig.parameters.freezePistonConstructs.get(); return CreateConfig.parameters.freezePistonConstructs.get();
} }
public void disassemble(IWorld world, BlockPos offset, BiPredicate<BlockPos, BlockState> customPlacement) {
for (BlockInfo block : blocks.values()) {
BlockPos targetPos = block.pos.add(offset);
BlockState state = block.state;
if (customPlacement.test(targetPos, state))
continue;
for (Direction face : Direction.values())
state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, targetPos,
targetPos.offset(face));
if (AllBlocks.SAW.typeOf(state))
state = state.with(SawBlock.RUNNING, false);
world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty());
world.setBlockState(targetPos, state, 3);
TileEntity tileEntity = world.getTileEntity(targetPos);
if (tileEntity != null && block.nbt != null) {
block.nbt.putInt("x", targetPos.getX());
block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt);
}
}
}
public List<MutablePair<BlockInfo, MovementContext>> getActors() {
return actors;
}
} }

View file

@ -0,0 +1,102 @@
package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.tuple.Pair;
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 com.simibubi.create.foundation.utility.PlacementSimulationWorld;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.client.model.data.EmptyModelData;
public class ContraptionRenderer {
protected static Cache<Contraption, ContraptionVertexBuffer> cachedConstructs;
protected static PlacementSimulationWorld renderWorld;
public static <T extends BufferManipulator> void cacheContraptionIfMissing(Contraption c) {
if (cachedConstructs == null)
cachedConstructs = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS).build();
if (cachedConstructs.getIfPresent(c) != null)
return;
if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world)
renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world);
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer();
Random random = new Random();
BufferBuilder builder = new BufferBuilder(0);
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
builder.setTranslation(0, 0, 0);
for (BlockInfo info : c.blocks.values()) {
renderWorld.setBlockState(info.pos, info.state);
}
for (BlockInfo info : c.blocks.values()) {
IBakedModel originalModel = dispatcher.getModelForState(info.state);
blockRenderer.renderModel(renderWorld, originalModel, info.state, info.pos, builder, true, random, 42,
EmptyModelData.INSTANCE);
}
builder.finishDrawing();
renderWorld.clear();
cachedConstructs.put(c, new ContraptionVertexBuffer(builder.getByteBuffer()));
}
public static ContraptionVertexBuffer get(Contraption c) {
return cachedConstructs.getIfPresent(c);
}
public static void renderActors(World world, Contraption c, float xIn, float yIn, float zIn, float yaw, float pitch,
BufferBuilder buffer) {
for (Pair<BlockInfo, MovementContext> actor : c.getActors()) {
MovementContext context = actor.getRight();
if (context == null)
continue;
if (context.world == null)
context.world = world;
BlockInfo blockInfo = actor.getLeft();
IHaveMovementBehavior block = (IHaveMovementBehavior) blockInfo.state.getBlock();
ByteBuffer renderInConstruct = block.renderInConstruct(context);
if (renderInConstruct == null)
continue;
int posX = blockInfo.pos.getX();
int posY = blockInfo.pos.getY();
int posZ = blockInfo.pos.getZ();
float x = xIn + posX;
float y = yIn + posY;
float z = zIn + posZ;
float xOrigin = -posX + c.anchor.getX() + .5f;
float yOrigin = -posY + c.anchor.getY() + .5f;
float zOrigin = -posZ + c.anchor.getZ() + .5f;
buffer.putBulkData(BufferManipulator.remanipulateBuffer(renderInConstruct, x, y, z, xOrigin, yOrigin,
zOrigin, yaw, pitch));
}
}
public static void invalidateCache() {
if (cachedConstructs != null)
cachedConstructs.invalidateAll();
}
}

View file

@ -0,0 +1,70 @@
package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.nio.ByteBuffer;
import com.simibubi.create.foundation.utility.BufferManipulator;
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.world.World;
public class ContraptionVertexBuffer extends BufferManipulator {
public ContraptionVertexBuffer(ByteBuffer original) {
super(original);
}
public ByteBuffer getTranslated(World world, float x, float y, float z, Vec3d offset) {
original.rewind();
mutable.rewind();
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
float xL = getX(original, vertex);
float yL = getY(original, vertex);
float zL = getZ(original, vertex);
putPos(mutable, vertex, xL + x + (float) offset.x, yL + y + (float) offset.y, zL + z + (float) offset.z);
BlockPos pos = new BlockPos(offset.x + xL, offset.y + yL, offset.z + zL);
putLight(mutable, vertex, world.getCombinedLight(pos, 0));
}
return mutable;
}
public ByteBuffer getTranslatedAndRotated(World world, float x, float y, float z, float yaw, float pitch,
Vec3d offset, Vec3d rotationOffset) {
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(xL + rotationOffset.x - .5f, yL + rotationOffset.y - .5f,
zL + rotationOffset.z - .5f);
putLight(mutable, vertex, world.getCombinedLight(pos, 15));
}
return mutable;
}
}

View file

@ -1,13 +1,19 @@
package com.simibubi.create.modules.contraptions.receivers.constructs; package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.nio.ByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
public interface IHaveMovementBehavior { public interface IHaveMovementBehavior {
@ -28,29 +34,50 @@ public interface IHaveMovementBehavior {
public class MovementContext { public class MovementContext {
public BlockPos currentGridPos; public BlockPos currentGridPos;
public Vec3d movementVec; public Vec3d motion;
public float movementSpeedModifier = 1; public float movementSpeedModifier = 1;
public MoverType moverType; public MoverType moverType;
public Object mover;
public World world; public World world;
public BlockState state; public BlockState state;
public MovementContext(World world, BlockState state, MoverType moverType, Object mover) { public MovementContext(BlockState state, MoverType moverType) {
this.world = world;
this.state = state; this.state = state;
this.moverType = moverType; this.moverType = moverType;
this.mover = mover;
} }
public Direction getMovementDirection() { public Direction getMovementDirection() {
return Direction.getFacingFromVector(movementVec.x, movementVec.y, movementVec.z); return Direction.getFacingFromVector(motion.x, motion.y, motion.z);
}
public float getAnimationSpeed() {
int modifier = moverType == MoverType.MINECART ? 1000 : 200;
return ((int) (motion.length() * modifier)) / 100 * 100;
}
public static MovementContext readNBT(CompoundNBT nbt) {
MovementContext context = new MovementContext(NBTUtil.readBlockState(nbt.getCompound("State")),
MoverType.valueOf(nbt.getString("MoverType")));
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
context.movementSpeedModifier = nbt.getFloat("SpeedModifier");
context.currentGridPos = NBTUtil.readBlockPos(nbt.getCompound("GridPos"));
return context;
}
public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("State", NBTUtil.writeBlockState(state));
nbt.putString("MoverType", moverType.name());
nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.putFloat("SpeedModifier", movementSpeedModifier);
nbt.put("GridPos", NBTUtil.writeBlockPos(currentGridPos));
return nbt;
} }
} }
@OnlyIn(value = Dist.CLIENT) @OnlyIn(value = Dist.CLIENT)
default void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) { default ByteBuffer renderInConstruct(MovementContext context) {
return null;
} }
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.modules.contraptions.receivers.constructs; package com.simibubi.create.modules.contraptions.receivers.constructs;
import static com.simibubi.create.CreateConfig.parameters; import static com.simibubi.create.CreateConfig.parameters;
import static com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.STATE;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
@ -11,17 +12,14 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.receivers.SawBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext; import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MoverType; import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MoverType;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.PistonState; import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.PistonState;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
@ -34,7 +32,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
public class MechanicalPistonTileEntity extends KineticTileEntity implements ITickableTileEntity { public class MechanicalPistonTileEntity extends KineticTileEntity implements ITickableTileEntity {
protected TranslationConstruct movingConstruct; protected PistonContraption movedContraption;
protected float offset; protected float offset;
protected boolean running; protected boolean running;
protected boolean assembleNextTick; protected boolean assembleNextTick;
@ -73,8 +71,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public CompoundNBT write(CompoundNBT tag) { public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running); tag.putBoolean("Running", running);
tag.putFloat("Offset", offset); tag.putFloat("Offset", offset);
if (running && !TranslationConstruct.isFrozen()) if (running && !PistonContraption.isFrozen())
tag.put("Construct", movingConstruct.writeNBT()); tag.put("Construct", movedContraption.writeNBT());
return super.write(tag); return super.write(tag);
} }
@ -83,12 +81,14 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public void read(CompoundNBT tag) { public void read(CompoundNBT tag) {
running = tag.getBoolean("Running"); running = tag.getBoolean("Running");
offset = tag.getFloat("Offset"); offset = tag.getFloat("Offset");
if (running && !TranslationConstruct.isFrozen()) { if (running && !PistonContraption.isFrozen()) {
movingConstruct = TranslationConstruct.fromNBT(tag.getCompound("Construct")); movedContraption = new PistonContraption();
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) { movedContraption.readNBT(tag.getCompound("Construct"));
MovementContext context = new MovementContext(world, pair.left.state, MoverType.PISTON, this); for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors()) {
MovementContext context = new MovementContext(pair.left.state, MoverType.PISTON);
context.world = world;
Direction direction = getBlockState().get(BlockStateProperties.FACING); Direction direction = getBlockState().get(BlockStateProperties.FACING);
context.movementVec = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize(); context.motion = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize();
context.currentGridPos = pair.left.pos.offset(direction, getModulatedOffset(offset)); context.currentGridPos = pair.left.pos.offset(direction, getModulatedOffset(offset));
pair.setRight(context); pair.setRight(context);
} }
@ -98,12 +98,12 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
} }
protected void onBlockVisited(float newOffset) { protected void onBlockVisited(float newOffset) {
if (TranslationConstruct.isFrozen()) if (PistonContraption.isFrozen())
return; return;
Direction direction = getBlockState().get(BlockStateProperties.FACING); Direction direction = getBlockState().get(BlockStateProperties.FACING);
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) { for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors()) {
BlockInfo block = pair.left; BlockInfo block = pair.left;
MovementContext context = pair.right; MovementContext context = pair.right;
@ -120,39 +120,40 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
Direction direction = getBlockState().get(BlockStateProperties.FACING); Direction direction = getBlockState().get(BlockStateProperties.FACING);
// Collect Construct // Collect Construct
movingConstruct = TranslationConstruct.movePistonAt(world, pos, direction, getMovementSpeed() < 0); movedContraption = PistonContraption.movePistonAt(world, pos, direction, getMovementSpeed() < 0);
if (movingConstruct == null) if (movedContraption == null)
return; return;
// Check if not at limit already // Check if not at limit already
float resultingOffset = movingConstruct.initialExtensionProgress + getMovementSpeed(); float resultingOffset = movedContraption.initialExtensionProgress + getMovementSpeed();
if (resultingOffset <= 0 || resultingOffset >= movingConstruct.extensionLength) { if (resultingOffset <= 0 || resultingOffset >= movedContraption.extensionLength) {
movingConstruct = null; movedContraption = null;
return; return;
} }
if (hasBlockCollisions(resultingOffset + .5f)) { if (hasBlockCollisions(resultingOffset + .5f)) {
movingConstruct = null; movedContraption = null;
return; return;
} }
// Run // Run
running = true; running = true;
offset = movingConstruct.initialExtensionProgress; offset = movedContraption.initialExtensionProgress;
if (!world.isRemote) if (!world.isRemote)
Create.constructHandler.add(this); Create.constructHandler.add(this);
sendData(); sendData();
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66); getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66);
for (BlockInfo block : movingConstruct.blocks.values()) { for (BlockInfo block : movedContraption.blocks.values()) {
BlockPos startPos = block.pos.offset(direction, movingConstruct.initialExtensionProgress); BlockPos startPos = block.pos.offset(direction, movedContraption.initialExtensionProgress);
if (startPos.equals(pos)) if (startPos.equals(pos))
continue; continue;
getWorld().setBlockState(startPos, Blocks.AIR.getDefaultState(), 67); getWorld().setBlockState(startPos, Blocks.AIR.getDefaultState(), 67);
} }
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) { for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors()) {
MovementContext context = new MovementContext(world, pair.left.state, MoverType.PISTON, this); MovementContext context = new MovementContext(pair.left.state, MoverType.PISTON);
context.movementVec = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize(); context.world = world;
context.motion = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize();
context.currentGridPos = pair.left.pos.offset(direction, getModulatedOffset(offset)); context.currentGridPos = pair.left.pos.offset(direction, getModulatedOffset(offset));
pair.setRight(context); pair.setRight(context);
} }
@ -167,38 +168,19 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
Direction direction = getBlockState().get(BlockStateProperties.FACING); Direction direction = getBlockState().get(BlockStateProperties.FACING);
if (!removed) if (!removed)
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3); getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3);
movedContraption.disassemble(world, BlockPos.ZERO.offset(direction, getModulatedOffset(offset)),
for (BlockInfo block : movingConstruct.blocks.values()) { (targetPos, state) -> {
BlockPos targetPos = block.pos.offset(direction, getModulatedOffset(offset));
BlockState state = block.state;
if (targetPos.equals(pos)) { if (targetPos.equals(pos)) {
if (!AllBlocks.PISTON_POLE.typeOf(state) && !removed) if (!AllBlocks.PISTON_POLE.typeOf(state) && !removed)
getWorld().setBlockState(pos, world.setBlockState(pos, getBlockState().with(STATE, PistonState.RETRACTED), 3);
getBlockState().with(MechanicalPistonBlock.STATE, PistonState.RETRACTED), 3); return true;
continue;
} }
for (Direction face : Direction.values()) return false;
state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, targetPos, });
targetPos.offset(face));
if (AllBlocks.SAW.typeOf(state))
state = state.with(SawBlock.RUNNING, false);
world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty());
getWorld().setBlockState(targetPos, state, 3);
TileEntity tileEntity = world.getTileEntity(targetPos);
if (tileEntity != null && block.nbt != null) {
block.nbt.putInt("x", targetPos.getX());
block.nbt.putInt("y", targetPos.getY());
block.nbt.putInt("z", targetPos.getZ());
tileEntity.read(block.nbt);
}
}
running = false; running = false;
if (!world.isRemote) if (!world.isRemote)
Create.constructHandler.remove(this); Create.constructHandler.remove(this);
movingConstruct = null; movedContraption = null;
sendData(); sendData();
if (removed) if (removed)
@ -213,10 +195,10 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (speed == 0) if (speed == 0)
disassembleConstruct(); disassembleConstruct();
else { else {
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors())
pair.right.movementVec = new Vec3d( pair.right.motion = new Vec3d(
getBlockState().get(BlockStateProperties.FACING).getDirectionVec()) getBlockState().get(BlockStateProperties.FACING).getDirectionVec())
.scale(getMovementSpeed()).normalize(); .scale(getMovementSpeed());
sendData(); sendData();
} }
return; return;
@ -257,14 +239,14 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
offset = newOffset; offset = newOffset;
if (offset <= 0 || offset >= movingConstruct.extensionLength) { if (offset <= 0 || offset >= movedContraption.extensionLength) {
disassembleConstruct(); disassembleConstruct();
return; return;
} }
} }
private boolean hasBlockCollisions(float newOffset) { private boolean hasBlockCollisions(float newOffset) {
if (TranslationConstruct.isFrozen()) if (PistonContraption.isFrozen())
return true; return true;
Direction movementDirection = getBlockState().get(BlockStateProperties.FACING); Direction movementDirection = getBlockState().get(BlockStateProperties.FACING);
@ -280,7 +262,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (otherPiston == this) if (otherPiston == this)
continue; continue;
if (!otherPiston.running || otherPiston.movingConstruct == null) { if (!otherPiston.running || otherPiston.movedContraption == null) {
iterator.remove(); iterator.remove();
continue; continue;
} }
@ -291,10 +273,10 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
BlockPos otherRelativePos = BlockPos.ZERO.offset(otherMovementDirection, BlockPos otherRelativePos = BlockPos.ZERO.offset(otherMovementDirection,
getModulatedOffset(otherPiston.offset)); getModulatedOffset(otherPiston.offset));
for (AxisAlignedBB tBB : Arrays.asList(movingConstruct.constructCollisionBox, for (AxisAlignedBB tBB : Arrays.asList(movedContraption.constructCollisionBox,
movingConstruct.pistonCollisionBox)) { movedContraption.pistonCollisionBox)) {
for (AxisAlignedBB oBB : Arrays.asList(otherPiston.movingConstruct.constructCollisionBox, for (AxisAlignedBB oBB : Arrays.asList(otherPiston.movedContraption.constructCollisionBox,
otherPiston.movingConstruct.pistonCollisionBox)) { otherPiston.movedContraption.pistonCollisionBox)) {
if (tBB == null || oBB == null) if (tBB == null || oBB == null)
continue; continue;
@ -306,9 +288,9 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (thisBB.intersects(otherBB)) { if (thisBB.intersects(otherBB)) {
boolean actuallyColliding = false; boolean actuallyColliding = false;
for (BlockPos colliderPos : movingConstruct.getColliders(world, movementDirection)) { for (BlockPos colliderPos : movedContraption.getColliders(world, movementDirection)) {
colliderPos = colliderPos.add(thisColliderOffset).subtract(otherRelativePos); colliderPos = colliderPos.add(thisColliderOffset).subtract(otherRelativePos);
if (!otherPiston.movingConstruct.blocks.containsKey(colliderPos)) if (!otherPiston.movedContraption.blocks.containsKey(colliderPos))
continue; continue;
actuallyColliding = true; actuallyColliding = true;
} }
@ -327,7 +309,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
return false; return false;
// Other Blocks in world // Other Blocks in world
for (BlockPos pos : movingConstruct.getColliders(world, for (BlockPos pos : movedContraption.getColliders(world,
getMovementSpeed() > 0 ? movementDirection : movementDirection.getOpposite())) { getMovementSpeed() > 0 ? movementDirection : movementDirection.getOpposite())) {
BlockPos colliderPos = pos.add(relativePos); BlockPos colliderPos = pos.add(relativePos);
@ -342,7 +324,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
} }
private int getModulatedOffset(float offset) { private int getModulatedOffset(float offset) {
return MathHelper.clamp((int) (offset + .5f), 0, movingConstruct.extensionLength); return MathHelper.clamp((int) (offset + .5f), 0, movedContraption.extensionLength);
} }
public float getMovementSpeed() { public float getMovementSpeed() {
@ -354,7 +336,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public Vec3d getConstructOffset(float partialTicks) { public Vec3d getConstructOffset(float partialTicks) {
float interpolatedOffset = MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0, float interpolatedOffset = MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0,
movingConstruct.extensionLength); movedContraption.extensionLength);
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset); return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset);
} }

View file

@ -1,38 +1,17 @@
package com.simibubi.create.modules.contraptions.receivers.constructs; package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.PlacementSimulationWorld;
import com.simibubi.create.modules.contraptions.base.IRotate; import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.client.model.data.EmptyModelData;
public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRenderer { public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRenderer {
protected static Cache<TranslationConstruct, TranslationConstructVertexBuffer> cachedConstructs;
protected static PlacementSimulationWorld renderWorld;
@Override @Override
public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks, public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) { int destroyStage, BufferBuilder buffer) {
@ -44,58 +23,21 @@ public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRendere
if (!pistonTe.running) if (!pistonTe.running)
return; return;
cacheConstructIfMissing(pistonTe.movingConstruct); ContraptionRenderer.cacheContraptionIfMissing(pistonTe.movedContraption);
renderConstructFromCache(pistonTe.movingConstruct, pistonTe, x, y, z, partialTicks, buffer); renderConstructFromCache(pistonTe.movedContraption, pistonTe, x, y, z, partialTicks, buffer);
for (Pair<BlockInfo, MovementContext> actor : pistonTe.movingConstruct.actors) {
MovementContext context = actor.getRight(); Vec3d offset = pistonTe.getConstructOffset(partialTicks).subtract(new Vec3d(pistonTe.getPos()));
if (context == null) ContraptionRenderer.renderActors(pistonTe.getWorld(), pistonTe.movedContraption, (float) (x + offset.x),
continue; (float) (y + offset.y), (float) (z + offset.z), 0, 0, buffer);
final Vec3d offset = pistonTe.getConstructOffset(partialTicks);
BlockInfo blockInfo = actor.getLeft();
IHaveMovementBehavior block = (IHaveMovementBehavior) blockInfo.state.getBlock();
BlockPos pos = blockInfo.pos.subtract(te.getPos());
block.renderInConstruct(context, x + offset.x + pos.getX(),
y + offset.y + pos.getY(), z + offset.z + pos.getZ(), buffer);
} }
} protected void renderConstructFromCache(Contraption c, MechanicalPistonTileEntity te, double x, double y, double z,
float partialTicks, BufferBuilder buffer) {
protected void cacheConstructIfMissing(TranslationConstruct c) {
if (cachedConstructs == null)
cachedConstructs = CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.SECONDS).build();
if (cachedConstructs.getIfPresent(c) != null)
return;
if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world)
renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world);
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
BlockModelRenderer blockRenderer = dispatcher.getBlockModelRenderer();
Random random = new Random();
BufferBuilder builder = new BufferBuilder(0);
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
builder.setTranslation(0, 0, 0);
for (BlockInfo info : c.blocks.values()) {
renderWorld.setBlockState(info.pos, info.state);
}
for (BlockInfo info : c.blocks.values()) {
IBakedModel originalModel = dispatcher.getModelForState(info.state);
blockRenderer.renderModel(renderWorld, originalModel, info.state, info.pos, builder, true, random, 42,
EmptyModelData.INSTANCE);
}
builder.finishDrawing();
renderWorld.clear();
cachedConstructs.put(c, new TranslationConstructVertexBuffer(builder.getByteBuffer()));
}
protected void renderConstructFromCache(TranslationConstruct c, MechanicalPistonTileEntity te, double x, double y,
double z, float partialTicks, BufferBuilder buffer) {
final Vec3d offset = te.getConstructOffset(partialTicks); final Vec3d offset = te.getConstructOffset(partialTicks);
buffer.putBulkData(cachedConstructs.getIfPresent(c).getTransformed(te, float xPos = (float) (x - te.getPos().getX());
(float) (x + offset.x - te.getPos().getX()), (float) (y + offset.y - te.getPos().getY()), float yPos = (float) (y - te.getPos().getY());
(float) (z + offset.z - te.getPos().getZ()), offset)); float zPos = (float) (z - te.getPos().getZ());
buffer.putBulkData(ContraptionRenderer.get(c).getTranslated(te.getWorld(), xPos, yPos, zPos, offset));
} }
@Override @Override
@ -104,9 +46,4 @@ public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRendere
((IRotate) te.getBlockState().getBlock()).getRotationAxis(te.getBlockState())); ((IRotate) te.getBlockState().getBlock()).getRotationAxis(te.getBlockState()));
} }
public static void invalidateCache() {
if (cachedConstructs != null)
cachedConstructs.invalidateAll();
}
} }

View file

@ -48,12 +48,12 @@ public class MovingConstructHandler {
public static void moveEntities(MechanicalPistonTileEntity te, float movementSpeed, Direction movementDirection, public static void moveEntities(MechanicalPistonTileEntity te, float movementSpeed, Direction movementDirection,
float newOffset) { float newOffset) {
if (TranslationConstruct.isFrozen()) if (PistonContraption.isFrozen())
return; return;
World world = te.getWorld(); World world = te.getWorld();
Vec3d movementVec = new Vec3d(te.getBlockState().get(BlockStateProperties.FACING).getDirectionVec()); Vec3d movementVec = new Vec3d(te.getBlockState().get(BlockStateProperties.FACING).getDirectionVec());
TranslationConstruct construct = te.movingConstruct; Contraption construct = te.movedContraption;
// if (world.isRemote) { // if (world.isRemote) {
// renderedBBs.clear(); // renderedBBs.clear();

View file

@ -0,0 +1,155 @@
package com.simibubi.create.modules.contraptions.receivers.constructs;
import static com.simibubi.create.AllBlocks.MECHANICAL_PISTON_HEAD;
import static com.simibubi.create.AllBlocks.PISTON_POLE;
import static com.simibubi.create.AllBlocks.STICKY_MECHANICAL_PISTON;
import static com.simibubi.create.CreateConfig.parameters;
import static net.minecraft.state.properties.BlockStateProperties.FACING;
import java.util.ArrayList;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.PistonState;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.PistonType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class PistonContraption extends Contraption {
protected AxisAlignedBB pistonCollisionBox;
protected int extensionLength;
protected int initialExtensionProgress;
protected Direction orientation;
public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
if (isFrozen())
return null;
PistonContraption construct = new PistonContraption();
construct.orientation = direction;
if (!construct.collectExtensions(world, pos, direction))
return null;
if (!construct.searchMovedStructure(world, pos.offset(direction, construct.initialExtensionProgress + 1),
retract ? direction.getOpposite() : direction))
return null;
return construct;
}
private boolean collectExtensions(World world, BlockPos pos, Direction direction) {
List<BlockInfo> poles = new ArrayList<>();
BlockPos actualStart = pos;
BlockState nextBlock = world.getBlockState(actualStart.offset(direction));
int extensionsInFront = 0;
boolean sticky = STICKY_MECHANICAL_PISTON.typeOf(world.getBlockState(pos));
if (world.getBlockState(pos).get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) {
while (PISTON_POLE.typeOf(nextBlock) && nextBlock.get(FACING).getAxis() == direction.getAxis()
|| MECHANICAL_PISTON_HEAD.typeOf(nextBlock) && nextBlock.get(FACING) == direction) {
actualStart = actualStart.offset(direction);
poles.add(new BlockInfo(actualStart, nextBlock.with(FACING, direction), null));
extensionsInFront++;
nextBlock = world.getBlockState(actualStart.offset(direction));
if (extensionsInFront > parameters.maxPistonPoles.get())
return false;
}
}
if (extensionsInFront == 0)
poles.add(
new BlockInfo(pos,
MECHANICAL_PISTON_HEAD.get().getDefaultState().with(FACING, direction).with(
BlockStateProperties.PISTON_TYPE, sticky ? PistonType.STICKY : PistonType.DEFAULT),
null));
else
poles.add(new BlockInfo(pos, PISTON_POLE.get().getDefaultState().with(FACING, direction), null));
BlockPos end = pos;
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
int extensionsInBack = 0;
while (PISTON_POLE.typeOf(nextBlock)) {
end = end.offset(direction.getOpposite());
poles.add(new BlockInfo(end, nextBlock.with(FACING, direction), null));
extensionsInBack++;
nextBlock = world.getBlockState(end.offset(direction.getOpposite()));
if (extensionsInFront + extensionsInBack > parameters.maxPistonPoles.get())
return false;
}
extensionLength = extensionsInBack + extensionsInFront;
initialExtensionProgress = extensionsInFront;
pistonCollisionBox = new AxisAlignedBB(end.offset(direction, -extensionsInFront));
for (BlockInfo pole : poles) {
BlockPos polePos = pole.pos.offset(direction, -extensionsInFront);
blocks.put(polePos, new BlockInfo(polePos, pole.state, null));
pistonCollisionBox = pistonCollisionBox.union(new AxisAlignedBB(polePos));
}
constructCollisionBox = new AxisAlignedBB(pos.offset(direction, initialExtensionProgress));
return true;
}
@Override
protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
for (int offset = 1; offset <= parameters.maxChassisRange.get(); offset++) {
BlockPos currentPos = pos.offset(direction, offset);
if (!world.isAreaLoaded(currentPos, 1))
return false;
if (!world.isBlockPresent(currentPos))
break;
BlockState state = world.getBlockState(currentPos);
if (state.getMaterial().isReplaceable())
break;
if (state.getCollisionShape(world, currentPos).isEmpty())
break;
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state) && state.get(FACING) == direction.getOpposite())
break;
if (!canPush(world, currentPos, direction))
return false;
frontier.add(currentPos);
}
return true;
}
protected void add(BlockPos pos, BlockInfo block) {
super.add(pos.offset(orientation, -initialExtensionProgress), block);
}
@Override
public void readNBT(CompoundNBT nbt) {
super.readNBT(nbt);
extensionLength = nbt.getInt("ExtensionLength");
if (nbt.contains("BoundsBack"))
pistonCollisionBox = readAABB(nbt.getList("BoundsBack", 5));
}
@Override
public CompoundNBT writeNBT() {
CompoundNBT nbt = super.writeNBT();
if (pistonCollisionBox != null) {
ListNBT bb = writeAABB(pistonCollisionBox);
nbt.put("BoundsBack", bb);
}
nbt.putInt("ExtensionLength", extensionLength);
return nbt;
}
public AxisAlignedBB getCollisionBoxBack() {
return pistonCollisionBox;
}
}

View file

@ -1,33 +0,0 @@
package com.simibubi.create.modules.contraptions.receivers.constructs;
import java.nio.ByteBuffer;
import com.simibubi.create.foundation.utility.BufferManipulator;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class TranslationConstructVertexBuffer extends BufferManipulator {
public TranslationConstructVertexBuffer(ByteBuffer original) {
super(original);
}
public ByteBuffer getTransformed(TileEntity te, float x, float y, float z, Vec3d offset) {
original.rewind();
mutable.rewind();
for (int vertex = 0; vertex < vertexCount(original); vertex++) {
float xL = getX(original, vertex);
float yL = getY(original, vertex);
float zL = getZ(original, vertex);
putPos(mutable, vertex, xL + x, yL + y, zL + z);
BlockPos pos = new BlockPos(offset.x + xL, offset.y + yL, offset.z + zL);
putLight(mutable, vertex, te.getWorld().getCombinedLight(pos, 0));
}
return mutable;
}
}

View file

@ -0,0 +1,152 @@
package com.simibubi.create.modules.contraptions.receivers.constructs.mounted;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.RenderUtilityBlock;
import net.minecraft.block.AbstractRailBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.material.PushReaction;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.IProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.RailShape;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class CartAssemblerBlock extends AbstractRailBlock {
public static IProperty<RailShape> RAIL_SHAPE = EnumProperty.create("shape", RailShape.class, RailShape.EAST_WEST,
RailShape.NORTH_SOUTH);
public static BooleanProperty POWERED = BlockStateProperties.POWERED;
public static VoxelShape X_SHAPE = VoxelShapes.or(VoxelShapes.fullCube(), makeCuboidShape(1, 0, -2, 15, 13, 18));
public static VoxelShape Z_SHAPE = VoxelShapes.or(VoxelShapes.fullCube(), makeCuboidShape(-2, 0, 1, 18, 13, 15));
public CartAssemblerBlock() {
super(true, Properties.from(Blocks.PISTON));
setDefaultState(getDefaultState().with(POWERED, false));
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(RAIL_SHAPE, POWERED);
super.fillStateContainer(builder);
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
boolean alongX = context.getPlacementHorizontalFacing().getAxis() == Axis.X;
boolean powered = context.getWorld().isBlockPowered(context.getPos());
return super.getStateForPlacement(context).with(POWERED, Boolean.valueOf(powered)).with(RAIL_SHAPE,
alongX ? RailShape.EAST_WEST : RailShape.NORTH_SOUTH);
}
@Override
public boolean canMakeSlopes(BlockState state, IBlockReader world, BlockPos pos) {
return false;
}
@Override
public void onMinecartPass(BlockState state, World world, BlockPos pos, AbstractMinecartEntity cart) {
if (!cart.canBeRidden())
return;
if (state.get(POWERED))
disassemble(world, pos, cart);
else
assemble(world, pos, cart);
}
protected void assemble(World world, BlockPos pos, AbstractMinecartEntity cart) {
if (!cart.getPassengers().isEmpty())
return;
MountedContraption contraption = MountedContraption.assembleMinecart(world, pos, cart);
ContraptionEntity entity = new ContraptionEntity(world, contraption,
ContraptionEntity.yawFromMotion(cart.getMotion()));
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
world.addEntity(entity);
entity.startRiding(cart);
}
protected void disassemble(World world, BlockPos pos, AbstractMinecartEntity cart) {
if (cart.getPassengers().isEmpty())
return;
Entity entity = cart.getPassengers().get(0);
if (!(entity instanceof ContraptionEntity))
return;
MountedContraption contraption = ((ContraptionEntity) entity).contraption;
if (contraption == null)
return;
contraption.disassemble(world, pos.subtract(contraption.getAnchor()), (targetPos, state) -> {
return targetPos.equals(pos);
});
cart.removePassengers();
}
@Override
public void neighborChanged(BlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos,
boolean isMoving) {
super.neighborChanged(state, worldIn, pos, blockIn, fromPos, isMoving);
if (worldIn.isRemote)
return;
boolean previouslyPowered = state.get(POWERED);
if (previouslyPowered != worldIn.isBlockPowered(pos)) {
worldIn.setBlockState(pos, state.cycle(POWERED), 2);
}
}
@Override
public IProperty<RailShape> getShapeProperty() {
return RAIL_SHAPE;
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? X_SHAPE : Z_SHAPE;
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader worldIn, BlockPos pos,
ISelectionContext context) {
if (context.getEntity() instanceof AbstractMinecartEntity)
return VoxelShapes.empty();
return VoxelShapes.fullCube();
}
@Override
public PushReaction getPushReaction(BlockState state) {
return PushReaction.BLOCK;
}
public static class MinecartAnchorBlock extends RenderUtilityBlock {
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(BlockStateProperties.HORIZONTAL_AXIS);
super.fillStateContainer(builder);
}
}
public static BlockState createAnchor(BlockState state) {
Axis axis = state.get(RAIL_SHAPE) == RailShape.NORTH_SOUTH ? Axis.Z : Axis.X;
return AllBlocks.MINECART_ANCHOR.get().getDefaultState().with(BlockStateProperties.HORIZONTAL_AXIS, axis);
}
}

View file

@ -0,0 +1,198 @@
package com.simibubi.create.modules.contraptions.receivers.constructs.mounted;
import com.simibubi.create.AllEntities;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.IPacket;
import net.minecraft.network.PacketBuffer;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.network.FMLPlayMessages.SpawnEntity;
import net.minecraftforge.fml.network.NetworkHooks;
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
protected MountedContraption contraption;
protected float initialAngle;
// Not synchronizing any of these
public float targetYaw;
public float targetPitch;
public float contraptionYaw;
public float contraptionPitch;
public ContraptionEntity(EntityType<?> entityTypeIn, World worldIn) {
super(entityTypeIn, worldIn);
}
protected ContraptionEntity(World world) {
this(AllEntities.CONTRAPTION.type, world);
}
public ContraptionEntity(World world, MountedContraption contraption, float initialAngle) {
this(world);
this.contraption = contraption;
this.initialAngle = initialAngle;
this.prevRotationYaw = initialAngle;
this.contraptionYaw = initialAngle;
this.targetYaw = initialAngle;
}
@Override
protected void registerData() {
}
@Override
public void tick() {
super.tick();
Entity e = getRidingEntity();
if (e == null)
remove();
else {
Vec3d movementVector = e.getMotion();
Vec3d motion = movementVector.normalize();
if (motion.length() > 0) {
targetYaw = yawFromMotion(motion);
targetPitch = (float) ((Math.atan(motion.y) * 73.0D) / Math.PI * 180);
if (targetYaw < 0)
targetYaw += 360;
if (contraptionYaw < 0)
contraptionYaw += 360;
}
float speed = 0.2f;
prevRotationYaw = contraptionYaw;
contraptionYaw = angleLerp(speed, contraptionYaw, targetYaw);
prevRotationPitch = contraptionPitch;
contraptionPitch = angleLerp(speed, contraptionPitch, targetPitch);
tickActors(movementVector);
}
}
public void tickActors(Vec3d movementVector) {
contraption.getActors().forEach(pair -> {
MovementContext context = pair.right;
float deg = -contraptionYaw + initialAngle;
context.motion = VecHelper.rotate(movementVector, deg, Axis.Y);
if (context.world == null)
context.world = world;
Vec3d offset = new Vec3d(pair.left.pos.subtract(contraption.getAnchor()));
world.addParticle(ParticleTypes.BUBBLE, offset.x, offset.y, offset.z, 0, 0, 0);
offset = VecHelper.rotate(offset, deg, Axis.Y);
world.addParticle(ParticleTypes.CRIT, offset.x, offset.y, offset.z, 0, 0, 0);
offset = offset.add(new Vec3d(getPosition()).add(0.5, 0, 0.5));
world.addParticle(ParticleTypes.NOTE, offset.x, offset.y, offset.z, 0, 10, 0);
if (world.isRemote)
return;
BlockPos gridPos = new BlockPos(offset);
if (context.currentGridPos.equals(gridPos))
return;
context.currentGridPos = gridPos;
IHaveMovementBehavior actor = (IHaveMovementBehavior) pair.left.state.getBlock();
actor.visitPosition(context);
});
}
public static float yawFromMotion(Vec3d motion) {
return (float) ((Math.PI / 2 - Math.atan2(motion.z, motion.x)) / Math.PI * 180);
}
public float getYaw(float partialTicks) {
float yaw = contraptionYaw;
return (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, this.prevRotationYaw, yaw)) - initialAngle;
}
public float getPitch(float partialTicks) {
float pitch = contraptionPitch;
return partialTicks == 1.0F ? pitch : angleLerp(partialTicks, this.prevRotationPitch, pitch);
}
private float angleLerp(float pct, float current, float target) {
current = current % 360;
target = target % 360;
float shortest_angle = ((((target - current) % 360) + 540) % 360) - 180;
return current + shortest_angle * pct;
}
public boolean hitByEntity(Entity entityIn) {
return entityIn instanceof PlayerEntity
? this.attackEntityFrom(DamageSource.causePlayerDamage((PlayerEntity) entityIn), 0.0F)
: false;
}
public boolean attackEntityFrom(DamageSource source, float amount) {
if (this.isInvulnerableTo(source)) {
return false;
} else {
if (this.isAlive() && !this.world.isRemote) {
this.remove();
this.markVelocityChanged();
}
return true;
}
}
public static EntityType.Builder<?> build(EntityType.Builder<?> builder) {
@SuppressWarnings("unchecked")
EntityType.Builder<ContraptionEntity> entityBuilder = (EntityType.Builder<ContraptionEntity>) builder;
return entityBuilder.setCustomClientFactory(ContraptionEntity::spawn).size(1, 1);
}
public static ContraptionEntity spawn(SpawnEntity spawnEntity, World world) {
return new ContraptionEntity(world);
}
@Override
protected void readAdditional(CompoundNBT compound) {
contraption = new MountedContraption();
contraption.readNBT(compound.getCompound("Contraption"));
initialAngle = compound.getFloat("InitialAngle");
prevRotationYaw = initialAngle;
contraptionYaw = initialAngle;
targetYaw = initialAngle;
}
@Override
protected void writeAdditional(CompoundNBT compound) {
compound.put("Contraption", contraption.writeNBT());
compound.putFloat("InitialAngle", initialAngle);
}
@Override
public IPacket<?> createSpawnPacket() {
return NetworkHooks.getEntitySpawningPacket(this);
}
@Override
public void writeSpawnData(PacketBuffer buffer) {
CompoundNBT compound = new CompoundNBT();
writeAdditional(compound);
buffer.writeCompoundTag(compound);
}
@Override
public void readSpawnData(PacketBuffer additionalData) {
readAdditional(additionalData.readCompoundTag());
}
}

View file

@ -0,0 +1,97 @@
package com.simibubi.create.modules.contraptions.receivers.constructs.mounted;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionRenderer;
import com.simibubi.create.modules.contraptions.receivers.constructs.ContraptionVertexBuffer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class ContraptionEntityRenderer extends EntityRenderer<ContraptionEntity> {
public ContraptionEntityRenderer(EntityRendererManager rendererManager) {
super(rendererManager);
}
@Override
protected ResourceLocation getEntityTexture(ContraptionEntity arg0) {
return null;
}
@Override
public void doRender(ContraptionEntity entity, double x, double y, double z, float yaw, float partialTicks) {
if (!entity.isAlive())
return;
if (entity.contraption == null)
return;
GlStateManager.pushMatrix();
GlStateManager.translated(0, .5, 0);
float angleYaw = (float) (entity.getYaw(partialTicks) / 180 * Math.PI);
float anglePitch = (float) (entity.getPitch(partialTicks) / 180 * Math.PI);
Entity ridingEntity = entity.getRidingEntity();
if (ridingEntity != null && ridingEntity instanceof AbstractMinecartEntity) {
AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity;
long i = (long) entity.getEntityId() * 493286711L;
i = i * i * 4392167121L + i * 98761L;
float f = (((float) (i >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float f1 = (((float) (i >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
float f2 = (((float) (i >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F;
GlStateManager.translatef(f, f1, f2);
double cartX = MathHelper.lerp((double) partialTicks, cart.lastTickPosX, cart.posX);
double cartY = MathHelper.lerp((double) partialTicks, cart.lastTickPosY, cart.posY);
double cartZ = MathHelper.lerp((double) partialTicks, cart.lastTickPosZ, cart.posZ);
Vec3d cartPos = cart.getPos(cartX, cartY, cartZ);
if (cartPos != null) {
Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F);
Vec3d cartPosBack = cart.getPosOffset(cartX, cartY, cartZ, (double) -0.3F);
if (cartPosFront == null)
cartPosFront = cartPos;
if (cartPosBack == null)
cartPosBack = cartPos;
cartX = cartPos.x - cartX;
cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY;
cartZ = cartPos.z - cartZ;
GlStateManager.translatef((float) cartX, (float) cartY, (float) cartZ);
}
}
ContraptionRenderer.cacheContraptionIfMissing(entity.contraption);
TessellatorHelper.prepareFastRender();
TessellatorHelper.begin(DefaultVertexFormats.BLOCK);
ContraptionVertexBuffer buffer = ContraptionRenderer.get(entity.contraption);
if (buffer != null) {
BlockPos anchor = entity.contraption.getAnchor();
Vec3d rotationOffset = VecHelper.getCenterOf(anchor);
Vec3d offset = VecHelper.getCenterOf(anchor).scale(-1);
Tessellator.getInstance().getBuffer().putBulkData(buffer.getTranslatedAndRotated(entity.world, (float) x,
(float) y, (float) z, angleYaw, -anglePitch, offset, rotationOffset));
ContraptionRenderer.renderActors(entity.world, entity.contraption, (float) (x + offset.x),
(float) (y + offset.y), (float) (z + offset.z), angleYaw, -anglePitch,
Tessellator.getInstance().getBuffer());
}
TessellatorHelper.draw();
GlStateManager.popMatrix();
super.doRender(entity, x, y, z, yaw, partialTicks);
}
}

View file

@ -0,0 +1,90 @@
package com.simibubi.create.modules.contraptions.receivers.constructs.mounted;
import static com.simibubi.create.modules.contraptions.receivers.constructs.mounted.CartAssemblerBlock.RAIL_SHAPE;
import java.util.List;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.receivers.constructs.Contraption;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MovementContext;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior.MoverType;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.RailShape;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class MountedContraption extends Contraption {
public static MountedContraption assembleMinecart(World world, BlockPos pos, AbstractMinecartEntity cart) {
if (isFrozen())
return null;
BlockState state = world.getBlockState(pos);
if (!state.has(RAIL_SHAPE))
return null;
MountedContraption contraption = new MountedContraption();
Vec3d vec = cart.getMotion();
if (!contraption.searchMovedStructure(world, pos, Direction.getFacingFromVector(vec.x, vec.y, vec.z)))
return null;
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z;
contraption.add(pos, new BlockInfo(pos,
AllBlocks.MINECART_ANCHOR.block.getDefaultState().with(BlockStateProperties.HORIZONTAL_AXIS, axis),
null));
for (BlockInfo block : contraption.blocks.values()) {
BlockPos startPos = pos;
if (startPos.equals(block.pos))
continue;
world.setBlockState(block.pos, Blocks.AIR.getDefaultState(), 67);
}
for (MutablePair<BlockInfo, MovementContext> pair : contraption.getActors()) {
MovementContext context = new MovementContext(pair.left.state, MoverType.MINECART);
context.world = world;
context.motion = vec;
context.currentGridPos = pair.left.pos;
pair.setRight(context);
}
return contraption;
}
@Override
protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List<BlockPos> frontier) {
frontier.clear();
frontier.add(pos.up());
BlockState state = world.getBlockState(pos);
if (!AllBlocks.CART_ASSEMBLER.typeOf(state))
return false;
Axis axis = state.get(CartAssemblerBlock.RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.Z : Axis.X;
for (AxisDirection axisDirection : AxisDirection.values())
frontier.add(pos.offset(Direction.getFacingFromAxis(axisDirection, axis)));
return true;
}
@Override
protected BlockInfo capture(World world, BlockPos pos) {
BlockInfo capture = super.capture(world, pos);
if (AllBlocks.CART_ASSEMBLER.typeOf(capture.state))
return new BlockInfo(capture.pos, CartAssemblerBlock.createAnchor(capture.state), null);
return capture;
}
public BlockPos getAnchor() {
return anchor;
}
}

View file

@ -5,7 +5,6 @@ import java.util.Random;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.ProperDirectionalBlock; import com.simibubi.create.foundation.block.ProperDirectionalBlock;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior; import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonTileEntity;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
@ -109,11 +108,9 @@ public class ContactBlock extends ProperDirectionalBlock implements IHaveMovemen
Direction direction = block.get(FACING); Direction direction = block.get(FACING);
if (!hasValidContact(world, pos, direction)) if (!hasValidContact(world, pos, direction))
return; return;
if (context.moverType != MoverType.PISTON)
return;
int ticksToStayActive = (int) Math int ticksToStayActive = (int) Math
.ceil(1 / Math.abs(((MechanicalPistonTileEntity) context.mover).getMovementSpeed())); .ceil(1 / Math.abs(context.motion.length()));
world.setBlockState(pos.offset(direction), world.getBlockState(pos.offset(direction)).with(POWERED, true)); world.setBlockState(pos.offset(direction), world.getBlockState(pos.offset(direction)).with(POWERED, true));
world.getPendingBlockTicks().scheduleTick(pos.offset(direction), this, ticksToStayActive, TickPriority.NORMAL); world.getPendingBlockTicks().scheduleTick(pos.offset(direction), this, ticksToStayActive, TickPriority.NORMAL);
return; return;

View file

@ -4,7 +4,6 @@ import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
@ -24,18 +23,6 @@ public class CardboardBoxEntityRenderer extends EntityRenderer<CardboardBoxEntit
return null; return null;
} }
@Override
public boolean shouldRender(CardboardBoxEntity livingEntity, ICamera camera, double camX, double camY,
double camZ) {
return super.shouldRender(livingEntity, camera, camX, camY, camZ);
}
@Override
public void renderMultipass(CardboardBoxEntity entityIn, double x, double y, double z, float entityYaw,
float partialTicks) {
super.renderMultipass(entityIn, x, y, z, entityYaw, partialTicks);
}
@Override @Override
public void doRender(CardboardBoxEntity entity, double x, double y, double z, float entityYaw, float partialTicks) { public void doRender(CardboardBoxEntity entity, double x, double y, double z, float entityYaw, float partialTicks) {
IBakedModel model = getModelForBox(entity); IBakedModel model = getModelForBox(entity);

View file

@ -5,13 +5,12 @@ import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer; import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.model.BookModel; import net.minecraft.client.renderer.entity.model.BookModel;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.BlockStateProperties;
@ -25,19 +24,8 @@ public class LogisticiansTableTileEntityRenderer extends TileEntityRenderer<Logi
public void render(LogisticiansTableTileEntity tileEntityIn, double x, double y, double z, float partialTicks, public void render(LogisticiansTableTileEntity tileEntityIn, double x, double y, double z, float partialTicks,
int destroyStage) { int destroyStage) {
Minecraft.getInstance().textureManager TessellatorHelper.prepareFastRender();
.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();
GlStateManager.disableCull();
if (net.minecraft.client.Minecraft.isAmbientOcclusionEnabled())
GlStateManager.shadeModel(GL11.GL_SMOOTH);
else
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.color3f(1, 1, 1);
BlockPos pos = tileEntityIn.getPos(); BlockPos pos = tileEntityIn.getPos();
BlockState blockState = tileEntityIn.getBlockState(); BlockState blockState = tileEntityIn.getBlockState();
BlockState renderedState = AllBlocks.LOGISTICIANS_TABLE_INDICATOR.get().getDefaultState(); BlockState renderedState = AllBlocks.LOGISTICIANS_TABLE_INDICATOR.get().getDefaultState();
@ -63,5 +51,4 @@ public class LogisticiansTableTileEntityRenderer extends TileEntityRenderer<Logi
GlStateManager.popMatrix(); GlStateManager.popMatrix();
} }
} }

View file

@ -0,0 +1,20 @@
{
"forge_marker": 1,
"defaults": {
"model": "create:block/cart_assembler"
},
"variants": {
"shape": {
"north_south": { },
"east_west": { "y": 90 }
},
"powered": {
"false": { },
"true": {
"textures": {
"clutch_off": "create:block/clutch_on"
}
}
}
}
}

View file

@ -0,0 +1,12 @@
{
"forge_marker": 1,
"defaults": {
"model": "create:block/minecart_anchor"
},
"variants": {
"axis": {
"x": { "y": 90 },
"z": { }
}
}
}

View file

@ -25,6 +25,8 @@
"item.create.dough": "Dough", "item.create.dough": "Dough",
"item.create.crushed_iron": "Crushed Iron Ore", "item.create.crushed_iron": "Crushed Iron Ore",
"item.create.crushed_gold": "Crushed Gold Ore", "item.create.crushed_gold": "Crushed Gold Ore",
"item.create.time_scarf": "Scarf with a clock on it",
"item.create.motion_scarf": "Scarf of Perpetuality",
"item.create.logistical_controller_supply": "Item Supply", "item.create.logistical_controller_supply": "Item Supply",
"item.create.logistical_controller_request": "Item Request", "item.create.logistical_controller_request": "Item Request",

View file

@ -0,0 +1,93 @@
{
"__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)",
"parent": "block/block",
"textures": {
"particle": "create:block/translation_chassis_side",
"gearbox_top": "create:block/gearbox_top",
"clutch_off": "create:block/clutch_off",
"rail": "minecraft:block/rail",
"translation_chassis_side": "create:block/translation_chassis_side"
},
"elements": [
{
"name": "Rail",
"from": [ 0, 1, 0 ],
"to": [ 16, 1, 16 ],
"faces": {
"up": { "texture": "#rail", "uv": [ 0, 0, 16, 16 ] },
"down": { "texture": "#rail", "uv": [ 0, 0, 16, 16 ], "rotation": 180 }
}
},
{
"name": "Side",
"from": [ 0, 0, 0 ],
"to": [ 2, 16, 16 ],
"faces": {
"north": { "texture": "#gearbox_top", "uv": [ 14, 0, 16, 16 ] },
"east": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ], "rotation": 90 },
"south": { "texture": "#gearbox_top", "uv": [ 0, 16, 2, 0 ] },
"west": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ], "rotation": 90 },
"up": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 2, 16 ] },
"down": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 2, 16 ] }
}
},
{
"name": "Side",
"from": [ 14, 0, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"north": { "texture": "#gearbox_top", "uv": [ 0, 0, 2, 16 ] },
"east": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ], "rotation": 90 },
"south": { "texture": "#gearbox_top", "uv": [ 14, 16, 16, 0 ] },
"west": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ], "rotation": 90 },
"up": { "texture": "#translation_chassis_side", "uv": [ 14, 0, 16, 16 ] },
"down": { "texture": "#translation_chassis_side", "uv": [ 14, 0, 16, 16 ] }
}
},
{
"name": "Top",
"from": [ 2, 14, 0 ],
"to": [ 14, 16, 16 ],
"faces": {
"north": { "texture": "#gearbox_top", "uv": [ 2, 0, 14, 2 ] },
"south": { "texture": "#gearbox_top", "uv": [ 2, 0, 14, 2 ] },
"up": { "texture": "#translation_chassis_side", "uv": [ 2, 0, 14, 16 ], "rotation": 180 },
"down": { "texture": "#translation_chassis_side", "uv": [ 2, 0, 14, 16 ] }
}
},
{
"name": "Indicator",
"from": [ 1, 10, 2 ],
"to": [ 15, 14, 14 ],
"faces": {
"north": { "texture": "#clutch_off", "uv": [ 1, 6, 15, 10 ] },
"south": { "texture": "#clutch_off", "uv": [ 1, 6, 15, 10 ] },
"down": { "texture": "#gearbox_top", "uv": [ 1, 2, 15, 14 ] }
}
},
{
"name": "Side",
"from": [ 15.875, 0.062, 1.125 ],
"to": [ 17.875, 12.937, 14.875 ],
"faces": {
"north": { "texture": "#gearbox_top", "uv": [ 0, 0, 2, 12.875 ] },
"east": { "texture": "#translation_chassis_side", "uv": [ 2, 1, 14, 15 ], "rotation": 90 },
"south": { "texture": "#gearbox_top", "uv": [ 14, 16, 16, 3 ] },
"up": { "texture": "#translation_chassis_side", "uv": [ 7, 1, 9, 15 ] },
"down": { "texture": "#translation_chassis_side", "uv": [ 7, 1, 9, 15 ] }
}
},
{
"name": "Side",
"from": [ -1.875, 0.062, 1.125 ],
"to": [ 0.125, 12.937, 14.875 ],
"faces": {
"north": { "texture": "#gearbox_top", "uv": [ 14, 0, 16, 12.875 ] },
"south": { "texture": "#gearbox_top", "uv": [ 0, 16, 2, 3 ] },
"west": { "texture": "#translation_chassis_side", "uv": [ 2, 1, 14, 15 ], "rotation": 90 },
"up": { "texture": "#translation_chassis_side", "uv": [ 7, 1, 9, 15 ] },
"down": { "texture": "#translation_chassis_side", "uv": [ 7, 1, 9, 15 ] }
}
}
]
}

View file

@ -0,0 +1,6 @@
{
"parent": "create:block/cart_assembler",
"textures": {
"clutch_off": "create:block/clutch_on"
}
}

View file

@ -0,0 +1,32 @@
{
"__comment": "Model generated using MrCrayfish's Model Creator (https://mrcrayfish.com/tools?id=mc)",
"textures": {
"translation_chassis_side": "create:block/translation_chassis_side"
},
"elements": [
{
"name": "Top",
"from": [ 0, 12, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"north": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 4 ] },
"east": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 4, 16 ], "rotation": 90 },
"south": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 4 ] },
"west": { "texture": "#translation_chassis_side", "uv": [ 12, 0, 16, 16 ], "rotation": 270 },
"up": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ] },
"down": { "texture": "#translation_chassis_side", "uv": [ 0, 0, 16, 16 ] }
}
},
{
"name": "Inner",
"from": [ 4, 4, 4 ],
"to": [ 12, 12, 12 ],
"faces": {
"north": { "texture": "#translation_chassis_side", "uv": [ 4, 8, 12, 16 ] },
"east": { "texture": "#translation_chassis_side", "uv": [ 4, 8, 12, 16 ] },
"south": { "texture": "#translation_chassis_side", "uv": [ 4, 8, 12, 16 ] },
"west": { "texture": "#translation_chassis_side", "uv": [ 4, 8, 12, 16 ] }
}
}
]
}

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/cart_assembler"
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "create:item/motion_scarf"
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "create:item/time_scarf"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"create:cart_assembler"
]
}