Actually enforce the iris shield instead of only rendering it

The shield's closed/open state only ever controlled the iris block's
appearance (bedrock vs water) - the teleport listener never checked
it, only whether the gate was open+outgoing. A solid bedrock block
stops normal walking, but nothing stopped a player who ended up
standing there anyway (flight, elytra, a vehicle) from still getting
teleported, which is what was reported: iris visibly closed, travel
still worked.

findOutgoingGateAt() now skips any gate whose iris is closed, and
both teleportPlayer()/teleportEntity() also refuse the trip if the
DESTINATION's shield is closed, matching a real iris blocking
whatever hits it from either side. Same check added to the
cross-server delivery path in CrossServerBridge for the race where
the shield closes between the proxy request and the player landing.
This commit is contained in:
Michael Burgess
2026-08-09 12:25:08 -04:00
parent c98f89c225
commit 576c078abf
3 changed files with 25 additions and 5 deletions
@@ -85,6 +85,7 @@ public class GateTeleportListener implements Listener {
List<RuntimeGate> gates = gateManager.all();
for (RuntimeGate rg : gates) {
if (!rg.isOpen() || !rg.isOutgoing() || rg.getStructure() == null || rg.getConnectedTo() == null) continue;
if (rg.getGate().isIrisClosed()) continue; // shield blocks travel even on a connected gate
for (Block iris : rg.getStructure().getIris()) {
if (iris.getX() == standing.getX() && iris.getY() == standing.getY() && iris.getZ() == standing.getZ()
&& iris.getWorld().equals(standing.getWorld())) {
@@ -98,6 +99,11 @@ public class GateTeleportListener implements Listener {
private void teleportPlayer(Player player, RuntimeGate entered) {
RuntimeGate dest = entered.getConnectedTo();
if (dest == null) return;
if (dest.getGate().isIrisClosed()) {
player.sendMessage(net.kyori.adventure.text.Component.text(
"The iris on the other end is closed.", net.kyori.adventure.text.format.NamedTextColor.RED));
return;
}
Location loc = player.getLocation();
Vector direction = loc.getDirection();
@@ -121,6 +127,7 @@ public class GateTeleportListener implements Listener {
private void teleportEntity(Entity entity, RuntimeGate entered) {
RuntimeGate dest = entered.getConnectedTo();
if (dest == null) return;
if (dest.getGate().isIrisClosed()) return; // shield blocks arrival too
if (!dest.getGate().getServerId().equals(plugin.getServerId())) return; // no cross-server carry for non-players
Location loc = entity.getLocation();
@@ -79,6 +79,14 @@ public class CrossServerBridge implements PluginMessageListener {
Bukkit.getScheduler().runTask(plugin, () -> {
Player p = Bukkit.getPlayer(playerId);
if (p == null) return;
if (rg.getGate().isIrisClosed()) {
// the shield closed between the request and arrival - can't send them back
// through the proxy, so just leave them at this server's default spawn
p.sendMessage(net.kyori.adventure.text.Component.text(
"The iris on the other end closed before you arrived.",
net.kyori.adventure.text.format.NamedTextColor.RED));
return;
}
double yawRad = Math.toRadians(yaw);
Vector direction = new Vector(-Math.sin(yawRad), 0, Math.cos(yawRad));
Location landing = gateManager.computeSafeLanding(rg, direction, yaw, pitch);