From 8cb5dac2c926317c99e0b4fe780a0e0170121dad Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 13 Mar 2020 13:01:55 +0100 Subject: [PATCH] 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 --- .../contraptions/ContraptionCollider.java | 16 +++-- .../contraptions/ContraptionEntity.java | 69 +++++++++++++++++-- .../piston/LinearActuatorTileEntity.java | 7 +- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionCollider.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionCollider.java index 852c7fb8a..64f287aff 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionCollider.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionCollider.java @@ -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; } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java index c1b029d6b..bf813c162 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java @@ -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 collidingEntities = new ArrayList<>(); + private static final DataParameter STALLED = EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN); @@ -120,7 +132,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD move(getMotion().x, getMotion().y, getMotion().z); if (ContraptionCollider.collideBlocks(this)) controllerTE.collided(); - + tickActors(new Vec3d(posX - prevPosX, posY - prevPosY, posZ - prevPosZ)); prevYaw = yaw; @@ -129,7 +141,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD super.tick(); } - + public void collisionTick() { ContraptionCollider.collideEntities(this); } @@ -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 stream = + VoxelShapes.compare(voxelshape, VoxelShapes.create(axisalignedbb.shrink(1.0E-7D)), IBooleanFunction.AND) + ? Stream.empty() + : Stream.of(voxelshape); + Stream stream1 = + this.world.getEmptyCollisionShapes(e, axisalignedbb.expand(vec), ImmutableSet.of()); + ReuseableStream 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; } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java index 888156cd9..88e5757b5 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java @@ -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)