From 1036f8eb6c21e3e9cfddaaa9005b21c3ce18d884 Mon Sep 17 00:00:00 2001 From: whimxiqal Date: Sat, 15 Aug 2026 23:21:36 -0700 Subject: [PATCH 1/2] use entity position when calculating nether portal location --- .../common/world/portal/SpongeNetherPortalExitCalculator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java index a8c7b17eb8b..9929f6176ca 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java @@ -62,7 +62,7 @@ public Optional calculatePortalExit(final ServerWorld from, fina return Optional.empty(); } final var scale = this.calculateScale(fromLevel, toLevel); - final var exitPosition = toLevel.getWorldBorder().clampToBounds(fromPos.x() * scale, fromPos.y(), fromPos.z() * scale); + final var exitPosition = toLevel.getWorldBorder().clampToBounds(entity.getX() * scale, entity.getY(), entity.getZ() * scale); return Optional.of(ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3i(exitPosition))); } From a4a41e50e7afd320f499e741e747b8ee42b663a7 Mon Sep 17 00:00:00 2001 From: Pieter Svenson Date: Sun, 16 Aug 2026 03:59:27 -0700 Subject: [PATCH 2/2] TeleportBehavior --- .../world/level/block/PortalBlockBridge.java | 2 +- .../portal/NoOpPortalTeleportBehavior.java | 16 ++++++ .../portal/SpongeCompositePortalLogic.java | 16 ++++-- .../world/portal/SpongeCustomPortalLogic.java | 47 ++++++++++------ .../SpongeNetherPortalExitCalculator.java | 2 +- .../SpongeNetherPortalTeleportBehavior.java | 54 +++++++++++++++++++ .../portal/SpongePortalLogicBuilder.java | 16 ++++-- .../portal/SpongePortalLogicFactory.java | 1 - .../world/level/block/PortalMixin_API.java | 13 ++++- .../level/block/EndPortalBlockMixin.java | 2 +- .../level/block/NetherPortalBlockMixin.java | 36 ++++++------- 11 files changed, 156 insertions(+), 49 deletions(-) create mode 100644 src/main/java/org/spongepowered/common/world/portal/NoOpPortalTeleportBehavior.java create mode 100644 src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalTeleportBehavior.java diff --git a/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java b/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java index 5a2e1182aae..de82e03a90f 100644 --- a/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java +++ b/src/main/java/org/spongepowered/common/bridge/world/level/block/PortalBlockBridge.java @@ -42,5 +42,5 @@ public interface PortalBlockBridge { Optional bridge$generatePortal(ServerLocation location, Axis axis); - boolean bridge$teleport(Entity entity, ServerLocation destination, boolean generateDestinationPortal); + boolean bridge$teleport(ServerLocation origin, Entity entity, ServerLocation destination, boolean generateDestinationPortal); } diff --git a/src/main/java/org/spongepowered/common/world/portal/NoOpPortalTeleportBehavior.java b/src/main/java/org/spongepowered/common/world/portal/NoOpPortalTeleportBehavior.java new file mode 100644 index 00000000000..8e6fd34d21a --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/NoOpPortalTeleportBehavior.java @@ -0,0 +1,16 @@ +package org.spongepowered.common.world.portal; + +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.world.portal.Portal; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; + +public enum NoOpPortalTeleportBehavior implements PortalLogic.TeleportBehavior { + INSTANCE; + + @Override + public ServerLocation spawnLocation(ServerLocation from, ServerLocation to, Entity entity) { + return to; + } + +} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java index 9e5f9112353..fbcae89818c 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeCompositePortalLogic.java @@ -73,6 +73,14 @@ public Optional finder() { .findFirst()); } + @Override + public Optional teleporter() { + return Optional.of((from, to, entity) -> this.rules.stream().map(PortalLogic.class::cast) + .map(PortalLogic::teleporter).flatMap(Optional::stream) + .map(c -> c.spawnLocation(from, to, entity)) + .findFirst().get()); + } + @Override public Optional generator() { return Optional.of((at, axis) -> this.rules.stream().map(PortalLogic.class::cast) @@ -82,17 +90,19 @@ public Optional generator() { } @Override - public boolean teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + public boolean teleport(final ServerLocation origin, final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { final var searchRange = 1; final var axis = Axis.X; var foundPortal = this.finder().flatMap(finder -> finder.findPortal(destination, searchRange)); if (foundPortal.isPresent()) { - return foundPortal.map(Portal::position).map(entity::setLocation).orElse(false); + return foundPortal.flatMap(p -> this.teleporter().map(b -> b.spawnLocation(origin, destination, entity))) + .map(entity::setLocation).orElse(false); } if (generateDestinationPortal) { var generatedPortal = this.generator().flatMap(generator -> generator.generatePortal(destination, axis)); - return generatedPortal.map(Portal::position).map(entity::setLocation).orElse(false); + return generatedPortal.flatMap(p -> this.teleporter().map(b -> b.spawnLocation(origin, destination, entity))) + .map(entity::setLocation).orElse(false); } return false; } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java b/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java index 65bf3c1c70d..799869a3c4c 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeCustomPortalLogic.java @@ -24,6 +24,7 @@ */ package org.spongepowered.common.world.portal; +import net.minecraft.BlockUtil; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; @@ -45,39 +46,46 @@ public final class SpongeCustomPortalLogic implements net.minecraft.world.level. private final PortalLogic.PortalExitCalculator exitCalculator; private final PortalLogic.PortalFinder finder; + private final PortalLogic.TeleportBehavior teleporter; private final PortalLogic.PortalGenerator generator; private int searchRange = 16; private Axis axis = Axis.X; - public SpongeCustomPortalLogic(final PortalLogic.PortalExitCalculator calulator, - final PortalLogic.PortalFinder finder, - final PortalLogic.PortalGenerator generator) { + public SpongeCustomPortalLogic(final PortalLogic.PortalExitCalculator calculator, + final PortalLogic.PortalFinder finder, + final PortalLogic.TeleportBehavior teleporter, + final PortalLogic.PortalGenerator generator) { - this.exitCalculator = calulator; + this.exitCalculator = calculator; this.finder = finder; + this.teleporter = teleporter; this.generator = generator; } - @Nullable @Override + @Nullable + @Override public DimensionTransition getPortalDestination(final ServerLevel fromLevel, final Entity entity, final BlockPos fromPos) { final var spongeEntity = (org.spongepowered.api.entity.Entity) entity; // Calculate desired portal location // Then find existing portal or generate if not found return this.exitCalculator.calculatePortalExit((ServerWorld) fromLevel, VecHelper.toVector3i(fromPos), spongeEntity) - .flatMap(calcExit -> this.finder.findPortal(calcExit, this.searchRange).map(Portal::position).or(() -> this.generator.generatePortal(calcExit, this.axis).map(Portal::position)) - .map(realExit -> SpongeCustomPortalLogic.generateTransition(entity, realExit)) - ).orElse(null); + .flatMap(calcExit -> this.finder.findPortal(calcExit, this.searchRange) + .flatMap(p -> this.teleporter().map(b -> b.spawnLocation(((ServerWorld) fromLevel).location(VecHelper.toVector3d(fromPos)), p.position(), spongeEntity))) + .or(() -> this.generator.generatePortal(calcExit, this.axis) + .flatMap(p -> this.teleporter().map(b -> b.spawnLocation(((ServerWorld) fromLevel).location(VecHelper.toVector3d(fromPos)), p.position(), spongeEntity)))) + .map(realExit -> SpongeCustomPortalLogic.generateTransition(entity, realExit)) + ).orElse(null); } private static DimensionTransition generateTransition(final Entity entity, final ServerLocation finalExit) { return new DimensionTransition( - (ServerLevel) finalExit.world(), - VecHelper.toVanillaVector3d(finalExit.position()), - entity.getDeltaMovement(), - entity.getYRot(), - entity.getXRot(), - DimensionTransition.PLACE_PORTAL_TICKET); + (ServerLevel) finalExit.world(), + VecHelper.toVanillaVector3d(finalExit.position()), + entity.getDeltaMovement(), + entity.getYRot(), + entity.getXRot(), + DimensionTransition.PLACE_PORTAL_TICKET); } @Override @@ -90,20 +98,25 @@ public Optional finder() { return Optional.of(this.finder); } + @Override + public Optional teleporter() { + return Optional.of(this.teleporter); + } + @Override public Optional generator() { return Optional.of(this.generator); } @Override - public boolean teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + public boolean teleport(final ServerLocation origin, final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { final var foundPortal = this.finder.findPortal(destination, this.searchRange); if (foundPortal.isPresent()) { - return foundPortal.map(Portal::position).map(entity::setLocation).orElse(false); + return foundPortal.flatMap(p -> this.teleporter().map(b -> b.spawnLocation(origin, destination, entity))).map(entity::setLocation).orElse(false); } if (generateDestinationPortal) { var generatedPortal = this.generator.generatePortal(destination, this.axis); - return generatedPortal.map(Portal::position).map(entity::setLocation).orElse(false); + return generatedPortal.flatMap(p -> this.teleporter().map(b -> b.spawnLocation(origin, destination, entity))).map(entity::setLocation).orElse(false); } return false; } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java index 9929f6176ca..ce5938b5b3b 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalExitCalculator.java @@ -62,7 +62,7 @@ public Optional calculatePortalExit(final ServerWorld from, fina return Optional.empty(); } final var scale = this.calculateScale(fromLevel, toLevel); - final var exitPosition = toLevel.getWorldBorder().clampToBounds(entity.getX() * scale, entity.getY(), entity.getZ() * scale); + final var exitPosition = toLevel.getWorldBorder().clampToBounds(entity.location().x() * scale, entity.location().y(), entity.location().z() * scale); return Optional.of(ServerLocation.of((ServerWorld) toLevel, VecHelper.toVector3i(exitPosition))); } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalTeleportBehavior.java b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalTeleportBehavior.java new file mode 100644 index 00000000000..3c3f439e57e --- /dev/null +++ b/src/main/java/org/spongepowered/common/world/portal/SpongeNetherPortalTeleportBehavior.java @@ -0,0 +1,54 @@ +package org.spongepowered.common.world.portal; + +import net.minecraft.BlockUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityDimensions; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.portal.PortalShape; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.api.entity.Entity; +import org.spongepowered.api.world.portal.PortalLogic; +import org.spongepowered.api.world.server.ServerLocation; +import org.spongepowered.common.util.VecHelper; + +public enum SpongeNetherPortalTeleportBehavior implements PortalLogic.TeleportBehavior { + INSTANCE; + + @Override + public ServerLocation spawnLocation(ServerLocation from, ServerLocation to, Entity spongeEntity) { + final var entity = (net.minecraft.world.entity.Entity) spongeEntity; + final var level = ((ServerLevel) to.world()); + final var originBlockPos = VecHelper.toBlockPos(from); + final var destBlockPos = VecHelper.toBlockPos(to); + final var portalBlockState = level.getBlockState(destBlockPos); + if (!portalBlockState.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) { + return to; + } + final var axis = portalBlockState.getValue(BlockStateProperties.HORIZONTAL_AXIS); + final var foundRectangle = BlockUtil.getLargestRectangleAround(destBlockPos, axis, 21, Direction.Axis.Y, 21, pos2 -> level.getBlockState(pos2) == portalBlockState); + BlockState $$5 = entity.level().getBlockState(originBlockPos); + + Vec3 relativePortalPosition; + Direction.Axis originAxis = $$5.getValue(BlockStateProperties.HORIZONTAL_AXIS); + BlockUtil.FoundRectangle $$7 = BlockUtil.getLargestRectangleAround(originBlockPos, originAxis, 21, Direction.Axis.Y, 21, ($$2x) -> entity.level().getBlockState($$2x) == $$5); + relativePortalPosition = entity.getRelativePortalPosition(originAxis, $$7); + + BlockPos minCorner = foundRectangle.minCorner; + BlockState blockState = level.getBlockState(minCorner); + Direction.Axis $$11 = blockState.getOptionalValue(BlockStateProperties.HORIZONTAL_AXIS).orElse(Direction.Axis.X); + double $$12 = foundRectangle.axis1Size; + double $$13 = foundRectangle.axis2Size; + EntityDimensions $$14 = entity.getDimensions(entity.getPose()); + double $$17 = (double) $$14.width() / (double) 2.0F + ($$12 - (double) $$14.width()) * relativePortalPosition.x(); + double $$18 = ($$13 - (double) $$14.height()) * relativePortalPosition.y(); + double $$19 = (double) 0.5F + relativePortalPosition.z(); + boolean $$20 = $$11 == Direction.Axis.X; + Vec3 $$21 = new Vec3((double) minCorner.getX() + ($$20 ? $$17 : $$19), (double) minCorner.getY() + $$18, (double) minCorner.getZ() + ($$20 ? $$19 : $$17)); + Vec3 collisionFreePosition = PortalShape.findCollisionFreePosition($$21, level, entity, $$14); + return to.world().location(VecHelper.toVector3d(collisionFreePosition)); + } + +} diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java index 5796681178a..fafd3320c75 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicBuilder.java @@ -43,17 +43,24 @@ public PortalLogic.Builder reset() { @Override - public PortalLogic.Builder addPortal(final PortalLogic.PortalExitCalculator calulator, + public PortalLogic.Builder addPortal(final PortalLogic.PortalExitCalculator calculator, final PortalLogic.PortalFinder finder, final PortalLogic.PortalGenerator generator) { - var portal = new SpongeCustomPortalLogic(calulator, finder, generator); + var portal = new SpongeCustomPortalLogic(calculator, finder, (from, to, entity) -> to, generator); this.rules.add(portal); return this; } @Override - public PortalLogic.Builder addPortal(final T logic) { - var portal = new SpongeCustomPortalLogic(logic, logic, logic); + public PortalLogic.Builder addPortal(PortalLogic.PortalExitCalculator calculator, PortalLogic.PortalFinder finder, PortalLogic.TeleportBehavior teleporter, PortalLogic.PortalGenerator generator) { + var portal = new SpongeCustomPortalLogic(calculator, finder, teleporter, generator); + this.rules.add(portal); + return this; + } + + @Override + public PortalLogic.Builder addPortal(final T logic) { + var portal = new SpongeCustomPortalLogic(logic, logic, logic, logic); this.rules.add(portal); return this; } @@ -63,5 +70,4 @@ public PortalLogic build() { return new SpongeCompositePortalLogic(this.rules); } - } diff --git a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java index 821a9d20ed5..282127faf3c 100644 --- a/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java +++ b/src/main/java/org/spongepowered/common/world/portal/SpongePortalLogicFactory.java @@ -103,5 +103,4 @@ public Portal portalOf(final PortalLogic logic, final ServerLocation position, f return new SpongePortal(position, logic, aabb); } - } diff --git a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java index eaa293c8d57..829a1192d2c 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java +++ b/src/mixins/java/org/spongepowered/common/mixin/api/minecraft/world/level/block/PortalMixin_API.java @@ -30,6 +30,7 @@ import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.common.bridge.world.level.block.PortalBlockBridge; +import org.spongepowered.common.world.portal.SpongeNetherPortalTeleportBehavior; import java.util.Optional; @@ -61,9 +62,17 @@ default Optional generator() { } @Override - default boolean teleport(final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + default Optional teleporter() { if (this instanceof PortalBlockBridge pbb) { - return pbb.bridge$teleport(entity, destination, generateDestinationPortal); + return Optional.of(SpongeNetherPortalTeleportBehavior.INSTANCE); + } + return Optional.empty(); + } + + @Override + default boolean teleport(final ServerLocation origin, final Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + if (this instanceof PortalBlockBridge pbb) { + return pbb.bridge$teleport(origin, entity, destination, generateDestinationPortal); } return false; } diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java index 74e5aca88c8..f8166698699 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/EndPortalBlockMixin.java @@ -98,7 +98,7 @@ public abstract class EndPortalBlockMixin implements PortalBlockBridge { } @Override - public boolean bridge$teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + public boolean bridge$teleport(final ServerLocation origin, final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { final var toLevel = (ServerLevel) destination.world(); if (toLevel.dimension() == Level.END) { if (generateDestinationPortal) { diff --git a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java index 8a39171148b..a0cd2a2db67 100644 --- a/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java +++ b/src/mixins/java/org/spongepowered/common/mixin/core/world/level/block/NetherPortalBlockMixin.java @@ -27,34 +27,43 @@ import net.minecraft.BlockUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.entity.ai.village.poi.PoiRecord; -import net.minecraft.world.entity.ai.village.poi.PoiTypes; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.NetherPortalBlock; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.portal.DimensionTransition; +import net.minecraft.world.level.portal.PortalShape; +import net.minecraft.world.phys.Vec3; import org.spongepowered.api.util.AABB; import org.spongepowered.api.util.Axis; +import org.spongepowered.api.world.World; import org.spongepowered.api.world.portal.Portal; import org.spongepowered.api.world.portal.PortalLogic; import org.spongepowered.api.world.server.ServerLocation; import org.spongepowered.api.world.server.ServerWorld; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.common.bridge.world.level.block.PortalBlockBridge; import org.spongepowered.common.util.AxisUtil; import org.spongepowered.common.util.VecHelper; +import org.spongepowered.common.world.portal.SpongeNetherPortalTeleportBehavior; import org.spongepowered.common.world.portal.SpongePortal; import org.spongepowered.math.vector.Vector3i; -import java.util.Comparator; import java.util.Optional; @Mixin(NetherPortalBlock.class) public abstract class NetherPortalBlockMixin implements PortalBlockBridge { + @Shadow + private static DimensionTransition getDimensionTransitionFromExit(Entity $$0, BlockPos $$1, BlockUtil.FoundRectangle $$2, ServerLevel $$3, DimensionTransition.PostDimensionTransition $$4) { + throw new UnsupportedOperationException("Implemented via mixin"); + } + @Override public Optional bridge$calculatePortalExit(final ServerWorld from, final Vector3i fromPos, final org.spongepowered.api.entity.Entity entity) { final var fromLevel = (ServerLevel) from.world(); @@ -73,16 +82,8 @@ public abstract class NetherPortalBlockMixin implements PortalBlockBridge { final var level = ((ServerLevel) at.world()); final var worldBorder = level.getWorldBorder(); final var blockPos = VecHelper.toBlockPos(at.position()); - final var poiManager = level.getPoiManager(); - final int range = Math.clamp(searchRange, 1, 128); - poiManager.ensureLoadedAndValid(level, blockPos, range); - final var foundPortalPos = poiManager.getInSquare(poi -> poi.is(PoiTypes.NETHER_PORTAL), blockPos, range, PoiManager.Occupancy.ANY) - .map(PoiRecord::getPos) - .filter(worldBorder::isWithinBounds) - .filter(pos -> level.getBlockState(pos).hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) - .min(Comparator.comparingDouble($$1x -> $$1x.distSqr(blockPos)).thenComparingInt(Vec3i::getY)); - return foundPortalPos.map(pos -> { + return level.getPortalForcer().findClosestPortalPosition(blockPos, level.dimension() == Level.NETHER, worldBorder).map(pos -> { final var portalBlockState = level.getBlockState(pos); final var axis = portalBlockState.getValue(BlockStateProperties.HORIZONTAL_AXIS); final var foundRectangle = BlockUtil.getLargestRectangleAround(pos, axis, 21, Direction.Axis.Y, 21, pos2 -> level.getBlockState(pos2) == portalBlockState); @@ -109,11 +110,11 @@ public abstract class NetherPortalBlockMixin implements PortalBlockBridge { } @Override - public boolean bridge$teleport(final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { + public boolean bridge$teleport(final ServerLocation origin, final org.spongepowered.api.entity.Entity entity, final ServerLocation destination, final boolean generateDestinationPortal) { final var toLevel = (ServerLevel) destination.world(); boolean toSmallerScaleLevel = toLevel.dimension() == Level.NETHER; var found = this.bridge$findPortal(destination, toSmallerScaleLevel ? 16 : 128); - var portalDestination = found.map(Portal::position); + var portalDestination = found.map(portal -> SpongeNetherPortalTeleportBehavior.INSTANCE.spawnLocation(origin, destination, entity)); if (portalDestination.isPresent()) { entity.setLocation(portalDestination.get()); return true; @@ -123,7 +124,7 @@ public abstract class NetherPortalBlockMixin implements PortalBlockBridge { } final Axis axis = AxisUtil.getFor(Direction.Axis.X); var generated = this.bridge$generatePortal(destination, axis); - portalDestination = generated.map(Portal::position); + portalDestination = generated.map(portal -> SpongeNetherPortalTeleportBehavior.INSTANCE.spawnLocation(origin, destination, entity)); if (portalDestination.isPresent()) { entity.setLocation(portalDestination.get()); return true; @@ -131,5 +132,4 @@ public abstract class NetherPortalBlockMixin implements PortalBlockBridge { return false; } - }