change DimensionalDoorBlock teleportation to happen when crossing portal plane

This commit is contained in:
CreepyCre 2021-10-13 23:45:00 +02:00
parent f244f2d4cf
commit 2dd8e2b9a3
9 changed files with 118 additions and 34 deletions

View file

@ -88,7 +88,7 @@ public final class ModConfig implements ConfigData {
}
public static class General {
@Tooltip public double teleportOffset = 0.5;
@Tooltip public double teleportOffset = 0;
@Tooltip public boolean riftBoundingBoxInCreative;
@Tooltip public double riftCloseSpeed = 0.01;
@Tooltip public double riftGrowthSpeed = 1;

View file

@ -3,9 +3,11 @@ package org.dimdev.dimdoors.api.block;
import net.minecraft.block.BlockState;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public interface AfterMoveCollidableBlock {
// only triggers on servers
void onAfterMovePlayerCollision(BlockState state, ServerWorld world, BlockPos pos, ServerPlayerEntity player);
ActionResult onAfterMovePlayerCollision(BlockState state, ServerWorld world, BlockPos pos, ServerPlayerEntity player, Vec3d positionChange);
}

View file

@ -0,0 +1,7 @@
package org.dimdev.dimdoors.api.entity;
import net.minecraft.util.math.Vec3d;
public interface LastPositionProvider {
Vec3d getLastPos();
}

View file

@ -32,6 +32,7 @@ import net.minecraft.world.World;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
// TODO: copy over all the necessary bits from DimensionalDoorBlock
public class DimensionalPortalBlock extends Block implements RiftProvider<EntranceRiftBlockEntity> {
public static DirectionProperty FACING = HorizontalFacingBlock.FACING;

View file

@ -12,6 +12,7 @@ import org.dimdev.dimdoors.DimensionalDoorsInitializer;
import org.dimdev.dimdoors.api.block.AfterMoveCollidableBlock;
import org.dimdev.dimdoors.api.block.CustomBreakBlock;
import org.dimdev.dimdoors.api.block.ExplosionConvertibleBlock;
import org.dimdev.dimdoors.api.entity.LastPositionProvider;
import org.dimdev.dimdoors.api.util.math.MathUtil;
import org.dimdev.dimdoors.api.util.math.TransformationMatrix3d;
import org.dimdev.dimdoors.block.CoordinateTransformerBlock;
@ -51,38 +52,78 @@ public class DimensionalDoorBlock extends WaterLoggableDoorBlock implements Rift
@Override
@SuppressWarnings("deprecation")
// TODO: change from onEntityCollision to some method for checking if player crossed portal plane
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
if (world.isClient || entity instanceof ServerPlayerEntity) {
return;
}
onCollision(state, world, pos, entity);
onCollision(state, world, pos, entity, entity.getPos().subtract(((LastPositionProvider) entity).getLastPos()));
super.onEntityCollision(state, world, pos, entity);
}
@Override
public void onAfterMovePlayerCollision(BlockState state, ServerWorld world, BlockPos pos, ServerPlayerEntity player) {
onCollision(state, world, pos, player);
public ActionResult onAfterMovePlayerCollision(BlockState state, ServerWorld world, BlockPos pos, ServerPlayerEntity player, Vec3d positionChange) {
return onCollision(state, world, pos, player, positionChange);
}
private void onCollision(BlockState state, World world, BlockPos pos, Entity entity) {
// TODO: replace with dimdoor cooldown?
if (entity.hasNetherPortalCooldown()) {
entity.resetNetherPortalCooldown();
return;
}
entity.resetNetherPortalCooldown();
private ActionResult onCollision(BlockState state, World world, BlockPos pos, Entity entity, Vec3d positionChange) {
BlockPos top = state.get(HALF) == DoubleBlockHalf.UPPER ? pos : pos.up();
BlockPos bottom = top.down();
BlockState doorState = world.getBlockState(bottom);
if (doorState.getBlock() == this && doorState.get(DoorBlock.OPEN)) { // '== this' to check if not half-broken
// TODO: decide whether door should need to be open for teleportation
if (doorState.getBlock() != this || !doorState.get(DoorBlock.OPEN)) { // '== this' to check if not half-broken
return ActionResult.PASS;
}
Vec3d currentPos = entity.getPos();
Vec3d previousPos = currentPos.subtract(positionChange);
// TODO: rewrite this to be usable more universally
// check whether portal plane was traversed
double portalHalfWidth = 0.5;
double portalHeight = 2;
// check in DefaultTransformation for the correct offset of the portal planes
double portalOffsetFromCenter = 0.31;
Vec3d portalNormal = Vec3d.of(state.get(FACING).getOpposite().getVector());
Vec3d origin = Vec3d.ofBottomCenter(bottom);
Vec3d bottomMiddlePortalPoint = origin.add(portalNormal.multiply(portalOffsetFromCenter));
double dotCurrent = portalNormal.dotProduct(currentPos.subtract(bottomMiddlePortalPoint));
double dotPrevious = portalNormal.dotProduct(previousPos.subtract(bottomMiddlePortalPoint));
if (!(dotCurrent <= 0 && dotPrevious >= 0) && !(dotCurrent >= 0 && dotPrevious <= 0) || (dotCurrent == 0 && dotPrevious == 0)) {
// start and end point of movement are on same side of the portal plane or both inside the plane
return ActionResult.PASS;
}
Vec3d yVec = new Vec3d(0, 1, 0);
Vec3d xzVec = portalNormal.crossProduct(yVec);
Vec3d vecFromPreviousPosToPortalPlane = bottomMiddlePortalPoint.subtract(previousPos);
Vec3d normalizedPositionChange = positionChange.normalize();
Vec3d pointOfIntersection = previousPos.add(normalizedPositionChange.multiply(vecFromPreviousPosToPortalPlane.dotProduct(normalizedPositionChange) / normalizedPositionChange.dotProduct(normalizedPositionChange)));
// figure out whether the point of Intersection is actually inside the portal plane;
Vec3d intersectionRelativeToPortalPlane = pointOfIntersection.subtract(bottomMiddlePortalPoint);
double relativeIntersectionHeight = intersectionRelativeToPortalPlane.dotProduct(yVec);
double relativeIntersectionWidth = intersectionRelativeToPortalPlane.dotProduct(xzVec);
if (relativeIntersectionHeight < 0 || relativeIntersectionHeight > portalHeight || Math.abs(relativeIntersectionWidth) > portalHalfWidth) {
// intersection is outside of plane width/ height
return ActionResult.PASS;
}
// TODO: replace with dimdoor cooldown?
if (entity.hasNetherPortalCooldown()) {
entity.resetNetherPortalCooldown();
return ActionResult.PASS;
}
entity.resetNetherPortalCooldown();
this.getRift(world, pos, state).teleport(entity);
if (DimensionalDoorsInitializer.getConfig().getDoorsConfig().closeDoorBehind) {
world.setBlockState(top, world.getBlockState(top).with(DoorBlock.OPEN, false));
world.setBlockState(bottom, world.getBlockState(bottom).with(DoorBlock.OPEN, false));
}
}
return ActionResult.SUCCESS;
}
@Override
@ -213,7 +254,7 @@ public class DimensionalDoorBlock extends WaterLoggableDoorBlock implements Rift
@Override
public TransformationMatrix3d.TransformationMatrix3dBuilder transformationBuilder(BlockState state, BlockPos pos) {
return TransformationMatrix3d.builder()
.inverseTranslate(Vec3d.ofCenter(pos).add(Vec3d.of(state.get(DoorBlock.FACING).getVector()).multiply(-0.5)))
.inverseTranslate(Vec3d.ofCenter(pos).add(Vec3d.of(state.get(DoorBlock.FACING).getVector()).multiply(-0.31)))
.inverseRotate(MathUtil.directionEulerAngle(state.get(DoorBlock.FACING).getOpposite()));
}

View file

@ -2,19 +2,14 @@ package org.dimdev.dimdoors.block.entity;
import java.util.Optional;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.World;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dimdev.dimdoors.DimensionalDoorsInitializer;
import org.dimdev.dimdoors.api.util.Location;
import org.dimdev.dimdoors.block.CoordinateTransformerBlock;
import org.dimdev.dimdoors.block.RiftProvider;
import org.dimdev.dimdoors.api.client.DefaultTransformation;
import org.dimdev.dimdoors.api.client.Transformer;
import org.dimdev.dimdoors.item.DimensionalDoorItem;
import org.dimdev.dimdoors.item.RiftKeyItem;
import org.dimdev.dimdoors.pockets.DefaultDungeonDestinations;
import org.dimdev.dimdoors.rift.registry.Rift;
@ -31,8 +26,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
@ -41,7 +34,6 @@ import net.minecraft.util.math.Vec3d;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
public class EntranceRiftBlockEntity extends RiftBlockEntity {
private static final EscapeTarget ESCAPE_TARGET = new EscapeTarget(true);
@ -99,7 +91,7 @@ public class EntranceRiftBlockEntity extends RiftBlockEntity {
public boolean receiveEntity(Entity entity, Vec3d relativePos, EulerAngle relativeAngle, Vec3d relativeVelocity) {
BlockState state = this.getWorld().getBlockState(this.getPos());
Block block = state.getBlock();
Vec3d targetPos = Vec3d.ofCenter(this.pos).add(Vec3d.of(this.getOrientation().getOpposite().getVector()).multiply(DimensionalDoorsInitializer.getConfig().getGeneralConfig().teleportOffset + 0.5));
Vec3d targetPos = Vec3d.ofCenter(this.pos).add(Vec3d.of(this.getOrientation().getOpposite().getVector()).multiply(DimensionalDoorsInitializer.getConfig().getGeneralConfig().teleportOffset + 0.01/* slight offset to prevent issues due to mathematical inaccuracies*/));
/*
Unused code that needs to be edited if there are other ways to get to limbo
But if it is only dimteleport and going through rifts then this code isn't nessecary
@ -118,8 +110,6 @@ public class EntranceRiftBlockEntity extends RiftBlockEntity {
relativeVelocity = flipper.transform(relativeVelocity);
}
relativePos = relativePos.add(new Vec3d(0, 0, 1).multiply(0.6)); // TODO: skip this for Immersive Portals
TransformationMatrix3d.TransformationMatrix3dBuilder transformationBuilder = transformer.transformationBuilder(state, this.getPos());
TransformationMatrix3d.TransformationMatrix3dBuilder rotatorBuilder = transformer.rotatorBuilder(state, this.getPos());
targetPos = transformer.transformOut(transformationBuilder, relativePos);
@ -127,6 +117,8 @@ public class EntranceRiftBlockEntity extends RiftBlockEntity {
relativeVelocity = transformer.rotateOut(rotatorBuilder, relativeVelocity);
}
// TODO: open door
TeleportUtil.teleport(entity, this.world, targetPos, relativeAngle, relativeVelocity);
return true;

View file

@ -0,0 +1,24 @@
package org.dimdev.dimdoors.mixin;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.Vec3d;
import org.dimdev.dimdoors.api.entity.LastPositionProvider;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Entity.class)
public abstract class EntityMixin implements LastPositionProvider {
private Vec3d lastPos;
@Inject(method = "checkBlockCollision()V", at = @At("TAIL"))
public void checkBlockCollisionSaveLastPos(CallbackInfo ci) {
lastPos = ((Entity) (Object) this).getPos();
}
public Vec3d getLastPos() {
return lastPos == null ? ((Entity) (Object) this).getPos() : lastPos;
}
}

View file

@ -18,6 +18,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class ServerPlayNetworkHandlerMixin {
@Shadow
public ServerPlayerEntity player;
@Shadow
private double lastTickX;
@Shadow
private double lastTickY;
@Shadow
private double lastTickZ;
@Inject(method = "onPlayerMove", at = @At("TAIL"))
protected void checkBlockCollision(PlayerMoveC2SPacket packet, CallbackInfo ci) {
@ -28,16 +34,26 @@ public class ServerPlayNetworkHandlerMixin {
if (player.world.isRegionLoaded(blockPos, blockPos2)) {
BlockPos.Mutable mutable = new BlockPos.Mutable();
boolean done = false;
for(int i = blockPos.getX(); i <= blockPos2.getX(); ++i) {
for(int j = blockPos.getY(); j <= blockPos2.getY(); ++j) {
for(int k = blockPos.getZ(); k <= blockPos2.getZ(); ++k) {
mutable.set(i, j, k);
BlockState blockState = player.world.getBlockState(mutable);
Block block = blockState.getBlock();
if (block instanceof AfterMoveCollidableBlock) {
((AfterMoveCollidableBlock) block).onAfterMovePlayerCollision(blockState, player.getServerWorld(), mutable, player);
if (block instanceof AfterMoveCollidableBlock && ((AfterMoveCollidableBlock) block).onAfterMovePlayerCollision(blockState, player.getServerWorld(), mutable, player, player.getPos().subtract(lastTickX, lastTickY, lastTickZ)).isAccepted()) {
done = true;
}
if (done) {
break;
}
}
if (done) {
break;
}
}
if (done) {
break;
}
}
}

View file

@ -4,6 +4,7 @@
"compatibilityLevel": "JAVA_16",
"mixins": [
"BlockMixin",
"EntityMixin",
"ExplosionMixin",
"ExtendedServerPlayNetworkhandlerMixin",
"ItemMixin",