mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Merge branch 'mc1.15/dev' into mc1.16/dev
This commit is contained in:
commit
2b4ef88fc1
7 changed files with 293 additions and 99 deletions
|
@ -455,6 +455,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
if (!ticking)
|
||||
contraption.stop(world);
|
||||
}
|
||||
if (contraption != null)
|
||||
contraption.onEntityRemoved(this);
|
||||
super.remove(keepData);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,30 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||
|
||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole;
|
||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.AllMovementBehaviours;
|
||||
import com.simibubi.create.content.contraptions.base.IRotate;
|
||||
|
@ -32,9 +57,22 @@ import com.simibubi.create.foundation.fluid.CombinedTankWrapper;
|
|||
import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld;
|
||||
import com.simibubi.create.foundation.render.backend.light.EmptyLighter;
|
||||
import com.simibubi.create.foundation.render.backend.light.GridAlignedBB;
|
||||
import com.simibubi.create.foundation.utility.*;
|
||||
import com.simibubi.create.foundation.utility.BlockFace;
|
||||
import com.simibubi.create.foundation.utility.Coordinate;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.NBTProcessors;
|
||||
import com.simibubi.create.foundation.utility.UniqueLinkedList;
|
||||
import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld;
|
||||
import net.minecraft.block.*;
|
||||
|
||||
import net.minecraft.block.AbstractButtonBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.ChestBlock;
|
||||
import net.minecraft.block.DoorBlock;
|
||||
import net.minecraft.block.IWaterLoggable;
|
||||
import net.minecraft.block.PressurePlateBlock;
|
||||
import net.minecraft.block.material.PushReaction;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
|
@ -54,6 +92,9 @@ import net.minecraft.util.Direction.Axis;
|
|||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.IBooleanFunction;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.util.palette.HashMapPalette;
|
||||
import net.minecraft.village.PointOfInterestType;
|
||||
|
@ -72,19 +113,10 @@ import net.minecraftforge.fluids.capability.templates.FluidTank;
|
|||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import org.apache.commons.lang3.tuple.MutablePair;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole;
|
||||
import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead;
|
||||
|
||||
public abstract class Contraption {
|
||||
|
||||
public Optional<List<AxisAlignedBB>> simplifiedEntityColliders;
|
||||
public AbstractContraptionEntity entity;
|
||||
public CombinedInvWrapper inventory;
|
||||
public CombinedTankWrapper fluidInventory;
|
||||
|
@ -105,6 +137,8 @@ public abstract class Contraption {
|
|||
private Map<BlockPos, Entity> initialPassengers;
|
||||
private List<BlockFace> pendingSubContraptions;
|
||||
|
||||
private CompletableFuture<Void> simplifiedEntityColliderProvider;
|
||||
|
||||
// Client
|
||||
public Map<BlockPos, TileEntity> presentTileEntities;
|
||||
public List<TileEntity> maybeInstancedTileEntities;
|
||||
|
@ -127,13 +161,12 @@ public abstract class Contraption {
|
|||
specialRenderedTileEntities = new ArrayList<>();
|
||||
pendingSubContraptions = new ArrayList<>();
|
||||
stabilizedSubContraptions = new HashMap<>();
|
||||
simplifiedEntityColliders = Optional.empty();
|
||||
}
|
||||
|
||||
public ContraptionWorld getContraptionWorld() {
|
||||
if (world == null) {
|
||||
if (world == null)
|
||||
world = new ContraptionWorld(entity.world, this);
|
||||
}
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
|
@ -160,6 +193,8 @@ public abstract class Contraption {
|
|||
String type = nbt.getString("Type");
|
||||
Contraption contraption = ContraptionType.fromType(type);
|
||||
contraption.readNBT(world, nbt, spawnData);
|
||||
contraption.world = new ContraptionWorld(world, contraption);
|
||||
contraption.gatherBBsOffThread();
|
||||
return contraption;
|
||||
}
|
||||
|
||||
|
@ -223,6 +258,14 @@ public abstract class Contraption {
|
|||
.collect(Collectors.toList());
|
||||
fluidInventory = new CombinedTankWrapper(
|
||||
Arrays.copyOf(fluidHandlers.toArray(), fluidHandlers.size(), IFluidHandler[].class));
|
||||
gatherBBsOffThread();
|
||||
}
|
||||
|
||||
public void onEntityRemoved(AbstractContraptionEntity entity) {
|
||||
if (simplifiedEntityColliderProvider != null) {
|
||||
simplifiedEntityColliderProvider.cancel(false);
|
||||
simplifiedEntityColliderProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onEntityInitialize(World world, AbstractContraptionEntity contraptionEntity) {
|
||||
|
@ -1136,6 +1179,28 @@ public abstract class Contraption {
|
|||
return new EmptyLighter(this);
|
||||
}
|
||||
|
||||
private void gatherBBsOffThread() {
|
||||
getContraptionWorld();
|
||||
simplifiedEntityColliderProvider = CompletableFuture.supplyAsync(() -> {
|
||||
VoxelShape combinedShape = VoxelShapes.empty();
|
||||
for (Entry<BlockPos, BlockInfo> entry : blocks.entrySet()) {
|
||||
BlockInfo info = entry.getValue();
|
||||
BlockPos localPos = entry.getKey();
|
||||
VoxelShape collisionShape = info.state.getCollisionShape(world, localPos);
|
||||
if (collisionShape.isEmpty())
|
||||
continue;
|
||||
combinedShape = VoxelShapes.combine(combinedShape,
|
||||
collisionShape.withOffset(localPos.getX(), localPos.getY(), localPos.getZ()), IBooleanFunction.OR);
|
||||
}
|
||||
return combinedShape.simplify()
|
||||
.toBoundingBoxList();
|
||||
})
|
||||
.thenAccept(r -> {
|
||||
simplifiedEntityColliders = Optional.of(r);
|
||||
simplifiedEntityColliderProvider = null;
|
||||
});
|
||||
}
|
||||
|
||||
public static float getRadius(Set<BlockPos> blocks, Direction.Axis axis) {
|
||||
switch (axis) {
|
||||
case X:
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.simibubi.create.foundation.collision.ContinuousOBBCollider.Continuous
|
|||
import com.simibubi.create.foundation.collision.Matrix3d;
|
||||
import com.simibubi.create.foundation.collision.OrientedBB;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
|
@ -36,6 +37,8 @@ import net.minecraft.util.Direction;
|
|||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.ReuseableStream;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -103,42 +106,56 @@ public class ContraptionCollider {
|
|||
AxisAlignedBB entityBounds = entity.getBoundingBox();
|
||||
Vector3d motion = entity.getMotion();
|
||||
float yawOffset = rotation.getYawOffset();
|
||||
|
||||
Vector3d position = getWorldToLocalTranslation(entity, anchorVec, rotationMatrix, yawOffset);
|
||||
|
||||
// Find all potential block shapes to collide with
|
||||
// Prepare entity bounds
|
||||
AxisAlignedBB localBB = entityBounds.offset(position)
|
||||
.grow(1.0E-7D);
|
||||
ReuseableStream<VoxelShape> potentialHits =
|
||||
getPotentiallyCollidedShapes(world, contraption, localBB.expand(motion));
|
||||
if (potentialHits.createStream()
|
||||
.count() == 0)
|
||||
continue;
|
||||
|
||||
// Prepare entity bounds
|
||||
OrientedBB obb = new OrientedBB(localBB);
|
||||
obb.setRotation(rotationMatrix);
|
||||
motion = motion.subtract(contraptionMotion);
|
||||
motion = rotationMatrix.transform(motion);
|
||||
|
||||
// Use simplified bbs when present
|
||||
final Vector3d motionCopy = motion;
|
||||
List<AxisAlignedBB> collidableBBs = contraption.simplifiedEntityColliders.orElseGet(() -> {
|
||||
|
||||
// Else find 'nearby' individual block shapes to collide with
|
||||
List<AxisAlignedBB> bbs = new ArrayList<>();
|
||||
ReuseableStream<VoxelShape> potentialHits =
|
||||
getPotentiallyCollidedShapes(world, contraption, localBB.expand(motionCopy));
|
||||
potentialHits.createStream()
|
||||
.forEach(shape -> shape.toBoundingBoxList()
|
||||
.forEach(bbs::add));
|
||||
return bbs;
|
||||
|
||||
});
|
||||
|
||||
MutableObject<Vector3d> collisionResponse = new MutableObject<>(Vector3d.ZERO);
|
||||
MutableObject<Vector3d> normal = new MutableObject<>(Vector3d.ZERO);
|
||||
MutableObject<Vector3d> location = new MutableObject<>(Vector3d.ZERO);
|
||||
MutableBoolean surfaceCollision = new MutableBoolean(false);
|
||||
MutableFloat temporalResponse = new MutableFloat(1);
|
||||
Vector3d obbCenter = obb.getCenter();
|
||||
|
||||
// Apply separation maths
|
||||
List<AxisAlignedBB> bbs = new ArrayList<>();
|
||||
potentialHits.createStream()
|
||||
.forEach(shape -> shape.toBoundingBoxList()
|
||||
.forEach(bbs::add));
|
||||
|
||||
boolean doHorizontalPass = !rotation.hasVerticalRotation();
|
||||
for (boolean horizontalPass : Iterate.trueAndFalse) {
|
||||
boolean verticalPass = !horizontalPass || !doHorizontalPass;
|
||||
|
||||
for (AxisAlignedBB bb : bbs) {
|
||||
for (AxisAlignedBB bb : collidableBBs) {
|
||||
Vector3d currentResponse = collisionResponse.getValue();
|
||||
obb.setCenter(obbCenter.add(currentResponse));
|
||||
Vector3d currentCenter = obbCenter.add(currentResponse);
|
||||
|
||||
if (Math.abs(currentCenter.x - bb.getCenter().x) - entityBounds.getXSize() - 1 > bb.getXSize() / 2)
|
||||
continue;
|
||||
if (Math.abs((currentCenter.y + motion.y) - bb.getCenter().y) - entityBounds.getYSize()
|
||||
- 1 > bb.getYSize() / 2)
|
||||
continue;
|
||||
if (Math.abs(currentCenter.z - bb.getCenter().z) - entityBounds.getZSize() - 1 > bb.getZSize() / 2)
|
||||
continue;
|
||||
|
||||
obb.setCenter(currentCenter);
|
||||
ContinuousSeparationManifold intersect = obb.intersect(bb, motion);
|
||||
|
||||
if (intersect == null)
|
||||
|
@ -147,15 +164,28 @@ public class ContraptionCollider {
|
|||
surfaceCollision.setValue(intersect.isSurfaceCollision());
|
||||
|
||||
double timeOfImpact = intersect.getTimeOfImpact();
|
||||
if (timeOfImpact > 0 && timeOfImpact < 1) {
|
||||
if (temporalResponse.getValue() > timeOfImpact)
|
||||
temporalResponse.setValue(timeOfImpact);
|
||||
continue;
|
||||
boolean isTemporal = timeOfImpact > 0 && timeOfImpact < 1;
|
||||
Vector3d collidingNormal = intersect.getCollisionNormal();
|
||||
Vector3d collisionPosition = intersect.getCollisionPosition();
|
||||
|
||||
if (!isTemporal) {
|
||||
Vector3d separation = intersect.asSeparationVec(entity.stepHeight);
|
||||
if (separation != null && !separation.equals(Vector3d.ZERO)) {
|
||||
collisionResponse.setValue(currentResponse.add(separation));
|
||||
timeOfImpact = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3d separation = intersect.asSeparationVec(entity.stepHeight);
|
||||
if (separation != null && !separation.equals(Vector3d.ZERO))
|
||||
collisionResponse.setValue(currentResponse.add(separation));
|
||||
boolean nearest = timeOfImpact >= 0 && temporalResponse.getValue() > timeOfImpact;
|
||||
if (collidingNormal != null && nearest)
|
||||
normal.setValue(collidingNormal);
|
||||
if (collisionPosition != null && nearest)
|
||||
location.setValue(collisionPosition);
|
||||
|
||||
if (isTemporal) {
|
||||
if (temporalResponse.getValue() > timeOfImpact)
|
||||
temporalResponse.setValue(timeOfImpact);
|
||||
}
|
||||
}
|
||||
|
||||
if (verticalPass)
|
||||
|
@ -174,6 +204,9 @@ public class ContraptionCollider {
|
|||
|
||||
// Resolve collision
|
||||
Vector3d entityMotion = entity.getMotion();
|
||||
Vector3d entityMotionNoTemporal = entityMotion;
|
||||
Vector3d collisionNormal = normal.getValue();
|
||||
Vector3d collisionLocation = location.getValue();
|
||||
Vector3d totalResponse = collisionResponse.getValue();
|
||||
boolean hardCollision = !totalResponse.equals(Vector3d.ZERO);
|
||||
boolean temporalCollision = temporalResponse.getValue() != 1;
|
||||
|
@ -186,8 +219,47 @@ public class ContraptionCollider {
|
|||
.add(contraptionMotion);
|
||||
totalResponse = rotationMatrix.transform(totalResponse);
|
||||
totalResponse = VecHelper.rotate(totalResponse, yawOffset, Axis.Y);
|
||||
collisionNormal = rotationMatrix.transform(collisionNormal);
|
||||
collisionNormal = VecHelper.rotate(collisionNormal, yawOffset, Axis.Y);
|
||||
collisionLocation = rotationMatrix.transform(collisionLocation);
|
||||
collisionLocation = VecHelper.rotate(collisionLocation, yawOffset, Axis.Y);
|
||||
rotationMatrix.transpose();
|
||||
|
||||
double bounce = 0;
|
||||
double slide = 0;
|
||||
|
||||
if (!collisionLocation.equals(Vector3d.ZERO)) {
|
||||
collisionLocation = collisionLocation.add(entity.getPositionVec()
|
||||
.add(entity.getBoundingBox()
|
||||
.getCenter())
|
||||
.scale(.5f));
|
||||
if (temporalCollision)
|
||||
collisionLocation = collisionLocation.add(0, motionResponse.y, 0);
|
||||
BlockPos pos = new BlockPos(contraptionEntity.toLocalVector(collisionLocation, 0));
|
||||
if (contraption.getBlocks()
|
||||
.containsKey(pos)) {
|
||||
BlockState blockState = contraption.getBlocks()
|
||||
.get(pos).state;
|
||||
bounce = BlockHelper.getBounceMultiplier(blockState.getBlock());
|
||||
slide = Math.max(0, blockState.getSlipperiness(contraption.world, pos, entity) - .6f);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasNormal = !collisionNormal.equals(Vector3d.ZERO);
|
||||
boolean anyCollision = hardCollision || temporalCollision;
|
||||
|
||||
if (bounce > 0 && hasNormal && anyCollision) {
|
||||
collisionNormal = collisionNormal.normalize();
|
||||
Vector3d newNormal = collisionNormal.crossProduct(collisionNormal.crossProduct(entityMotionNoTemporal))
|
||||
.normalize();
|
||||
if (bounceEntity(entity, newNormal, contraptionEntity, bounce)) {
|
||||
entity.world.playSound(playerType == PlayerType.CLIENT ? (PlayerEntity) entity : null,
|
||||
entity.getX(), entity.getY(), entity.getZ(), SoundEvents.BLOCK_SLIME_BLOCK_FALL,
|
||||
SoundCategory.BLOCKS, .5f, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (temporalCollision) {
|
||||
double idealVerticalMotion = motionResponse.y;
|
||||
if (idealVerticalMotion != entityMotion.y) {
|
||||
|
@ -215,6 +287,18 @@ public class ContraptionCollider {
|
|||
entityMotion = entityMotion.mul(1, 1, 0);
|
||||
}
|
||||
|
||||
if (bounce == 0 && slide > 0 && hasNormal && anyCollision && rotation.hasVerticalRotation()) {
|
||||
collisionNormal = collisionNormal.normalize();
|
||||
Vector3d motionIn = entityMotionNoTemporal.mul(0, 1, 0)
|
||||
.add(0, -.01f, 0);
|
||||
Vector3d slideNormal = collisionNormal.crossProduct(motionIn.crossProduct(collisionNormal))
|
||||
.normalize();
|
||||
entity.setMotion(entityMotion.mul(.8, 0, .8)
|
||||
.add(slideNormal.scale((.2f + slide) * motionIn.length())
|
||||
.add(0, -0.1, 0)));
|
||||
entityMotion = entity.getMotion();
|
||||
}
|
||||
|
||||
if (!hardCollision && surfaceCollision.isFalse())
|
||||
continue;
|
||||
|
||||
|
@ -228,10 +312,14 @@ public class ContraptionCollider {
|
|||
|
||||
if (surfaceCollision.isTrue()) {
|
||||
entity.fallDistance = 0;
|
||||
entity.setOnGround(true);
|
||||
contraptionEntity.collidingEntities.put(entity, new MutableInt(0));
|
||||
if (entity instanceof ItemEntity)
|
||||
entityMotion = entityMotion.mul(.5f, 1, .5f);
|
||||
boolean canWalk = bounce != 0 || slide == 0;
|
||||
if (canWalk || !rotation.hasVerticalRotation()) {
|
||||
if (canWalk)
|
||||
entity.onGround = true;
|
||||
if (entity instanceof ItemEntity)
|
||||
entityMotion = entityMotion.mul(.5f, 1, .5f);
|
||||
}
|
||||
contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition);
|
||||
allowedMovement = getAllowedMovement(contactPointMotion, entity);
|
||||
entity.setPosition(entityPosition.x + allowedMovement.x, entityPosition.y,
|
||||
|
@ -253,6 +341,42 @@ public class ContraptionCollider {
|
|||
|
||||
}
|
||||
|
||||
static boolean bounceEntity(Entity entity, Vector3d normal, AbstractContraptionEntity contraption, double factor) {
|
||||
if (factor == 0)
|
||||
return false;
|
||||
if (entity.bypassesLandingEffects())
|
||||
return false;
|
||||
if (normal.equals(Vector3d.ZERO))
|
||||
return false;
|
||||
|
||||
Vector3d contraptionVec = Vector3d.ZERO;
|
||||
Vector3d contactPointMotion = contraption.getContactPointMotion(entity.getPositionVec());
|
||||
Vector3d motion = entity.getMotion()
|
||||
.subtract(contactPointMotion);
|
||||
|
||||
Vector3d v2 = motion.crossProduct(normal)
|
||||
.normalize();
|
||||
if (v2 != Vector3d.ZERO)
|
||||
contraptionVec = normal.scale(contraptionVec.dotProduct(normal))
|
||||
.add(v2.scale(contraptionVec.dotProduct(v2)));
|
||||
else
|
||||
v2 = normal.crossProduct(normal.add(Math.random(), Math.random(), Math.random()))
|
||||
.normalize();
|
||||
|
||||
Vector3d v3 = normal.crossProduct(v2);
|
||||
motion = motion.subtract(contraptionVec);
|
||||
Vector3d lr = new Vector3d(factor * motion.dotProduct(normal), -motion.dotProduct(v2), -motion.dotProduct(v3));
|
||||
|
||||
if (lr.dotProduct(lr) > 1 / 16f) {
|
||||
Vector3d newMot = contactPointMotion.add(normal.x * lr.x + v2.x * lr.y + v3.x * lr.z,
|
||||
normal.y * lr.x + v2.y * lr.y + v3.y * lr.z, normal.z * lr.x + v2.z * lr.y + v3.z * lr.z);
|
||||
entity.setMotion(newMot);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Vector3d getWorldToLocalTranslation(Entity entity, AbstractContraptionEntity contraptionEntity) {
|
||||
return getWorldToLocalTranslation(entity, contraptionEntity.getAnchorVec(), contraptionEntity.getRotationState());
|
||||
}
|
||||
|
|
|
@ -36,24 +36,25 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
checkCount = 0;
|
||||
mf.stepSeparationAxis = uB1;
|
||||
mf.stepSeparation = Double.MAX_VALUE;
|
||||
mf.normalSeparation = Double.MAX_VALUE;
|
||||
|
||||
if (
|
||||
// Separate along A's local axes (global XYZ)
|
||||
!(separate(mf, uA0, diff.x, eA.x, a00 * eB.x + a01 * eB.y + a02 * eB.z, motion.x)
|
||||
|| separate(mf, uA1, diff.y, eA.y, a10 * eB.x + a11 * eB.y + a12 * eB.z, motion.y)
|
||||
|| separate(mf, uA2, diff.z, eA.z, a20 * eB.x + a21 * eB.y + a22 * eB.z, motion.z)
|
||||
!(separate(mf, uA0, diff.x, eA.x, a00 * eB.x + a01 * eB.y + a02 * eB.z, motion.x, true)
|
||||
|| separate(mf, uA1, diff.y, eA.y, a10 * eB.x + a11 * eB.y + a12 * eB.z, motion.y, true)
|
||||
|| separate(mf, uA2, diff.z, eA.z, a20 * eB.x + a21 * eB.y + a22 * eB.z, motion.z, true)
|
||||
|
||||
// Separate along B's local axes
|
||||
|| separate(mf, uB0, diff2.x, eA.x * a00 + eA.y * a10 + eA.z * a20, eB.x, motion2.x)
|
||||
|| separate(mf, uB1, diff2.y, eA.x * a01 + eA.y * a11 + eA.z * a21, eB.y, motion2.y)
|
||||
|| separate(mf, uB2, diff2.z, eA.x * a02 + eA.y * a12 + eA.z * a22, eB.z, motion2.z)))
|
||||
|| separate(mf, uB0, diff2.x, eA.x * a00 + eA.y * a10 + eA.z * a20, eB.x, motion2.x, false)
|
||||
|| separate(mf, uB1, diff2.y, eA.x * a01 + eA.y * a11 + eA.z * a21, eB.y, motion2.y, false)
|
||||
|| separate(mf, uB2, diff2.z, eA.x * a02 + eA.y * a12 + eA.z * a22, eB.z, motion2.z, false)))
|
||||
return mf;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static boolean separate(ContinuousSeparationManifold mf, Vector3d axis, double TL, double rA, double rB,
|
||||
double projectedMotion) {
|
||||
double projectedMotion, boolean axisOfObjA) {
|
||||
checkCount++;
|
||||
double distance = abs(TL);
|
||||
double diff = distance - (rA + rB);
|
||||
|
@ -82,7 +83,12 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
Vector3d normalizedAxis = axis.normalize();
|
||||
|
||||
boolean isBestSeperation = distance != 0 && -(diff) <= abs(mf.separation);
|
||||
// boolean isBestSeperation = discreteCollision && checkCount == 5; // Debug specific separations
|
||||
// boolean isBestSeperation = discreteCollision && checkCount == 5; // Debug specific separations
|
||||
|
||||
if (axisOfObjA && distance != 0 && -(diff) <= abs(mf.normalSeparation)) {
|
||||
mf.normalAxis = normalizedAxis;
|
||||
mf.normalSeparation = seperation;
|
||||
}
|
||||
|
||||
double dot = mf.stepSeparationAxis.dotProduct(axis);
|
||||
if (dot != 0 && discreteCollision) {
|
||||
|
@ -98,45 +104,19 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
stepSeparationVec =
|
||||
sepVec.subtract(axisPlane.scale(sepVec.dotProduct(stepPlane) / axisPlane.dotProduct(stepPlane)));
|
||||
stepSeparation = stepSeparationVec.length();
|
||||
|
||||
|
||||
if (abs(mf.stepSeparation) > abs(stepSeparation) && stepSeparation != 0) {
|
||||
// CollisionDebugger.showDebugLine(Vector3d.ZERO, sepVec, 0x111155, "stepsep", -16);
|
||||
if (abs(mf.stepSeparation) > abs(stepSeparation) && stepSeparation != 0)
|
||||
mf.stepSeparation = stepSeparation;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (abs(mf.stepSeparation) > stepSeparation) {
|
||||
if (abs(mf.stepSeparation) > stepSeparation)
|
||||
mf.stepSeparation = stepSeparation;
|
||||
// CollisionDebugger.showDebugLine(Vector3d.ZERO, stepSeparationVec, 0xff9999, "axis", -16);
|
||||
}
|
||||
}
|
||||
|
||||
// if (abs(mf.separation) < abs(stepSeparation) && stepSeparation != 0)
|
||||
}
|
||||
|
||||
if (isBestSeperation) {
|
||||
|
||||
mf.axis = normalizedAxis;
|
||||
mf.separation = seperation;
|
||||
|
||||
// Visualize values
|
||||
// if (CollisionDebugger.AABB != null) {
|
||||
// Vector3d normalizedAxis = axis.normalize();
|
||||
// showDebugLine(Vector3d.ZERO, normalizedAxis.scale(projectedMotion), 0x111155, "motion", 5);
|
||||
// showDebugLine(Vector3d.ZERO, normalizedAxis.scale(TL), 0xbb00bb, "tl", 4);
|
||||
// showDebugLine(Vector3d.ZERO, normalizedAxis.scale(sTL * rA), 0xff4444, "ra", 3);
|
||||
// showDebugLine(normalizedAxis.scale(sTL * rA),
|
||||
// normalizedAxis.scale(sTL * rA - entryTime * projectedMotion), 0x44ff44, "entry", 0);
|
||||
// showDebugLine(normalizedAxis.scale(sTL * rA - entryTime * projectedMotion),
|
||||
// normalizedAxis.scale(sTL * rA - entryTime * projectedMotion + exitTime * projectedMotion), 0x44ffff,
|
||||
// "exit", -1);
|
||||
// showDebugLine(normalizedAxis.scale(sTL * (distance - rB)), normalizedAxis.scale(TL), 0x4444ff, "rb", 2);
|
||||
// showDebugLine(normalizedAxis.scale(sTL * (distance - rB)),
|
||||
// normalizedAxis.scale(sTL * (distance - rB) + value), 0xff9966, "separation", 1);
|
||||
//// System.out.println("TL:" + TL + ", rA: " + rA + ", rB: " + rB);
|
||||
// }
|
||||
|
||||
mf.collisionPosition = normalizedAxis.scale(signum(TL) * (axisOfObjA ? -rB : -rB) - signum(seperation) * .125f);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -148,10 +128,14 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
double latestCollisionEntryTime = UNDEFINED;
|
||||
double earliestCollisionExitTime = Double.MAX_VALUE;
|
||||
boolean isDiscreteCollision = true;
|
||||
Vector3d collisionPosition;
|
||||
|
||||
Vector3d stepSeparationAxis;
|
||||
double stepSeparation;
|
||||
|
||||
Vector3d normalAxis;
|
||||
double normalSeparation;
|
||||
|
||||
public double getTimeOfImpact() {
|
||||
if (latestCollisionEntryTime == UNDEFINED)
|
||||
return UNDEFINED;
|
||||
|
@ -164,9 +148,17 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
return true;
|
||||
}
|
||||
|
||||
public Vector3d getCollisionNormal() {
|
||||
return normalAxis == null ? null : createSeparationVec(normalSeparation, normalAxis);
|
||||
}
|
||||
|
||||
public Vector3d getCollisionPosition() {
|
||||
return collisionPosition;
|
||||
}
|
||||
|
||||
public Vector3d asSeparationVec(double obbStepHeight) {
|
||||
if (isDiscreteCollision) {
|
||||
if (stepSeparation <= obbStepHeight)
|
||||
if (stepSeparation <= obbStepHeight)
|
||||
return createSeparationVec(stepSeparation, stepSeparationAxis);
|
||||
return super.asSeparationVec();
|
||||
}
|
||||
|
@ -175,7 +167,7 @@ public class ContinuousOBBCollider extends OBBCollider {
|
|||
return null;
|
||||
return Vector3d.ZERO;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Vector3d asSeparationVec() {
|
||||
return asSeparationVec(0);
|
||||
|
|
|
@ -16,6 +16,7 @@ import net.minecraft.util.math.vector.Vector3d;
|
|||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template;
|
||||
import org.apache.logging.log4j.util.TriConsumer;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
@ -30,10 +31,12 @@ import java.util.stream.Collectors;
|
|||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class StepSoundMixin {
|
||||
private final Entity self = (Entity) (Object) this;
|
||||
|
||||
@Shadow
|
||||
public World world;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
protected Random rand;
|
||||
|
||||
|
@ -55,21 +58,20 @@ public abstract class StepSoundMixin {
|
|||
@Shadow
|
||||
protected abstract void playStepSound(BlockPos p_180429_1_, BlockState p_180429_2_);
|
||||
|
||||
private Set<AbstractContraptionEntity> getIntersectingContraptions(Entity entity) {
|
||||
Set<AbstractContraptionEntity> contraptions = ContraptionHandler.loadedContraptions.get(entity.world)
|
||||
private Set<AbstractContraptionEntity> getIntersectingContraptions() {
|
||||
Set<AbstractContraptionEntity> contraptions = ContraptionHandler.loadedContraptions.get(this.world)
|
||||
.values()
|
||||
.stream()
|
||||
.map(Reference::get)
|
||||
.filter(cEntity -> cEntity != null && cEntity.collidingEntities.containsKey(entity))
|
||||
.filter(cEntity -> cEntity != null && cEntity.collidingEntities.containsKey(self))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
contraptions.addAll(entity.world.getEntitiesWithinAABB(AbstractContraptionEntity.class, getBoundingBox().grow(1f)));
|
||||
contraptions.addAll(this.world.getEntitiesWithinAABB(AbstractContraptionEntity.class, getBoundingBox().grow(1f)));
|
||||
return contraptions;
|
||||
}
|
||||
|
||||
private void forCollision(Vector3d anchorPos, TriConsumer<Contraption, BlockState, BlockPos> action) {
|
||||
Entity thi = (Entity) (Object) this;
|
||||
getIntersectingContraptions(thi).forEach(cEntity -> {
|
||||
getIntersectingContraptions().forEach(cEntity -> {
|
||||
Vector3d localPos = ContraptionCollider.getWorldToLocalTranslation(anchorPos, cEntity);
|
||||
|
||||
localPos = anchorPos.add(localPos);
|
||||
|
@ -87,15 +89,14 @@ public abstract class StepSoundMixin {
|
|||
|
||||
@Inject(at = @At(
|
||||
value = "JUMP",
|
||||
opcode = 154, //IFNE
|
||||
opcode = 154, // IFNE line 587 injecting before `!blockstate.isAir(this.world, blockpos)`
|
||||
ordinal = 4
|
||||
),
|
||||
method = "move"
|
||||
)
|
||||
private void movementMixin(MoverType mover, Vector3d movement, CallbackInfo ci) {
|
||||
Entity thi = (Entity) (Object) this;
|
||||
World entityWorld = world;
|
||||
Vector3d worldPos = thi.getPositionVec().add(0, -0.2, 0);
|
||||
Vector3d worldPos = self.getPositionVec().add(0, -0.2, 0);
|
||||
AtomicBoolean stepped = new AtomicBoolean(false);
|
||||
|
||||
forCollision(worldPos, (contraption, blockstate, blockPos) -> {
|
||||
|
@ -110,19 +111,18 @@ public abstract class StepSoundMixin {
|
|||
world = entityWorld;
|
||||
}
|
||||
|
||||
@Inject(method = {"Lnet/minecraft/entity/Entity;spawnSprintingParticles()V"}, at = @At(value = "TAIL"))
|
||||
@Inject(method = {"spawnSprintingParticles"}, at = @At(value = "TAIL"))
|
||||
private void createRunningParticlesMixin(CallbackInfo ci) {
|
||||
Entity thi = (Entity) (Object) this;
|
||||
Vector3d worldPos = thi.getPositionVec().add(0, -0.2, 0);
|
||||
Vector3d worldPos = self.getPositionVec().add(0, -0.2, 0);
|
||||
BlockPos pos = new BlockPos(worldPos); // pos where particles are spawned
|
||||
|
||||
forCollision(worldPos, (contraption, blockstate, blockpos) -> {
|
||||
if (!blockstate.addRunningEffects(world, blockpos, thi) && blockstate.getRenderType() != BlockRenderType.INVISIBLE) {
|
||||
Vector3d Vector3d = thi.getMotion();
|
||||
if (!blockstate.addRunningEffects(world, blockpos, self) && blockstate.getRenderType() != BlockRenderType.INVISIBLE) {
|
||||
Vector3d vec3d = self.getMotion();
|
||||
this.world.addParticle(new BlockParticleData(ParticleTypes.BLOCK, blockstate).setPos(pos),
|
||||
thi.getX() + ((double) rand.nextFloat() - 0.5D) * (double) thi.getWidth(),
|
||||
thi.getY() + 0.1D, thi.getZ() + ((double) rand.nextFloat() - 0.5D) * (double) thi.getWidth(),
|
||||
Vector3d.x * -4.0D, 1.5D, Vector3d.z * -4.0D);
|
||||
self.getX() + ((double) rand.nextFloat() - 0.5D) * (double) self.getWidth(),
|
||||
self.getY() + 0.1D, self.getZ() + ((double) rand.nextFloat() - 0.5D) * (double) self.getWidth(),
|
||||
vec3d.x * -4.0D, 1.5D, vec3d.z * -4.0D);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,10 +8,13 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.components.actors.SeatBlock;
|
||||
|
||||
import net.minecraft.block.BedBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.SlimeBlock;
|
||||
import net.minecraft.client.particle.DiggingParticle;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
|
@ -260,6 +263,14 @@ public class BlockHelper {
|
|||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
public static double getBounceMultiplier(Block block) {
|
||||
if (block instanceof SlimeBlock)
|
||||
return 0.8D;
|
||||
if (block instanceof BedBlock || block instanceof SeatBlock)
|
||||
return 0.66 * 0.8D;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean hasBlockSolidSide(BlockState p_220056_0_, IBlockReader p_220056_1_, BlockPos p_220056_2_, Direction p_220056_3_) {
|
||||
return !p_220056_0_.isIn(BlockTags.LEAVES) && Block.doesSideFillSquare(p_220056_0_.getCollisionShape(p_220056_1_, p_220056_2_), p_220056_3_);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
"package": "com.simibubi.create.foundation.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"refmap": "create.refmap.json",
|
||||
"mixins": ["StepSoundMixin"],
|
||||
"client": [
|
||||
"TileWorldHookMixin",
|
||||
"CancelTileEntityRenderMixin",
|
||||
|
@ -13,7 +12,8 @@
|
|||
"NetworkLightUpdateMixin",
|
||||
"RenderHooksMixin",
|
||||
"ShaderCloseMixin",
|
||||
"TileRemoveMixin"
|
||||
"TileRemoveMixin",
|
||||
"StepSoundMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
Loading…
Reference in a new issue