mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-11 04:22:00 +01:00
S.A.T. will separate thee!
- Implemented a prototype of a new collision resolver that supports rotated bounding boxes
This commit is contained in:
parent
7b64f06d79
commit
56fe0c9c8a
5 changed files with 417 additions and 66 deletions
|
@ -3,8 +3,14 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
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.OrientedBB;
|
||||||
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
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;
|
||||||
|
@ -23,7 +29,6 @@ import net.minecraft.util.ReuseableStream;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.shapes.ISelectionContext;
|
|
||||||
import net.minecraft.util.math.shapes.VoxelShape;
|
import net.minecraft.util.math.shapes.VoxelShape;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||||
|
@ -43,10 +48,11 @@ public class ContraptionCollider {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
World world = contraptionEntity.getEntityWorld();
|
World world = contraptionEntity.getEntityWorld();
|
||||||
Vec3d contraptionMotion = contraptionEntity.getMotion();
|
// 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();
|
||||||
|
Vec3d contraptionRotation = contraptionEntity.getRotationVec();
|
||||||
contraptionEntity.collidingEntities.clear();
|
contraptionEntity.collidingEntities.clear();
|
||||||
|
|
||||||
if (contraption == null)
|
if (contraption == null)
|
||||||
|
@ -55,41 +61,104 @@ 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))) {
|
e -> canBeCollidedWith(e))) {
|
||||||
|
|
||||||
ReuseableStream<VoxelShape> potentialHits =
|
|
||||||
getPotentiallyCollidedShapes(world, contraption, contraptionPosition, entity);
|
|
||||||
if (potentialHits.createStream().count() == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
contraptionEntity.collidingEntities.add(entity);
|
|
||||||
|
|
||||||
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)
|
if (entity instanceof PlayerEntity && !world.isRemote)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
entity.setMotion(allowedMovement.add(contraptionMotion));
|
Vec3d centerOf = VecHelper.getCenterOf(BlockPos.ZERO);
|
||||||
entity.velocityChanged = true;
|
Vec3d entityPosition = entity.getPositionVec();
|
||||||
|
Vec3d position = entityPosition.subtract(contraptionPosition)
|
||||||
|
.subtract(centerOf);
|
||||||
|
position =
|
||||||
|
VecHelper.rotate(position, -contraptionRotation.x, -contraptionRotation.y, -contraptionRotation.z);
|
||||||
|
position = position.add(centerOf)
|
||||||
|
.subtract(entityPosition);
|
||||||
|
AxisAlignedBB localBB = entity.getBoundingBox()
|
||||||
|
.offset(position)
|
||||||
|
.grow(1.0E-7D);
|
||||||
|
|
||||||
|
OrientedBB obb = new OrientedBB(localBB);
|
||||||
|
if (!contraptionRotation.equals(Vec3d.ZERO)) {
|
||||||
|
Matrix3d rotation = new Matrix3d().asIdentity();
|
||||||
|
rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(contraptionRotation.x)));
|
||||||
|
rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(contraptionRotation.y)));
|
||||||
|
rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(contraptionRotation.z)));
|
||||||
|
obb.setRotation(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReuseableStream<VoxelShape> potentialHits = getPotentiallyCollidedShapes(world, contraption, localBB);
|
||||||
|
if (potentialHits.createStream()
|
||||||
|
.count() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MutableBoolean onCollide = new MutableBoolean(true);
|
||||||
|
potentialHits.createStream()
|
||||||
|
.forEach(shape -> {
|
||||||
|
AxisAlignedBB bb = shape.getBoundingBox();
|
||||||
|
Vec3d intersect = obb.intersect(bb);
|
||||||
|
if (intersect == null)
|
||||||
|
return;
|
||||||
|
intersect = VecHelper.rotate(intersect, contraptionRotation.x, contraptionRotation.y,
|
||||||
|
contraptionRotation.z);
|
||||||
|
|
||||||
|
obb.setCenter(obb.getCenter()
|
||||||
|
.add(intersect));
|
||||||
|
entity.move(MoverType.PISTON, intersect);
|
||||||
|
|
||||||
|
Vec3d entityMotion = entity.getMotion();
|
||||||
|
if (entityMotion.getX() > 0 == intersect.getX() < 0)
|
||||||
|
entityMotion = entityMotion.mul(0, 1, 1);
|
||||||
|
if (entityMotion.getY() > 0 == intersect.getY() < 0)
|
||||||
|
entityMotion = entityMotion.mul(1, 0, 1);
|
||||||
|
if (entityMotion.getZ() > 0 == intersect.getZ() < 0)
|
||||||
|
entityMotion = entityMotion.mul(1, 1, 0);
|
||||||
|
entity.setMotion(entityMotion);
|
||||||
|
|
||||||
|
if (onCollide.isTrue()) {
|
||||||
|
onCollide.setFalse();
|
||||||
|
contraptionEntity.collidingEntities.add(entity);
|
||||||
|
entity.velocityChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersect.y > 0) {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -112,11 +181,14 @@ 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) {
|
Vec3d shapeMotion) {
|
||||||
AxisAlignedBB entityBB = entity.getBoundingBox().offset(positionOffset);
|
AxisAlignedBB entityBB = entity.getBoundingBox()
|
||||||
|
.offset(positionOffset);
|
||||||
Vec3d entityMotion = entity.getMotion();
|
Vec3d entityMotion = entity.getMotion();
|
||||||
|
|
||||||
if (!voxelShape.toBoundingBoxList().stream().anyMatch(entityBB::intersects))
|
if (!voxelShape.toBoundingBoxList()
|
||||||
|
.stream()
|
||||||
|
.anyMatch(entityBB::intersects))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AxisAlignedBB shapeBB = voxelShape.getBoundingBox();
|
AxisAlignedBB shapeBB = voxelShape.getBoundingBox();
|
||||||
|
@ -127,8 +199,7 @@ public class ContraptionCollider {
|
||||||
for (Direction face : Direction.values()) {
|
for (Direction face : Direction.values()) {
|
||||||
Axis axis = face.getAxis();
|
Axis axis = face.getAxis();
|
||||||
double d = axis == Axis.X ? entityBB.getXSize() + shapeBB.getXSize()
|
double d = axis == Axis.X ? entityBB.getXSize() + shapeBB.getXSize()
|
||||||
: axis == Axis.Y ? entityBB.getYSize() + shapeBB.getYSize()
|
: axis == Axis.Y ? entityBB.getYSize() + shapeBB.getYSize() : entityBB.getZSize() + shapeBB.getZSize();
|
||||||
: entityBB.getZSize() + shapeBB.getZSize();
|
|
||||||
d = d + .5f;
|
d = d + .5f;
|
||||||
|
|
||||||
Vec3d nudge = new Vec3d(face.getDirectionVec()).scale(d);
|
Vec3d nudge = new Vec3d(face.getDirectionVec()).scale(d);
|
||||||
|
@ -171,13 +242,14 @@ public class ContraptionCollider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
public static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
||||||
Vec3d contraptionPosition, Entity entity) {
|
AxisAlignedBB localBB) {
|
||||||
AxisAlignedBB blockScanBB = entity.getBoundingBox().offset(contraptionPosition.scale(-1)).grow(.5f);
|
AxisAlignedBB blockScanBB = localBB.grow(.5f);
|
||||||
BlockPos min = new BlockPos(blockScanBB.minX, blockScanBB.minY, blockScanBB.minZ);
|
BlockPos min = new BlockPos(blockScanBB.minX, blockScanBB.minY, blockScanBB.minZ);
|
||||||
BlockPos max = new BlockPos(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ);
|
BlockPos max = new BlockPos(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ);
|
||||||
|
|
||||||
ReuseableStream<VoxelShape> potentialHits =
|
ReuseableStream<VoxelShape> potentialHits = new ReuseableStream<>(BlockPos.getAllInBox(min, max)
|
||||||
new ReuseableStream<>(BlockPos.getAllInBox(min, max).filter(contraption.blocks::containsKey).map(p -> {
|
.filter(contraption.blocks::containsKey)
|
||||||
|
.map(p -> {
|
||||||
BlockState blockState = contraption.blocks.get(p).state;
|
BlockState blockState = contraption.blocks.get(p).state;
|
||||||
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);
|
||||||
|
@ -217,7 +289,7 @@ public class ContraptionCollider {
|
||||||
|
|
||||||
// Other moving Contraptions
|
// Other moving Contraptions
|
||||||
for (ContraptionEntity otherContraptionEntity : world.getEntitiesWithinAABB(ContraptionEntity.class,
|
for (ContraptionEntity otherContraptionEntity : world.getEntitiesWithinAABB(ContraptionEntity.class,
|
||||||
bounds.grow(1), e -> !e.equals(contraptionEntity))) {
|
bounds.grow(1), e -> !e.equals(contraptionEntity))) {
|
||||||
|
|
||||||
if (!otherContraptionEntity.collisionEnabled())
|
if (!otherContraptionEntity.collisionEnabled())
|
||||||
continue;
|
continue;
|
||||||
|
@ -232,11 +304,13 @@ public class ContraptionCollider {
|
||||||
if (otherBounds == null)
|
if (otherBounds == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bounds.offset(motion).intersects(otherBounds.offset(otherMotion)))
|
if (!bounds.offset(motion)
|
||||||
|
.intersects(otherBounds.offset(otherMotion)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (BlockPos colliderPos : contraption.getColliders(world, movementDirection)) {
|
for (BlockPos colliderPos : contraption.getColliders(world, movementDirection)) {
|
||||||
colliderPos = colliderPos.add(gridPos).subtract(new BlockPos(otherPosition));
|
colliderPos = colliderPos.add(gridPos)
|
||||||
|
.subtract(new BlockPos(otherPosition));
|
||||||
if (!otherContraption.blocks.containsKey(colliderPos))
|
if (!otherContraption.blocks.containsKey(colliderPos))
|
||||||
continue;
|
continue;
|
||||||
return true;
|
return true;
|
||||||
|
@ -247,7 +321,7 @@ public class ContraptionCollider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCollidingWithWorld(World world, Contraption contraption, BlockPos anchor,
|
public static boolean isCollidingWithWorld(World world, Contraption contraption, BlockPos anchor,
|
||||||
Direction movementDirection) {
|
Direction movementDirection) {
|
||||||
for (BlockPos pos : contraption.getColliders(world, movementDirection)) {
|
for (BlockPos pos : contraption.getColliders(world, movementDirection)) {
|
||||||
BlockPos colliderPos = pos.add(anchor);
|
BlockPos colliderPos = pos.add(anchor);
|
||||||
|
|
||||||
|
@ -263,7 +337,8 @@ public class ContraptionCollider {
|
||||||
BlockBreakingMovementBehaviour behaviour =
|
BlockBreakingMovementBehaviour behaviour =
|
||||||
(BlockBreakingMovementBehaviour) block.getMovementBehaviour();
|
(BlockBreakingMovementBehaviour) block.getMovementBehaviour();
|
||||||
if (!behaviour.canBreak(world, colliderPos, collidedState)
|
if (!behaviour.canBreak(world, colliderPos, collidedState)
|
||||||
&& !collidedState.getCollisionShape(world, pos).isEmpty()) {
|
&& !collidedState.getCollisionShape(world, pos)
|
||||||
|
.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -271,12 +346,14 @@ public class ContraptionCollider {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AllBlocks.PULLEY_MAGNET.has(collidedState) && pos.equals(BlockPos.ZERO)
|
if (AllBlocks.PULLEY_MAGNET.has(collidedState) && pos.equals(BlockPos.ZERO)
|
||||||
&& movementDirection == Direction.UP)
|
&& movementDirection == Direction.UP)
|
||||||
continue;
|
continue;
|
||||||
if (collidedState.getBlock() instanceof CocoaBlock)
|
if (collidedState.getBlock() instanceof CocoaBlock)
|
||||||
continue;
|
continue;
|
||||||
if (!collidedState.getMaterial().isReplaceable()
|
if (!collidedState.getMaterial()
|
||||||
&& !collidedState.getCollisionShape(world, colliderPos).isEmpty()) {
|
.isReplaceable()
|
||||||
|
&& !collidedState.getCollisionShape(world, colliderPos)
|
||||||
|
.isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ 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.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.content.contraptions.components.structureMovement.piston.LinearActuatorTileEntity;
|
|
||||||
import com.simibubi.create.foundation.item.ItemHelper;
|
import com.simibubi.create.foundation.item.ItemHelper;
|
||||||
import com.simibubi.create.foundation.networking.AllPackets;
|
import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
|
@ -136,7 +135,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean collisionEnabled() {
|
public boolean collisionEnabled() {
|
||||||
return getController() instanceof LinearActuatorTileEntity;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -624,5 +623,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
|
||||||
public float getInitialAngle() {
|
public float getInitialAngle() {
|
||||||
return initialAngle;
|
return initialAngle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vec3d getRotationVec() {
|
||||||
|
return new Vec3d(pitch, yaw, roll);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
super.addBehaviours(behaviours);
|
super.addBehaviours(behaviours);
|
||||||
movementMode = new ScrollOptionBehaviour<>(RotationMode.class, Lang.translate("contraptions.movement_mode"),
|
movementMode = new ScrollOptionBehaviour<>(RotationMode.class, Lang.translate("contraptions.movement_mode"),
|
||||||
this, getMovementModeSlot());
|
this, getMovementModeSlot());
|
||||||
movementMode.requiresWrench();
|
movementMode.requiresWrench();
|
||||||
behaviours.add(movementMode);
|
behaviours.add(movementMode);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
public void neighbourChanged() {
|
public void neighbourChanged() {
|
||||||
if (!hasWorld())
|
if (!hasWorld())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boolean shouldWindmill = world.isBlockPowered(pos);
|
boolean shouldWindmill = world.isBlockPowered(pos);
|
||||||
if (shouldWindmill == isWindmill)
|
if (shouldWindmill == isWindmill)
|
||||||
return;
|
return;
|
||||||
|
@ -153,7 +153,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assemble() {
|
public void assemble() {
|
||||||
if (!(world.getBlockState(pos).getBlock() instanceof MechanicalBearingBlock))
|
if (!(world.getBlockState(pos)
|
||||||
|
.getBlock() instanceof MechanicalBearingBlock))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Direction direction = getBlockState().get(FACING);
|
Direction direction = getBlockState().get(FACING);
|
||||||
|
@ -168,7 +169,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
return;
|
return;
|
||||||
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
contraption.removeBlocksFromWorld(world, BlockPos.ZERO);
|
||||||
|
|
||||||
movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this);
|
movedContraption = ContraptionEntity.createStationary(world, contraption)
|
||||||
|
.controlledBy(this);
|
||||||
BlockPos anchor = pos.offset(direction);
|
BlockPos anchor = pos.offset(direction);
|
||||||
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
|
movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ());
|
||||||
world.addEntity(movedContraption);
|
world.addEntity(movedContraption);
|
||||||
|
@ -206,7 +208,8 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
|
|
||||||
if (world.isRemote)
|
if (world.isRemote)
|
||||||
clientAngleDiff /= 2;
|
clientAngleDiff /= 2;
|
||||||
|
if (movedContraption != null)
|
||||||
|
movedContraption.collisionTick();
|
||||||
if (running && Contraption.isFrozen())
|
if (running && Contraption.isFrozen())
|
||||||
disassemble();
|
disassemble();
|
||||||
|
|
||||||
|
@ -214,11 +217,12 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
assembleNextTick = false;
|
assembleNextTick = false;
|
||||||
if (running) {
|
if (running) {
|
||||||
boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE
|
boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE
|
||||||
|| (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED);
|
|| (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED);
|
||||||
if (speed == 0 && (canDisassemble || movedContraption == null
|
if (speed == 0 && (canDisassemble || movedContraption == null
|
||||||
|| movedContraption.getContraption().blocks.isEmpty())) {
|
|| movedContraption.getContraption().blocks.isEmpty())) {
|
||||||
if (movedContraption != null)
|
if (movedContraption != null)
|
||||||
movedContraption.getContraption().stop(world);
|
movedContraption.getContraption()
|
||||||
|
.stop(world);
|
||||||
disassemble();
|
disassemble();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -255,9 +259,11 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
|
|
||||||
protected void applyRotation() {
|
protected void applyRotation() {
|
||||||
if (movedContraption != null) {
|
if (movedContraption != null) {
|
||||||
Axis axis = getBlockState().get(FACING).getAxis();
|
Axis axis = getBlockState().get(FACING)
|
||||||
|
.getAxis();
|
||||||
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
|
Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
|
||||||
Vec3d vec = new Vec3d(1, 1, 1).scale(angle).mul(new Vec3d(direction.getDirectionVec()));
|
Vec3d vec = new Vec3d(1, 1, 1).scale(angle)
|
||||||
|
.mul(new Vec3d(direction.getDirectionVec()));
|
||||||
movedContraption.rotateTo(vec.x, vec.y, vec.z);
|
movedContraption.rotateTo(vec.x, vec.y, vec.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,14 +300,14 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
|
||||||
protected ValueBoxTransform getMovementModeSlot() {
|
protected ValueBoxTransform getMovementModeSlot() {
|
||||||
return new DirectionalExtenderScrollOptionSlot((state, d) -> {
|
return new DirectionalExtenderScrollOptionSlot((state, d) -> {
|
||||||
Axis axis = d.getAxis();
|
Axis axis = d.getAxis();
|
||||||
Axis bearingAxis = state.get(MechanicalBearingBlock.FACING).getAxis();
|
Axis bearingAxis = state.get(MechanicalBearingBlock.FACING)
|
||||||
|
.getAxis();
|
||||||
return bearingAxis != axis;
|
return bearingAxis != axis;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collided() {
|
public void collided() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAttachedTo(ContraptionEntity contraption) {
|
public boolean isAttachedTo(ContraptionEntity contraption) {
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.simibubi.create.foundation.collision;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
public class Matrix3d {
|
||||||
|
|
||||||
|
double m00, m01, m02;
|
||||||
|
double m10, m11, m12;
|
||||||
|
double m20, m21, m22;
|
||||||
|
|
||||||
|
public Matrix3d asIdentity() {
|
||||||
|
m00 = m11 = m22 = 1;
|
||||||
|
m01 = m02 = m10 = m12 = m20 = m21 = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d asXRotation(float radians) {
|
||||||
|
asIdentity();
|
||||||
|
double s = MathHelper.sin(radians);
|
||||||
|
double c = MathHelper.cos(radians);
|
||||||
|
m22 = m11 = c;
|
||||||
|
m21 = s;
|
||||||
|
m12 = -s;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d asYRotation(float radians) {
|
||||||
|
asIdentity();
|
||||||
|
double s = MathHelper.sin(radians);
|
||||||
|
double c = MathHelper.cos(radians);
|
||||||
|
m00 = m22 = c;
|
||||||
|
m20 = s;
|
||||||
|
m02 = -s;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d asZRotation(float radians) {
|
||||||
|
asIdentity();
|
||||||
|
double s = MathHelper.sin(radians);
|
||||||
|
double c = MathHelper.cos(radians);
|
||||||
|
m00 = m11 = c;
|
||||||
|
m01 = -s;
|
||||||
|
m10 = s;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d transpose() {
|
||||||
|
double d = m01;
|
||||||
|
m01 = m10;
|
||||||
|
m10 = d;
|
||||||
|
d = m02;
|
||||||
|
m02 = m20;
|
||||||
|
m20 = d;
|
||||||
|
d = m12;
|
||||||
|
m12 = m21;
|
||||||
|
m21 = d;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d scale(double d) {
|
||||||
|
m00 *= d;
|
||||||
|
m11 *= d;
|
||||||
|
m22 *= d;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d add(Matrix3d matrix) {
|
||||||
|
m00 += matrix.m00;
|
||||||
|
m01 += matrix.m01;
|
||||||
|
m02 += matrix.m02;
|
||||||
|
m10 += matrix.m10;
|
||||||
|
m11 += matrix.m11;
|
||||||
|
m12 += matrix.m12;
|
||||||
|
m20 += matrix.m20;
|
||||||
|
m21 += matrix.m21;
|
||||||
|
m22 += matrix.m22;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d multiply(Matrix3d m) {
|
||||||
|
double new00 = m00 * m.m00 + m01 * m.m10 + m02 * m.m20;
|
||||||
|
double new01 = m00 * m.m01 + m01 * m.m11 + m02 * m.m21;
|
||||||
|
double new02 = m00 * m.m02 + m01 * m.m12 + m02 * m.m22;
|
||||||
|
double new10 = m10 * m.m00 + m11 * m.m10 + m12 * m.m20;
|
||||||
|
double new11 = m10 * m.m01 + m11 * m.m11 + m12 * m.m21;
|
||||||
|
double new12 = m10 * m.m02 + m11 * m.m12 + m12 * m.m22;
|
||||||
|
double new20 = m20 * m.m00 + m21 * m.m10 + m22 * m.m20;
|
||||||
|
double new21 = m20 * m.m01 + m21 * m.m11 + m22 * m.m21;
|
||||||
|
double new22 = m20 * m.m02 + m21 * m.m12 + m22 * m.m22;
|
||||||
|
m00 = new00;
|
||||||
|
m01 = new01;
|
||||||
|
m02 = new02;
|
||||||
|
m10 = new10;
|
||||||
|
m11 = new11;
|
||||||
|
m12 = new12;
|
||||||
|
m20 = new20;
|
||||||
|
m21 = new21;
|
||||||
|
m22 = new22;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3d transform(Vec3d vec) {
|
||||||
|
double x = vec.x;
|
||||||
|
double y = vec.y;
|
||||||
|
double z = vec.z;
|
||||||
|
x = x * m00 + y * m01 + z * m02;
|
||||||
|
y = x * m10 + y * m11 + z * m12;
|
||||||
|
z = x * m20 + y * m21 + z * m22;
|
||||||
|
return new Vec3d(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d copy() {
|
||||||
|
return new Matrix3d().add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
package com.simibubi.create.foundation.collision;
|
||||||
|
|
||||||
|
import static java.lang.Math.abs;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||||
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
public class OrientedBB {
|
||||||
|
|
||||||
|
Vec3d center;
|
||||||
|
Vec3d extents;
|
||||||
|
Matrix3d rotation;
|
||||||
|
|
||||||
|
public OrientedBB(AxisAlignedBB bb) {
|
||||||
|
this(bb.getCenter(), extentsFromBB(bb), new Matrix3d().asIdentity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrientedBB() {
|
||||||
|
this(Vec3d.ZERO, Vec3d.ZERO, new Matrix3d().asIdentity());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrientedBB(Vec3d center, Vec3d extents, Matrix3d rotation) {
|
||||||
|
this.setCenter(center);
|
||||||
|
this.extents = extents;
|
||||||
|
this.setRotation(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3d intersect(AxisAlignedBB bb) {
|
||||||
|
Vec3d extentsA = extentsFromBB(bb);
|
||||||
|
// Inverse rotation, to bring our OBB to AA space
|
||||||
|
Vec3d intersects = separateBBs(bb.getCenter(), center, extentsA, extents, rotation.transpose());
|
||||||
|
// clean up
|
||||||
|
rotation.transpose();
|
||||||
|
return intersects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3d extentsFromBB(AxisAlignedBB bb) {
|
||||||
|
return new Vec3d(bb.getXSize() / 2, bb.getYSize() / 2, bb.getZSize() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vec3d separateBBs(Vec3d cA, Vec3d cB, Vec3d eA, Vec3d eB, Matrix3d m) {
|
||||||
|
Vec3d t = cB.subtract(cA);
|
||||||
|
double a00 = abs(m.m00);
|
||||||
|
double a01 = abs(m.m01);
|
||||||
|
double a02 = abs(m.m02);
|
||||||
|
double a10 = abs(m.m10);
|
||||||
|
double a11 = abs(m.m11);
|
||||||
|
double a12 = abs(m.m12);
|
||||||
|
double a20 = abs(m.m20);
|
||||||
|
double a21 = abs(m.m21);
|
||||||
|
double a22 = abs(m.m22);
|
||||||
|
|
||||||
|
MutableObject<Vec3d> bestAxis = new MutableObject<>(Vec3d.ZERO);
|
||||||
|
MutableDouble bestSep = new MutableDouble(Double.MAX_VALUE);
|
||||||
|
|
||||||
|
Vec3d uA0 = new Vec3d(1, 0, 0);
|
||||||
|
Vec3d uA1 = new Vec3d(0, 1, 0);
|
||||||
|
Vec3d uA2 = new Vec3d(0, 0, 1);
|
||||||
|
|
||||||
|
Vec3d uB0 = new Vec3d(m.m00, m.m01, m.m02);
|
||||||
|
Vec3d uB1 = new Vec3d(m.m10, m.m11, m.m12);
|
||||||
|
Vec3d uB2 = new Vec3d(m.m20, m.m21, m.m22);
|
||||||
|
|
||||||
|
checkCount = 0;
|
||||||
|
|
||||||
|
if (
|
||||||
|
|
||||||
|
// Separate along A's local axes (global XYZ)
|
||||||
|
!(isSeparatedAlong(bestAxis, bestSep, uA0, t.x, eA.x, a00 * eB.x + a01 * eB.y + a02 * eB.z)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA1, t.y, eA.y, a10 * eB.x + a11 * eB.y + a12 * eB.z)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA2, t.z, eA.z, a20 * eB.x + a21 * eB.y + a22 * eB.z)
|
||||||
|
|
||||||
|
// Separate along B's local axes
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uB0, t.x * m.m00 + t.y * m.m10 + t.z * m.m20,
|
||||||
|
eA.x * a00 + eA.y * a10 + eA.z * a20, eB.x)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uB1, t.x * m.m01 + t.y * m.m11 + t.z * m.m21,
|
||||||
|
eA.x * a01 + eA.y * a11 + eA.z * a21, eB.y)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uB2, t.x * m.m02 + t.y * m.m12 + t.z * m.m22,
|
||||||
|
eA.x * a02 + eA.y * a12 + eA.z * a22, eB.z)
|
||||||
|
|
||||||
|
// Separate along axes perpendicular to AxB
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB0), t.z * m.m10 - t.y * m.m20,
|
||||||
|
eA.y * a20 + eA.z * a10, eB.y * a02 + eB.z * a01)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB1), t.z * m.m11 - t.y * m.m21,
|
||||||
|
eA.y * a21 + eA.z * a11, eB.x * a02 + eB.z * a00)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB2), t.z * m.m12 - t.y * m.m22,
|
||||||
|
eA.y * a22 + eA.z * a12, eB.x * a01 + eB.y * a00)
|
||||||
|
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB0), t.x * m.m20 - t.z * m.m00,
|
||||||
|
eA.x * a20 + eA.z * a00, eB.y * a12 + eB.z * a11)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB1), t.x * m.m21 - t.z * m.m01,
|
||||||
|
eA.x * a21 + eA.z * a01, eB.x * a12 + eB.z * a10)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB2), t.x * m.m22 - t.z * m.m02,
|
||||||
|
eA.x * a22 + eA.z * a02, eB.x * a11 + eB.y * a10)
|
||||||
|
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB0), t.y * m.m00 - t.x * m.m10,
|
||||||
|
eA.x * a10 + eA.y * a00, eB.y * a22 + eB.z * a21)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB1), t.y * m.m01 - t.x * m.m11,
|
||||||
|
eA.x * a11 + eA.y * a01, eB.x * a22 + eB.z * a20)
|
||||||
|
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB2), t.y * m.m02 - t.x * m.m12,
|
||||||
|
eA.x * a12 + eA.y * a02, eB.x * a21 + eB.y * a20)))
|
||||||
|
|
||||||
|
return bestAxis.getValue()
|
||||||
|
.normalize()
|
||||||
|
.scale(bestSep.getValue());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int checkCount = 0;
|
||||||
|
|
||||||
|
static boolean isSeparatedAlong(MutableObject<Vec3d> bestAxis, MutableDouble bestSeparation, Vec3d axis, double TL,
|
||||||
|
double rA, double rB) {
|
||||||
|
double distance = abs(TL);
|
||||||
|
|
||||||
|
checkCount++;
|
||||||
|
|
||||||
|
double diff = distance - (rA + rB);
|
||||||
|
if (diff > 0)
|
||||||
|
return true;
|
||||||
|
if (distance != 0 && -diff < abs(bestSeparation.getValue())) {
|
||||||
|
bestAxis.setValue(axis);
|
||||||
|
bestSeparation.setValue(Math.signum(TL) * abs(diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3d getRotation() {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation(Matrix3d rotation) {
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3d getCenter() {
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCenter(Vec3d center) {
|
||||||
|
this.center = center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue