diff --git a/README.md b/README.md
index 8e864c398..3d8590c60 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Create
-
+
@@ -19,7 +19,7 @@ Check out the wiki and in-game Tool-tips for further info on how to use these fe
[](https://www.patreon.com/simibubi "Support Us")
- Support for Minecraft 1.12: Not planned
-- Support for Minecraft 1.16: Porting efforts will begin soon.
+- Support for Minecraft 1.16: Porting efforts are making good progress.
- Support for Fabric: Not planned
Find out more about Create on our Project Page
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java
index 6b93996d4..e5b89a27d 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BellMovementBehaviour.java
@@ -18,8 +18,7 @@ public class BellMovementBehaviour extends MovementBehaviour {
public void onSpeedChanged(MovementContext context, Vec3d oldMotion, Vec3d motion) {
double dotProduct = oldMotion.dotProduct(motion);
- if (dotProduct <= 0 && (context.relativeMotion.length() != 0 || context.rotation.length() == 0)
- || context.firstMovement)
+ if (dotProduct <= 0 && (context.relativeMotion.length() != 0) || context.firstMovement)
context.world.playSound(null, new BlockPos(context.position), SoundEvents.BLOCK_BELL_USE,
SoundCategory.BLOCKS, 2.0F, 1.0F);
}
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java
index f91b4dca7..a3ff3fa8b 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/PortableStorageInterfaceMovement.java
@@ -138,7 +138,7 @@ public class PortableStorageInterfaceMovement extends MovementBehaviour {
private Optional getCurrentFacingIfValid(MovementContext context) {
Vec3d directionVec = new Vec3d(context.state.get(PortableStorageInterfaceBlock.FACING)
.getDirectionVec());
- directionVec = VecHelper.rotate(directionVec, context.rotation.x, context.rotation.y, context.rotation.z);
+ directionVec = context.rotation.apply(directionVec);
Direction facingFromVector = Direction.getFacingFromVector(directionVec.x, directionVec.y, directionVec.z);
if (directionVec.distanceTo(new Vec3d(facingFromVector.getDirectionVec())) > 1 / 8f)
return Optional.empty();
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java
index ac78f32f6..5a608e69d 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/DispenserMovementBehaviour.java
@@ -5,7 +5,6 @@ import java.util.HashMap;
import javax.annotation.ParametersAreNonnullByDefault;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
-import com.simibubi.create.foundation.utility.VecHelper;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.Block;
@@ -63,7 +62,7 @@ public class DispenserMovementBehaviour extends DropperMovementBehaviour {
}
Vec3d facingVec = new Vec3d(context.state.get(DispenserBlock.FACING).getDirectionVec());
- facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
+ facingVec = context.rotation.apply(facingVec);
facingVec.normalize();
Direction clostestFacing = Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z);
ContraptionBlockSource blockSource = new ContraptionBlockSource(context, pos, clostestFacing);
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java
index bcd4e4b59..b66d3bb75 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/dispenser/MovedDefaultDispenseItemBehaviour.java
@@ -1,7 +1,6 @@
package com.simibubi.create.content.contraptions.components.actors.dispenser;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
-import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.DispenserBlock;
import net.minecraft.entity.item.ItemEntity;
@@ -37,7 +36,7 @@ public class MovedDefaultDispenseItemBehaviour implements IMovedDispenseItemBeha
@Override
public ItemStack dispense(ItemStack itemStack, MovementContext context, BlockPos pos) {
Vec3d facingVec = new Vec3d(context.state.get(DispenserBlock.FACING).getDirectionVec());
- facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
+ facingVec = context.rotation.apply(facingVec);
facingVec.normalize();
Direction closestToFacing = getClosestFacingDirection(facingVec);
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java
index 11a175391..9dd309231 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java
@@ -13,7 +13,6 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov
import com.simibubi.create.content.logistics.item.filter.FilterItem;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.utility.NBTHelper;
-import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.entity.player.PlayerInventory;
@@ -52,7 +51,7 @@ public class DeployerMovementBehaviour extends MovementBehaviour {
public void activate(MovementContext context, BlockPos pos, DeployerFakePlayer player, Mode mode) {
Vec3d facingVec = new Vec3d(context.state.get(DeployerBlock.FACING)
.getDirectionVec());
- facingVec = VecHelper.rotate(facingVec, context.rotation.x, context.rotation.y, context.rotation.z);
+ facingVec = context.rotation.apply(facingVec);
Vec3d vec = context.position.subtract(facingVec.scale(2));
player.rotationYaw = ContraptionEntity.yawFromVector(facingVec);
player.rotationPitch = ContraptionEntity.pitchFromVector(facingVec) - 90;
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java
index 76ea8832a..fadd0ef75 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java
@@ -332,9 +332,14 @@ public abstract class Contraption {
frontier.add(otherPartPos);
}
+ // Cart assemblers attach themselves
+ BlockState stateBelow = world.getBlockState(pos.down());
+ if (!visited.contains(pos.down()) && AllBlocks.CART_ASSEMBLER.has(stateBelow))
+ frontier.add(pos.down());
+
Map superglue = SuperGlueHandler.gatherGlue(world, pos);
- // Slime blocks drag adjacent blocks if possible
+ // Slime blocks and super glue drag adjacent blocks if possible
boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock;
for (Direction offset : Direction.values()) {
BlockPos offsetPos = pos.offset(offset);
@@ -348,16 +353,13 @@ public abstract class Contraption {
}
boolean wasVisited = visited.contains(offsetPos);
- boolean isMinecartAssembler = AllBlocks.CART_ASSEMBLER.has(blockState) && offset == Direction.DOWN;
boolean faceHasGlue = superglue.containsKey(offset);
boolean blockAttachedTowardsFace =
BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite());
boolean brittle = BlockMovementTraits.isBrittle(blockState);
- if (!wasVisited
- && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue || isMinecartAssembler))
+ if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue))
frontier.add(offsetPos);
-
if (faceHasGlue)
addGlue(superglue.get(offset));
}
@@ -763,7 +765,7 @@ public abstract class Contraption {
ctx.position = null;
ctx.motion = Vec3d.ZERO;
ctx.relativeMotion = Vec3d.ZERO;
- ctx.rotation = Vec3d.ZERO;
+ ctx.rotation = v -> v;
});
}
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java
index d273554b9..ff77620b8 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java
@@ -32,6 +32,7 @@ import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.Direction;
+import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.ReuseableStream;
import net.minecraft.util.math.AxisAlignedBB;
@@ -71,8 +72,18 @@ public class ContraptionCollider {
Vec3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO);
double conRotX = contraptionRotation.x;
- double conRotY = contraptionRotation.y;
+ double conRotY = contraptionRotation.y + contraptionEntity.getInitialYaw();
double conRotZ = contraptionRotation.z;
+
+ double reverseYaw = 0;
+
+ // Collision algorithm does not support rotation around two axes -> rotate
+ // entities manually
+ if (conRotZ != 0 && contraptionRotation.y != 0) {
+ reverseYaw = contraptionRotation.y;
+ conRotY = contraptionEntity.getInitialYaw();
+ }
+
Vec3d contraptionCentreOffset = contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0);
boolean axisAlignedCollision = contraptionRotation.equals(Vec3d.ZERO);
Matrix3d rotation = null;
@@ -100,13 +111,15 @@ public class ContraptionCollider {
Vec3d centerY = new Vec3d(0, entityBounds.getYSize() / 2, 0);
Vec3d motion = entity.getMotion();
- Vec3d position = entityPosition.subtract(contraptionCentreOffset)
- .add(centerY);
+ Vec3d position = entityPosition;
+ position = position.subtract(contraptionCentreOffset);
+ position = position.add(centerY);
position = position.subtract(contraptionPosition);
+ position = VecHelper.rotate(position, -reverseYaw, Axis.Y);
position = rotation.transform(position);
- position = position.add(centerOfBlock)
- .subtract(centerY)
- .subtract(entityPosition);
+ position = position.add(centerOfBlock);
+ position = position.subtract(centerY);
+ position = position.subtract(entityPosition);
// Find all potential block shapes to collide with
AxisAlignedBB localBB = entityBounds.offset(position)
@@ -186,11 +199,13 @@ public class ContraptionCollider {
Vec3d totalResponse = collisionResponse.getValue();
Vec3d motionResponse = allowedMotion.getValue();
boolean hardCollision = !totalResponse.equals(Vec3d.ZERO);
+
rotation.transpose();
motionResponse = rotation.transform(motionResponse)
.add(contraptionMotion);
totalResponse = rotation.transform(totalResponse);
+ totalResponse = VecHelper.rotate(totalResponse, reverseYaw, Axis.Y);
rotation.transpose();
if (futureCollision.isTrue() && playerType != PlayerType.SERVER) {
@@ -206,7 +221,7 @@ public class ContraptionCollider {
entity.fallDistance = 0;
entity.onGround = true;
contraptionEntity.collidingEntities.add(entity);
- if (playerType != PlayerType.SERVER)
+ if (playerType != PlayerType.SERVER)
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
}
@@ -235,6 +250,7 @@ public class ContraptionCollider {
continue;
}
+
totalResponse = totalResponse.add(contactPointMotion);
Vec3d allowedMovement = getAllowedMovement(totalResponse, entity);
contraptionEntity.collidingEntities.add(entity);
@@ -245,7 +261,7 @@ public class ContraptionCollider {
if (playerType != PlayerType.CLIENT)
continue;
-
+
double d0 = entity.getX() - entity.prevPosX - contactPointMotion.x;
double d1 = entity.getZ() - entity.prevPosZ - contactPointMotion.z;
float limbSwing = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java
index ed74360c3..ea4a3e165 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java
@@ -25,6 +25,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.AngleHelper;
+import com.simibubi.create.foundation.utility.Couple;
+import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
@@ -33,7 +35,6 @@ import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.IProjectile;
-import net.minecraft.entity.item.BoatEntity;
import net.minecraft.entity.item.HangingEntity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
@@ -49,10 +50,12 @@ import net.minecraft.network.PacketBuffer;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
+import net.minecraft.network.datasync.IDataSerializer;
import net.minecraft.tags.BlockTags;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Direction;
+import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@@ -69,26 +72,48 @@ import net.minecraftforge.fml.network.PacketDistributor;
public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData {
+ public static final IDataSerializer> OPTIONAL_DIRECTION =
+ new IDataSerializer>() {
+
+ public void write(PacketBuffer buffer, Optional opt) {
+ buffer.writeVarInt(opt.map(Direction::ordinal)
+ .orElse(-1) + 1);
+ }
+
+ public Optional read(PacketBuffer buffer) {
+ int i = buffer.readVarInt();
+ return i == 0 ? Optional.empty() : Optional.of(Direction.values()[i - 1]);
+ }
+
+ public Optional copyValue(Optional opt) {
+ return Optional.ofNullable(opt.orElse(null));
+ }
+ };
+
+ static {
+ DataSerializers.registerSerializer(OPTIONAL_DIRECTION);
+ }
+
+ final List collidingEntities = new ArrayList<>();
+
protected Contraption contraption;
- protected float initialAngle;
- protected float forcedAngle;
protected BlockPos controllerPos;
protected Vec3d motionBeforeStall;
+ protected boolean forceAngle;
protected boolean stationary;
protected boolean initialized;
- final List collidingEntities = new ArrayList<>();
private boolean isSerializingFurnaceCart;
private boolean attachedExtraInventories;
private boolean prevPosInvalid;
private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL);
+
private static final DataParameter STALLED =
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
-
private static final DataParameter> COUPLING =
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID);
- private static final DataParameter> COUPLED_CART =
- EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID);
+ private static final DataParameter> INITIAL_ORIENTATION =
+ EntityDataManager.createKey(ContraptionEntity.class, ContraptionEntity.OPTIONAL_DIRECTION);
public float prevYaw;
public float prevPitch;
@@ -108,23 +133,15 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
stationary = entityTypeIn == AllEntityTypes.STATIONARY_CONTRAPTION.get();
isSerializingFurnaceCart = false;
attachedExtraInventories = false;
- forcedAngle = -1;
prevPosInvalid = true;
}
- public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) {
+ public static ContraptionEntity createMounted(World world, Contraption contraption,
+ Optional initialOrientation) {
ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.CONTRAPTION.get(), world);
entity.contraptionCreated(contraption);
- entity.initialAngle = initialAngle;
- entity.forceYaw(initialAngle);
- return entity;
- }
-
- public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle,
- Direction facing) {
- ContraptionEntity entity = createMounted(world, contraption, initialAngle);
- entity.forcedAngle = facing.getHorizontalAngle();
- entity.forceYaw(entity.forcedAngle);
+ initialOrientation.ifPresent(entity::setInitialOrientation);
+ entity.startAtInitialYaw();
return entity;
}
@@ -134,6 +151,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return entity;
}
+ public void reOrientate(Direction newInitialAngle) {
+ setInitialOrientation(newInitialAngle);
+ }
+
protected void contraptionCreated(Contraption contraption) {
this.contraption = contraption;
if (contraption == null)
@@ -220,7 +241,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
BlockPos seat = contraption.getSeat(passenger.getUniqueID());
if (seat == null)
return null;
- Vec3d transformedVector = toGlobalVector(new Vec3d(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5))
+ Vec3d transformedVector = toGlobalVector(new Vec3d(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5), 1)
.add(VecHelper.getCenterOf(BlockPos.ZERO))
.subtract(0.5, ySize, 0.5);
return transformedVector;
@@ -268,20 +289,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return true;
}
- public Vec3d toGlobalVector(Vec3d localVec) {
+ public Vec3d toGlobalVector(Vec3d localVec, float partialTicks) {
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
localVec = localVec.subtract(rotationOffset);
- localVec = VecHelper.rotate(localVec, getRotationVec());
+ localVec = applyRotation(localVec, partialTicks);
localVec = localVec.add(rotationOffset)
.add(getAnchorVec());
return localVec;
}
- public Vec3d toLocalVector(Vec3d globalVec) {
+ public Vec3d toLocalVector(Vec3d globalVec, float partialTicks) {
Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
globalVec = globalVec.subtract(getAnchorVec())
.subtract(rotationOffset);
- globalVec = VecHelper.rotate(globalVec, getRotationVec().scale(-1));
+ globalVec = reverseRotation(globalVec, partialTicks);
globalVec = globalVec.add(rotationOffset);
return globalVec;
}
@@ -311,7 +332,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
if (getMotion().length() < 1 / 4098f)
setMotion(Vec3d.ZERO);
-
move(getMotion().x, getMotion().y, getMotion().z);
if (ContraptionCollider.collideBlocks(this))
getController().collided();
@@ -323,6 +343,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
prevRoll = roll;
super.tick();
+
}
public void tickAsPassenger(Entity e) {
@@ -330,51 +351,68 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
boolean pauseWhileRotating = false;
boolean rotating = false;
boolean wasStalled = isStalled();
-
- Entity riding = e;
- while (riding.getRidingEntity() != null)
- riding = riding.getRidingEntity();
- if (!attachedExtraInventories) {
- contraption.addExtraInventories(riding);
- attachedExtraInventories = true;
- }
-
if (contraption instanceof MountedContraption) {
MountedContraption mountedContraption = (MountedContraption) contraption;
rotationLock = mountedContraption.rotationMode == CartMovementMode.ROTATION_LOCKED;
pauseWhileRotating = mountedContraption.rotationMode == CartMovementMode.ROTATE_PAUSED;
}
+ Entity riding = e;
+ while (riding.getRidingEntity() != null)
+ riding = riding.getRidingEntity();
+
boolean isOnCoupling = false;
UUID couplingId = getCouplingId();
isOnCoupling = couplingId != null && riding instanceof AbstractMinecartEntity;
+ if (!attachedExtraInventories) {
+ attachInventoriesFromRidingCarts(riding, isOnCoupling, couplingId);
+ attachedExtraInventories = true;
+ }
+
if (isOnCoupling) {
-// MinecartCoupling coupling = MinecartCouplingHandler.getCoupling(world, couplingId);
-// if (coupling != null && coupling.areBothEndsPresent()) {
-// boolean notOnMainCart = !coupling.getId()
-// .equals(riding.getUniqueID());
-// Vec3d positionVec = coupling.asCouple()
-// .get(notOnMainCart)
-// .getPositionVec();
-// prevYaw = yaw;
-// prevPitch = pitch;
-// double diffZ = positionVec.z - riding.getZ();
-// double diffX = positionVec.x - riding.getX();
-// yaw = (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI);
-// pitch = (float) (Math.atan2(positionVec.y - getY(), Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180
-// / Math.PI);
-//
-// if (notOnMainCart) {
-// yaw += 180;
-// }
-// }
+ Couple coupledCarts = getCoupledCartsIfPresent();
+ if (coupledCarts != null) {
+
+ Vec3d positionVec = coupledCarts.getFirst()
+ .cart()
+ .getPositionVec();
+ Vec3d coupledVec = coupledCarts.getSecond()
+ .cart()
+ .getPositionVec();
+
+ double diffX = positionVec.x - coupledVec.x;
+ double diffY = positionVec.y - coupledVec.y;
+ double diffZ = positionVec.z - coupledVec.z;
+
+ prevYaw = yaw;
+ prevPitch = pitch;
+ yaw = (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI);
+ pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI);
+
+ if (couplingId.equals(riding.getUniqueID())) {
+ pitch *= -1;
+ yaw += 180;
+ }
+
+ }
+
} else if (!wasStalled) {
Vec3d movementVector = riding.getMotion();
- if (riding instanceof BoatEntity)
+ if (!(riding instanceof AbstractMinecartEntity))
movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ);
Vec3d motion = movementVector.normalize();
+ if (!dataManager.get(INITIAL_ORIENTATION)
+ .isPresent() && !world.isRemote) {
+ if (motion.length() > 0) {
+ Direction facingFromVector = Direction.getFacingFromVector(motion.x, motion.y, motion.z);
+ if (facingFromVector.getAxis()
+ .isHorizontal())
+ setInitialOrientation(facingFromVector);
+ }
+ }
+
if (!rotationLock) {
if (motion.length() > 0) {
targetYaw = yawFromVector(motion);
@@ -415,52 +453,109 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
}
}
- if (!isStalled() && (riding instanceof FurnaceMinecartEntity)) {
- FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding;
+ if (world.isRemote)
+ return;
- // Notify to not trigger serialization side-effects
- isSerializingFurnaceCart = true;
- CompoundNBT nbt = furnaceCart.serializeNBT();
- isSerializingFurnaceCart = false;
-
- int fuel = nbt.getInt("Fuel");
- int fuelBefore = fuel;
- double pushX = nbt.getDouble("PushX");
- double pushZ = nbt.getDouble("PushZ");
-
- int i = MathHelper.floor(furnaceCart.getX());
- int j = MathHelper.floor(furnaceCart.getY());
- int k = MathHelper.floor(furnaceCart.getZ());
- if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k))
- .isIn(BlockTags.RAILS))
- --j;
-
- BlockPos blockpos = new BlockPos(i, j, k);
- BlockState blockstate = this.world.getBlockState(blockpos);
- if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS))
- if (fuel > 1)
- riding.setMotion(riding.getMotion()
- .normalize()
- .scale(1));
- if (fuel < 5 && contraption != null) {
- ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false);
- if (!coal.isEmpty())
- fuel += 3600;
- }
-
- if (fuel != fuelBefore || pushX != 0 || pushZ != 0) {
- nbt.putInt("Fuel", fuel);
- nbt.putDouble("PushX", 0);
- nbt.putDouble("PushZ", 0);
- furnaceCart.deserializeNBT(nbt);
+ if (!isStalled()) {
+ if (isOnCoupling) {
+ Couple coupledCarts = getCoupledCartsIfPresent();
+ if (coupledCarts == null)
+ return;
+ coupledCarts.map(MinecartController::cart)
+ .forEach(this::powerFurnaceCartWithFuelFromStorage);
+ return;
}
+ powerFurnaceCartWithFuelFromStorage(riding);
}
}
+ protected void powerFurnaceCartWithFuelFromStorage(Entity riding) {
+ if (!(riding instanceof FurnaceMinecartEntity))
+ return;
+ FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding;
+
+ // Notify to not trigger serialization side-effects
+ isSerializingFurnaceCart = true;
+ CompoundNBT nbt = furnaceCart.serializeNBT();
+ isSerializingFurnaceCart = false;
+
+ int fuel = nbt.getInt("Fuel");
+ int fuelBefore = fuel;
+ double pushX = nbt.getDouble("PushX");
+ double pushZ = nbt.getDouble("PushZ");
+
+ int i = MathHelper.floor(furnaceCart.getX());
+ int j = MathHelper.floor(furnaceCart.getY());
+ int k = MathHelper.floor(furnaceCart.getZ());
+ if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k))
+ .isIn(BlockTags.RAILS))
+ --j;
+
+ BlockPos blockpos = new BlockPos(i, j, k);
+ BlockState blockstate = this.world.getBlockState(blockpos);
+ if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS))
+ if (fuel > 1)
+ riding.setMotion(riding.getMotion()
+ .normalize()
+ .scale(1));
+ if (fuel < 5 && contraption != null) {
+ ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false);
+ if (!coal.isEmpty())
+ fuel += 3600;
+ }
+
+ if (fuel != fuelBefore || pushX != 0 || pushZ != 0) {
+ nbt.putInt("Fuel", fuel);
+ nbt.putDouble("PushX", 0);
+ nbt.putDouble("PushZ", 0);
+ furnaceCart.deserializeNBT(nbt);
+ }
+ }
+
+ @Nullable
+ public Couple getCoupledCartsIfPresent() {
+ UUID couplingId = getCouplingId();
+ if (couplingId == null)
+ return null;
+ MinecartController controller = CapabilityMinecartController.getIfPresent(world, couplingId);
+ if (controller == null || !controller.isPresent())
+ return null;
+ UUID coupledCart = controller.getCoupledCart(true);
+ MinecartController coupledController = CapabilityMinecartController.getIfPresent(world, coupledCart);
+ if (coupledController == null || !coupledController.isPresent())
+ return null;
+ return Couple.create(controller, coupledController);
+ }
+
+ protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) {
+ if (isOnCoupling) {
+ Couple coupledCarts = getCoupledCartsIfPresent();
+ if (coupledCarts == null)
+ return;
+ coupledCarts.map(MinecartController::cart)
+ .forEach(contraption::addExtraInventories);
+ return;
+ }
+ contraption.addExtraInventories(riding);
+ }
+
+ public Vec3d applyRotation(Vec3d localPos, float partialTicks) {
+ localPos = VecHelper.rotate(localPos, getRoll(partialTicks), Axis.X);
+ localPos = VecHelper.rotate(localPos, getInitialYaw(), Axis.Y);
+ localPos = VecHelper.rotate(localPos, getPitch(partialTicks), Axis.Z);
+ localPos = VecHelper.rotate(localPos, getYaw(partialTicks), Axis.Y);
+ return localPos;
+ }
+
+ public Vec3d reverseRotation(Vec3d localPos, float partialTicks) {
+ localPos = VecHelper.rotate(localPos, -getYaw(partialTicks), Axis.Y);
+ localPos = VecHelper.rotate(localPos, -getPitch(partialTicks), Axis.Z);
+ localPos = VecHelper.rotate(localPos, -getInitialYaw(), Axis.Y);
+ localPos = VecHelper.rotate(localPos, -getRoll(partialTicks), Axis.X);
+ return localPos;
+ }
+
public void tickActors() {
- Vec3d rotationVec = getRotationVec();
- Vec3d reversedRotationVec = rotationVec.scale(-1);
- Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO);
boolean stalledPreviously = contraption.stalled;
if (!world.isRemote)
@@ -471,12 +566,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
BlockInfo blockInfo = pair.left;
MovementBehaviour actor = Contraption.getMovement(blockInfo.state);
- Vec3d actorPosition = new Vec3d(blockInfo.pos);
- actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
- actorPosition = VecHelper.rotate(actorPosition, rotationVec);
- actorPosition = actorPosition.add(rotationOffset)
- .add(getAnchorVec());
-
+ Vec3d actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos)
+ .add(actor.getActiveAreaOffset(context)), 1);
boolean newPosVisited = false;
BlockPos gridPosition = new BlockPos(actorPosition);
Vec3d oldMotion = context.motion;
@@ -486,7 +577,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
if (previousPosition != null) {
context.motion = actorPosition.subtract(previousPosition);
Vec3d relativeMotion = context.motion;
- relativeMotion = VecHelper.rotate(relativeMotion, reversedRotationVec);
+ relativeMotion = reverseRotation(relativeMotion, 1);
context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition)
|| context.relativeMotion.length() > 0 && context.firstMovement;
@@ -514,7 +605,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
}
}
- context.rotation = rotationVec;
+ context.rotation = v -> applyRotation(v, 1);
context.position = actorPosition;
if (actor.isActive(context)) {
@@ -561,6 +652,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override
public void notifyDataManagerChange(DataParameter> key) {
super.notifyDataManagerChange(key);
+ if (key == INITIAL_ORIENTATION)
+ startAtInitialYaw();
}
public void rotate(double roll, double yaw, double pitch) {
@@ -599,7 +692,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public float getYaw(float partialTicks) {
return (getRidingEntity() == null ? 1 : -1)
- * (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) + initialAngle;
+ * (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw));
}
public float getPitch(float partialTicks) {
@@ -620,16 +713,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected void registerData() {
this.dataManager.register(STALLED, false);
this.dataManager.register(COUPLING, Optional.empty());
- this.dataManager.register(COUPLED_CART, Optional.empty());
+ this.dataManager.register(INITIAL_ORIENTATION, Optional.empty());
}
@Override
protected void readAdditional(CompoundNBT compound) {
initialized = compound.getBoolean("Initialized");
contraption = Contraption.fromNBT(world, compound.getCompound("Contraption"));
- initialAngle = compound.getFloat("InitialAngle");
- forceYaw(compound.contains("ForcedYaw") ? compound.getFloat("ForcedYaw") : initialAngle);
dataManager.set(STALLED, compound.getBoolean("Stalled"));
+
+ if (compound.contains("InitialOrientation"))
+ setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class));
+ if (compound.contains("ForceYaw"))
+ startAtYaw(compound.getFloat("ForceYaw"));
+
ListNBT vecNBT = compound.getList("CachedMotion", 6);
if (!vecNBT.isEmpty()) {
motionBeforeStall = new Vec3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2));
@@ -637,20 +734,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall);
setMotion(Vec3d.ZERO);
}
+
if (compound.contains("Controller"))
controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller"));
-
- if (compound.contains("OnCoupling")) {
- setCouplingId(NBTUtil.readUniqueId(compound.getCompound("OnCoupling")));
- setCoupledCart(NBTUtil.readUniqueId(compound.getCompound("CoupledCart")));
- } else {
- setCouplingId(null);
- setCoupledCart(null);
- }
+ setCouplingId(
+ compound.contains("OnCoupling") ? NBTUtil.readUniqueId(compound.getCompound("OnCoupling")) : null);
}
- public void forceYaw(float forcedYaw) {
- targetYaw = yaw = prevYaw = forcedYaw;
+ public void startAtInitialYaw() {
+ startAtYaw(getInitialYaw());
+ }
+
+ public void startAtYaw(float yaw) {
+ targetYaw = this.yaw = prevYaw = yaw;
+ forceAngle = true;
}
public void checkController() {
@@ -679,17 +776,20 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
if (controllerPos != null)
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
- if (forcedAngle != -1)
- compound.putFloat("ForcedYaw", forcedAngle);
- compound.putFloat("InitialAngle", initialAngle);
+ Optional optional = dataManager.get(INITIAL_ORIENTATION);
+ if (optional.isPresent())
+ NBTHelper.writeEnum(compound, "InitialOrientation", optional.get());
+ if (forceAngle) {
+ compound.putFloat("ForceYaw", yaw);
+ forceAngle = false;
+ }
+
compound.putBoolean("Stalled", isStalled());
compound.putBoolean("Initialized", initialized);
- if (getCouplingId() != null) {
+ if (getCouplingId() != null)
compound.put("OnCoupling", NBTUtil.writeUniqueId(getCouplingId()));
- compound.put("CoupledCart", NBTUtil.writeUniqueId(getCoupledCart()));
- }
}
@Override
@@ -715,7 +815,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
if (getContraption() != null) {
remove();
BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5));
- Vec3d rotation = getRotationVec();
+ Vec3d rotation = getRotationVec().add(0, getInitialYaw(), 0);
StructureTransform transform = new StructureTransform(offset, rotation);
contraption.addBlocksToWorld(world, transform);
contraption.addPassengersToWorld(world, transform, getPassengers());
@@ -725,7 +825,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
Vec3d positionVec = getPositionVec();
Vec3d localVec = entity.getPositionVec()
.subtract(positionVec);
- localVec = VecHelper.rotate(localVec, getRotationVec().scale(-1));
+ localVec = VecHelper.rotate(localVec, rotation.scale(-1));
Vec3d transformed = transform.apply(localVec);
entity.setPositionAndUpdate(transformed.x, transformed.y, transformed.z);
}
@@ -844,8 +944,18 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
return false;
}
- public float getInitialAngle() {
- return initialAngle;
+ public void setInitialOrientation(Direction direction) {
+ dataManager.set(INITIAL_ORIENTATION, Optional.of(direction));
+ }
+
+ public Optional getInitialOrientation() {
+ return dataManager.get(INITIAL_ORIENTATION);
+ }
+
+ public float getInitialYaw() {
+ return dataManager.get(INITIAL_ORIENTATION)
+ .orElse(Direction.SOUTH)
+ .getHorizontalAngle();
}
public Vec3d getRotationVec() {
@@ -863,18 +973,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public Vec3d getContactPointMotion(Vec3d globalContactPoint) {
if (prevPosInvalid)
return Vec3d.ZERO;
-
- Vec3d positionVec = getPositionVec();
- Vec3d conMotion = positionVec.subtract(getPrevPositionVec());
- Vec3d conAngularMotion = getRotationVec().subtract(getPrevRotationVec());
- Vec3d contraptionCentreOffset = stationary ? VecHelper.getCenterOf(BlockPos.ZERO) : Vec3d.ZERO.add(0, 0.5, 0);
- Vec3d contactPoint = globalContactPoint.subtract(contraptionCentreOffset)
- .subtract(positionVec);
- contactPoint = VecHelper.rotate(contactPoint, conAngularMotion.x, conAngularMotion.y, conAngularMotion.z);
- contactPoint = contactPoint.add(positionVec)
- .add(contraptionCentreOffset)
- .add(conMotion);
- return contactPoint.subtract(globalContactPoint);
+ Vec3d contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1);
+ return contactPoint.subtract(globalContactPoint)
+ .add(getPositionVec().subtract(getPrevPositionVec()));
}
public boolean canCollideWith(Entity e) {
@@ -915,16 +1016,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
dataManager.set(COUPLING, Optional.ofNullable(id));
}
- @Nullable
- public UUID getCoupledCart() {
- Optional uuid = dataManager.get(COUPLED_CART);
- return uuid.isPresent() ? uuid.get() : null;
- }
-
- public void setCoupledCart(UUID id) {
- dataManager.set(COUPLED_CART, Optional.ofNullable(id));
- }
-
@Override
public boolean isOnePlayerRiding() {
return false;
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java
index af7aff573..7d7cbeba9 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java
@@ -39,13 +39,10 @@ public class ContraptionEntityRenderer extends EntityRenderer
MatrixStack msLocal = getLocalTransform(entity);
MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal };
- float degYaw = entity.getYaw(partialTicks);
- float degPitch = entity.getPitch(partialTicks);
- float degRoll = entity.getRoll(partialTicks);
-
- float angleYaw = (float) (degYaw / 180 * Math.PI);
- float anglePitch = (float) (degPitch / 180 * Math.PI);
- float angleRoll = (float) (degRoll / 180 * Math.PI);
+ float angleInitialYaw = entity.getInitialYaw();
+ float angleYaw = entity.getYaw(partialTicks);
+ float anglePitch = entity.getPitch(partialTicks);
+ float angleRoll = entity.getRoll(partialTicks);
ms.push();
Entity ridingEntity = entity.getRidingEntity();
@@ -80,7 +77,10 @@ public class ContraptionEntityRenderer extends EntityRenderer
MatrixStacker.of(stack)
.nudge(entity.getEntityId())
.centre()
- .rotateRadians(angleRoll, angleYaw, anglePitch)
+ .rotateY(angleYaw)
+ .rotateZ(anglePitch)
+ .rotateY(angleInitialYaw)
+ .rotateX(angleRoll)
.unCentre();
ContraptionRenderer.render(entity.world, entity.getContraption(), ms, msLocal, buffers);
ms.pop();
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java
index 191f19bc3..82fa74d47 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java
@@ -78,8 +78,8 @@ public class ContraptionHandlerClient {
for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class,
new AxisAlignedBB(origin, target))) {
- Vec3d localOrigin = contraptionEntity.toLocalVector(origin);
- Vec3d localTarget = contraptionEntity.toLocalVector(target);
+ Vec3d localOrigin = contraptionEntity.toLocalVector(origin, 1);
+ Vec3d localTarget = contraptionEntity.toLocalVector(target, 1);
Contraption contraption = contraptionEntity.getContraption();
MutableObject mutableResult = new MutableObject<>();
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java
index c3228b4c5..def5748e9 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java
@@ -1,5 +1,7 @@
package com.simibubi.create.content.contraptions.components.structureMovement;
+import java.util.function.UnaryOperator;
+
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
@@ -15,7 +17,7 @@ public class MovementContext {
public Vec3d position;
public Vec3d motion;
public Vec3d relativeMotion;
- public Vec3d rotation;
+ public UnaryOperator rotation;
public World world;
public BlockState state;
public BlockPos localPos;
@@ -36,7 +38,7 @@ public class MovementContext {
firstMovement = true;
motion = Vec3d.ZERO;
relativeMotion = Vec3d.ZERO;
- rotation = Vec3d.ZERO;
+ rotation = v -> v;
position = null;
data = new CompoundNBT();
stall = false;
@@ -56,7 +58,6 @@ public class MovementContext {
MovementContext context = new MovementContext(world, info);
context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE));
context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE));
- context.rotation = VecHelper.readNBT(nbt.getList("Rotation", NBT.TAG_DOUBLE));
if (nbt.contains("Position"))
context.position = VecHelper.readNBT(nbt.getList("Position", NBT.TAG_DOUBLE));
context.stall = nbt.getBoolean("Stall");
@@ -68,7 +69,6 @@ public class MovementContext {
public CompoundNBT writeToNBT(CompoundNBT nbt) {
nbt.put("Motion", VecHelper.writeNBT(motion));
nbt.put("RelativeMotion", VecHelper.writeNBT(relativeMotion));
- nbt.put("Rotation", VecHelper.writeNBT(rotation));
if (position != null)
nbt.put("Position", VecHelper.writeNBT(position));
nbt.putBoolean("Stall", stall);
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java
index 36fb6b837..249e4e84f 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java
@@ -2,6 +2,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.mo
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -12,11 +14,15 @@ import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler;
+import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
+import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.block.ITE;
+import com.simibubi.create.foundation.utility.Couple;
+import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.AbstractRailBlock;
@@ -58,6 +64,7 @@ import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameters;
+import net.minecraftforge.common.util.LazyOptional;
public class CartAssemblerBlock extends AbstractRailBlock
implements ITE, IWrenchable, ISpecialBlockItemRequirement {
@@ -116,56 +123,64 @@ public class CartAssemblerBlock extends AbstractRailBlock
AbstractMinecartEntity cart) {
if (!canAssembleTo(cart))
return;
+ if (world.isRemote)
+ return;
withTileEntityDo(world, pos, te -> {
- if (te.isMinecartUpdateValid()) {
- switch (state.get(RAIL_TYPE)) {
- case POWERED_RAIL:
- if (state.get(POWERED)) {
- assemble(world, pos, cart);
- Direction facing = cart.getAdjustedHorizontalFacing();
- float speed = getRailMaxSpeed(state, world, pos, cart);
- cart.setMotion(facing.getXOffset() * speed, facing.getYOffset() * speed,
- facing.getZOffset() * speed);
- } else {
- disassemble(world, pos, cart);
- Vec3d diff = VecHelper.getCenterOf(pos)
- .subtract(cart.getPositionVec());
- cart.setMotion(diff.x / 16f, 0, diff.z / 16f);
- }
- break;
- case REGULAR:
- if (state.get(POWERED)) {
- assemble(world, pos, cart);
- } else {
- disassemble(world, pos, cart);
- }
- break;
- case ACTIVATOR_RAIL:
- if (state.get(POWERED)) {
- disassemble(world, pos, cart);
- }
- break;
- case DETECTOR_RAIL:
- if (cart.getPassengers()
- .isEmpty()) {
- assemble(world, pos, cart);
- Direction facing = cart.getAdjustedHorizontalFacing();
- float speed = getRailMaxSpeed(state, world, pos, cart);
- cart.setMotion(facing.getXOffset() * speed, facing.getYOffset() * speed,
- facing.getZOffset() * speed);
- } else {
- disassemble(world, pos, cart);
- }
- break;
- default:
- break;
- }
- te.resetTicksSinceMinecartUpdate();
+ if (!te.isMinecartUpdateValid())
+ return;
+
+ CartAssemblerAction action = getActionForCart(state, cart);
+ if (action.shouldAssemble())
+ assemble(world, pos, cart);
+ if (action.shouldDisassemble())
+ disassemble(world, pos, cart);
+ if (action == CartAssemblerAction.ASSEMBLE_ACCELERATE) {
+ Direction facing = cart.getAdjustedHorizontalFacing();
+ float speed = getRailMaxSpeed(state, world, pos, cart);
+ cart.setMotion(facing.getXOffset() * speed, facing.getYOffset() * speed, facing.getZOffset() * speed);
}
+ if (action == CartAssemblerAction.DISASSEMBLE_BRAKE) {
+ Vec3d diff = VecHelper.getCenterOf(pos)
+ .subtract(cart.getPositionVec());
+ cart.setMotion(diff.x / 16f, 0, diff.z / 16f);
+ }
+
});
}
+ public enum CartAssemblerAction {
+ ASSEMBLE, DISASSEMBLE, ASSEMBLE_ACCELERATE, DISASSEMBLE_BRAKE, PASS;
+
+ public boolean shouldAssemble() {
+ return this == ASSEMBLE || this == ASSEMBLE_ACCELERATE;
+ }
+
+ public boolean shouldDisassemble() {
+ return this == DISASSEMBLE || this == DISASSEMBLE_BRAKE;
+ }
+ }
+
+ public static CartAssemblerAction getActionForCart(BlockState state, AbstractMinecartEntity cart) {
+ CartAssembleRailType type = state.get(RAIL_TYPE);
+ boolean powered = state.get(POWERED);
+
+ if (type == CartAssembleRailType.REGULAR)
+ return powered ? CartAssemblerAction.ASSEMBLE : CartAssemblerAction.DISASSEMBLE;
+
+ if (type == CartAssembleRailType.ACTIVATOR_RAIL)
+ return powered ? CartAssemblerAction.DISASSEMBLE : CartAssemblerAction.PASS;
+
+ if (type == CartAssembleRailType.POWERED_RAIL)
+ return powered ? CartAssemblerAction.ASSEMBLE_ACCELERATE : CartAssemblerAction.DISASSEMBLE_BRAKE;
+
+ if (type == CartAssembleRailType.DETECTOR_RAIL)
+ return cart.getPassengers()
+ .isEmpty() ? CartAssemblerAction.ASSEMBLE_ACCELERATE : CartAssemblerAction.DISASSEMBLE;
+
+ return CartAssemblerAction.PASS;
+ }
+
public static boolean canAssembleTo(AbstractMinecartEntity cart) {
return cart.canBeRidden() || cart instanceof FurnaceMinecartEntity || cart instanceof ChestMinecartEntity;
}
@@ -204,34 +219,44 @@ public class CartAssemblerBlock extends AbstractRailBlock
.isEmpty())
return;
+ LazyOptional optional =
+ cart.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
+ if (optional.isPresent() && optional.orElse(null)
+ .isCoupledThroughContraption())
+ return;
+
MountedContraption contraption = MountedContraption.assembleMinecart(world, pos);
if (contraption == null)
return;
if (contraption.blocks.size() == 1)
return;
- Direction facing = cart.getAdjustedHorizontalFacing();
- float initialAngle = facing.getHorizontalAngle();
-
withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]);
boolean couplingFound = contraption.connectedCart != null;
+ Optional initialOrientation = cart.getMotion()
+ .length() < 1 / 512f ? Optional.empty() : Optional.of(cart.getAdjustedHorizontalFacing());
+
+ if (couplingFound) {
+ cart.setPosition(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f);
+ if (!CouplingHandler.tryToCoupleCarts(null, world, cart.getEntityId(),
+ contraption.connectedCart.getEntityId()))
+ return;
+ }
+
+ contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
+ contraption.initActors(world);
+ contraption.expandBoundsAroundAxis(Axis.Y);
+
if (couplingFound) {
- CouplingHandler.tryToCoupleCarts(null, world, cart.getEntityId(),
- contraption.connectedCart.getEntityId());
Vec3d diff = contraption.connectedCart.getPositionVec()
.subtract(cart.getPositionVec());
- initialAngle = Direction.fromAngle(MathHelper.atan2(diff.z, diff.x) * 180 / Math.PI)
- .getHorizontalAngle();
+ initialOrientation = Optional.of(Direction.fromAngle(MathHelper.atan2(diff.z, diff.x) * 180 / Math.PI));
}
- ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialAngle, facing);
-
- if (couplingFound) {
+ ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialOrientation);
+ if (couplingFound)
entity.setCouplingId(cart.getUniqueID());
- entity.setCoupledCart(contraption.connectedCart.getUniqueID());
- }
-
entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
world.addEntity(entity);
entity.startRiding(cart);
@@ -248,11 +273,44 @@ public class CartAssemblerBlock extends AbstractRailBlock
if (cart.getPassengers()
.isEmpty())
return;
- if (!(cart.getPassengers()
- .get(0) instanceof ContraptionEntity))
+ Entity entity = cart.getPassengers()
+ .get(0);
+ if (!(entity instanceof ContraptionEntity))
return;
- cart.removePassengers();
+ ContraptionEntity contraption = (ContraptionEntity) entity;
+ UUID couplingId = contraption.getCouplingId();
+ if (couplingId == null) {
+ disassembleCart(cart);
+ return;
+ }
+
+ Couple coupledCarts = contraption.getCoupledCartsIfPresent();
+ if (coupledCarts == null)
+ return;
+
+ // Make sure connected cart is present and being disassembled
+ for (boolean current : Iterate.trueAndFalse) {
+ MinecartController minecartController = coupledCarts.get(current);
+ if (minecartController.cart() == cart)
+ continue;
+ BlockPos otherPos = minecartController.cart()
+ .getPosition();
+ BlockState blockState = world.getBlockState(otherPos);
+ if (!AllBlocks.CART_ASSEMBLER.has(blockState))
+ return;
+ if (!getActionForCart(blockState, minecartController.cart()).shouldDisassemble())
+ return;
+ }
+
+ for (boolean current : Iterate.trueAndFalse)
+ coupledCarts.get(current)
+ .removeConnection(current);
+ disassembleCart(cart);
+ }
+
+ protected void disassembleCart(AbstractMinecartEntity cart) {
+ cart.removePassengers();
if (cart instanceof FurnaceMinecartEntity) {
CompoundNBT nbt = cart.serializeNBT();
nbt.putDouble("PushZ", cart.getMotion().x);
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java
deleted file mode 100644
index 3dd313411..000000000
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/ItemHandlerModifiableFromIInventory.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
-
-import javax.annotation.Nonnull;
-import javax.annotation.ParametersAreNonnullByDefault;
-
-import mcp.MethodsReturnNonnullByDefault;
-import net.minecraft.inventory.IInventory;
-import net.minecraft.item.ItemStack;
-import net.minecraftforge.items.IItemHandlerModifiable;
-import net.minecraftforge.items.ItemHandlerHelper;
-
-
-@MethodsReturnNonnullByDefault
-@ParametersAreNonnullByDefault
-public class ItemHandlerModifiableFromIInventory implements IItemHandlerModifiable {
- private final IInventory inventory;
-
- public ItemHandlerModifiableFromIInventory(IInventory inventory) {
- this.inventory = inventory;
- }
-
- @Override
- public void setStackInSlot(int slot, ItemStack stack) {
- inventory.setInventorySlotContents(slot, stack);
- }
-
- @Override
- public int getSlots() {
- return inventory.getSizeInventory();
- }
-
- @Override
- public ItemStack getStackInSlot(int slot) {
- return inventory.getStackInSlot(slot);
- }
-
- @Override
- @Nonnull
- public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate)
- {
- if (stack.isEmpty())
- return ItemStack.EMPTY;
-
- if (!isItemValid(slot, stack))
- return stack;
-
- validateSlotIndex(slot);
-
- ItemStack existing = getStackInSlot(slot);
-
- int limit = getStackLimit(slot, stack);
-
- if (!existing.isEmpty())
- {
- if (!ItemHandlerHelper.canItemStacksStack(stack, existing))
- return stack;
-
- limit -= existing.getCount();
- }
-
- if (limit <= 0)
- return stack;
-
- boolean reachedLimit = stack.getCount() > limit;
-
- if (!simulate)
- {
- if (existing.isEmpty())
- {
- setStackInSlot(slot, reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack);
- }
- else
- {
- existing.grow(reachedLimit ? limit : stack.getCount());
- }
- }
-
- return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount()- limit) : ItemStack.EMPTY;
- }
-
- @Override
- @Nonnull
- public ItemStack extractItem(int slot, int amount, boolean simulate)
- {
- if (amount == 0)
- return ItemStack.EMPTY;
-
- validateSlotIndex(slot);
-
- ItemStack existing = getStackInSlot(slot);
-
- if (existing.isEmpty())
- return ItemStack.EMPTY;
-
- int toExtract = Math.min(amount, existing.getMaxStackSize());
-
- if (existing.getCount() <= toExtract)
- {
- if (!simulate)
- {
- setStackInSlot(slot, ItemStack.EMPTY);
- return existing;
- }
- else
- {
- return existing.copy();
- }
- }
- else
- {
- if (!simulate)
- {
- setStackInSlot(slot, ItemHandlerHelper.copyStackWithSize(existing, existing.getCount() - toExtract));
- }
-
- return ItemHandlerHelper.copyStackWithSize(existing, toExtract);
- }
- }
-
- @Override
- public int getSlotLimit(int slot) {
- return inventory.getInventoryStackLimit();
- }
-
- @Override
- public boolean isItemValid(int slot, ItemStack stack) {
- return inventory.isItemValidForSlot(slot, stack);
- }
-
- private void validateSlotIndex(int slot)
- {
- if (slot < 0 || slot >= getSlots())
- throw new RuntimeException("Slot " + slot + " not in valid range - [0," + getSlots() + ")");
- }
-
- private int getStackLimit(int slot, ItemStack stack)
- {
- return Math.min(getSlotLimit(slot), stack.getMaxStackSize());
- }
-}
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java
index a0d3c23c2..6ed2b83c3 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java
@@ -1,12 +1,14 @@
package com.simibubi.create.content.contraptions.components.structureMovement.mounted;
import java.util.List;
+import java.util.Optional;
import javax.annotation.Nullable;
import com.simibubi.create.AllItems;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
+import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.block.AbstractRailBlock;
import net.minecraft.block.BlockState;
@@ -27,6 +29,7 @@ import net.minecraft.state.properties.RailShape;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
+import net.minecraft.util.Direction.Axis;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -154,18 +157,21 @@ public class MinecartContraptionItem extends Item {
CompoundNBT tag = itemstack.getOrCreateTag();
if (tag.contains("Contraption")) {
CompoundNBT contraptionTag = tag.getCompound("Contraption");
- float initialAngle = contraptionTag.getFloat("InitialAngle");
+
+ Direction initialOrientation = Direction.SOUTH;
+ if (contraptionTag.contains("InitialOrientation"))
+ initialOrientation = NBTHelper.readEnum(contraptionTag, "InitialOrientation", Direction.class);
+
Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag);
- ContraptionEntity contraption;
+ ContraptionEntity contraptionEntity =
+ ContraptionEntity.createMounted(world, mountedContraption, Optional.of(initialOrientation));
if (newFacing != null)
- contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle, newFacing);
- else
- contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle);
+ contraptionEntity.reOrientate(newFacing.getAxis() == Axis.X ? newFacing : newFacing.getOpposite());
- contraption.startRiding(cart);
- contraption.setPosition(cart.getX(), cart.getY(), cart.getZ());
- world.addEntity(contraption);
+ contraptionEntity.startRiding(cart);
+ contraptionEntity.setPosition(cart.getX(), cart.getY(), cart.getZ());
+ world.addEntity(contraptionEntity);
}
}
@@ -218,7 +224,11 @@ public class MinecartContraptionItem extends Item {
tag.remove("UUID");
tag.remove("Pos");
tag.remove("Motion");
- tag.putFloat("InitialAngle", entity.getInitialAngle());
+
+ Optional initialOrientation = entity.getInitialOrientation();
+ if (initialOrientation.isPresent())
+ NBTHelper.writeEnum(tag, "InitialOrientation", initialOrientation.orElse(null));
+
stack.getOrCreateTag()
.put("Contraption", tag);
return stack;
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java
index 91cb2ed84..82b11e8a8 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java
@@ -29,7 +29,9 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
+import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
+import net.minecraftforge.items.wrapper.InvWrapper;
public class MountedContraption extends Contraption {
@@ -57,10 +59,6 @@ public class MountedContraption extends Contraption {
Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z;
contraption.add(pos, Pair.of(new BlockInfo(pos, AllBlocks.MINECART_ANCHOR.getDefaultState()
.with(BlockStateProperties.HORIZONTAL_AXIS, axis), null), null));
- contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
- contraption.initActors(world);
- contraption.expandBoundsAroundAxis(Axis.Y);
-
return contraption;
}
@@ -75,35 +73,51 @@ public class MountedContraption extends Contraption {
protected Pair capture(World world, BlockPos pos) {
Pair pair = super.capture(world, pos);
BlockInfo capture = pair.getKey();
- if (AllBlocks.CART_ASSEMBLER.has(capture.state)) {
- if (!pos.equals(anchor)) {
- for (Axis axis : Iterate.axes) {
- if (axis.isVertical())
- continue;
- if (VecHelper.onSameAxis(anchor, pos, axis) && connectedCart == null) {
- for (AbstractMinecartEntity abstractMinecartEntity : world
- .getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
- if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
- break;
- connectedCart = abstractMinecartEntity;
- addExtraInventories(abstractMinecartEntity);
- }
- }
- }
+ if (!AllBlocks.CART_ASSEMBLER.has(capture.state))
+ return pair;
+
+ Pair anchorSwap =
+ Pair.of(new BlockInfo(pos, CartAssemblerBlock.createAnchor(capture.state), null), pair.getValue());
+ if (pos.equals(anchor) || connectedCart != null)
+ return anchorSwap;
+
+ for (Axis axis : Iterate.axes) {
+ if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis))
+ continue;
+ for (AbstractMinecartEntity abstractMinecartEntity : world
+ .getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
+ if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
+ break;
+ connectedCart = abstractMinecartEntity;
+ connectedCart.setPosition(pos.getX() + .5, pos.getY(), pos.getZ() + .5f);
}
- return Pair.of(new BlockInfo(pos, CartAssemblerBlock.createAnchor(capture.state), null), pair.getValue());
}
- return pair;
+
+ return anchorSwap;
}
@Override
protected boolean movementAllowed(World world, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if (!pos.equals(anchor) && AllBlocks.CART_ASSEMBLER.has(blockState))
- return true;
+ return testSecondaryCartAssembler(world, blockState, pos);
return super.movementAllowed(world, pos);
}
+ protected boolean testSecondaryCartAssembler(World world, BlockState state, BlockPos pos) {
+ for (Axis axis : Iterate.axes) {
+ if (axis.isVertical() || !VecHelper.onSameAxis(anchor, pos, axis))
+ continue;
+ for (AbstractMinecartEntity abstractMinecartEntity : world
+ .getEntitiesWithinAABB(AbstractMinecartEntity.class, new AxisAlignedBB(pos))) {
+ if (!CartAssemblerBlock.canAssembleTo(abstractMinecartEntity))
+ break;
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public CompoundNBT writeNBT() {
CompoundNBT writeNBT = super.writeNBT();
@@ -129,7 +143,9 @@ public class MountedContraption extends Contraption {
@Override
public void addExtraInventories(Entity cart) {
- if (cart instanceof IInventory)
- inventory = new CombinedInvWrapper(new ItemHandlerModifiableFromIInventory((IInventory) cart), inventory);
+ if (!(cart instanceof IInventory))
+ return;
+ IItemHandlerModifiable handlerFromInv = new InvWrapper((IInventory) cart);
+ inventory = new CombinedInvWrapper(handlerFromInv, inventory);
}
}
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java
index 6aa5a599b..2cdbb52d6 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java
@@ -8,6 +8,7 @@ import javax.annotation.Nullable;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
+import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
import com.simibubi.create.foundation.config.AllConfigs;
@@ -22,9 +23,30 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.World;
+import net.minecraftforge.common.util.LazyOptional;
+import net.minecraftforge.event.entity.EntityMountEvent;
+import net.minecraftforge.eventbus.api.Event.Result;
+import net.minecraftforge.eventbus.api.SubscribeEvent;
+import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
+@EventBusSubscriber
public class CouplingHandler {
+ @SubscribeEvent
+ public static void preventEntitiesFromMoutingOccupiedCart(EntityMountEvent event) {
+ Entity e = event.getEntityBeingMounted();
+ LazyOptional optional = e.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
+ if (!optional.isPresent())
+ return;
+ if (event.getEntityMounting() instanceof ContraptionEntity)
+ return;
+ MinecartController controller = optional.orElse(null);
+ if (controller.isCoupledThroughContraption()) {
+ event.setCanceled(true);
+ event.setResult(Result.DENY);
+ }
+ }
+
public static void forEachLoadedCoupling(World world, Consumer> consumer) {
if (world == null)
return;
@@ -45,14 +67,14 @@ public class CouplingHandler {
});
}
- public static void tryToCoupleCarts(@Nullable PlayerEntity player, World world, int cartId1, int cartId2) {
+ public static boolean tryToCoupleCarts(@Nullable PlayerEntity player, World world, int cartId1, int cartId2) {
Entity entity1 = world.getEntityByID(cartId1);
Entity entity2 = world.getEntityByID(cartId2);
if (!(entity1 instanceof AbstractMinecartEntity))
- return;
+ return false;
if (!(entity2 instanceof AbstractMinecartEntity))
- return;
+ return false;
String tooMany = "two_couplings_max";
String unloaded = "unloaded";
@@ -61,16 +83,17 @@ public class CouplingHandler {
int distanceTo = (int) entity1.getPositionVec()
.distanceTo(entity2.getPositionVec());
+ boolean contraptionCoupling = player == null;
if (distanceTo < 2) {
- if (player == null)
- return; // dont allow train contraptions with <2 distance
+ if (contraptionCoupling)
+ return false; // dont allow train contraptions with <2 distance
distanceTo = 2;
}
if (distanceTo > AllConfigs.SERVER.kinetics.maxCartCouplingLength.get()) {
status(player, tooFar);
- return;
+ return false;
}
AbstractMinecartEntity cart1 = (AbstractMinecartEntity) entity1;
@@ -82,18 +105,18 @@ public class CouplingHandler {
if (mainController == null || connectedController == null) {
status(player, unloaded);
- return;
+ return false;
}
if (mainController.isFullyCoupled() || connectedController.isFullyCoupled()) {
status(player, tooMany);
- return;
+ return false;
}
if (mainController.isLeadingCoupling() && mainController.getCoupledCart(true)
.equals(connectedID) || connectedController.isLeadingCoupling()
&& connectedController.getCoupledCart(true)
.equals(mainID))
- return;
+ return false;
for (boolean main : Iterate.trueAndFalse) {
MinecartController current = main ? mainController : connectedController;
@@ -103,24 +126,24 @@ public class CouplingHandler {
while (true) {
if (safetyCount-- <= 0) {
Create.logger.warn("Infinite loop in coupling iteration");
- return;
+ return false;
}
current = getNextInCouplingChain(world, current, forward);
if (current == null) {
status(player, unloaded);
- return;
+ return false;
}
if (current == connectedController) {
status(player, noLoops);
- return;
+ return false;
}
if (current == MinecartController.EMPTY)
break;
}
}
- if (player != null) {
+ if (!contraptionCoupling) {
for (Hand hand : Hand.values()) {
if (player.isCreative())
break;
@@ -135,8 +158,9 @@ public class CouplingHandler {
mainController.prepareForCoupling(true);
connectedController.prepareForCoupling(false);
- mainController.coupleWith(true, connectedID, distanceTo);
- connectedController.coupleWith(false, mainID, distanceTo);
+ mainController.coupleWith(true, connectedID, distanceTo, contraptionCoupling);
+ connectedController.coupleWith(false, mainID, distanceTo, contraptionCoupling);
+ return true;
}
@Nullable
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java
index 78e87fb35..9f9a7e926 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingRenderer.java
@@ -32,7 +32,11 @@ public class CouplingRenderer {
public static void renderAll(MatrixStack ms, IRenderTypeBuffer buffer) {
CouplingHandler.forEachLoadedCoupling(Minecraft.getInstance().world,
- c -> CouplingRenderer.renderCoupling(ms, buffer, c.map(MinecartController::cart)));
+ c -> {
+ if (c.getFirst().hasContraptionCoupling(true))
+ return;
+ CouplingRenderer.renderCoupling(ms, buffer, c.map(MinecartController::cart));
+ });
}
public static void tickDebugModeRenders() {
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java
index 98f89cdc1..a01d3e6ff 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/MinecartSim2020.java
@@ -2,16 +2,15 @@ package com.simibubi.create.content.contraptions.components.structureMovement.tr
import static net.minecraft.entity.Entity.horizontalMag;
-import java.util.List;
import java.util.Map;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
-import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
+import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
+import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController;
import net.minecraft.block.AbstractRailBlock;
import net.minecraft.block.BlockState;
-import net.minecraft.entity.Entity;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
import net.minecraft.state.properties.RailShape;
@@ -21,6 +20,7 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
+import net.minecraftforge.common.util.LazyOptional;
/**
* Useful methods for dealing with Minecarts
@@ -47,10 +47,10 @@ public class MinecartSim2020 {
});
public static Vec3d predictMotionOf(AbstractMinecartEntity cart) {
- if (cart instanceof FurnaceMinecartEntity) {
- return cart.getPositionVec()
- .subtract(cart.lastTickPosX, cart.lastTickPosY, cart.lastTickPosZ);
- }
+// if (cart instanceof FurnaceMinecartEntity) {
+// return cart.getPositionVec()
+// .subtract(cart.lastTickPosX, cart.lastTickPosY, cart.lastTickPosZ);
+// }
return cart.getMotion().scale(1f);
// if (cart instanceof ContainerMinecartEntity) {
// ContainerMinecartEntity containerCart = (ContainerMinecartEntity) cart;
@@ -71,15 +71,9 @@ public class MinecartSim2020 {
if (c instanceof FurnaceMinecartEntity)
return MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushX, 0)
&& MathHelper.epsilonEquals(((FurnaceMinecartEntity) c).pushZ, 0);
- List passengers = c.getPassengers();
- if (passengers.isEmpty())
- return true;
- for (Entity entity : passengers) {
- if (entity instanceof ContraptionEntity) {
- ContraptionEntity contraptionEntity = (ContraptionEntity) entity;
- return !contraptionEntity.isStalled();
- }
- }
+ LazyOptional capability = c.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
+ if (capability.isPresent() && capability.orElse(null).isStalled())
+ return false;
return true;
}
diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java
index 31eef4d3d..3120a64c6 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/CapabilityMinecartController.java
@@ -130,6 +130,8 @@ public class CapabilityMinecartController implements ICapabilitySerializable {
UUID idOfOther = cd.idOfCart(!main);
MinecartController otherCart = CapabilityMinecartController.getIfPresent(world, idOfOther);
internalStall.setValue(
- internalStall.booleanValue() || otherCart == null || !otherCart.isPresent() || otherCart.isStalled());
+ internalStall.booleanValue() || otherCart == null || !otherCart.isPresent() || otherCart.isStalled(false));
}));
if (!world.isRemote)
@@ -93,6 +96,18 @@ public class MinecartController implements INBTSerializable {
.isPresent();
}
+ public boolean isCoupledThroughContraption() {
+ for (boolean current : Iterate.trueAndFalse)
+ if (hasContraptionCoupling(current))
+ return true;
+ return false;
+ }
+
+ public boolean hasContraptionCoupling(boolean current) {
+ Optional optional = couplings.get(current);
+ return optional.isPresent() && optional.get().contraption;
+ }
+
public float getCouplingLength(boolean leading) {
Optional optional = couplings.get(leading);
if (optional.isPresent())
@@ -113,6 +128,15 @@ public class MinecartController implements INBTSerializable {
}
public void removeConnection(boolean main) {
+ if (hasContraptionCoupling(main) && !getWorld().isRemote) {
+ List passengers = cart().getPassengers();
+ if (!passengers.isEmpty()) {
+ Entity entity = passengers.get(0);
+ if (entity instanceof ContraptionEntity)
+ ((ContraptionEntity) entity).disassemble();
+ }
+ }
+
couplings.set(main, Optional.empty());
needsEntryRefresh |= main;
sendData();
@@ -140,7 +164,28 @@ public class MinecartController implements INBTSerializable {
for (MinecartController minecartController : cartsToFlip) {
MinecartController mc = minecartController;
- mc.couplings.forEach(opt -> opt.ifPresent(CouplingData::flip));
+ mc.couplings.forEachWithContext((opt, leading) -> opt.ifPresent(cd -> {
+ cd.flip();
+ if (!cd.contraption)
+ return;
+ List passengers = mc.cart()
+ .getPassengers();
+ if (passengers.isEmpty())
+ return;
+ Entity entity = passengers.get(0);
+ if (!(entity instanceof ContraptionEntity))
+ return;
+ ContraptionEntity contraption = (ContraptionEntity) entity;
+ UUID couplingId = contraption.getCouplingId();
+ if (couplingId == cd.mainCartID) {
+ contraption.setCouplingId(cd.connectedCartID);
+ return;
+ }
+ if (couplingId == cd.connectedCartID) {
+ contraption.setCouplingId(cd.mainCartID);
+ return;
+ }
+ }));
mc.couplings = mc.couplings.swap();
if (mc == this)
continue;
@@ -150,10 +195,10 @@ public class MinecartController implements INBTSerializable {
}
}
- public void coupleWith(boolean isLeading, UUID coupled, float length) {
+ public void coupleWith(boolean isLeading, UUID coupled, float length, boolean contraption) {
UUID mainID = isLeading ? cart().getUniqueID() : coupled;
UUID connectedID = isLeading ? coupled : cart().getUniqueID();
- couplings.set(isLeading, Optional.of(new CouplingData(mainID, connectedID, length)));
+ couplings.set(isLeading, Optional.of(new CouplingData(mainID, connectedID, length, contraption)));
needsEntryRefresh |= isLeading;
sendData();
}
@@ -261,11 +306,13 @@ public class MinecartController implements INBTSerializable {
private UUID mainCartID;
private UUID connectedCartID;
private float length;
+ private boolean contraption;
- public CouplingData(UUID mainCartID, UUID connectedCartID, float length) {
+ public CouplingData(UUID mainCartID, UUID connectedCartID, float length, boolean contraption) {
this.mainCartID = mainCartID;
this.connectedCartID = connectedCartID;
this.length = length;
+ this.contraption = contraption;
}
void flip() {
@@ -279,13 +326,16 @@ public class MinecartController implements INBTSerializable {
nbt.put("Main", NBTUtil.writeUniqueId(mainCartID));
nbt.put("Connected", NBTUtil.writeUniqueId(connectedCartID));
nbt.putFloat("Length", length);
+ nbt.putBoolean("Contraption", contraption);
return nbt;
}
static CouplingData read(CompoundNBT nbt) {
UUID mainCartID = NBTUtil.readUniqueId(nbt.getCompound("Main"));
UUID connectedCartID = NBTUtil.readUniqueId(nbt.getCompound("Connected"));
- return new CouplingData(mainCartID, connectedCartID, nbt.getFloat("Length"));
+ float length = nbt.getFloat("Length");
+ boolean contraption = nbt.getBoolean("Contraption");
+ return new CouplingData(mainCartID, connectedCartID, length, contraption);
}
public UUID idOfCart(boolean main) {
diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java
index 2bb4a4b60..cc76a74f1 100644
--- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java
@@ -5,7 +5,6 @@ import java.util.Map;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
-import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.item.ItemStack;
@@ -31,7 +30,7 @@ public class BasinMovementBehaviour extends MovementBehaviour {
public void tick(MovementContext context) {
super.tick(context);
if (context.temporaryData == null || (boolean) context.temporaryData) {
- Vec3d facingVec = VecHelper.rotate(new Vec3d(Direction.UP.getDirectionVec()), context.rotation.x, context.rotation.y, context.rotation.z);
+ Vec3d facingVec = context.rotation.apply(new Vec3d(Direction.UP.getDirectionVec()));
facingVec.normalize();
if (Direction.getFacingFromVector(facingVec.x, facingVec.y, facingVec.z) == Direction.DOWN)
dump(context, facingVec);
@@ -41,16 +40,21 @@ public class BasinMovementBehaviour extends MovementBehaviour {
private void dump(MovementContext context, Vec3d facingVec) {
getOrReadInventory(context).forEach((key, itemStackHandler) -> {
for (int i = 0; i < itemStackHandler.getSlots(); i++) {
- if (itemStackHandler.getStackInSlot(i).isEmpty())
+ if (itemStackHandler.getStackInSlot(i)
+ .isEmpty())
continue;
- ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y, context.position.z, itemStackHandler.getStackInSlot(i));
+ ItemEntity itemEntity = new ItemEntity(context.world, context.position.x, context.position.y,
+ context.position.z, itemStackHandler.getStackInSlot(i));
itemEntity.setMotion(facingVec.scale(.05));
context.world.addEntity(itemEntity);
itemStackHandler.setStackInSlot(i, ItemStack.EMPTY);
}
context.tileData.put(key, itemStackHandler.serializeNBT());
});
- context.contraption.customRenderTEs.stream().filter(te -> te.getPos().equals(context.localPos) && te instanceof BasinTileEntity).forEach(te -> ((BasinTileEntity) te).readOnlyItems(context.tileData));
+ context.contraption.customRenderTEs.stream()
+ .filter(te -> te.getPos()
+ .equals(context.localPos) && te instanceof BasinTileEntity)
+ .forEach(te -> ((BasinTileEntity) te).readOnlyItems(context.tileData));
context.temporaryData = false; // did already dump, so can't any more
}
}
diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java
index 368758376..6f05a3486 100644
--- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java
+++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/ContactMovementBehaviour.java
@@ -3,7 +3,6 @@ package com.simibubi.create.content.logistics.block.redstone;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
-import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.NBTUtil;
@@ -36,7 +35,7 @@ public class ContactMovementBehaviour extends MovementBehaviour {
return;
Vec3d contact = new Vec3d(block.get(RedstoneContactBlock.FACING).getDirectionVec());
- contact = VecHelper.rotate(contact, context.rotation.x, context.rotation.y, context.rotation.z);
+ contact = context.rotation.apply(contact);
Direction direction = Direction.getFacingFromVector(contact.x, contact.y, contact.z);
if (!RedstoneContactBlock.hasValidContact(world, pos.offset(direction.getOpposite()), direction))
diff --git a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java
index 545d41a50..5e7e973ea 100644
--- a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java
+++ b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java
@@ -33,13 +33,6 @@ public class MatrixStacker {
return multiply(Vector3f.POSITIVE_Z, angle);
}
- public MatrixStacker rotateRadians(double angleRoll, double angleYaw, double anglePitch) {
- rotateX(AngleHelper.deg(angleRoll));
- rotateY(AngleHelper.deg(angleYaw));
- rotateZ(AngleHelper.deg(anglePitch));
- return this;
- }
-
public MatrixStacker centre() {
return translate(center);
}