change DimensionalDoorBlock teleportation to happen when crossing portal plane
This commit is contained in:
parent
f244f2d4cf
commit
2dd8e2b9a3
9 changed files with 118 additions and 34 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package org.dimdev.dimdoors.api.entity;
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public interface LastPositionProvider {
|
||||
Vec3d getLastPos();
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
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));
|
||||
}
|
||||
// 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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
24
src/main/java/org/dimdev/dimdoors/mixin/EntityMixin.java
Normal file
24
src/main/java/org/dimdev/dimdoors/mixin/EntityMixin.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"compatibilityLevel": "JAVA_16",
|
||||
"mixins": [
|
||||
"BlockMixin",
|
||||
"EntityMixin",
|
||||
"ExplosionMixin",
|
||||
"ExtendedServerPlayNetworkhandlerMixin",
|
||||
"ItemMixin",
|
||||
|
|
Loading…
Reference in a new issue