CollideCarts

- Contraptions now run their collision from a separate ticking hook
- Minecart mounted contraptions now run the collision algorithm
This commit is contained in:
simibubi 2020-06-22 10:58:02 +02:00
parent d9105b4e60
commit a13d9fcede
3 changed files with 135 additions and 85 deletions

View file

@ -6,7 +6,7 @@ org.gradle.daemon=false
# mod version info # mod version info
mod_version=0.3 mod_version=0.3
minecraft_version=1.15.2 minecraft_version=1.15.2
forge_version=31.2.3 forge_version=31.2.21
# dependency versions # dependency versions
registrate_version=0.0.3.17 registrate_version=0.0.3.17

View file

@ -1,10 +1,18 @@
package com.simibubi.create.content.contraptions.components.structureMovement; package com.simibubi.create.content.contraptions.components.structureMovement;
import java.util.HashMap; import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.Map;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import com.google.common.base.Predicates;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour;
import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.collision.Matrix3d;
@ -14,11 +22,10 @@ import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.CocoaBlock; import net.minecraft.block.CocoaBlock;
import net.minecraft.block.material.PushReaction;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.MoverType; import net.minecraft.entity.MoverType;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
@ -34,21 +41,72 @@ import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.TickEvent.ClientTickEvent;
import net.minecraftforge.event.TickEvent.Phase;
import net.minecraftforge.event.TickEvent.WorldTickEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
@EventBusSubscriber
public class ContraptionCollider { public class ContraptionCollider {
static Map<Object, AxisAlignedBB> renderedBBs = new HashMap<>();
public static boolean wasClientPlayerGrounded; public static boolean wasClientPlayerGrounded;
public static Cache<World, List<WeakReference<ContraptionEntity>>> activeContraptions = CacheBuilder.newBuilder()
.expireAfterAccess(20, SECONDS)
.build();
@SubscribeEvent
public static void addSpawnedContraptionsToCollisionList(EntityJoinWorldEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof ContraptionEntity))
return;
try {
List<WeakReference<ContraptionEntity>> list = activeContraptions.get(event.getWorld(), ArrayList::new);
ContraptionEntity contraption = (ContraptionEntity) entity;
list.add(new WeakReference<>(contraption));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@SubscribeEvent
@OnlyIn(Dist.CLIENT)
public static void playerCollisionHappensOnClientTick(ClientTickEvent event) {
if (event.phase == Phase.START)
return;
ClientWorld world = Minecraft.getInstance().world;
if (world == null)
return;
runCollisions(world);
}
@SubscribeEvent
public static void entityCollisionHappensPreWorldTick(WorldTickEvent event) {
if (event.phase == Phase.START)
return;
World world = event.world;
runCollisions(world);
}
private static void runCollisions(World world) {
List<WeakReference<ContraptionEntity>> list = activeContraptions.getIfPresent(world);
if (list == null)
return;
for (Iterator<WeakReference<ContraptionEntity>> iterator = list.iterator(); iterator.hasNext();) {
WeakReference<ContraptionEntity> weakReference = iterator.next();
ContraptionEntity contraptionEntity = weakReference.get();
if (contraptionEntity == null || !contraptionEntity.isAlive()) {
iterator.remove();
continue;
}
collideEntities(contraptionEntity);
}
}
public static void collideEntities(ContraptionEntity contraptionEntity) { public static void collideEntities(ContraptionEntity contraptionEntity) {
if (Contraption.isFrozen())
return;
if (!contraptionEntity.collisionEnabled())
return;
World world = contraptionEntity.getEntityWorld(); World world = contraptionEntity.getEntityWorld();
// Vec3d contraptionMotion = contraptionEntity.getMotion();
Contraption contraption = contraptionEntity.getContraption(); Contraption contraption = contraptionEntity.getContraption();
AxisAlignedBB bounds = contraptionEntity.getBoundingBox(); AxisAlignedBB bounds = contraptionEntity.getBoundingBox();
Vec3d contraptionPosition = contraptionEntity.getPositionVec(); Vec3d contraptionPosition = contraptionEntity.getPositionVec();
@ -61,7 +119,7 @@ public class ContraptionCollider {
return; return;
for (Entity entity : world.getEntitiesWithinAABB((EntityType<?>) null, bounds.grow(1), for (Entity entity : world.getEntitiesWithinAABB((EntityType<?>) null, bounds.grow(1),
e -> canBeCollidedWith(e))) { contraptionEntity::canCollideWith)) {
if (entity instanceof PlayerEntity && !world.isRemote) if (entity instanceof PlayerEntity && !world.isRemote)
return; return;
@ -70,7 +128,7 @@ public class ContraptionCollider {
Vec3d centerY = new Vec3d(0, entity.getBoundingBox() Vec3d centerY = new Vec3d(0, entity.getBoundingBox()
.getYSize() / 2, 0); .getYSize() / 2, 0);
Vec3d position = entityPosition.subtract(contraptionPosition) Vec3d position = entityPosition.subtract(contraptionPosition)
.subtract(centerOfBlock) .subtract(contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0))
.add(centerY); .add(centerY);
position = position =
VecHelper.rotate(position, -contraptionRotation.z, -contraptionRotation.y, -contraptionRotation.x); VecHelper.rotate(position, -contraptionRotation.z, -contraptionRotation.y, -contraptionRotation.x);
@ -107,7 +165,7 @@ public class ContraptionCollider {
obb.setCenter(obb.getCenter() obb.setCenter(obb.getCenter()
.add(intersect)); .add(intersect));
entity.move(MoverType.PLAYER, intersect); entity.move(MoverType.PISTON, intersect);
Vec3d entityMotion = entity.getMotion(); Vec3d entityMotion = entity.getMotion();
if (entityMotion.getX() > 0 == intersect.getX() < 0) if (entityMotion.getX() > 0 == intersect.getX() < 0)
@ -134,49 +192,10 @@ public class ContraptionCollider {
if (entity instanceof ServerPlayerEntity) if (entity instanceof ServerPlayerEntity)
((ServerPlayerEntity) entity).connection.floatingTickCount = 0; ((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
}); });
// Vec3d positionOffset = contraptionPosition.scale(-1);
// AxisAlignedBB entityBB = entity.getBoundingBox()
// .offset(positionOffset)
// .grow(1.0E-7D);
// Vec3d entityMotion = entity.getMotion();
// Vec3d relativeMotion = entityMotion.subtract(contraptionMotion);
// Vec3d allowedMovement = Entity.getAllowedMovement(relativeMotion, entityBB, world,
// ISelectionContext.forEntity(entity), potentialHits);
// potentialHits.createStream()
// .forEach(voxelShape -> pushEntityOutOfShape(entity, voxelShape, positionOffset, contraptionMotion));
//
//
// if (allowedMovement.equals(relativeMotion))
// continue;
//
// if (allowedMovement.y != relativeMotion.y) {
// entity.handleFallDamage(entity.fallDistance, 1);
// entity.fallDistance = 0;
// entity.onGround = true;
// DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> checkForClientPlayerCollision(entity));
// }
//
// if (entity instanceof ServerPlayerEntity)
// ((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
// if (entity instanceof PlayerEntity && !world.isRemote)
// return;
//
// entity.setMotion(allowedMovement.add(contraptionMotion));
} }
} }
public static boolean canBeCollidedWith(Entity e) {
if (e instanceof PlayerEntity && e.isSpectator())
return false;
if (e.noClip)
return false;
if (e instanceof IProjectile)
return false;
return e.getPushReaction() == PushReaction.NORMAL;
}
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
private static void checkForClientPlayerCollision(Entity entity) { private static void checkForClientPlayerCollision(Entity entity) {
if (entity != Minecraft.getInstance().player) if (entity != Minecraft.getInstance().player)
@ -258,7 +277,8 @@ public class ContraptionCollider {
BlockPos pos = contraption.blocks.get(p).pos; BlockPos pos = contraption.blocks.get(p).pos;
VoxelShape collisionShape = blockState.getCollisionShape(world, p); VoxelShape collisionShape = blockState.getCollisionShape(world, p);
return collisionShape.withOffset(pos.getX(), pos.getY(), pos.getZ()); return collisionShape.withOffset(pos.getX(), pos.getY(), pos.getZ());
})); })
.filter(Predicates.not(VoxelShape::isEmpty)));
return potentialHits; return potentialHits;
} }

