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
@@ -38,7 +38,7 @@ public class StargateVelocityPlugin {
// playerId -> (targetServerName, gateId) pending until they finish connecting
private final Map<UUID, PendingWarp> pending = new ConcurrentHashMap<>();
private record PendingWarp(String gateId) {}
private record PendingWarp(String gateId, float yaw, float pitch) {}
@Inject
public StargateVelocityPlugin(ProxyServer server, Logger logger) {
@@ -66,6 +66,8 @@ public class StargateVelocityPlugin {
UUID playerId = UUID.fromString(in.readUTF());
String targetServer = in.readUTF();
String gateId = in.readUTF();
float yaw = in.readFloat();
float pitch = in.readFloat();
Optional<Player> playerOpt = server.getPlayer(playerId);
Optional<RegisteredServer> targetOpt = server.getServer(targetServer);
@@ -74,7 +76,7 @@ public class StargateVelocityPlugin {
return;
}
pending.put(playerId, new PendingWarp(gateId));
pending.put(playerId, new PendingWarp(gateId, yaw, pitch));
playerOpt.get().createConnectionRequest(targetOpt.get()).connectWithIndication().thenAccept(success -> {
if (Boolean.TRUE.equals(success)) {
deliver(playerId, targetOpt.get());
@@ -102,6 +104,8 @@ public class StargateVelocityPlugin {
out.writeByte(StargateChannel.OP_TELEPORT_DELIVER);
out.writeUTF(playerId.toString());
out.writeUTF(warp.gateId());
out.writeFloat(warp.yaw());
out.writeFloat(warp.pitch());
connection.get().sendPluginMessage(channel, bytes.toByteArray());
} catch (Exception e) {
logger.warn("Failed to deliver stargate teleport", e);