Initial Stargate plugin: Paper gate plugin + Velocity/Bungee cross-server bridges
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
id("com.gradleup.shadow") version "8.3.5"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":stargate-common"))
|
||||
compileOnly("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT")
|
||||
annotationProcessor("com.velocitypowered:velocity-api:3.4.0-SNAPSHOT")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set("")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package dev.skywalker3200.stargate.velocity;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||
import dev.skywalker3200.stargate.common.network.StargateChannel;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Relays stargate cross-server teleport requests: when a backend server asks to move a
|
||||
* player to another backend, this plugin connects them there, then forwards a "deliver"
|
||||
* message to the new backend once they land so the Paper plugin can warp them to the gate.
|
||||
*/
|
||||
@Plugin(id = "stargate-velocity", name = "Stargate Velocity Bridge", version = "1.0.0", authors = {"skywalker3200"})
|
||||
public class StargateVelocityPlugin {
|
||||
|
||||
private final ProxyServer server;
|
||||
private final Logger logger;
|
||||
private final ChannelIdentifier channel = MinecraftChannelIdentifier.from(StargateChannel.CHANNEL);
|
||||
|
||||
// playerId -> (targetServerName, gateId) pending until they finish connecting
|
||||
private final Map<UUID, PendingWarp> pending = new ConcurrentHashMap<>();
|
||||
|
||||
private record PendingWarp(String gateId) {}
|
||||
|
||||
@Inject
|
||||
public StargateVelocityPlugin(ProxyServer server, Logger logger) {
|
||||
this.server = server;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onInit(ProxyInitializeEvent event) {
|
||||
server.getChannelRegistrar().register(channel);
|
||||
logger.info("Stargate Velocity bridge ready on channel {}", StargateChannel.CHANNEL);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
if (!event.getIdentifier().equals(channel)) return;
|
||||
event.setResult(PluginMessageEvent.ForwardResult.handled());
|
||||
|
||||
byte[] data = event.getData();
|
||||
try {
|
||||
DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
|
||||
byte op = in.readByte();
|
||||
if (op != StargateChannel.OP_TELEPORT_REQUEST) return;
|
||||
|
||||
UUID playerId = UUID.fromString(in.readUTF());
|
||||
String targetServer = in.readUTF();
|
||||
String gateId = in.readUTF();
|
||||
|
||||
Optional<Player> playerOpt = server.getPlayer(playerId);
|
||||
Optional<RegisteredServer> targetOpt = server.getServer(targetServer);
|
||||
if (playerOpt.isEmpty() || targetOpt.isEmpty()) {
|
||||
logger.warn("Stargate teleport request for unknown player/server ({}/{})", playerId, targetServer);
|
||||
return;
|
||||
}
|
||||
|
||||
pending.put(playerId, new PendingWarp(gateId));
|
||||
playerOpt.get().createConnectionRequest(targetOpt.get()).connectWithIndication().thenAccept(success -> {
|
||||
if (Boolean.TRUE.equals(success)) {
|
||||
deliver(playerId, targetOpt.get());
|
||||
} else {
|
||||
pending.remove(playerId);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to process stargate plugin message", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void deliver(UUID playerId, RegisteredServer server) {
|
||||
PendingWarp warp = pending.remove(playerId);
|
||||
if (warp == null) return;
|
||||
Optional<ServerConnection> connection = server.getPlayersConnected().stream()
|
||||
.filter(p -> p.getUniqueId().equals(playerId))
|
||||
.findFirst()
|
||||
.flatMap(Player::getCurrentServer);
|
||||
if (connection.isEmpty()) return;
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(bytes);
|
||||
out.writeByte(StargateChannel.OP_TELEPORT_DELIVER);
|
||||
out.writeUTF(playerId.toString());
|
||||
out.writeUTF(warp.gateId());
|
||||
connection.get().sendPluginMessage(channel, bytes.toByteArray());
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to deliver stargate teleport", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user