View file

@ -12,6 +12,7 @@ import org.apache.commons.lang3.tuple.MutablePair;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode;
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption;
import com.simibubi.create.foundation.item.ItemHelper; import com.simibubi.create.foundation.item.ItemHelper;
@ -24,8 +25,11 @@ import net.minecraft.block.material.PushReaction;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.item.BoatEntity; import net.minecraft.entity.item.BoatEntity;
import net.minecraft.entity.item.HangingEntity;
import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; import net.minecraft.entity.item.minecart.FurnaceMinecartEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.Ingredient;
@ -103,7 +107,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle, public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle,
Direction facing) { Direction facing) {
ContraptionEntity entity = createMounted(world, contraption, initialAngle); ContraptionEntity entity = createMounted(world, contraption, initialAngle);
entity.forcedAngle = facing.getHorizontalAngle(); entity.forcedAngle = facing.getHorizontalAngle();
entity.forceYaw(entity.forcedAngle); entity.forceYaw(entity.forcedAngle);
@ -170,7 +174,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
public void collisionTick() { public void collisionTick() {
ContraptionCollider.collideEntities(this); // ContraptionCollider.collideEntities(this);
} }
public void tickAsPassenger(Entity e) { public void tickAsPassenger(Entity e) {
@ -233,14 +237,17 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
int i = MathHelper.floor(furnaceCart.getX()); int i = MathHelper.floor(furnaceCart.getX());
int j = MathHelper.floor(furnaceCart.getY()); int j = MathHelper.floor(furnaceCart.getY());
int k = MathHelper.floor(furnaceCart.getZ()); int k = MathHelper.floor(furnaceCart.getZ());
if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k)).isIn(BlockTags.RAILS)) if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k))
.isIn(BlockTags.RAILS))
--j; --j;
BlockPos blockpos = new BlockPos(i, j, k); BlockPos blockpos = new BlockPos(i, j, k);
BlockState blockstate = this.world.getBlockState(blockpos); BlockState blockstate = this.world.getBlockState(blockpos);
if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS)) if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS))
if (fuel > 1) if (fuel > 1)
riding.setMotion(riding.getMotion().normalize().scale(1)); riding.setMotion(riding.getMotion()
.normalize()
.scale(1));
if (fuel < 5 && contraption != null) { if (fuel < 5 && contraption != null) {
ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false); ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false);
if (!coal.isEmpty()) if (!coal.isEmpty())
@ -277,7 +284,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
Vec3d actorPosition = new Vec3d(blockInfo.pos); Vec3d actorPosition = new Vec3d(blockInfo.pos);
actorPosition = actorPosition.add(actor.getActiveAreaOffset(context)); actorPosition = actorPosition.add(actor.getActiveAreaOffset(context));
actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch); actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch);
actorPosition = actorPosition.add(rotationOffset).add(getAnchorVec()); actorPosition = actorPosition.add(rotationOffset)
.add(getAnchorVec());
boolean newPosVisited = false; boolean newPosVisited = false;
BlockPos gridPosition = new BlockPos(actorPosition); BlockPos gridPosition = new BlockPos(actorPosition);
@ -290,7 +298,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch); relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch);
context.relativeMotion = relativeMotion; context.relativeMotion = relativeMotion;
newPosVisited = !new BlockPos(previousPosition).equals(gridPosition) newPosVisited = !new BlockPos(previousPosition).equals(gridPosition)
|| context.relativeMotion.length() > 0 && context.firstMovement; || context.relativeMotion.length() > 0 && context.firstMovement;
} }
if (getContraption() instanceof BearingContraption) { if (getContraption() instanceof BearingContraption) {
@ -298,10 +306,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
Direction facing = bc.getFacing(); Direction facing = bc.getFacing();
Vec3d activeAreaOffset = actor.getActiveAreaOffset(context); Vec3d activeAreaOffset = actor.getActiveAreaOffset(context);
if (activeAreaOffset.mul(VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec()))) if (activeAreaOffset.mul(VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec())))
.equals(Vec3d.ZERO)) { .equals(Vec3d.ZERO)) {
if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) { if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) {
context.motion = new Vec3d(facing.getDirectionVec()).scale( context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis()
facing.getAxis().getCoordinate(roll - prevRoll, yaw - prevYaw, pitch - prevPitch)); .getCoordinate(roll - prevRoll, yaw - prevYaw, pitch - prevPitch));
context.relativeMotion = context.motion; context.relativeMotion = context.motion;
int timer = context.data.getInt("StationaryTimer"); int timer = context.data.getInt("StationaryTimer");
if (timer > 0) { if (timer > 0) {
@ -333,7 +341,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
if (getController() != null) if (getController() != null)
getController().onStall(); getController().onStall();
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this),
new ContraptionStallPacket(getEntityId(), getX(), getY(), getZ(), yaw, pitch, roll)); new ContraptionStallPacket(getEntityId(), getX(), getY(), getZ(), yaw, pitch, roll));
} }
dataManager.set(STALLED, contraption.stalled); dataManager.set(STALLED, contraption.stalled);
} else { } else {
@ -353,7 +361,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public void rotateTo(double roll, double yaw, double pitch) { public void rotateTo(double roll, double yaw, double pitch) {
rotate(getShortestAngleDiff(this.roll, roll), getShortestAngleDiff(this.yaw, yaw), rotate(getShortestAngleDiff(this.roll, roll), getShortestAngleDiff(this.yaw, yaw),
getShortestAngleDiff(this.pitch, pitch)); getShortestAngleDiff(this.pitch, pitch));
} }
@Override @Override
@ -397,7 +405,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public float getYaw(float partialTicks) { public float getYaw(float partialTicks) {
return (getRidingEntity() == null ? 1 : -1) return (getRidingEntity() == null ? 1 : -1)
* (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) + initialAngle; * (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)) + initialAngle;
} }
public float getPitch(float partialTicks) { public float getPitch(float partialTicks) {
@ -463,7 +471,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
compound.put("Contraption", contraption.writeNBT()); compound.put("Contraption", contraption.writeNBT());
if (!stationary && motionBeforeStall != null) if (!stationary && motionBeforeStall != null)
compound.put("CachedMotion", compound.put("CachedMotion",
newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z)); newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
if (controllerPos != null) if (controllerPos != null)
compound.put("Controller", NBTUtil.writeBlockPos(controllerPos)); compound.put("Controller", NBTUtil.writeBlockPos(controllerPos));
if (forcedAngle != -1) if (forcedAngle != -1)
@ -504,8 +512,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
} }
@Override @Override
protected void doWaterSplashEffect() { protected void doWaterSplashEffect() {}
}
public void preventMovedEntitiesFromGettingStuck() { public void preventMovedEntitiesFromGettingStuck() {
Vec3d stuckTest = new Vec3d(0, -2, 0); Vec3d stuckTest = new Vec3d(0, -2, 0);
@ -514,31 +521,33 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
e.onGround = true; e.onGround = true;
Vec3d vec = stuckTest; Vec3d vec = stuckTest;
AxisAlignedBB axisalignedbb = e.getBoundingBox().offset(0, 2, 0); AxisAlignedBB axisalignedbb = e.getBoundingBox()
.offset(0, 2, 0);
ISelectionContext iselectioncontext = ISelectionContext.forEntity(this); ISelectionContext iselectioncontext = ISelectionContext.forEntity(this);
VoxelShape voxelshape = e.world.getWorldBorder().getShape(); VoxelShape voxelshape = e.world.getWorldBorder()
.getShape();
Stream<VoxelShape> stream = Stream<VoxelShape> stream =
VoxelShapes.compare(voxelshape, VoxelShapes.create(axisalignedbb.shrink(1.0E-7D)), IBooleanFunction.AND) VoxelShapes.compare(voxelshape, VoxelShapes.create(axisalignedbb.shrink(1.0E-7D)), IBooleanFunction.AND)
? Stream.empty() ? Stream.empty()
: Stream.of(voxelshape); : Stream.of(voxelshape);
Stream<VoxelShape> stream1 = Stream<VoxelShape> stream1 =
this.world.getEmptyCollisionShapes(e, axisalignedbb.expand(vec), ImmutableSet.of()); this.world.getEmptyCollisionShapes(e, axisalignedbb.expand(vec), ImmutableSet.of());
ReuseableStream<VoxelShape> reuseablestream = new ReuseableStream<>(Stream.concat(stream1, stream)); ReuseableStream<VoxelShape> reuseablestream = new ReuseableStream<>(Stream.concat(stream1, stream));
Vec3d vec3d = vec.lengthSquared() == 0.0D ? vec Vec3d vec3d = vec.lengthSquared() == 0.0D ? vec
: collideBoundingBoxHeuristically(this, vec, axisalignedbb, e.world, iselectioncontext, : collideBoundingBoxHeuristically(this, vec, axisalignedbb, e.world, iselectioncontext,
reuseablestream); reuseablestream);
boolean flag = vec.x != vec3d.x; boolean flag = vec.x != vec3d.x;
boolean flag1 = vec.y != vec3d.y; boolean flag1 = vec.y != vec3d.y;
boolean flag2 = vec.z != vec3d.z; boolean flag2 = vec.z != vec3d.z;
boolean flag3 = e.onGround || flag1 && vec.y < 0.0D; boolean flag3 = e.onGround || flag1 && vec.y < 0.0D;
if (this.stepHeight > 0.0F && flag3 && (flag || flag2)) { if (this.stepHeight > 0.0F && flag3 && (flag || flag2)) {
Vec3d vec3d1 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, (double) e.stepHeight, vec.z), Vec3d vec3d1 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, (double) e.stepHeight, vec.z),
axisalignedbb, e.world, iselectioncontext, reuseablestream); axisalignedbb, e.world, iselectioncontext, reuseablestream);
Vec3d vec3d2 = collideBoundingBoxHeuristically(e, new Vec3d(0.0D, (double) e.stepHeight, 0.0D), Vec3d vec3d2 = collideBoundingBoxHeuristically(e, new Vec3d(0.0D, (double) e.stepHeight, 0.0D),
axisalignedbb.expand(vec.x, 0.0D, vec.z), e.world, iselectioncontext, reuseablestream); axisalignedbb.expand(vec.x, 0.0D, vec.z), e.world, iselectioncontext, reuseablestream);
if (vec3d2.y < (double) e.stepHeight) { if (vec3d2.y < (double) e.stepHeight) {
Vec3d vec3d3 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, 0.0D, vec.z), Vec3d vec3d3 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, 0.0D, vec.z),
axisalignedbb.offset(vec3d2), e.world, iselectioncontext, reuseablestream).add(vec3d2); axisalignedbb.offset(vec3d2), e.world, iselectioncontext, reuseablestream).add(vec3d2);
if (horizontalMag(vec3d3) > horizontalMag(vec3d1)) { if (horizontalMag(vec3d3) > horizontalMag(vec3d1)) {
vec3d1 = vec3d3; vec3d1 = vec3d3;
} }
@ -546,7 +555,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
if (horizontalMag(vec3d1) > horizontalMag(vec3d)) { if (horizontalMag(vec3d1) > horizontalMag(vec3d)) {
vec3d = vec3d1.add(collideBoundingBoxHeuristically(e, new Vec3d(0.0D, -vec3d1.y + vec.y, 0.0D), vec3d = vec3d1.add(collideBoundingBoxHeuristically(e, new Vec3d(0.0D, -vec3d1.y + vec.y, 0.0D),
axisalignedbb.offset(vec3d1), e.world, iselectioncontext, reuseablestream)); axisalignedbb.offset(vec3d1), e.world, iselectioncontext, reuseablestream));
} }
} }
@ -568,7 +577,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
@Override @Override
public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch,
int posRotationIncrements, boolean teleport) { int posRotationIncrements, boolean teleport) {
// Stationary Anchors are responsible for keeping position and motion in sync // Stationary Anchors are responsible for keeping position and motion in sync
// themselves. // themselves.
if (stationary) if (stationary)
@ -592,8 +601,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
@Override @Override
// Make sure nothing can move contraptions out of the way // Make sure nothing can move contraptions out of the way
public void setMotion(Vec3d motionIn) { public void setMotion(Vec3d motionIn) {}
}
@Override @Override
public void setPositionAndUpdate(double x, double y, double z) { public void setPositionAndUpdate(double x, double y, double z) {
@ -623,9 +631,31 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public float getInitialAngle() { public float getInitialAngle() {
return initialAngle; return initialAngle;
} }
public Vec3d getRotationVec() { public Vec3d getRotationVec() {
return new Vec3d(pitch, yaw, roll); return new Vec3d(getPitch(1), getYaw(1), getRoll(1));
}
public boolean canCollideWith(Entity e) {
if (e instanceof PlayerEntity && e.isSpectator())
return false;
if (e.noClip)
return false;
if (e instanceof HangingEntity)
return false;
if (e instanceof SuperGlueEntity)
return false;
if (e instanceof IProjectile)
return false;
Entity riding = this.getRidingEntity();
while (riding != null) {
if (riding == e)
return false;
riding = riding.getRidingEntity();
}
return e.getPushReaction() == PushReaction.NORMAL;
} }
} }