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:
@@ -39,6 +39,12 @@ public class Gate {
|
||||
private int linkX;
|
||||
private int linkY;
|
||||
private int linkZ;
|
||||
// Iris shield: a separate safety barrier from the wormhole connection itself. While the
|
||||
// gate is connected, the iris being closed blocks travel and shows a solid barrier instead
|
||||
// of the event horizon. Defaults open so a freshly linked gate works immediately.
|
||||
private boolean irisClosed = false;
|
||||
// If set, opening a closed iris via the button requires typing this in chat first.
|
||||
private String pinCode;
|
||||
|
||||
public Gate(UUID id, String name, String network, String serverId, String world,
|
||||
int exitX, int exitY, int exitZ, float exitYaw,
|
||||
@@ -97,6 +103,10 @@ public class Gate {
|
||||
public int getLinkX() { return linkX; }
|
||||
public int getLinkY() { return linkY; }
|
||||
public int getLinkZ() { return linkZ; }
|
||||
public boolean isIrisClosed() { return irisClosed; }
|
||||
public void setIrisClosed(boolean irisClosed) { this.irisClosed = irisClosed; }
|
||||
public String getPinCode() { return pinCode; }
|
||||
public void setPinCode(String pinCode) { this.pinCode = pinCode; }
|
||||
|
||||
/** Fully-qualified identity used for cross-server lookups: server/network/name */
|
||||
public String qualifiedName() {
|
||||
|
||||
+30
-12
@@ -78,18 +78,22 @@ public class SqlGateStorage implements GateStorage {
|
||||
"fixed_destination VARCHAR(64)," +
|
||||
"link_x INTEGER NOT NULL DEFAULT 0," +
|
||||
"link_y INTEGER NOT NULL DEFAULT 0," +
|
||||
"link_z INTEGER NOT NULL DEFAULT 0" +
|
||||
"link_z INTEGER NOT NULL DEFAULT 0," +
|
||||
"iris_closed INTEGER NOT NULL DEFAULT 0," +
|
||||
"pin_code VARCHAR(32)" +
|
||||
")");
|
||||
s.executeUpdate("CREATE INDEX IF NOT EXISTS idx_" + tablePrefix + "network ON " + tablePrefix + "gates(network)");
|
||||
migrateColumn(s, "link_x");
|
||||
migrateColumn(s, "link_y");
|
||||
migrateColumn(s, "link_z");
|
||||
migrateIntColumn(s, "link_x");
|
||||
migrateIntColumn(s, "link_y");
|
||||
migrateIntColumn(s, "link_z");
|
||||
migrateIntColumn(s, "iris_closed");
|
||||
migrateStringColumn(s, "pin_code", "VARCHAR(32)");
|
||||
}
|
||||
logger.info("[Stargate] Storage initialised (" + driver + ")");
|
||||
}
|
||||
|
||||
/** Best-effort ALTER TABLE for databases created before link_x/y/z existed; ignored if the column is already there. */
|
||||
private void migrateColumn(Statement s, String column) {
|
||||
/** Best-effort ALTER TABLE for databases created before this column existed; ignored if it's already there. */
|
||||
private void migrateIntColumn(Statement s, String column) {
|
||||
try {
|
||||
s.executeUpdate("ALTER TABLE " + tablePrefix + "gates ADD COLUMN " + column + " INTEGER NOT NULL DEFAULT 0");
|
||||
} catch (Exception ignored) {
|
||||
@@ -97,6 +101,14 @@ public class SqlGateStorage implements GateStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private void migrateStringColumn(Statement s, String column, String type) {
|
||||
try {
|
||||
s.executeUpdate("ALTER TABLE " + tablePrefix + "gates ADD COLUMN " + column + " " + type);
|
||||
} catch (Exception ignored) {
|
||||
// column already exists
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (dataSource != null) dataSource.close();
|
||||
@@ -105,17 +117,18 @@ public class SqlGateStorage implements GateStorage {
|
||||
@Override
|
||||
public void saveGate(Gate gate) {
|
||||
String sql = "REPLACE INTO " + tablePrefix + "gates " +
|
||||
"(id,name,network,server_id,world,exit_x,exit_y,exit_z,exit_yaw,sign_x,sign_y,sign_z,sign_world,facing,owner,flags,fixed_destination,link_x,link_y,link_z) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
"(id,name,network,server_id,world,exit_x,exit_y,exit_z,exit_yaw,sign_x,sign_y,sign_z,sign_world,facing,owner,flags,fixed_destination,link_x,link_y,link_z,iris_closed,pin_code) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
if (driver == Driver.MYSQL) {
|
||||
sql = "INSERT INTO " + tablePrefix + "gates " +
|
||||
"(id,name,network,server_id,world,exit_x,exit_y,exit_z,exit_yaw,sign_x,sign_y,sign_z,sign_world,facing,owner,flags,fixed_destination,link_x,link_y,link_z) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE " +
|
||||
"(id,name,network,server_id,world,exit_x,exit_y,exit_z,exit_yaw,sign_x,sign_y,sign_z,sign_world,facing,owner,flags,fixed_destination,link_x,link_y,link_z,iris_closed,pin_code) " +
|
||||
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE " +
|
||||
"name=VALUES(name),network=VALUES(network),server_id=VALUES(server_id),world=VALUES(world)," +
|
||||
"exit_x=VALUES(exit_x),exit_y=VALUES(exit_y),exit_z=VALUES(exit_z),exit_yaw=VALUES(exit_yaw)," +
|
||||
"sign_x=VALUES(sign_x),sign_y=VALUES(sign_y),sign_z=VALUES(sign_z),sign_world=VALUES(sign_world)," +
|
||||
"facing=VALUES(facing),owner=VALUES(owner),flags=VALUES(flags),fixed_destination=VALUES(fixed_destination)," +
|
||||
"link_x=VALUES(link_x),link_y=VALUES(link_y),link_z=VALUES(link_z)";
|
||||
"link_x=VALUES(link_x),link_y=VALUES(link_y),link_z=VALUES(link_z)," +
|
||||
"iris_closed=VALUES(iris_closed),pin_code=VALUES(pin_code)";
|
||||
}
|
||||
try (Connection c = dataSource.getConnection(); PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
ps.setString(1, gate.getId().toString());
|
||||
@@ -138,6 +151,8 @@ public class SqlGateStorage implements GateStorage {
|
||||
ps.setInt(18, gate.getLinkX());
|
||||
ps.setInt(19, gate.getLinkY());
|
||||
ps.setInt(20, gate.getLinkZ());
|
||||
ps.setInt(21, gate.isIrisClosed() ? 1 : 0);
|
||||
ps.setString(22, gate.getPinCode());
|
||||
ps.executeUpdate();
|
||||
} catch (Exception e) {
|
||||
logger.severe("[Stargate] Failed to save gate " + gate.getName() + ": " + e.getMessage());
|
||||
@@ -190,7 +205,7 @@ public class SqlGateStorage implements GateStorage {
|
||||
private Gate fromRow(ResultSet rs) throws Exception {
|
||||
String ownerStr = rs.getString("owner");
|
||||
String fixedDest = rs.getString("fixed_destination");
|
||||
return new Gate(
|
||||
Gate gate = new Gate(
|
||||
UUID.fromString(rs.getString("id")),
|
||||
rs.getString("name"),
|
||||
rs.getString("network"),
|
||||
@@ -204,6 +219,9 @@ public class SqlGateStorage implements GateStorage {
|
||||
fixedDest,
|
||||
rs.getInt("link_x"), rs.getInt("link_y"), rs.getInt("link_z")
|
||||
);
|
||||
gate.setIrisClosed(rs.getInt("iris_closed") != 0);
|
||||
gate.setPinCode(rs.getString("pin_code"));
|
||||
return gate;
|
||||
}
|
||||
|
||||
private String serializeFlags(Set<Gate.Flag> flags) {
|
||||
|
||||
Reference in New Issue
Block a user