Collision tweaks

- Fixed pulleys/pistons crashing when collided with blocks on client
- Entities moved by a colliding contraption now try to unstuck themselves when the structure disassembles
This commit is contained in:
simibubi 2020-03-13 13:01:55 +01:00
parent 6031d9fce1
commit 8cb5dac2c9
3 changed files with 79 additions and 13 deletions

View file

@ -39,6 +39,7 @@ public class ContraptionCollider {
Contraption contraption = contraptionEntity.getContraption();
AxisAlignedBB bounds = contraptionEntity.getBoundingBox();
Vec3d contraptionPosition = contraptionEntity.getPositionVec();
contraptionEntity.collidingEntities.clear();
if (contraption == null)
return;
@ -60,7 +61,9 @@ public class ContraptionCollider {
Vec3d allowedMovement = Entity.getAllowedMovement(relativeMotion, entityBB, world,
ISelectionContext.forEntity(entity), potentialHits);
potentialHits.createStream()
.forEach(voxelShape -> pushEntityOutOfShape(entity, voxelShape, positionOffset));
.forEach(voxelShape -> pushEntityOutOfShape(entity, voxelShape, positionOffset, contraptionMotion));
contraptionEntity.collidingEntities.add(entity);
if (allowedMovement.equals(relativeMotion))
continue;
@ -79,7 +82,8 @@ public class ContraptionCollider {
}
public static void pushEntityOutOfShape(Entity entity, VoxelShape voxelShape, Vec3d positionOffset) {
public static void pushEntityOutOfShape(Entity entity, VoxelShape voxelShape, Vec3d positionOffset,
Vec3d shapeMotion) {
AxisAlignedBB entityBB = entity.getBoundingBox().offset(positionOffset);
Vec3d entityMotion = entity.getMotion();
@ -117,18 +121,20 @@ public class ContraptionCollider {
double clamped;
switch (bestSide.getAxis()) {
case X:
clamped = positive ? Math.max(0, entityMotion.x) : Math.min(0, entityMotion.x);
clamped = positive ? Math.max(shapeMotion.x, entityMotion.x) : Math.min(shapeMotion.x, entityMotion.x);
entity.setMotion(clamped, entityMotion.y, entityMotion.z);
break;
case Y:
clamped = positive ? Math.max(0, entityMotion.y) : Math.min(0, entityMotion.y);
clamped = positive ? Math.max(shapeMotion.y, entityMotion.y) : Math.min(shapeMotion.y, entityMotion.y);
if (bestSide == Direction.UP)
clamped = shapeMotion.y;
entity.setMotion(entityMotion.x, clamped, entityMotion.z);
entity.fall(entity.fallDistance, 1);
entity.fallDistance = 0;
entity.onGround = true;
break;
case Z:
clamped = positive ? Math.max(0, entityMotion.z) : Math.min(0, entityMotion.z);
clamped = positive ? Math.max(shapeMotion.z, entityMotion.z) : Math.min(shapeMotion.z, entityMotion.z);
entity.setMotion(entityMotion.x, entityMotion.y, clamped);
break;
}

View file

@ -3,8 +3,13 @@ package com.simibubi.create.modules.contraptions.components.contraptions;
import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp;
import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngleDiff;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.MutablePair;
import com.google.common.collect.ImmutableSet;
import com.simibubi.create.AllEntities;
import com.simibubi.create.AllPackets;
import com.simibubi.create.foundation.utility.VecHelper;
@ -27,9 +32,14 @@ import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ReuseableStream;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraft.world.server.ServerWorld;
@ -48,6 +58,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
protected Vec3d motionBeforeStall;
protected boolean stationary;
final List<Entity> collidingEntities = new ArrayList<>();
private static final DataParameter<Boolean> STALLED =
EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN);
@ -400,12 +412,61 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
public void disassemble() {
if (getContraption() != null) {
getContraption().disassemble(world, new BlockPos(getPositionVec().add(.5, .5, .5)),
new Vec3d(getRoll(1), getYaw(1), getPitch(1)));
BlockPos offset = new BlockPos(getPositionVec().add(.5, .5, .5));
Vec3d rotation = new Vec3d(getRoll(1), getYaw(1), getPitch(1));
getContraption().disassemble(world, offset, rotation);
preventMovedEntitiesFromGettingStuck();
}
remove();
}
public void preventMovedEntitiesFromGettingStuck() {
Vec3d stuckTest = new Vec3d(0, -2, 0);
for (Entity e : collidingEntities) {
Vec3d vec = stuckTest;
AxisAlignedBB axisalignedbb = e.getBoundingBox().offset(0, 2, 0);
ISelectionContext iselectioncontext = ISelectionContext.forEntity(this);
VoxelShape voxelshape = e.world.getWorldBorder().getShape();
Stream<VoxelShape> stream =
VoxelShapes.compare(voxelshape, VoxelShapes.create(axisalignedbb.shrink(1.0E-7D)), IBooleanFunction.AND)
? Stream.empty()
: Stream.of(voxelshape);
Stream<VoxelShape> stream1 =
this.world.getEmptyCollisionShapes(e, axisalignedbb.expand(vec), ImmutableSet.of());
ReuseableStream<VoxelShape> reuseablestream = new ReuseableStream<>(Stream.concat(stream1, stream));
Vec3d vec3d = vec.lengthSquared() == 0.0D ? vec
: collideBoundingBoxHeuristically(this, vec, axisalignedbb, e.world, iselectioncontext,
reuseablestream);
boolean flag = vec.x != vec3d.x;
boolean flag1 = vec.y != vec3d.y;
boolean flag2 = vec.z != vec3d.z;
boolean flag3 = e.onGround || flag1 && vec.y < 0.0D;
if (this.stepHeight > 0.0F && flag3 && (flag || flag2)) {
Vec3d vec3d1 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, (double) e.stepHeight, vec.z),
axisalignedbb, e.world, iselectioncontext, reuseablestream);
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);
if (vec3d2.y < (double) e.stepHeight) {
Vec3d vec3d3 = collideBoundingBoxHeuristically(e, new Vec3d(vec.x, 0.0D, vec.z),
axisalignedbb.offset(vec3d2), e.world, iselectioncontext, reuseablestream).add(vec3d2);
if (horizontalMag(vec3d3) > horizontalMag(vec3d1)) {
vec3d1 = vec3d3;
}
}
if (horizontalMag(vec3d1) > horizontalMag(vec3d)) {
vec3d = vec3d1.add(collideBoundingBoxHeuristically(e, new Vec3d(0.0D, -vec3d1.y + vec.y, 0.0D),
axisalignedbb.offset(vec3d1), e.world, iselectioncontext, reuseablestream));
}
}
vec = vec3d.subtract(stuckTest);
if (vec.equals(Vec3d.ZERO))
continue;
e.setPosition(e.posX + vec.x, e.posY + vec.y, e.posZ + vec.z);
}
}
public Contraption getContraption() {
return contraption;
}

View file

@ -48,9 +48,8 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
@Override
public void tick() {
super.tick();
boolean contraptionPresent = movedContraption != null;
if (contraptionPresent) {
if (movedContraption != null) {
movedContraption.collisionTick();
if (!movedContraption.isAlive())
movedContraption = null;
@ -59,7 +58,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
if (world.isRemote)
clientOffsetDiff *= .75f;
if (waitingForSpeedChange && contraptionPresent) {
if (waitingForSpeedChange && movedContraption != null) {
if (world.isRemote) {
float syncSpeed = clientOffsetDiff / 2f;
offset += syncSpeed;
@ -86,7 +85,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
if (!running)
return;
contraptionPresent = movedContraption != null;
boolean contraptionPresent = movedContraption != null;
float movementSpeed = getMovementSpeed();
float newOffset = offset + movementSpeed;
if ((int) newOffset != (int) offset)