forked from git-mirrors/GeyserConnect
Add custom servers base and direct connect
This commit is contained in:
parent
fc3b792e84
commit
3679fd5034
13 changed files with 194 additions and 37 deletions
|
@ -4,11 +4,14 @@ package org.geysermc.multi;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.multi.utils.PlayerStorageManager;
|
||||
import org.geysermc.multi.utils.Server;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class GeyserMultiConfig {
|
||||
private GeyserConfigSection geyser;
|
||||
|
||||
private int port;
|
||||
|
||||
|
@ -20,11 +23,29 @@ public class GeyserMultiConfig {
|
|||
@JsonProperty("debug-mode")
|
||||
private boolean debugMode;
|
||||
|
||||
private GeyserConfigSection geyser;
|
||||
|
||||
private List<Server> servers;
|
||||
|
||||
@JsonProperty("custom-servers")
|
||||
private CustomServersSection customServers;
|
||||
|
||||
@Getter
|
||||
public static class GeyserConfigSection {
|
||||
|
||||
private int port;
|
||||
|
||||
@JsonProperty("debug-mode")
|
||||
private boolean debugMode;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class CustomServersSection {
|
||||
|
||||
private boolean enabled;
|
||||
private int max;
|
||||
|
||||
@JsonProperty("storage-type")
|
||||
private PlayerStorageManager.StorageType storageType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,15 @@ import org.geysermc.connector.utils.FileUtils;
|
|||
import org.geysermc.multi.proxy.GeyserProxyBootstrap;
|
||||
import org.geysermc.multi.utils.Logger;
|
||||
import org.geysermc.multi.utils.Player;
|
||||
import org.geysermc.multi.utils.PlayerStorageManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
|
@ -45,6 +49,8 @@ public class MasterServer {
|
|||
private GeyserMultiConfig geyserMultiConfig;
|
||||
|
||||
public MasterServer() {
|
||||
this.instance = this;
|
||||
|
||||
logger = new Logger();
|
||||
|
||||
try {
|
||||
|
@ -57,7 +63,6 @@ public class MasterServer {
|
|||
|
||||
logger.setDebug(geyserMultiConfig.isDebugMode());
|
||||
|
||||
this.instance = this;
|
||||
this.generalThreadPool = Executors.newScheduledThreadPool(32);
|
||||
|
||||
// Start a timer to keep the thread running
|
||||
|
@ -65,6 +70,8 @@ public class MasterServer {
|
|||
TimerTask task = new TimerTask() { public void run() { } };
|
||||
timer.scheduleAtFixedRate(task, 0L, 1000L);
|
||||
|
||||
PlayerStorageManager.setupStorage();
|
||||
|
||||
start(geyserMultiConfig.getPort());
|
||||
|
||||
logger.start();
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.nukkitx.protocol.bedrock.handler.BedrockPacketHandler;
|
|||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import com.nukkitx.protocol.bedrock.util.EncryptionUtils;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.common.window.response.CustomFormResponse;
|
||||
import org.geysermc.common.window.response.SimpleFormResponse;
|
||||
import org.geysermc.multi.ui.FormID;
|
||||
import org.geysermc.multi.ui.UIHandler;
|
||||
|
@ -130,7 +131,7 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
public boolean handle(ResourcePackClientResponsePacket packet) {
|
||||
switch (packet.getStatus()) {
|
||||
case COMPLETED:
|
||||
masterServer.getLogger().info("Logged in " + player.getDisplayName() + " (" + player.getXuid() + ")");
|
||||
masterServer.getLogger().info("Logged in " + player.getDisplayName() + " (" + player.getXuid() + ", " + player.getIdentity() + ")");
|
||||
player.sendStartGame();
|
||||
break;
|
||||
case HAVE_ALL_PACKS:
|
||||
|
@ -152,7 +153,7 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
public boolean handle(SetLocalPlayerAsInitializedPacket packet) {
|
||||
masterServer.getLogger().debug("Player initialized: " + player.getDisplayName());
|
||||
|
||||
player.sendWindow(FormID.MAIN, UIHandler.getServerListFormPacket(player.getServers()));;
|
||||
player.sendWindow(FormID.MAIN, UIHandler.getServerList(player.getServers()));;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
window.setResponse(packet.getFormData().trim());
|
||||
|
||||
// Resend the form if they closed it
|
||||
if (window.getResponse() == null) {
|
||||
if (window.getResponse() == null && id != FormID.DIRECT_CONNECT) {
|
||||
player.resendWindow();
|
||||
} else {
|
||||
// Send the response to the correct response function
|
||||
|
@ -178,6 +179,10 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
UIHandler.handleServerListResponse(player, (SimpleFormResponse) window.getResponse());
|
||||
break;
|
||||
|
||||
case DIRECT_CONNECT:
|
||||
UIHandler.handleDirectConnectResponse(player, (CustomFormResponse) window.getResponse());
|
||||
break;
|
||||
|
||||
default:
|
||||
player.resendWindow();
|
||||
break;
|
||||
|
|
|
@ -2,21 +2,20 @@ package org.geysermc.multi.proxy;
|
|||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import org.apache.logging.log4j.core.util.IOUtils;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.bootstrap.GeyserBootstrap;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.command.CommandManager;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.multi.GeyserMultiConfig;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import org.geysermc.multi.utils.Logger;
|
||||
import org.geysermc.multi.utils.Server;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package org.geysermc.multi.proxy;
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
|
|
@ -18,6 +18,8 @@ public class ProxyConnectorServerEventHandler extends ConnectorServerEventHandle
|
|||
|
||||
@Override
|
||||
public void onSessionCreation(BedrockServerSession bedrockServerSession) {
|
||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); // Only done here as it allows us to disconnect the player
|
||||
|
||||
Player player = MasterServer.getInstance().getPlayers().get(bedrockServerSession.getAddress());
|
||||
if (player == null) {
|
||||
bedrockServerSession.disconnect("Please connect to the master server and pick a server first!");
|
||||
|
@ -28,7 +30,6 @@ public class ProxyConnectorServerEventHandler extends ConnectorServerEventHandle
|
|||
|
||||
// This doesn't clean up the old packet handler, so may cause a memory leak?
|
||||
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserProxySession(connector, bedrockServerSession)));
|
||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); // Only done here as it sometimes gets cleared
|
||||
|
||||
// Add another disconnect handler to remove the player on final disconnect
|
||||
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
package org.geysermc.multi.ui;
|
||||
|
||||
import org.geysermc.common.window.CustomFormBuilder;
|
||||
import org.geysermc.common.window.CustomFormWindow;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.common.window.SimpleFormWindow;
|
||||
import org.geysermc.common.window.button.FormButton;
|
||||
import org.geysermc.common.window.button.FormImage;
|
||||
import org.geysermc.common.window.component.InputComponent;
|
||||
import org.geysermc.common.window.response.CustomFormResponse;
|
||||
import org.geysermc.common.window.response.SimpleFormResponse;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import org.geysermc.multi.utils.Player;
|
||||
import org.geysermc.multi.utils.Server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UIHandler {
|
||||
|
@ -18,14 +23,24 @@ public class UIHandler {
|
|||
* @param servers A list of {@link Server} objects
|
||||
* @return A {@link SimpleFormWindow} object
|
||||
*/
|
||||
public static FormWindow getServerListFormPacket(List<Server> servers) {
|
||||
public static FormWindow getServerList(List<Server> servers) {
|
||||
SimpleFormWindow window = new SimpleFormWindow("Servers", "");
|
||||
|
||||
// Add a button for each server with the server icon as the image
|
||||
for (Server server : servers) {
|
||||
window.getButtons().add(new FormButton("Direct connect"));
|
||||
window.getButtons().add(new FormButton("Edit servers"));
|
||||
|
||||
// Add a button for each global server
|
||||
for (Server server : MasterServer.getInstance().getGeyserMultiConfig().getServers()) {
|
||||
window.getButtons().add(new FormButton(server.toString(), new FormImage(FormImage.FormImageType.URL, "https://eu.mc-api.net/v3/server/favicon/" + server.getAddress() + ":" + server.getPort() + ".png")));
|
||||
}
|
||||
|
||||
// Add a button for each personal server
|
||||
if (MasterServer.getInstance().getGeyserMultiConfig().getCustomServers().isEnabled()) {
|
||||
for (Server server : servers) {
|
||||
window.getButtons().add(new FormButton(server.toString(), new FormImage(FormImage.FormImageType.URL, "https://eu.mc-api.net/v3/server/favicon/" + server.getAddress() + ":" + server.getPort() + ".png")));
|
||||
}
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
|
@ -40,6 +55,19 @@ public class UIHandler {
|
|||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a direct connect form
|
||||
*
|
||||
* @return A {@link SimpleFormWindow} object
|
||||
*/
|
||||
public static FormWindow getDirectConnect() {
|
||||
CustomFormWindow window = new CustomFormBuilder("Direct Connect")
|
||||
.addComponent(new InputComponent("IP", "play.cubecraft.net", ""))
|
||||
.addComponent(new InputComponent("Port", "25565", "25565"))
|
||||
.build();
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the server list response
|
||||
*
|
||||
|
@ -47,18 +75,30 @@ public class UIHandler {
|
|||
* @param data The form response data
|
||||
*/
|
||||
public static void handleServerListResponse(Player player, SimpleFormResponse data) {
|
||||
// Get the server
|
||||
Server server = player.getServers().get(data.getClickedButtonId());
|
||||
switch (data.getClickedButtonId()) {
|
||||
case 0:
|
||||
player.sendWindow(FormID.DIRECT_CONNECT, getDirectConnect());
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
// Get the server
|
||||
List<Server> servers = new ArrayList<>(MasterServer.getInstance().getGeyserMultiConfig().getServers());
|
||||
servers.addAll(player.getServers());
|
||||
Server server = servers.get(data.getClickedButtonId() - 2);
|
||||
|
||||
// Tell the user we are connecting them
|
||||
// this wont show up in alot of cases as the client connects quite quickly
|
||||
player.sendWindow(FormID.CONNECTING, getWaitingScreen(server));
|
||||
player.sendToServer(server);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the Geyser instance if its not already running
|
||||
MasterServer.getInstance().createGeyserProxy();
|
||||
public static void handleDirectConnectResponse(Player player, CustomFormResponse data) {
|
||||
// Take them back to the main menu if they close the direct connect window
|
||||
if (data == null) {
|
||||
player.sendWindow(FormID.MAIN, getServerList(player.getServers()));;
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the user over to the server
|
||||
player.setCurrentServer(server);
|
||||
player.connectToProxy();
|
||||
player.sendToServer(new Server(data.getInputResponses().get(0), Integer.valueOf(data.getInputResponses().get(1))));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,10 @@ package org.geysermc.multi.utils;
|
|||
import lombok.extern.log4j.Log4j2;
|
||||
import net.minecrell.terminalconsole.SimpleTerminalConsole;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
import org.apache.logging.log4j.message.Message;
|
||||
import org.geysermc.common.ChatColor;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@Log4j2
|
||||
public class Logger extends SimpleTerminalConsole implements GeyserLogger {
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import com.nukkitx.nbt.stream.NBTInputStream;
|
|||
import com.nukkitx.nbt.stream.NBTOutputStream;
|
||||
import com.nukkitx.nbt.tag.CompoundTag;
|
||||
import com.nukkitx.nbt.tag.ListTag;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
|
|
@ -5,13 +5,16 @@ import com.nukkitx.math.vector.Vector2f;
|
|||
import com.nukkitx.math.vector.Vector3f;
|
||||
import com.nukkitx.math.vector.Vector3i;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.data.*;
|
||||
import com.nukkitx.protocol.bedrock.data.GamePublishSetting;
|
||||
import com.nukkitx.protocol.bedrock.data.GameRuleData;
|
||||
import com.nukkitx.protocol.bedrock.data.PlayerPermission;
|
||||
import com.nukkitx.protocol.bedrock.packet.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import org.geysermc.multi.ui.FormID;
|
||||
import org.geysermc.multi.ui.UIHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -42,8 +45,9 @@ public class Player {
|
|||
this.session = session;
|
||||
|
||||
// Should fetch the servers from some form of db
|
||||
servers.add(new Server("play.cubecraft.net"));
|
||||
servers.add(new Server("81.174.164.211", 25580));
|
||||
if (MasterServer.getInstance().getGeyserMultiConfig().getCustomServers().isEnabled()) {
|
||||
servers.addAll(PlayerStorageManager.loadServers(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,4 +159,17 @@ public class Player {
|
|||
transferPacket.setPort(MasterServer.getInstance().getGeyserProxy().getGeyserConfig().getBedrock().getPort());
|
||||
session.sendPacket(transferPacket);
|
||||
}
|
||||
|
||||
public void sendToServer(Server server) {
|
||||
// Tell the user we are connecting them
|
||||
// this wont show up in alot of cases as the client connects quite quickly
|
||||
sendWindow(FormID.CONNECTING, UIHandler.getWaitingScreen(server));
|
||||
|
||||
// Create the Geyser instance if its not already running
|
||||
MasterServer.getInstance().createGeyserProxy();
|
||||
|
||||
// Send the user over to the server
|
||||
setCurrentServer(server);
|
||||
connectToProxy();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package org.geysermc.multi.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlayerStorageManager {
|
||||
|
||||
public static void setupStorage() {
|
||||
if (!MasterServer.getInstance().getGeyserMultiConfig().getCustomServers().isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (MasterServer.getInstance().getGeyserMultiConfig().getCustomServers().getStorageType()) {
|
||||
case JSON:
|
||||
File playersFolder = new File("players/");
|
||||
if (!playersFolder.exists()) {
|
||||
playersFolder.mkdirs();
|
||||
}
|
||||
break;
|
||||
case SQLITE:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveServers(Player player, List<Server> servers) {
|
||||
|
||||
}
|
||||
|
||||
public static List<Server> loadServers(Player player) {
|
||||
List<Server> servers = new ArrayList<>();
|
||||
servers.add(new Server("81.174.164.211", 25580));
|
||||
return servers;
|
||||
}
|
||||
|
||||
public enum StorageType {
|
||||
JSON("json"),
|
||||
SQLITE("sqlite");
|
||||
|
||||
@JsonValue
|
||||
private String name;
|
||||
|
||||
StorageType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,12 @@ import lombok.Getter;
|
|||
@AllArgsConstructor
|
||||
public class Server {
|
||||
private String address;
|
||||
private int port;
|
||||
private int port = 25565;
|
||||
|
||||
// Added so we can load from config
|
||||
public Server() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Server(String address) {
|
||||
this(address, 25565);
|
||||
|
|
|
@ -21,3 +21,20 @@ geyser:
|
|||
|
||||
# If debug messages should be sent through console, has to be enabled in both places to work
|
||||
debug-mode: false
|
||||
|
||||
# A global list of servers sent to all clients
|
||||
servers:
|
||||
- address: "play.cubecraft.net"
|
||||
- address: "127.0.0.1"
|
||||
port: 25565
|
||||
|
||||
custom-servers:
|
||||
# Should custom servers be enabled for users
|
||||
enabled: false
|
||||
|
||||
# Max amount of custom servers per user
|
||||
max: 10
|
||||
|
||||
# Storage engine for custom servers
|
||||
# Can be json, sqlite
|
||||
storage-type: json
|
||||
|
|
Loading…
Add table
Reference in a new issue