diff --git a/README.md b/README.md index 5779297..79a01d1 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/gate/GateManager.java b/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/gate/GateManager.java index 147dfa1..195bda9 100644 --- a/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/gate/GateManager.java +++ b/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/gate/GateManager.java @@ -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); } }