forked from git-mirrors/GeyserConnect
Rewrite to move to a Geyser extension
This commit is contained in:
parent
6b6973c5b9
commit
91bc9657a4
49 changed files with 1350 additions and 2796 deletions
|
@ -0,0 +1,61 @@
|
|||
package org.geysermc.connect.extension;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacketHandler;
|
||||
import org.geysermc.connect.extension.config.Config;
|
||||
import org.geysermc.connect.extension.config.ConfigLoader;
|
||||
import org.geysermc.connect.extension.storage.AbstractStorageManager;
|
||||
import org.geysermc.connect.extension.storage.DisabledStorageManager;
|
||||
import org.geysermc.event.subscribe.Subscribe;
|
||||
import org.geysermc.geyser.api.event.bedrock.SessionInitializeEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
public class GeyserConnect implements Extension {
|
||||
private static GeyserConnect instance;
|
||||
private Config config;
|
||||
private AbstractStorageManager storageManager;
|
||||
|
||||
public GeyserConnect() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static GeyserConnect instance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Config config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public AbstractStorageManager storageManager() {
|
||||
return storageManager;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPostInitialize(GeyserPostInitializeEvent event) {
|
||||
config = ConfigLoader.load(this, GeyserConnect.class, Config.class);
|
||||
|
||||
if (!config.customServers().enabled()) {
|
||||
// Force the storage manager if we have it disabled
|
||||
storageManager = new DisabledStorageManager();
|
||||
this.logger().info("Disabled custom player servers");
|
||||
} else {
|
||||
try {
|
||||
storageManager = config.customServers().storageType().storageManager().getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
this.logger().severe("Invalid storage manager class!", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
storageManager.setupStorage();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onSessionInitialize(SessionInitializeEvent event) {
|
||||
GeyserSession session = (GeyserSession) event.connection();
|
||||
BedrockPacketHandler packetHandler = session.getUpstream().getSession().getPacketHandler();
|
||||
session.getUpstream().getSession().setPacketHandler(new PacketHandler(this, session, packetHandler));
|
||||
}
|
||||
}
|
142
src/main/java/org/geysermc/connect/extension/PacketHandler.java
Normal file
142
src/main/java/org/geysermc/connect/extension/PacketHandler.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.data.AttributeData;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacketHandler;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
|
||||
import org.cloudburstmc.protocol.common.PacketSignal;
|
||||
import org.geysermc.connect.extension.ui.UIHandler;
|
||||
import org.geysermc.connect.extension.utils.ServerManager;
|
||||
import org.geysermc.connect.extension.utils.Utils;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
|
||||
import org.geysermc.geyser.network.UpstreamPacketHandler;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PacketHandler extends UpstreamPacketHandler {
|
||||
|
||||
private final GeyserSession session;
|
||||
private final GeyserConnect geyserConnect;
|
||||
private final BedrockPacketHandler originalPacketHandler;
|
||||
|
||||
public PacketHandler(GeyserConnect geyserConnect, GeyserSession session, BedrockPacketHandler packetHandler) {
|
||||
super(GeyserImpl.getInstance(), session);
|
||||
|
||||
this.session = session;
|
||||
this.geyserConnect = geyserConnect;
|
||||
this.originalPacketHandler = packetHandler;
|
||||
|
||||
// Spawn the player in the end (it just looks better)
|
||||
session.setDimension(DimensionUtils.THE_END);
|
||||
DimensionUtils.setBedrockDimension(session, DimensionUtils.THE_END);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(String reason) {
|
||||
geyserConnect.logger().info(Utils.displayName(session) + " has disconnected (" + reason + ")");
|
||||
ServerManager.unloadServers(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketSignal handle(SetLocalPlayerAsInitializedPacket packet) {
|
||||
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
|
||||
if (!session.getUpstream().isInitialized()) {
|
||||
session.getUpstream().setInitialized(true);
|
||||
|
||||
// Load the players servers
|
||||
ServerManager.loadServers(session);
|
||||
|
||||
geyserConnect.logger().debug("Player initialized: " + Utils.displayName(session));
|
||||
|
||||
UIHandler uiHandler = new UIHandler(session, packet, originalPacketHandler);
|
||||
uiHandler.initialiseSession();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the virtual host if specified
|
||||
// GeyserConnectConfig.VirtualHostSection vhost = MasterServer.getInstance().getGeyserConnectConfig().getVhost();
|
||||
// if (vhost.isEnabled()) {
|
||||
// String domain = player.getClientData().getServerAddress().split(":")[0];
|
||||
// if (!domain.equals(vhost.getBaseDomain()) && domain.endsWith("." + vhost.getBaseDomain())) {
|
||||
// String address = "";
|
||||
// int port = 25565;
|
||||
// boolean online = true;
|
||||
//
|
||||
// // Parse the address used
|
||||
// String[] domainParts = domain.replaceFirst("\\." + vhost.getBaseDomain() + "$", "").split("\\._");
|
||||
// for (int i = 0; i < domainParts.length; i++) {
|
||||
// String part = domainParts[i];
|
||||
// if (i == 0) {
|
||||
// address = part;
|
||||
// } else if (part.startsWith("p")) {
|
||||
// port = Integer.parseInt(part.substring(1));
|
||||
// } else if (part.startsWith("o")) {
|
||||
// online = false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // They didn't specify an address so disconnect them
|
||||
// if (address.startsWith("_")) {
|
||||
// session.disconnect("disconnectionScreen.invalidIP");
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // Log the virtual host usage
|
||||
// masterServer.getLogger().info(player.getAuthData().name() + " is using virtualhost: " + address + ":" + port + (!online ? " (offline)" : ""));
|
||||
//
|
||||
// // Send the player to the wanted server
|
||||
// player.sendToServer(new Server(address, port, online, false));
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketSignal handle(NetworkStackLatencyPacket packet) {
|
||||
// This is to fix a bug in the client where it doesn't load form images
|
||||
UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket();
|
||||
updateAttributesPacket.setRuntimeEntityId(1);
|
||||
List<AttributeData> attributes = Collections.singletonList(GeyserAttributeType.EXPERIENCE_LEVEL.getAttribute(0f));
|
||||
updateAttributesPacket.setAttributes(attributes);
|
||||
|
||||
// Doesn't work 100% of the time but fixes it most of the time
|
||||
GeyserImpl.getInstance().getScheduledThread().schedule(() -> session.sendUpstreamPacket(updateAttributesPacket), 500, TimeUnit.MILLISECONDS);
|
||||
|
||||
return super.handle(packet);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record Config(
|
||||
@JsonProperty("welcome-file") String welcomeFile,
|
||||
List<Server> servers,
|
||||
@JsonProperty("custom-servers") CustomServersSection customServers,
|
||||
VirtualHostSection vhost) {
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package org.geysermc.connect.extension.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
|
||||
public class ConfigLoader {
|
||||
public static <T> T load(Extension extension, Class<?> extensionClass, Class<T> configClass) {
|
||||
File configFile = extension.dataFolder().resolve("config.yml").toFile();
|
||||
|
||||
// Ensure the data folder exists
|
||||
if (!extension.dataFolder().toFile().exists()) {
|
||||
if (!extension.dataFolder().toFile().mkdirs()) {
|
||||
extension.logger().error("Failed to create data folder");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the config file if it doesn't exist
|
||||
if (!configFile.exists()) {
|
||||
try (FileWriter writer = new FileWriter(configFile)) {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(new File(extensionClass.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(), Collections.emptyMap())) {
|
||||
try (InputStream input = Files.newInputStream(fileSystem.getPath("config.yml"))) {
|
||||
byte[] bytes = new byte[input.available()];
|
||||
|
||||
input.read(bytes);
|
||||
|
||||
writer.write(new String(bytes).toCharArray());
|
||||
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
extension.logger().error("Failed to create config", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the config file
|
||||
try {
|
||||
return new ObjectMapper(new YAMLFactory())
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.readValue(configFile, configClass);
|
||||
} catch (IOException e) {
|
||||
extension.logger().error("Failed to load config", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.geysermc.connect.extension.config;
|
||||
|
||||
//import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
//import org.geysermc.connect.extension.storage.AbstractStorageManager;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.geysermc.connect.extension.storage.AbstractStorageManager;
|
||||
|
||||
public record CustomServersSection(
|
||||
boolean enabled,
|
||||
int max,
|
||||
@JsonProperty("storage-type") AbstractStorageManager.StorageType storageType,
|
||||
MySQLConnectionSection mysql) {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.geysermc.connect.extension.config;
|
||||
|
||||
public record MySQLConnectionSection(
|
||||
String user,
|
||||
String pass,
|
||||
String database,
|
||||
String host,
|
||||
int port) {
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.geysermc.connect.extension.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public record VirtualHostSection(
|
||||
boolean enabled,
|
||||
@JsonProperty("base-domain") String baseDomain) {
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
import org.geysermc.connect.extension.utils.ServerManager;
|
||||
import org.geysermc.connect.extension.utils.Utils;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AbstractSQLStorageManager extends AbstractStorageManager {
|
||||
protected Connection connection;
|
||||
|
||||
@Override
|
||||
public void setupStorage() {
|
||||
try {
|
||||
connectToDatabase();
|
||||
|
||||
try (Statement createPlayersTable = connection.createStatement()) {
|
||||
createPlayersTable.executeUpdate("CREATE TABLE IF NOT EXISTS players (xuid VARCHAR(32), servers TEXT, PRIMARY KEY(xuid));");
|
||||
}
|
||||
|
||||
try (PreparedStatement getPlayersServers = connection.prepareStatement("SELECT xuid, servers FROM players")) {
|
||||
ResultSet rs = getPlayersServers.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
List<Server> loadedServers = Utils.OBJECT_MAPPER.readValue(rs.getString("servers"), new TypeReference<>() {});
|
||||
GeyserConnect.instance().logger().info("Loaded " + loadedServers.size() + " servers for " + rs.getString("xuid"));
|
||||
}
|
||||
} catch (IOException | SQLException exception) {
|
||||
GeyserConnect.instance().logger().error("Couldn't load servers", exception);
|
||||
}
|
||||
} catch (ClassNotFoundException | SQLException e) {
|
||||
GeyserConnect.instance().logger().severe("Unable to connect to MySQL database!", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void connectToDatabase() throws ClassNotFoundException, SQLException;
|
||||
|
||||
@Override
|
||||
public void closeStorage() {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException exception) {
|
||||
GeyserConnect.instance().logger().error("Failed to close SQL connection", exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveServers(GeyserSession session) {
|
||||
// replace into works on MySQL and SQLite
|
||||
try (PreparedStatement updatePlayersServers = connection.prepareStatement("REPLACE INTO players(xuid, servers) VALUES(?, ?)")) {
|
||||
updatePlayersServers.setString(1, session.getAuthData().xuid());
|
||||
updatePlayersServers.setString(2, Utils.OBJECT_MAPPER.writeValueAsString(ServerManager.getServers(session)));
|
||||
updatePlayersServers.executeUpdate();
|
||||
} catch (IOException | SQLException exception) {
|
||||
GeyserConnect.instance().logger().error("Couldn't save servers for " + session.getAuthData().name(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Server> loadServers(GeyserSession session) {
|
||||
List<Server> servers = new ArrayList<>();
|
||||
|
||||
try (PreparedStatement getPlayersServers = connection.prepareStatement("SELECT servers FROM players WHERE xuid=?")) {
|
||||
getPlayersServers.setString(1, session.getAuthData().xuid());
|
||||
ResultSet rs = getPlayersServers.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
List<Server> loadedServers = Utils.OBJECT_MAPPER.readValue(rs.getString("servers"), new TypeReference<>() {});
|
||||
if (loadedServers != null) {
|
||||
servers.addAll(loadedServers);
|
||||
}
|
||||
}
|
||||
} catch (IOException | SQLException exception) {
|
||||
GeyserConnect.instance().logger().error("Couldn't load servers for " + session.getAuthData().name(), exception);
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AbstractStorageManager {
|
||||
|
||||
public void setupStorage() { }
|
||||
|
||||
public void closeStorage() { }
|
||||
|
||||
public void saveServers(GeyserSession session) { }
|
||||
|
||||
public List<Server> loadServers(GeyserSession session) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
public enum StorageType {
|
||||
JSON("json", JsonStorageManager.class),
|
||||
SQLITE("sqlite", SQLiteStorageManager.class),
|
||||
MYSQL("mysql", MySQLStorageManager.class);
|
||||
|
||||
@JsonValue
|
||||
private final String configName;
|
||||
|
||||
private final Class<? extends AbstractStorageManager> storageManager;
|
||||
|
||||
StorageType(String configName, Class<? extends AbstractStorageManager> storageManager) {
|
||||
this.configName = configName;
|
||||
this.storageManager = storageManager;
|
||||
}
|
||||
|
||||
public String configName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
public Class<? extends AbstractStorageManager> storageManager() {
|
||||
return storageManager;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DisabledStorageManager extends AbstractStorageManager {
|
||||
|
||||
@Override
|
||||
public void setupStorage() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveServers(GeyserSession session) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Server> loadServers(GeyserSession session) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
import org.geysermc.connect.extension.utils.ServerManager;
|
||||
import org.geysermc.connect.extension.utils.Utils;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class JsonStorageManager extends AbstractStorageManager {
|
||||
private Path dataFolder;
|
||||
|
||||
@Override
|
||||
public void setupStorage() {
|
||||
dataFolder = GeyserConnect.instance().dataFolder().resolve("players/");
|
||||
if (!dataFolder.toFile().exists()) {
|
||||
dataFolder.toFile().mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveServers(GeyserSession session) {
|
||||
try {
|
||||
Utils.OBJECT_MAPPER.writeValue(dataFolder.resolve(session.getAuthData().xuid() + ".json").toFile(), ServerManager.getServers(session));
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Server> loadServers(GeyserSession session) {
|
||||
List<Server> servers = new ArrayList<>();
|
||||
|
||||
try {
|
||||
List<Server> loadedServers = Utils.OBJECT_MAPPER.readValue(dataFolder.resolve(session.getAuthData().xuid() + ".json").toFile(), new TypeReference<>(){});
|
||||
if (loadedServers != null) {
|
||||
servers.addAll(loadedServers);
|
||||
}
|
||||
} catch (IOException ignored) { }
|
||||
|
||||
return servers;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.connect.extension.config.MySQLConnectionSection;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class MySQLStorageManager extends AbstractSQLStorageManager {
|
||||
@Override
|
||||
protected void connectToDatabase() throws ClassNotFoundException, SQLException {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
MySQLConnectionSection connectionInformation = GeyserConnect.instance().config().customServers().mysql();
|
||||
connection = DriverManager.getConnection("jdbc:mysql://" + connectionInformation.host() + ":" + connectionInformation.port() + "/" + connectionInformation.database(), connectionInformation.user(), connectionInformation.pass());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.storage;
|
||||
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class SQLiteStorageManager extends AbstractSQLStorageManager {
|
||||
@Override
|
||||
protected void connectToDatabase() throws ClassNotFoundException, SQLException {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + GeyserConnect.instance().dataFolder().resolve("players.db"));
|
||||
}
|
||||
}
|
314
src/main/java/org/geysermc/connect/extension/ui/UIHandler.java
Normal file
314
src/main/java/org/geysermc/connect/extension/ui/UIHandler.java
Normal file
|
@ -0,0 +1,314 @@
|
|||
package org.geysermc.connect.extension.ui;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacketHandler;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TransferPacket;
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.connect.extension.utils.Server;
|
||||
import org.geysermc.connect.extension.utils.ServerCategory;
|
||||
import org.geysermc.connect.extension.utils.ServerManager;
|
||||
import org.geysermc.connect.extension.utils.Utils;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
import org.geysermc.cumulus.form.ModalForm;
|
||||
import org.geysermc.cumulus.form.SimpleForm;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class UIHandler {
|
||||
private final GeyserSession session;
|
||||
private final SetLocalPlayerAsInitializedPacket initializedPacket;
|
||||
private final BedrockPacketHandler originalPacketHandler;
|
||||
|
||||
public UIHandler(GeyserSession session, SetLocalPlayerAsInitializedPacket packet, BedrockPacketHandler originalPacketHandler) {
|
||||
this.session = session;
|
||||
this.initializedPacket = new SetLocalPlayerAsInitializedPacket();
|
||||
this.initializedPacket.setRuntimeEntityId(packet.getRuntimeEntityId());
|
||||
this.originalPacketHandler = originalPacketHandler;
|
||||
}
|
||||
|
||||
private void sendToServer(Server server) {
|
||||
GeyserConnect.instance().logger().info("Sending " + Utils.displayName(session) + " to " + server.title());
|
||||
GeyserConnect.instance().logger().debug(server.toString());
|
||||
|
||||
if (server.bedrock()) {
|
||||
// Send them to the bedrock server
|
||||
TransferPacket transferPacket = new TransferPacket();
|
||||
transferPacket.setAddress(server.address());
|
||||
transferPacket.setPort(server.port());
|
||||
session.sendUpstreamPacket(transferPacket);
|
||||
} else {
|
||||
// Save the players servers since we are changing packet handlers
|
||||
ServerManager.unloadServers(session);
|
||||
|
||||
// Restore the original packet handler
|
||||
session.getUpstream().getSession().setPacketHandler(originalPacketHandler);
|
||||
|
||||
// Set the remote server and un-initialize the session
|
||||
session.remoteServer(server);
|
||||
session.getUpstream().setInitialized(false);
|
||||
|
||||
// Hand back to core geyser
|
||||
originalPacketHandler.handle(initializedPacket);
|
||||
}
|
||||
}
|
||||
|
||||
public void initialiseSession() {
|
||||
String message = "";
|
||||
try {
|
||||
File messageFile = Utils.fileOrCopiedFromResource(GeyserConnect.instance().config().welcomeFile(), "welcome.txt");
|
||||
message = new String(FileUtils.readAllBytes(messageFile), StandardCharsets.UTF_8);
|
||||
} catch (IOException ignored) { }
|
||||
|
||||
if (!message.trim().isEmpty()) {
|
||||
session.sendForm(CustomForm.builder()
|
||||
.title("Notice")
|
||||
.label(message)
|
||||
.resultHandler((customForm, customFormResponseFormResponseResult) -> {
|
||||
sendMainMenu();
|
||||
// this.sendToServer(new Server("test.geysermc.org", 25565));
|
||||
})
|
||||
.build());
|
||||
} else {
|
||||
sendMainMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMainMenu() {
|
||||
SimpleForm.Builder mainMenu = SimpleForm.builder()
|
||||
.title("Main Menu")
|
||||
.button("Official Servers")
|
||||
.button("Geyser Servers");
|
||||
|
||||
// Add a buttons for custom servers
|
||||
if (GeyserConnect.instance().config().customServers().enabled()) {
|
||||
mainMenu.button("Custom Servers");
|
||||
mainMenu.button("Direct connect");
|
||||
}
|
||||
|
||||
mainMenu
|
||||
.button("Disconnect")
|
||||
.closedResultHandler(response -> {
|
||||
sendMainMenu();
|
||||
})
|
||||
.invalidResultHandler(response -> {
|
||||
session.disconnect("disconnectionScreen.disconnected");
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
switch (response.clickedButtonId()) {
|
||||
case 0:
|
||||
sendServersMenu(ServerCategory.OFFICIAL);
|
||||
return;
|
||||
case 1:
|
||||
sendServersMenu(ServerCategory.GEYSER);
|
||||
return;
|
||||
default:
|
||||
if (GeyserConnect.instance().config().customServers().enabled()) {
|
||||
switch (response.clickedButtonId()) {
|
||||
case 2:
|
||||
sendServersMenu(ServerCategory.CUSTOM);
|
||||
return;
|
||||
case 3:
|
||||
sendDirectConnectMenu();
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
session.disconnect("disconnectionScreen.disconnected");
|
||||
});
|
||||
|
||||
session.sendForm(mainMenu);
|
||||
}
|
||||
|
||||
public void sendServersMenu(ServerCategory category) {
|
||||
SimpleForm.Builder serversMenu = SimpleForm.builder()
|
||||
.title(category.title() + " Servers");
|
||||
|
||||
List<Server> servers;
|
||||
if (category == ServerCategory.CUSTOM) {
|
||||
servers = ServerManager.getServers(session);
|
||||
} else {
|
||||
servers = Utils.getServers(category);
|
||||
}
|
||||
|
||||
for (Server server : servers) {
|
||||
serversMenu.button(server.title(), server.formImage());
|
||||
}
|
||||
|
||||
if (category == ServerCategory.CUSTOM) {
|
||||
serversMenu.button("Edit servers");
|
||||
}
|
||||
|
||||
serversMenu
|
||||
.button("Back")
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendMainMenu();
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
if (category == ServerCategory.CUSTOM) {
|
||||
if (response.clickedButtonId() == servers.size()) {
|
||||
sendEditServersMenu();
|
||||
return;
|
||||
} else if (response.clickedButtonId() == servers.size() + 1) {
|
||||
sendMainMenu();
|
||||
return;
|
||||
}
|
||||
} else if (response.clickedButtonId() == servers.size()) {
|
||||
sendMainMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = servers.get(response.clickedButtonId());
|
||||
sendToServer(server);
|
||||
});
|
||||
|
||||
session.sendForm(serversMenu);
|
||||
}
|
||||
|
||||
public void sendEditServersMenu() {
|
||||
SimpleForm.Builder editServersMenu = SimpleForm.builder()
|
||||
.title("Edit Servers")
|
||||
.content("Select a server to edit");
|
||||
|
||||
List<Server> servers = ServerManager.getServers(session);
|
||||
|
||||
for (Server server : servers) {
|
||||
editServersMenu.button(server.title(), server.formImage());
|
||||
}
|
||||
|
||||
editServersMenu
|
||||
.button("Add server")
|
||||
.button("Back")
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendServersMenu(ServerCategory.CUSTOM);
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
if (response.clickedButtonId() == servers.size()) {
|
||||
sendAddServerMenu();
|
||||
return;
|
||||
} else if (response.clickedButtonId() == servers.size() + 1) {
|
||||
sendServersMenu(ServerCategory.CUSTOM);
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = servers.get(response.clickedButtonId());
|
||||
sendServerOptionsMenu(server);
|
||||
});
|
||||
|
||||
session.sendForm(editServersMenu);
|
||||
}
|
||||
|
||||
public void sendAddServerMenu() {
|
||||
session.sendForm(CustomForm.builder()
|
||||
.title("Add Server")
|
||||
.input("IP", "play.cubecraft.net")
|
||||
.input("Port", "25565", "25565")
|
||||
.toggle("Online mode", true)
|
||||
.toggle("Bedrock/Geyser server", false)
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendEditServersMenu();
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
String ip = response.asInput(0);
|
||||
int port = Integer.parseInt(response.asInput(1));
|
||||
boolean onlineMode = response.asToggle(2);
|
||||
boolean geyserServer = response.asToggle(3);
|
||||
|
||||
Server server = new Server(ip, port, onlineMode, geyserServer, null, null, ServerCategory.CUSTOM);
|
||||
ServerManager.addServer(session, server);
|
||||
sendEditServersMenu();
|
||||
}));
|
||||
}
|
||||
|
||||
public void sendServerOptionsMenu(Server server) {
|
||||
session.sendForm(SimpleForm.builder()
|
||||
.title("Server Options")
|
||||
.content(server.title())
|
||||
.button("Edit server")
|
||||
.button("Delete server")
|
||||
.button("Back")
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendEditServersMenu();
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
switch (response.clickedButtonId()) {
|
||||
case 0:
|
||||
sendEditServerMenu(server);
|
||||
return;
|
||||
case 1:
|
||||
sendDeleteServerMenu(server);
|
||||
return;
|
||||
case 2:
|
||||
sendEditServersMenu();
|
||||
return;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public void sendEditServerMenu(Server server) {
|
||||
int serverIndex = ServerManager.getServerIndex(session, server);
|
||||
session.sendForm(CustomForm.builder()
|
||||
.title("Edit Server")
|
||||
.input("IP", server.address(), server.address())
|
||||
.input("Port", String.valueOf(server.port()), String.valueOf(server.port()))
|
||||
.toggle("Online mode", server.online())
|
||||
.toggle("Bedrock/Geyser server", server.bedrock())
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendServerOptionsMenu(server);
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
String ip = response.asInput(0);
|
||||
int port = Integer.parseInt(response.asInput(1));
|
||||
boolean onlineMode = response.asToggle(2);
|
||||
boolean geyserServer = response.asToggle(3);
|
||||
|
||||
Server newServer = new Server(ip, port, onlineMode, geyserServer, null, null, ServerCategory.CUSTOM);
|
||||
ServerManager.updateServer(session, serverIndex, newServer);
|
||||
sendServerOptionsMenu(newServer);
|
||||
}));
|
||||
}
|
||||
|
||||
public void sendDeleteServerMenu(Server server) {
|
||||
session.sendForm(ModalForm.builder()
|
||||
.title("Delete Server")
|
||||
.content("Are you sure you want to delete " + server.title() + "?")
|
||||
.button1("Yes")
|
||||
.button2("No")
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendServerOptionsMenu(server);
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
if (response.clickedButtonId() == 0) {
|
||||
ServerManager.removeServer(session, server);
|
||||
}
|
||||
sendEditServersMenu();
|
||||
}));
|
||||
}
|
||||
|
||||
public void sendDirectConnectMenu() {
|
||||
session.sendForm(CustomForm.builder()
|
||||
.title("Direct Connect")
|
||||
.input("IP", "play.cubecraft.net")
|
||||
.input("Port", "25565", "25565")
|
||||
.toggle("Online mode", true)
|
||||
.toggle("Bedrock/Geyser server", false)
|
||||
.closedOrInvalidResultHandler(response -> {
|
||||
sendMainMenu();
|
||||
})
|
||||
.validResultHandler(response -> {
|
||||
String ip = response.asInput(0);
|
||||
int port = Integer.parseInt(response.asInput(1));
|
||||
boolean onlineMode = response.asToggle(2);
|
||||
boolean geyserServer = response.asToggle(3);
|
||||
|
||||
Server server = new Server(ip, port, onlineMode, geyserServer, null, null, ServerCategory.CUSTOM);
|
||||
sendToServer(server);
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.cumulus.util.FormImage;
|
||||
import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
|
||||
public record Server(
|
||||
String address,
|
||||
int port,
|
||||
boolean online,
|
||||
boolean bedrock,
|
||||
String name,
|
||||
String imageUrl,
|
||||
ServerCategory category
|
||||
) implements RemoteServer {
|
||||
public Server(String address, int port) {
|
||||
this(address, port, true, false, null, null, ServerCategory.CUSTOM);
|
||||
}
|
||||
|
||||
private int defaultPort() { return bedrock ? 19132 : 25565; }
|
||||
|
||||
@Override
|
||||
public int port() {
|
||||
return port < 0 ? defaultPort() : port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull AuthType authType() {
|
||||
return this.online ? AuthType.ONLINE : AuthType.OFFLINE;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public FormImage formImage() {
|
||||
if (imageUrl != null && !imageUrl.isEmpty()) {
|
||||
return FormImage.of(FormImage.Type.URL, imageUrl);
|
||||
} else {
|
||||
return FormImage.of(FormImage.Type.URL, "https://eu.mc-api.net/v3/server/favicon/" + address + ":" + port + ".png?use-fallback-icon=true");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String minecraftVersion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int protocolVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String title() {
|
||||
return name != null ? name : address + (port() != defaultPort() ? ":" + port() : "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/GeyserConnect
|
||||
*/
|
||||
|
||||
package org.geysermc.connect.extension.utils;
|
||||
|
||||
public enum ServerCategory {
|
||||
OFFICIAL("Official"),
|
||||
GEYSER("Geyser"),
|
||||
CUSTOM("Custom");
|
||||
|
||||
private final String title;
|
||||
|
||||
ServerCategory(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String title() {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package org.geysermc.connect.extension.utils;
|
||||
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerManager {
|
||||
private static final Map<String, List<Server>> servers = new HashMap<>();
|
||||
|
||||
public static void loadServers(GeyserSession session) {
|
||||
GeyserConnect.instance().logger().debug("Loading servers for " + Utils.displayName(session));
|
||||
servers.put(session.xuid(), GeyserConnect.instance().storageManager().loadServers(session));
|
||||
}
|
||||
|
||||
public static void unloadServers(GeyserSession session) {
|
||||
GeyserConnect.instance().logger().debug("Saving and unloading servers for " + Utils.displayName(session));
|
||||
GeyserConnect.instance().storageManager().saveServers(session);
|
||||
servers.remove(session.xuid());
|
||||
}
|
||||
|
||||
public static List<Server> getServers(GeyserSession session) {
|
||||
return servers.get(session.xuid());
|
||||
}
|
||||
|
||||
public static void addServer(GeyserSession session, Server server) {
|
||||
servers.get(session.xuid()).add(server);
|
||||
}
|
||||
|
||||
public static void removeServer(GeyserSession session, Server server) {
|
||||
getServers(session).remove(server);
|
||||
}
|
||||
|
||||
public static int getServerIndex(GeyserSession session, Server server) {
|
||||
return getServers(session).indexOf(server);
|
||||
}
|
||||
|
||||
public static void updateServer(GeyserSession session, int serverIndex, Server server) {
|
||||
getServers(session).set(serverIndex, server);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.geysermc.connect.extension.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.geysermc.connect.extension.GeyserConnect;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils {
|
||||
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
|
||||
public static List<Server> getServers(ServerCategory category) {
|
||||
return GeyserConnect.instance().config().servers().stream().filter(server -> server.category() == category).toList();
|
||||
}
|
||||
|
||||
public static File fileOrCopiedFromResource(String fileName, String name) throws IOException {
|
||||
File file = GeyserConnect.instance().dataFolder().resolve(fileName).toFile();
|
||||
|
||||
if (!file.exists()) {
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
try (FileSystem fileSystem = FileSystems.newFileSystem(new File(GeyserConnect.class.getProtectionDomain().getCodeSource().getLocation().toURI()).toPath(), Collections.emptyMap())) {
|
||||
try (InputStream input = Files.newInputStream(fileSystem.getPath(name))) {
|
||||
byte[] bytes = new byte[input.available()];
|
||||
|
||||
input.read(bytes);
|
||||
|
||||
writer.write(new String(bytes).toCharArray());
|
||||
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException ignored) { }
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public static String displayName(GeyserSession session) {
|
||||
return session.bedrockUsername() + " (" + session.xuid() + ")";
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue