Fix one-way travel, rework iris to SG-1 mechanics, glowstone chevrons, pin-locked shield

One-way travel bug: the exit point landed players directly inside the
destination gate's own iris footprint. Since dialing opens both ends,
arriving there immediately re-triggered the teleport listener and
bounced them straight back - reading exactly like one-way travel.
GateManager.computeSafeLanding now nudges the landing spot along the
player's travel direction until it clears the destination's iris
blocks, and GateTeleportListener adds a short per-player cooldown as a
second guard against re-trigger. Same-server teleports now also
preserve the player's exact yaw/pitch and velocity instead of forcing
a fixed stored orientation, so entering forward always means exiting
forward; the cross-server plugin-messaging protocol was extended to
carry yaw/pitch through the proxy hop for the same reason.

Iris rework to match SG-1 rather than a binary open/closed gate:
- Idle (not connected): iris-idle-material, default AIR - you see
  straight through an inactive ring, not a wall.
- Connected: iris-open-material (WATER, the event horizon) unless the
  gate's separate iris shield is closed, in which case
  iris-shield-material (IRON_BLOCK) blocks travel even though the
  wormhole is active.
- A button placed directly below the control sign toggles the shield
  (GateIrisButtonListener). Closing needs nothing; opening a gate with
  a pin code set (/sg pin <code>) prompts the player to type it in
  chat within gate.pin-timeout-seconds first.

Also: gate.chevron-lit-material default changed from gilded blackstone
to glowstone per feedback.
This commit is contained in:
Michael Burgess
2026-08-09 11:36:17 -04:00
parent 190f875d23
commit b822389387
13 changed files with 387 additions and 70 deletions
@@ -22,7 +22,9 @@ import java.util.concurrent.ConcurrentHashMap;
/** BungeeCord counterpart of the Velocity bridge: same wire protocol, same job. */
public class StargateBungeePlugin extends Plugin implements Listener {
private final Map<UUID, String> pendingGateByPlayer = new ConcurrentHashMap<>();
private record PendingWarp(String gateId, float yaw, float pitch) {}
private final Map<UUID, PendingWarp> pendingGateByPlayer = new ConcurrentHashMap<>();
@Override
public void onEnable() {
@@ -44,6 +46,8 @@ public class StargateBungeePlugin extends Plugin implements Listener {
UUID playerId = UUID.fromString(in.readUTF());
String targetServer = in.readUTF();
String gateId = in.readUTF();
float yaw = in.readFloat();
float pitch = in.readFloat();
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(playerId);
ServerInfo target = ProxyServer.getInstance().getServerInfo(targetServer);
@@ -52,7 +56,7 @@ public class StargateBungeePlugin extends Plugin implements Listener {
return;
}
pendingGateByPlayer.put(playerId, gateId);
pendingGateByPlayer.put(playerId, new PendingWarp(gateId, yaw, pitch));
player.connect(target);
} catch (Exception e) {
getLogger().warning("Failed to process stargate plugin message: " + e.getMessage());
@@ -62,8 +66,8 @@ public class StargateBungeePlugin extends Plugin implements Listener {
@EventHandler
public void onServerConnected(ServerConnectedEvent event) {
ProxiedPlayer player = event.getPlayer();
String gateId = pendingGateByPlayer.remove(player.getUniqueId());
if (gateId == null) return;
PendingWarp warp = pendingGateByPlayer.remove(player.getUniqueId());
if (warp == null) return;
Server server = event.getServer();
try {
@@ -71,7 +75,9 @@ public class StargateBungeePlugin extends Plugin implements Listener {
DataOutputStream out = new DataOutputStream(bytes);
out.writeByte(StargateChannel.OP_TELEPORT_DELIVER);
out.writeUTF(player.getUniqueId().toString());
out.writeUTF(gateId);
out.writeUTF(warp.gateId());
out.writeFloat(warp.yaw());
out.writeFloat(warp.pitch());
server.sendData(StargateChannel.CHANNEL, bytes.toByteArray());
} catch (Exception e) {
getLogger().warning("Failed to deliver stargate teleport: " + e.getMessage());