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.RotationChassisBlock;
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.relays.ClutchBlock;
import com.simibubi.create.modules.contraptions.relays.CogWheelBlock;
@ -125,6 +127,8 @@ public enum AllBlocks {
SAW(new SawBlock()),
HARVESTER(new HarvesterBlock()),
HARVESTER_BLADE(new HarvesterBladeBlock()),
CART_ASSEMBLER(new CartAssemblerBlock()),
MINECART_ANCHOR(new MinecartAnchorBlock()),
__LOGISTICS__(),
CONTACT(new ContactBlock()),

View file

@ -2,6 +2,8 @@ package com.simibubi.create;
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.CardboardBoxEntityRenderer;
@ -19,6 +21,7 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry;
public enum AllEntities {
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)
public static void registerRenderers() {
RenderingRegistry.registerEntityRenderingHandler(CardboardBoxEntity.class, CardboardBoxEntityRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(ContraptionEntity.class, ContraptionEntityRenderer::new);
}
}

View file

@ -81,6 +81,8 @@ public enum AllItems {
PROPELLER(ingredient()),
CRUSHED_IRON(ingredient()),
CRUSHED_GOLD(ingredient()),
TIME_SCARF(ingredient()),
MOTION_SCARF(ingredient()),
__LOGISTICS__(),
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.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.MathHelper;
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 mutable;
@ -23,66 +24,66 @@ public abstract class BufferManipulator {
mutable.rewind();
}
protected int vertexCount(ByteBuffer buffer) {
protected static int vertexCount(ByteBuffer buffer) {
return buffer.limit() / FORMAT_LENGTH;
}
protected int getBufferPosition(int vertexIndex) {
protected static int getBufferPosition(int vertexIndex) {
return vertexIndex * FORMAT_LENGTH;
}
protected float getX(ByteBuffer buffer, int index) {
protected static float getX(ByteBuffer buffer, int 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);
}
protected float getZ(ByteBuffer buffer, int index) {
protected static float getZ(ByteBuffer buffer, int index) {
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);
}
protected byte getG(ByteBuffer buffer, int index) {
protected static byte getG(ByteBuffer buffer, int index) {
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);
}
protected byte getA(ByteBuffer buffer, int index) {
protected static byte getA(ByteBuffer buffer, int index) {
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);
buffer.putFloat(pos, x);
buffer.putFloat(pos + 4, y);
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;
}
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;
}
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;
}
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);
}
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);
buffer.put(bufferPosition + 12, r);
buffer.put(bufferPosition + 13, g);
@ -90,4 +91,35 @@ public abstract class BufferManipulator {
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.BufferBuilder;
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.VertexFormat;
import net.minecraft.util.math.BlockPos;
@ -30,6 +31,22 @@ public class TessellatorHelper {
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() {
begin(DefaultVertexFormats.POSITION_TEX);
}

View file

@ -2,6 +2,8 @@ package com.simibubi.create.foundation.utility;
import java.util.Random;
import net.minecraft.nbt.DoubleNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
@ -36,4 +38,16 @@ public class VecHelper {
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.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.MechanicalPistonTileEntityRenderer;
import net.minecraft.client.resources.ReloadListener;
import net.minecraft.profiler.IProfiler;
@ -19,7 +19,7 @@ public class CachedBufferReloader extends ReloadListener<String> {
@Override
protected void apply(String splashList, IResourceManager resourceManagerIn, IProfiler profilerIn) {
KineticTileEntityRenderer.invalidateCache();
MechanicalPistonTileEntityRenderer.invalidateCache();
ContraptionRenderer.invalidateCache();
MechanicalBearingTileEntityRenderer.invalidateCache();
ColoredIndicatorRenderer.invalidateCache();
}

View file

@ -1,5 +1,6 @@
package com.simibubi.create.modules.contraptions.receivers;
import java.nio.ByteBuffer;
import java.util.List;
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.DirectionalBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateContainer.Builder;
@ -80,17 +80,17 @@ public class DrillBlock extends DirectionalKineticBlock
@Override
@OnlyIn(value = Dist.CLIENT)
public void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) {
DrillTileEntityRenderer.renderInConstruct(context, x, y, z, buffer);
public ByteBuffer renderInConstruct(MovementContext context) {
return DrillTileEntityRenderer.renderInConstruct(context);
}
@Override
public void visitPosition(MovementContext context) {
Direction movement = context.getMovementDirection();
BlockState block = context.state;
if (movement != block.get(FACING))
return;
// BlockState block = context.state;
// if (movement == block.get(FACING).getOpposite())
// return;
World world = context.world;
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 java.nio.ByteBuffer;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.modules.contraptions.base.IRotate;
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.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.BlockPos;
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));
}
public static void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) {
public static ByteBuffer renderInConstruct(MovementContext context) {
World world = context.world;
BlockState state = context.state;
BlockPos pos = context.currentGridPos;
@ -35,12 +36,13 @@ public class DrillTileEntityRenderer extends KineticTileEntityRenderer {
final BlockState renderedState = getRenderedBlockState(state);
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);
float time = Animation.getWorldTime(Minecraft.getInstance().world,
Minecraft.getInstance().getRenderPartialTicks());
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;
import java.nio.ByteBuffer;
import java.util.List;
import com.simibubi.create.AllBlocks;
@ -14,7 +15,6 @@ import net.minecraft.block.CropsBlock;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.SugarCaneBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
@ -74,8 +74,8 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
@Override
@OnlyIn(value = Dist.CLIENT)
public void renderInConstruct(MovementContext context, double x, double y, double z, BufferBuilder buffer) {
HarvesterTileEntityRenderer.renderInConstruct(context, x, y, z, buffer);
public ByteBuffer renderInConstruct(MovementContext context) {
return HarvesterTileEntityRenderer.renderInConstruct(context);
}
@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;
BlockState state = context.state;
BlockPos pos = context.currentGridPos;
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)
speed = -speed;
float time = Animation.getWorldTime(Minecraft.getInstance().world,
Minecraft.getInstance().getRenderPartialTicks());
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
public void renderTileEntityFast(HarvesterTileEntity te, double x, double y, double z, float partialTicks,
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,
BufferBuilder buffer) {
public static ByteBuffer getVertexData(World world, BlockState state, BlockPos pos, double x, double y, double z,
float angle) {
if (!AllBlocks.HARVESTER.typeOf(state))
return;
return ByteBuffer.wrap(new byte[] {});
BlockState renderedState = AllBlocks.HARVESTER_BLADE.get().getDefaultState().with(HORIZONTAL_FACING,
state.get(HORIZONTAL_FACING));
KineticTileEntityRenderer.cacheIfMissing(renderedState, world, HarvesterRenderer::new);
HarvesterRenderer renderer = (HarvesterRenderer) KineticTileEntityRenderer.getBuffer(renderedState);
buffer.putBulkData(renderer.getTransformed((float) x, (float) y, (float) z, angle, state.get(HORIZONTAL_FACING),
state.getPackedLightmapCoords(world, pos)));
ByteBuffer byteBuffer = renderer.getTransformed((float) x, (float) y, (float) z, angle,
state.get(HORIZONTAL_FACING), state.getPackedLightmapCoords(world, pos));
return byteBuffer;
}
}

View file

@ -1,8 +1,5 @@
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.AXIS;
import static net.minecraft.state.properties.BlockStateProperties.FACING;
@ -14,6 +11,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Function;
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.modules.contraptions.receivers.SawBlock;
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.FallingBlock;
@ -34,47 +31,66 @@ import net.minecraft.nbt.FloatNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.state.properties.PistonType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
public class TranslationConstruct {
public class Contraption {
protected Map<BlockPos, BlockInfo> blocks;
protected List<MutablePair<BlockInfo, MovementContext>> actors;
protected AxisAlignedBB constructCollisionBox;
protected AxisAlignedBB pistonCollisionBox;
protected Set<BlockPos> cachedColliders;
protected Direction cachedColliderDirection;
protected BlockPos anchor;
protected int extensionLength;
protected int initialExtensionProgress;
protected Direction orientation;
public TranslationConstruct() {
public Contraption() {
blocks = new HashMap<>();
actors = new ArrayList<>();
}
public static TranslationConstruct movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) {
if (isFrozen())
return null;
TranslationConstruct construct = new TranslationConstruct();
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 static List<BlockInfo> getChassisClusterAt(World world, BlockPos pos) {
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;
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(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) {
@ -101,86 +117,17 @@ public class TranslationConstruct {
return cachedColliders;
}
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));
}
return true;
}
private boolean searchMovedStructure(World world, BlockPos pos, Direction direction) {
protected boolean searchMovedStructure(World world, BlockPos pos, Direction direction) {
List<BlockPos> frontier = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
constructCollisionBox = new AxisAlignedBB(pos.offset(direction, initialExtensionProgress));
frontier.add(pos);
anchor = pos;
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);
}
if (constructCollisionBox == null)
constructCollisionBox = new AxisAlignedBB(pos);
frontier.add(pos);
if (!addToInitialFrontier(world, pos, direction, frontier))
return false;
for (int limit = 1000; limit > 0; limit--) {
if (frontier.isEmpty())
@ -192,6 +139,10 @@ public class TranslationConstruct {
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,
Set<BlockPos> visited) {
visited.add(pos);
@ -349,42 +300,8 @@ public class TranslationConstruct {
return true;
}
private static List<BlockInfo> getChassisClusterAt(World world, BlockPos pos) {
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;
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 static boolean isChassis(BlockState state) {
return TranslationChassisBlock.isChassis(state);
}
private boolean notSupportive(World world, BlockPos pos, Direction facing) {
@ -396,11 +313,7 @@ public class TranslationConstruct {
return false;
}
private static boolean isChassis(BlockState state) {
return TranslationChassisBlock.isChassis(state);
}
private static boolean canPush(World world, BlockPos pos, Direction direction) {
protected static boolean canPush(World world, BlockPos pos, Direction direction) {
BlockState blockState = world.getBlockState(pos);
if (isChassis(blockState))
return true;
@ -409,19 +322,15 @@ public class TranslationConstruct {
return PistonBlock.canPush(blockState, world, pos, direction, true, direction);
}
private void add(BlockPos pos, BlockInfo block) {
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) {
protected BlockInfo capture(World world, BlockPos pos) {
BlockState blockstate = world.getBlockState(pos);
if (AllBlocks.SAW.typeOf(blockstate))
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);
CompoundNBT compoundnbt = null;
if (tileentity != null) {
@ -430,17 +339,43 @@ public class TranslationConstruct {
compoundnbt.remove("y");
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() {
return constructCollisionBox;
}
public AxisAlignedBB getCollisionBoxBack() {
return pistonCollisionBox;
}
public CompoundNBT writeNBT() {
CompoundNBT nbt = new CompoundNBT();
ListNBT blocks = new ListNBT();
@ -453,18 +388,21 @@ public class TranslationConstruct {
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) {
ListNBT bb = writeAABB(constructCollisionBox);
nbt.put("BoundsFront", bb);
}
if (pistonCollisionBox != null) {
ListNBT bb = writeAABB(pistonCollisionBox);
nbt.put("BoundsBack", bb);
}
nbt.put("Blocks", blocks);
nbt.putInt("ExtensionLength", extensionLength);
nbt.put("Anchor", NBTUtil.writeBlockPos(anchor));
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() {
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;
import java.nio.ByteBuffer;
import com.simibubi.create.foundation.utility.VecHelper;
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.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
public interface IHaveMovementBehavior {
@ -28,29 +34,50 @@ public interface IHaveMovementBehavior {
public class MovementContext {
public BlockPos currentGridPos;
public Vec3d movementVec;
public Vec3d motion;
public float movementSpeedModifier = 1;
public MoverType moverType;
public Object mover;
public World world;
public BlockState state;
public MovementContext(World world, BlockState state, MoverType moverType, Object mover) {
this.world = world;
public MovementContext(BlockState state, MoverType moverType) {
this.state = state;
this.moverType = moverType;
this.mover = mover;
}
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)
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;
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.Iterator;
@ -11,17 +12,14 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.Create;
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.MoverType;
import com.simibubi.create.modules.contraptions.receivers.constructs.MechanicalPistonBlock.PistonState;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.AxisAlignedBB;
@ -34,7 +32,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
public class MechanicalPistonTileEntity extends KineticTileEntity implements ITickableTileEntity {
protected TranslationConstruct movingConstruct;
protected PistonContraption movedContraption;
protected float offset;
protected boolean running;
protected boolean assembleNextTick;
@ -73,8 +71,8 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putFloat("Offset", offset);
if (running && !TranslationConstruct.isFrozen())
tag.put("Construct", movingConstruct.writeNBT());
if (running && !PistonContraption.isFrozen())
tag.put("Construct", movedContraption.writeNBT());
return super.write(tag);
}
@ -83,12 +81,14 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
offset = tag.getFloat("Offset");
if (running && !TranslationConstruct.isFrozen()) {
movingConstruct = TranslationConstruct.fromNBT(tag.getCompound("Construct"));
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) {
MovementContext context = new MovementContext(world, pair.left.state, MoverType.PISTON, this);
if (running && !PistonContraption.isFrozen()) {
movedContraption = new PistonContraption();
movedContraption.readNBT(tag.getCompound("Construct"));
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);
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));
pair.setRight(context);
}
@ -98,12 +98,12 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
}
protected void onBlockVisited(float newOffset) {
if (TranslationConstruct.isFrozen())
if (PistonContraption.isFrozen())
return;
Direction direction = getBlockState().get(BlockStateProperties.FACING);
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) {
for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors()) {
BlockInfo block = pair.left;
MovementContext context = pair.right;
@ -120,39 +120,40 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
Direction direction = getBlockState().get(BlockStateProperties.FACING);
// Collect Construct
movingConstruct = TranslationConstruct.movePistonAt(world, pos, direction, getMovementSpeed() < 0);
if (movingConstruct == null)
movedContraption = PistonContraption.movePistonAt(world, pos, direction, getMovementSpeed() < 0);
if (movedContraption == null)
return;
// Check if not at limit already
float resultingOffset = movingConstruct.initialExtensionProgress + getMovementSpeed();
if (resultingOffset <= 0 || resultingOffset >= movingConstruct.extensionLength) {
movingConstruct = null;
float resultingOffset = movedContraption.initialExtensionProgress + getMovementSpeed();
if (resultingOffset <= 0 || resultingOffset >= movedContraption.extensionLength) {
movedContraption = null;
return;
}
if (hasBlockCollisions(resultingOffset + .5f)) {
movingConstruct = null;
movedContraption = null;
return;
}
// Run
running = true;
offset = movingConstruct.initialExtensionProgress;
offset = movedContraption.initialExtensionProgress;
if (!world.isRemote)
Create.constructHandler.add(this);
sendData();
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66);
for (BlockInfo block : movingConstruct.blocks.values()) {
BlockPos startPos = block.pos.offset(direction, movingConstruct.initialExtensionProgress);
for (BlockInfo block : movedContraption.blocks.values()) {
BlockPos startPos = block.pos.offset(direction, movedContraption.initialExtensionProgress);
if (startPos.equals(pos))
continue;
getWorld().setBlockState(startPos, Blocks.AIR.getDefaultState(), 67);
}
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors) {
MovementContext context = new MovementContext(world, pair.left.state, MoverType.PISTON, this);
context.movementVec = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize();
for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors()) {
MovementContext context = new MovementContext(pair.left.state, MoverType.PISTON);
context.world = world;
context.motion = new Vec3d(direction.getDirectionVec()).scale(getMovementSpeed()).normalize();
context.currentGridPos = pair.left.pos.offset(direction, getModulatedOffset(offset));
pair.setRight(context);
}
@ -167,38 +168,19 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
Direction direction = getBlockState().get(BlockStateProperties.FACING);
if (!removed)
getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3);
for (BlockInfo block : movingConstruct.blocks.values()) {
BlockPos targetPos = block.pos.offset(direction, getModulatedOffset(offset));
BlockState state = block.state;
if (targetPos.equals(pos)) {
if (!AllBlocks.PISTON_POLE.typeOf(state) && !removed)
getWorld().setBlockState(pos,
getBlockState().with(MechanicalPistonBlock.STATE, PistonState.RETRACTED), 3);
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());
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);
}
}
movedContraption.disassemble(world, BlockPos.ZERO.offset(direction, getModulatedOffset(offset)),
(targetPos, state) -> {
if (targetPos.equals(pos)) {
if (!AllBlocks.PISTON_POLE.typeOf(state) && !removed)
world.setBlockState(pos, getBlockState().with(STATE, PistonState.RETRACTED), 3);
return true;
}
return false;
});
running = false;
if (!world.isRemote)
Create.constructHandler.remove(this);
movingConstruct = null;
movedContraption = null;
sendData();
if (removed)
@ -213,10 +195,10 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (speed == 0)
disassembleConstruct();
else {
for (MutablePair<BlockInfo, MovementContext> pair : movingConstruct.actors)
pair.right.movementVec = new Vec3d(
for (MutablePair<BlockInfo, MovementContext> pair : movedContraption.getActors())
pair.right.motion = new Vec3d(
getBlockState().get(BlockStateProperties.FACING).getDirectionVec())
.scale(getMovementSpeed()).normalize();
.scale(getMovementSpeed());
sendData();
}
return;
@ -257,14 +239,14 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
offset = newOffset;
if (offset <= 0 || offset >= movingConstruct.extensionLength) {
if (offset <= 0 || offset >= movedContraption.extensionLength) {
disassembleConstruct();
return;
}
}
private boolean hasBlockCollisions(float newOffset) {
if (TranslationConstruct.isFrozen())
if (PistonContraption.isFrozen())
return true;
Direction movementDirection = getBlockState().get(BlockStateProperties.FACING);
@ -280,7 +262,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (otherPiston == this)
continue;
if (!otherPiston.running || otherPiston.movingConstruct == null) {
if (!otherPiston.running || otherPiston.movedContraption == null) {
iterator.remove();
continue;
}
@ -291,10 +273,10 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
BlockPos otherRelativePos = BlockPos.ZERO.offset(otherMovementDirection,
getModulatedOffset(otherPiston.offset));
for (AxisAlignedBB tBB : Arrays.asList(movingConstruct.constructCollisionBox,
movingConstruct.pistonCollisionBox)) {
for (AxisAlignedBB oBB : Arrays.asList(otherPiston.movingConstruct.constructCollisionBox,
otherPiston.movingConstruct.pistonCollisionBox)) {
for (AxisAlignedBB tBB : Arrays.asList(movedContraption.constructCollisionBox,
movedContraption.pistonCollisionBox)) {
for (AxisAlignedBB oBB : Arrays.asList(otherPiston.movedContraption.constructCollisionBox,
otherPiston.movedContraption.pistonCollisionBox)) {
if (tBB == null || oBB == null)
continue;
@ -306,9 +288,9 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
if (thisBB.intersects(otherBB)) {
boolean actuallyColliding = false;
for (BlockPos colliderPos : movingConstruct.getColliders(world, movementDirection)) {
for (BlockPos colliderPos : movedContraption.getColliders(world, movementDirection)) {
colliderPos = colliderPos.add(thisColliderOffset).subtract(otherRelativePos);
if (!otherPiston.movingConstruct.blocks.containsKey(colliderPos))
if (!otherPiston.movedContraption.blocks.containsKey(colliderPos))
continue;
actuallyColliding = true;
}
@ -327,7 +309,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
return false;
// Other Blocks in world
for (BlockPos pos : movingConstruct.getColliders(world,
for (BlockPos pos : movedContraption.getColliders(world,
getMovementSpeed() > 0 ? movementDirection : movementDirection.getOpposite())) {
BlockPos colliderPos = pos.add(relativePos);
@ -342,7 +324,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
}
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() {
@ -354,7 +336,7 @@ public class MechanicalPistonTileEntity extends KineticTileEntity implements ITi
public Vec3d getConstructOffset(float partialTicks) {
float interpolatedOffset = MathHelper.clamp(offset + (partialTicks - .5f) * getMovementSpeed(), 0,
movingConstruct.extensionLength);
movedContraption.extensionLength);
return new Vec3d(getBlockState().get(BlockStateProperties.FACING).getDirectionVec()).scale(interpolatedOffset);
}

View file

@ -1,38 +1,17 @@
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.foundation.utility.PlacementSimulationWorld;
import com.simibubi.create.modules.contraptions.base.IRotate;
import com.simibubi.create.modules.contraptions.base.KineticTileEntity;
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.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.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
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 {
protected static Cache<TranslationConstruct, TranslationConstructVertexBuffer> cachedConstructs;
protected static PlacementSimulationWorld renderWorld;
@Override
public void renderTileEntityFast(KineticTileEntity te, double x, double y, double z, float partialTicks,
int destroyStage, BufferBuilder buffer) {
@ -44,58 +23,21 @@ public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRendere
if (!pistonTe.running)
return;
cacheConstructIfMissing(pistonTe.movingConstruct);
renderConstructFromCache(pistonTe.movingConstruct, pistonTe, x, y, z, partialTicks, buffer);
for (Pair<BlockInfo, MovementContext> actor : pistonTe.movingConstruct.actors) {
MovementContext context = actor.getRight();
if (context == null)
continue;
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);
}
ContraptionRenderer.cacheContraptionIfMissing(pistonTe.movedContraption);
renderConstructFromCache(pistonTe.movedContraption, pistonTe, x, y, z, partialTicks, buffer);
Vec3d offset = pistonTe.getConstructOffset(partialTicks).subtract(new Vec3d(pistonTe.getPos()));
ContraptionRenderer.renderActors(pistonTe.getWorld(), pistonTe.movedContraption, (float) (x + offset.x),
(float) (y + offset.y), (float) (z + offset.z), 0, 0, 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) {
protected void renderConstructFromCache(Contraption c, MechanicalPistonTileEntity te, double x, double y, double z,
float partialTicks, BufferBuilder buffer) {
final Vec3d offset = te.getConstructOffset(partialTicks);
buffer.putBulkData(cachedConstructs.getIfPresent(c).getTransformed(te,
(float) (x + offset.x - te.getPos().getX()), (float) (y + offset.y - te.getPos().getY()),
(float) (z + offset.z - te.getPos().getZ()), offset));
float xPos = (float) (x - te.getPos().getX());
float yPos = (float) (y - te.getPos().getY());
float zPos = (float) (z - te.getPos().getZ());
buffer.putBulkData(ContraptionRenderer.get(c).getTranslated(te.getWorld(), xPos, yPos, zPos, offset));
}
@Override
@ -104,9 +46,4 @@ public class MechanicalPistonTileEntityRenderer extends KineticTileEntityRendere
((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,
float newOffset) {
if (TranslationConstruct.isFrozen())
if (PistonContraption.isFrozen())
return;
World world = te.getWorld();
Vec3d movementVec = new Vec3d(te.getBlockState().get(BlockStateProperties.FACING).getDirectionVec());
TranslationConstruct construct = te.movingConstruct;
Contraption construct = te.movedContraption;
// if (world.isRemote) {
// 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.foundation.block.ProperDirectionalBlock;
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.BlockState;
@ -109,11 +108,9 @@ public class ContactBlock extends ProperDirectionalBlock implements IHaveMovemen
Direction direction = block.get(FACING);
if (!hasValidContact(world, pos, direction))
return;
if (context.moverType != MoverType.PISTON)
return;
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.getPendingBlockTicks().scheduleTick(pos.offset(direction), this, ticksToStayActive, TickPriority.NORMAL);
return;

View file

@ -4,7 +4,6 @@ import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.block.Blocks;
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.EntityRendererManager;
import net.minecraft.client.renderer.model.IBakedModel;
@ -24,18 +23,6 @@ public class CardboardBoxEntityRenderer extends EntityRenderer<CardboardBoxEntit
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
public void doRender(CardboardBoxEntity entity, double x, double y, double z, float entityYaw, float partialTicks) {
IBakedModel model = getModelForBox(entity);

View file

@ -5,13 +5,12 @@ import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.ColoredIndicatorRenderer;
import com.simibubi.create.foundation.utility.TessellatorHelper;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
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.vertex.DefaultVertexFormats;
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,
int destroyStage) {
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();
TessellatorHelper.prepareFastRender();
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();
BlockState blockState = tileEntityIn.getBlockState();
BlockState renderedState = AllBlocks.LOGISTICIANS_TABLE_INDICATOR.get().getDefaultState();
@ -63,5 +51,4 @@ public class LogisticiansTableTileEntityRenderer extends TileEntityRenderer<Logi
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.crushed_iron": "Crushed Iron 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_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"
]
}