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:
parent
6031d9fce1
commit
8cb5dac2c9
3 changed files with 79 additions and 13 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue