Check landing spot is actually open space, not just clear of the iris

computeSafeLanding() pushed the arrival point along the entry
direction only until it cleared the destination's iris footprint - it
never checked whether that spot was solid ground. A gate built close
to a wall (e.g. inside a room/temple) could push the landing straight
into that wall, embedding the player in it - which incidentally let
them walk out through the wall instead of a door, since they're
already clipped partway through it.

Now checks feet AND head height at each step for solid blocks while
searching forward (up to 8 blocks), stopping at the first spot that's
both clear of the iris and open space. Falls back to the furthest
wall-clear point found if nothing satisfies both within range, rather
than the original blind offset.
This commit is contained in:
Michael Burgess
2026-08-09 14:49:12 -04:00
parent 508a3d9b51
commit 7204e1f1dd
2 changed files with 29 additions and 4 deletions
+4 -1
View File
@@ -80,7 +80,10 @@ material, unsealed interior, too far from the sign, etc.
- Travel is **one-way**: only the gate you dialed *from* can send anything anywhere.
Walking (or wandering, or drifting) into its event horizon teleports whatever
entered to the destination, arriving just clear of its iris (never inside it) and
still facing whatever direction it was already moving, so entering forward always
clear of any wall too - if the gate sits close to a wall (built inside a room, say),
the plugin checks the landing spot is actually open space and searches forward
along the entry direction for one instead of embedding the arrival in solid block.
It still faces whatever direction it was already moving, so entering forward always
means exiting forward. The destination's horizon is visible but not walkable -
stepping into it does nothing, same as a real Stargate only running one direction
at a time.
@@ -491,13 +491,35 @@ public class GateManager {
if (dir.lengthSquared() < 0.0001) dir = new Vector(0, 0, 1);
dir.normalize();
for (int i = 0; i < 8 && !irisXZ.isEmpty(); i++) {
long key = ((long) Math.floor(x) << 32) ^ ((long) Math.floor(z) & 0xFFFFFFFFL);
if (!irisXZ.contains(key)) break;
// Push clear of the iris footprint (so arrival doesn't immediately re-trigger the
// teleport) AND clear of any solid block at foot/head height - a wall close behind the
// gate (e.g. built inside a room) can otherwise land the player embedded in it. Falls
// back to the furthest wall-clear spot found if nothing satisfies both within range.
double lastClearX = x, lastClearZ = z;
boolean foundClear = false;
for (int i = 0; i <= 16; i++) {
boolean inIris = irisXZ.contains(((long) Math.floor(x) << 32) ^ ((long) Math.floor(z) & 0xFFFFFFFFL));
Block feet = world.getBlockAt((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z));
Block head = feet.getRelative(0, 1, 0);
boolean solid = feet.getType().isSolid() || head.getType().isSolid();
if (!inIris && !solid) {
foundClear = true;
break;
}
if (!solid) {
lastClearX = x;
lastClearZ = z;
}
x += dir.getX() * 0.5;
z += dir.getZ() * 0.5;
}
if (!foundClear) {
x = lastClearX;
z = lastClearZ;
}
return new Location(world, x, y, z, yaw, pitch);
}
}