Merge branch 'mc1.15/dev' into mc1.16/dev

This commit is contained in:
simibubi 2021-03-31 14:50:16 +02:00
commit 2b4ef88fc1
7 changed files with 293 additions and 99 deletions

View file

@ -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);
}

View file

@ -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:

View file

@ -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));
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());
}

View file

@ -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,6 +148,14 @@ 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)

View file

@ -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);
}
});
}

View file

@ -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;
@ -261,6 +264,14 @@ public class BlockHelper {
}
}
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_);
}

View file

@ -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