Created
April 2, 2026 04:40
-
-
Save gamerchamper/dce40aebca811eb57c956a5d95ee565d to your computer and use it in GitHub Desktop.
velocity-main
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.normalsmp.normalSurvivalWorlds; | |
| import com.google.common.io.ByteArrayDataInput; | |
| import com.google.common.io.ByteArrayDataOutput; | |
| import com.google.common.io.ByteStreams; | |
| 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.ProxyServer; | |
| import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; | |
| import org.slf4j.Logger; | |
| import java.util.Map; | |
| import java.util.UUID; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| @Plugin(id = "normalsurvivalworlds", name = "NormalSurvivalWorlds", version = "3.0") | |
| public class NormalSurvivalWorlds { | |
| public static final MinecraftChannelIdentifier CHANNEL = | |
| MinecraftChannelIdentifier.from("nsw:playerdata"); | |
| private final ProxyServer server; | |
| private final Logger logger; | |
| private final boolean DEBUG = true; | |
| // 🔥 THIS IS THE MAGIC NUMBER (size of server1 border * 2) | |
| private static final double SHIFT = 16000; | |
| private final Map<UUID, PlayerData> playerDataMap = new ConcurrentHashMap<>(); | |
| private final Map<UUID, Long> lastTransfer = new ConcurrentHashMap<>(); | |
| @Inject | |
| public NormalSurvivalWorlds(ProxyServer server, Logger logger) { | |
| this.server = server; | |
| this.logger = logger; | |
| } | |
| @Subscribe | |
| public void onProxyInitialization(ProxyInitializeEvent event) { | |
| server.getChannelRegistrar().register(CHANNEL); | |
| logger.info("[NSW] Velocity initialized."); | |
| } | |
| @Subscribe | |
| public void onPluginMessage(PluginMessageEvent event) { | |
| if (!event.getIdentifier().equals(CHANNEL)) return; | |
| ByteArrayDataInput in = ByteStreams.newDataInput(event.getData()); | |
| try { | |
| String sub = in.readUTF(); | |
| // ========================= | |
| // 📥 RECEIVE PLAYER DATA | |
| // ========================= | |
| if (sub.equals("DATA")) { | |
| UUID uuid = UUID.fromString(in.readUTF()); | |
| String username = in.readUTF(); | |
| String serverName = in.readUTF(); | |
| String world = in.readUTF(); | |
| double x = in.readDouble(); | |
| double y = in.readDouble(); | |
| double z = in.readDouble(); | |
| float yaw = in.readFloat(); | |
| float pitch = in.readFloat(); | |
| boolean borderHit = in.readBoolean(); | |
| String targetServerName = in.readUTF(); | |
| String edge = in.readUTF(); | |
| // 🔥 APPLY OFFSET IF CROSSING | |
| double newX = x; | |
| double newZ = z; | |
| if (borderHit) { | |
| switch (edge) { | |
| case "EAST" -> newX = x - SHIFT; | |
| case "WEST" -> newX = x + SHIFT; | |
| case "SOUTH" -> newZ = z - SHIFT; | |
| case "NORTH" -> newZ = z + SHIFT; | |
| } | |
| if (DEBUG) { | |
| logger.info("[OFFSET] {} {} -> X:{} Z:{}", | |
| username, edge, | |
| round(newX), round(newZ)); | |
| } | |
| } | |
| PlayerData data = new PlayerData( | |
| uuid, username, serverName, world, | |
| newX, y, newZ, yaw, pitch, edge | |
| ); | |
| playerDataMap.put(uuid, data); | |
| if (borderHit) { | |
| long now = System.currentTimeMillis(); | |
| long last = lastTransfer.getOrDefault(uuid, 0L); | |
| if (now - last < 2000) { | |
| if (DEBUG) logger.info("[SKIP] Cooldown {}", username); | |
| return; | |
| } | |
| lastTransfer.put(uuid, now); | |
| server.getPlayer(uuid).ifPresent(player -> { | |
| server.getServer(targetServerName).ifPresent(target -> { | |
| logger.info("[TRANSFER] {} -> {} EDGE:{}", | |
| username, targetServerName, edge); | |
| player.createConnectionRequest(target).fireAndForget(); | |
| }); | |
| }); | |
| } | |
| } | |
| // ========================= | |
| // 📤 HANDLE REQUEST | |
| // ========================= | |
| if (sub.equals("REQUEST")) { | |
| UUID uuid = UUID.fromString(in.readUTF()); | |
| PlayerData data = playerDataMap.get(uuid); | |
| if (data == null) { | |
| logger.warn("[REQUEST] No data for {}", uuid); | |
| return; | |
| } | |
| server.getPlayer(uuid).ifPresent(player -> { | |
| ByteArrayDataOutput out = ByteStreams.newDataOutput(); | |
| out.writeUTF("RESPONSE"); | |
| out.writeDouble(data.getX()); | |
| out.writeDouble(data.getY()); | |
| out.writeDouble(data.getZ()); | |
| out.writeFloat(data.getYaw()); | |
| out.writeFloat(data.getPitch()); | |
| player.sendPluginMessage(CHANNEL, out.toByteArray()); | |
| if (DEBUG) { | |
| logger.info("[RESPONSE] {} -> X:{} Z:{}", | |
| data.getUsername(), | |
| round(data.getX()), | |
| round(data.getZ())); | |
| } | |
| }); | |
| } | |
| } catch (Exception e) { | |
| logger.error("[ERROR] Plugin message failed", e); | |
| } | |
| } | |
| private double round(double val) { | |
| return Math.round(val * 100.0) / 100.0; | |
| } | |
| } | |
| package com.normalsmp.normalSurvivalWorlds; | |
| import java.util.UUID; | |
| public class PlayerData { | |
| private final UUID uuid; | |
| private final String username; | |
| private final String server; | |
| private final String world; | |
| private final double x, y, z; | |
| private final float yaw, pitch; | |
| private final String edge; | |
| public PlayerData(UUID uuid, String username, String server, String world, | |
| double x, double y, double z, | |
| float yaw, float pitch, | |
| String edge) { | |
| this.uuid = uuid; | |
| this.username = username; | |
| this.server = server; | |
| this.world = world; | |
| this.x = x; | |
| this.y = y; | |
| this.z = z; | |
| this.yaw = yaw; | |
| this.pitch = pitch; | |
| this.edge = edge; | |
| } | |
| public String getEdge() { return edge; } | |
| public UUID getUuid() { return uuid; } | |
| public String getUsername() { return username; } | |
| public String getServer() { return server; } | |
| public String getWorld() { return world; } | |
| public double getX() { return x; } | |
| public double getY() { return y; } | |
| public double getZ() { return z; } | |
| public float getYaw() { return yaw; } | |
| public float getPitch() { return pitch; } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment