diff --git a/README.md b/README.md index f2e8b63..d215f5c 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,13 @@ proxy (over the `stargate:teleport` plugin channel) to connect the player to tha server; once they land, the proxy forwards a delivery message so the destination server's Stargate instance teleports them to the gate's exit point. +Each backend only loads gates from the shared database at startup (and on +`/sg reload`), then polls for what other servers have added, changed, or removed +every `cross-server.refresh-seconds` (default 30) while `cross-server.enabled: true`. +So a gate built on one server shows up as a destination on another within that +window automatically - no restart or manual reload needed, though `/sg reload` +still works if you want it immediately. + ## Permissions - `stargate.use` (default: true) — dial/cycle gates diff --git a/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/StargatePlugin.java b/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/StargatePlugin.java index b4ec921..2c479e5 100644 --- a/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/StargatePlugin.java +++ b/stargate-paper/src/main/java/dev/skywalker3200/stargate/paper/StargatePlugin.java @@ -41,6 +41,9 @@ public class StargatePlugin extends JavaPlugin { this.crossServerBridge = new CrossServerBridge(this, gateManager); if (crossServer) { this.crossServerBridge.register(); + int refreshSeconds = Math.max(5, getConfig().getInt("cross-server.refresh-seconds", 30)); + getServer().getScheduler().runTaskTimerAsynchronously(this, gateManager::refreshRemoteGates, + 20L * refreshSeconds, 20L * refreshSeconds); } getServer().getPluginManager().registerEvents(new SignCreateListener(this, gateManager), this); 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 4c9a68d..6133ff9 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 @@ -80,6 +80,50 @@ public class GateManager { plugin.getLogger().info("[Stargate] Loaded " + gatesById.size() + " gate(s), " + gatesBySignBlock.size() + " local."); } + /** + * Picks up gates created/removed on OTHER servers since the last load, without touching + * anything local (structures, open/connected/outgoing runtime state). loadAll() only ever + * runs at startup or /sg reload, so without this, a server that's already running never + * finds out about a gate another backend created after it booted - the shared MySQL row + * exists, but nothing tells this JVM to look. Safe to call from any thread; the actual + * gatesById mutation is scheduled back onto the main thread. + */ + public void refreshRemoteGates() { + List all; + try { + all = storage.loadAll(); + } catch (Exception e) { + plugin.getLogger().warning("[Stargate] Failed to refresh remote gates: " + e.getMessage()); + return; + } + Bukkit.getScheduler().runTask(plugin, () -> mergeRemoteGates(all)); + } + + private void mergeRemoteGates(List all) { + Set currentRemoteIds = new HashSet<>(); + int added = 0; + for (Gate gate : all) { + if (gate.getServerId().equals(plugin.getServerId())) continue; // local gates are handled by loadAll()/live state + currentRemoteIds.add(gate.getId()); + if (!gatesById.containsKey(gate.getId())) { + gatesById.put(gate.getId(), new RuntimeGate(gate, null)); + added++; + } + } + int removed = 0; + var it = gatesById.entrySet().iterator(); + while (it.hasNext()) { + RuntimeGate rg = it.next().getValue(); + if (!rg.getGate().getServerId().equals(plugin.getServerId()) && !currentRemoteIds.contains(rg.getGate().getId())) { + it.remove(); + removed++; + } + } + if (added > 0 || removed > 0) { + plugin.getLogger().info("[Stargate] Remote gate sync: +" + added + " -" + removed); + } + } + private String signKey(String world, int x, int y, int z) { return world + "," + x + "," + y + "," + z; } diff --git a/stargate-paper/src/main/resources/config.yml b/stargate-paper/src/main/resources/config.yml index 63b2c15..d23beac 100644 --- a/stargate-paper/src/main/resources/config.yml +++ b/stargate-paper/src/main/resources/config.yml @@ -33,6 +33,12 @@ storage: # share gate data. cross-server: enabled: false + # How often (in seconds) this server checks the shared database for gates other + # servers have created, updated, or removed since it last looked. Without this, a + # server that's already running never finds out about a gate another backend made + # after it booted - the row exists, but nothing prompts a reload. Doesn't touch + # this server's own gates or any live dial/open state. + refresh-seconds: 30 gate: # Any of these materials count as the ring's frame (and count as a valid chevron