From a391d74810f043a2cac5855e7bae9b78024ee4ab Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sun, 27 Oct 2019 14:15:39 +0100 Subject: [PATCH] Cart Assembler and Agile Contraptions - Started generalizing contraptions for other means of transportation - Added mounted contraptions for minecarts --- .../java/com/simibubi/create/AllBlocks.java | 4 + .../java/com/simibubi/create/AllEntities.java | 4 + .../java/com/simibubi/create/AllItems.java | 2 + .../foundation/utility/BufferManipulator.java | 84 +++-- .../foundation/utility/TessellatorHelper.java | 17 + .../create/foundation/utility/VecHelper.java | 14 + .../contraptions/CachedBufferReloader.java | 4 +- .../contraptions/receivers/DrillBlock.java | 14 +- .../receivers/DrillTileEntityRenderer.java | 10 +- .../receivers/HarvesterBlock.java | 6 +- .../HarvesterTileEntityRenderer.java | 24 +- ...slationConstruct.java => Contraption.java} | 326 ++++++++---------- .../constructs/ContraptionRenderer.java | 102 ++++++ .../constructs/ContraptionVertexBuffer.java | 70 ++++ .../constructs/IHaveMovementBehavior.java | 43 ++- .../MechanicalPistonTileEntity.java | 120 +++---- .../MechanicalPistonTileEntityRenderer.java | 85 +---- .../constructs/MovingConstructHandler.java | 4 +- .../constructs/PistonContraption.java | 155 +++++++++ .../TranslationConstructVertexBuffer.java | 33 -- .../mounted/CartAssemblerBlock.java | 152 ++++++++ .../constructs/mounted/ContraptionEntity.java | 198 +++++++++++ .../mounted/ContraptionEntityRenderer.java | 97 ++++++ .../mounted/MountedContraption.java | 90 +++++ .../contraptions/redstone/ContactBlock.java | 5 +- .../transport/CardboardBoxEntityRenderer.java | 13 - .../LogisticiansTableTileEntityRenderer.java | 17 +- .../create/blockstates/cart_assembler.json | 20 ++ .../create/blockstates/minecart_anchor.json | 12 + .../resources/assets/create/lang/en_us.json | 2 + .../create/models/block/cart_assembler.json | 93 +++++ .../models/block/cart_assembler_powered.json | 6 + .../create/models/block/minecart_anchor.json | 32 ++ .../create/models/item/cart_assembler.json | 3 + .../create/models/item/motion_scarf.json | 6 + .../assets/create/models/item/time_scarf.json | 6 + .../create/textures/item/motion_scarf.png | Bin 0 -> 603 bytes .../create/textures/item/time_scarf.png | Bin 0 -> 630 bytes .../data/minecraft/tags/blocks/rails.json | 6 + 39 files changed, 1417 insertions(+), 462 deletions(-) rename src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/{TranslationConstruct.java => Contraption.java} (69%) create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionRenderer.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionVertexBuffer.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/PistonContraption.java delete mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/TranslationConstructVertexBuffer.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/CartAssemblerBlock.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntity.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntityRenderer.java create mode 100644 src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/MountedContraption.java create mode 100644 src/main/resources/assets/create/blockstates/cart_assembler.json create mode 100644 src/main/resources/assets/create/blockstates/minecart_anchor.json create mode 100644 src/main/resources/assets/create/models/block/cart_assembler.json create mode 100644 src/main/resources/assets/create/models/block/cart_assembler_powered.json create mode 100644 src/main/resources/assets/create/models/block/minecart_anchor.json create mode 100644 src/main/resources/assets/create/models/item/cart_assembler.json create mode 100644 src/main/resources/assets/create/models/item/motion_scarf.json create mode 100644 src/main/resources/assets/create/models/item/time_scarf.json create mode 100644 src/main/resources/assets/create/textures/item/motion_scarf.png create mode 100644 src/main/resources/assets/create/textures/item/time_scarf.png create mode 100644 src/main/resources/data/minecraft/tags/blocks/rails.json diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 03d479a7e..e6f19d687 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -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()), diff --git a/src/main/java/com/simibubi/create/AllEntities.java b/src/main/java/com/simibubi/create/AllEntities.java index 74bd8d7bf..d4095dc29 100644 --- a/src/main/java/com/simibubi/create/AllEntities.java +++ b/src/main/java/com/simibubi/create/AllEntities.java @@ -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); } } diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 2e50fd542..f452f968d 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -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())), diff --git a/src/main/java/com/simibubi/create/foundation/utility/BufferManipulator.java b/src/main/java/com/simibubi/create/foundation/utility/BufferManipulator.java index 0fd541163..2888abfe8 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/BufferManipulator.java +++ b/src/main/java/com/simibubi/create/foundation/utility/BufferManipulator.java @@ -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; + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java b/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java index 052442c47..81f529ac2 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java @@ -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; @@ -29,6 +30,22 @@ public class TessellatorHelper { Vec3d view = renderInfo.getProjectedView(); 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); diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index 25e52117b..cc22db867 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -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)); + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/CachedBufferReloader.java b/src/main/java/com/simibubi/create/modules/contraptions/CachedBufferReloader.java index 04914c81f..862496802 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/CachedBufferReloader.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/CachedBufferReloader.java @@ -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 { @Override protected void apply(String splashList, IResourceManager resourceManagerIn, IProfiler profilerIn) { KineticTileEntityRenderer.invalidateCache(); - MechanicalPistonTileEntityRenderer.invalidateCache(); + ContraptionRenderer.invalidateCache(); MechanicalBearingTileEntityRenderer.invalidateCache(); ColoredIndicatorRenderer.invalidateCache(); } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillBlock.java index ba22574aa..efe254c46 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillBlock.java @@ -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; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntityRenderer.java index b472f171c..9d1a7daf8 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/DrillTileEntityRenderer.java @@ -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)); } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterBlock.java index 81b5f58c8..21d42444e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterBlock.java @@ -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 diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterTileEntityRenderer.java index 49fed62e0..4ab6337d1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/HarvesterTileEntityRenderer.java @@ -58,40 +58,42 @@ public class HarvesterTileEntityRenderer extends TileEntityRenderer blocks; protected List> actors; - protected AxisAlignedBB constructCollisionBox; - protected AxisAlignedBB pistonCollisionBox; - protected Set 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 getChassisClusterAt(World world, BlockPos pos) { + List search = new LinkedList<>(); + Set visited = new HashSet<>(); + List 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 getColliders(World world, Direction movementDirection) { @@ -101,86 +117,17 @@ public class TranslationConstruct { return cachedColliders; } - private boolean collectExtensions(World world, BlockPos pos, Direction direction) { - List 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 frontier = new ArrayList<>(); Set 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 frontier) { + return true; + } + private boolean moveBlock(World world, BlockPos pos, Direction direction, List frontier, Set visited) { visited.add(pos); @@ -349,42 +300,8 @@ public class TranslationConstruct { return true; } - private static List getChassisClusterAt(World world, BlockPos pos) { - List search = new LinkedList<>(); - Set visited = new HashSet<>(); - List 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(); @@ -452,19 +387,22 @@ public class TranslationConstruct { c.put("Data", block.nbt); blocks.add(c); } + + ListNBT actorsNBT = new ListNBT(); + for (MutablePair 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 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> getActors() { + return actors; + } + +} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionRenderer.java new file mode 100644 index 000000000..f7cacbc8d --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionRenderer.java @@ -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 cachedConstructs; + protected static PlacementSimulationWorld renderWorld; + + public static 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 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(); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionVertexBuffer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionVertexBuffer.java new file mode 100644 index 000000000..fc2c81851 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/ContraptionVertexBuffer.java @@ -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; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/IHaveMovementBehavior.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/IHaveMovementBehavior.java index 47c1daa7d..8d749567b 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/IHaveMovementBehavior.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/IHaveMovementBehavior.java @@ -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; } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java index cdc2d6721..19968f290 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntity.java @@ -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 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 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 pair : movingConstruct.actors) { + for (MutablePair 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 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 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 pair : movingConstruct.actors) - pair.right.movementVec = new Vec3d( + for (MutablePair 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); } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntityRenderer.java index 02e121c0b..a064e9bda 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MechanicalPistonTileEntityRenderer.java @@ -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 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 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(); - } - } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MovingConstructHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MovingConstructHandler.java index 703c79265..4463f285d 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MovingConstructHandler.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/MovingConstructHandler.java @@ -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(); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/PistonContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/PistonContraption.java new file mode 100644 index 000000000..29a406ce9 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/PistonContraption.java @@ -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 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 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; + } +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/TranslationConstructVertexBuffer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/TranslationConstructVertexBuffer.java deleted file mode 100644 index d562ea39f..000000000 --- a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/TranslationConstructVertexBuffer.java +++ /dev/null @@ -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; - } - -} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/CartAssemblerBlock.java new file mode 100644 index 000000000..e81dd354a --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/CartAssemblerBlock.java @@ -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 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 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 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 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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntity.java new file mode 100644 index 000000000..e1d336cab --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntity.java @@ -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 entityBuilder = (EntityType.Builder) 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()); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntityRenderer.java new file mode 100644 index 000000000..5e83d1fdf --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/ContraptionEntityRenderer.java @@ -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 { + + 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); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/MountedContraption.java new file mode 100644 index 000000000..dcbee14aa --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/receivers/constructs/mounted/MountedContraption.java @@ -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 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 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; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/redstone/ContactBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/redstone/ContactBlock.java index d63a21bcf..93f076fcd 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/redstone/ContactBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/redstone/ContactBlock.java @@ -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; diff --git a/src/main/java/com/simibubi/create/modules/logistics/transport/CardboardBoxEntityRenderer.java b/src/main/java/com/simibubi/create/modules/logistics/transport/CardboardBoxEntityRenderer.java index d261bdadb..4c4637437 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/transport/CardboardBoxEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/logistics/transport/CardboardBoxEntityRenderer.java @@ -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 EntityRendererPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0q{vgK~y+TV;}|m z|NkG#LI6f64F(&+jzC$Mp!ZSt|3k+&z}0UIKMJN9VVVL~*??(uU~AzIwsvmX42Gcg z1h5zgT)wq~5o8Dpl#c=m!yEs<|N4R9-M9A)1r`Nhv3n05Gpwsz0A?c_gkk_pqrHeL z1D`S%!>5nmz*tCxo8cGG9Uw!L6l9^Q85sOmS|hx0ka6$-Y_D{Ne}DfoynXS3;qAK* z3{0#{42(cuGqRur71$8FN)Lt^_EQ;|pkiRaE6dKn%*DhYEFr)kB`?gt%E83I!j4b^ z(uk}XB*qAfnnd5C|Ftm{3_N0N3}0UTV)*;*AH$cgpBZ?#dBO4^P~6lArvLu=%W&@Z zDX<~%FaQPEt9$Q&EFrKVAi(^JiDAlwrC|1*7q=MFL*l{g$Io6eoZEW}%!V7FEUL(` zYSVUxFh5TqPYA3LS(Dl`C5D-67J}I-5^7)?1i%IqMKt}dNY4X19i$Oth_j6)SkvAk z$H59=hJkFqb?+Wn3Gr!002ovPDHLkV1kV#{-yu` literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/create/textures/item/time_scarf.png b/src/main/resources/assets/create/textures/item/time_scarf.png new file mode 100644 index 0000000000000000000000000000000000000000..1841a8745cf655a226cc872683f7ac41bb505fb2 GIT binary patch literal 630 zcmV-+0*U>JP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0t-n*K~y+TV;}{5 z|Nb4yLI6f64F=JZH$YjK;P$pD|3UP@b(_I@Qs(RgQ4EYQO-pkFz%(*AxvT0w!@o}q z4F5hbT;;7|=%`6#xVYm0+)|JsOi(ro2rn-Ge{xUT|K2%w7~cH#WO(yGl0oNV34eGE4qK44hTn$6&v)ejB}Mp)E@ z<`@3|aqkX;xVSjO%a<>~HhF3yqD?$#9>cnIOTg^kfB!OkzjX?12;2oy(R8IwqA3JvfOdkbm4ho6^v!A_w!LSQx00_Vh5R+D7xO(vnTr)`HiwAcQnq(E= zE|5@A0n;D=_Ci8U!~fLyEQU8felX<4dw?ZChJb8(@c03k4>JrVc5C}$uovJ4fTFJ; zrxI+)lod-+G=Tuv*|VC#Y!HA4A}A%!NpS}Yf&vm|$hlj0F*LopejlC+;mIE40%YtM z5&D16rHB8`JYD{aX)2t<8 literal 0 HcmV?d00001 diff --git a/src/main/resources/data/minecraft/tags/blocks/rails.json b/src/main/resources/data/minecraft/tags/blocks/rails.json new file mode 100644 index 000000000..50ede31ea --- /dev/null +++ b/src/main/resources/data/minecraft/tags/blocks/rails.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "create:cart_assembler" + ] +} \ No newline at end of file