Newer
Older
ChallengeSystem / Lobby / src / main / java / de / fanta / lobby / Server.java
@fanta fanta on 20 Jun 2024 14 KB components :,)
package de.fanta.lobby;

import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import de.fanta.challengeutils.Color;
import net.kyori.adventure.text.Component;
import org.apache.commons.io.FileUtils;
import org.bukkit.Location;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;

public class Server {
    public static HashMap<Server, UUID> serverPlayers = new HashMap<>();

    private final Lobby plugin;

    private final String name;

    private int serverVersion;

    private final String gPLocation;

    private final String dir;

    private final ServerType serverType;

    private final Location piglinLocation;

    private boolean online;

    public Server(String name, @Nullable Integer serverVersion, String gPLocation, String dir, ServerType serverType, Lobby plugin, Location piglinLocation) {
        this.name = name;
        this.serverVersion = serverVersion == null ? 0 : serverVersion;
        this.gPLocation = gPLocation;
        this.dir = dir;
        this.serverType = serverType;
        this.plugin = plugin;
        this.online = (plugin.getGlobalDataHelper().getServer(name) != null);
        this.piglinLocation = piglinLocation;
    }

    public static Server getServerfromPlayer(Player p) {
        Server server = null;
        if (serverPlayers.containsValue(p.getUniqueId()))
            for (Map.Entry<Server, UUID> entry : serverPlayers.entrySet()) {
                if (entry.getValue().equals(p.getUniqueId()))
                    server = entry.getKey();
            }
        return server;
    }

    public boolean isOnline() {
        return this.online;
    }

    public void setOnline(boolean online) {
        this.online = online;
    }

    public String getName() {
        return this.name;
    }

    public String getGPLocation() {
        return this.gPLocation;
    }

    public void setServerVersion(int serverVersion) {
        this.serverVersion = serverVersion;
    }

    public void loadSaved(Player p, UUID playerID, String slot) {
        this.online = true;
        serverPlayers.put(this, p.getUniqueId());
        File dir;
        if (serverType == ServerType.CHALLENGES) {
            dir = new File(plugin.getChallengeSavePath().toFile(), "/" + playerID + "/" + slot);
        } else {
            dir = new File(plugin.getAdventureSavePath().toFile(), "/" + playerID + "/" + slot);
        }

        String path = playerID + "/" + slot;


        if (!dir.isDirectory()) {
            plugin.getComponentUtil().sendErrorMessage(p, "Map " + path + " nicht gefunden!");
            this.online = false;
            serverPlayers.remove(this);
            return;
        }
        load(p, this.serverType.getDir(), path, getMapVersion(new File(dir + "/" + getPluginFolderPrefix(dir) + "/serverconfig.yml")));
    }

    public void loadNewAdventure(Player player, String category, String map, String mapVersion) {
        int playerVersion = Via.getAPI().getPlayerVersion(player.getUniqueId());
        int mapProtocolVersion = ProtocolVersion.getClosest(mapVersion).getVersion();
        if (playerVersion >= mapProtocolVersion) {
            this.online = true;
            serverPlayers.put(this, player.getUniqueId());
            //File dir = new File("/home/storagebox/Adventure-Maps", category + "/" + map);
            File dir = new File(plugin.getAdventureMapsPath().toFile(), category + "/" + map);
            if (!dir.isDirectory()) {
                plugin.getComponentUtil().sendErrorMessage(player, "Map " + map + " nicht gefunden!");
                this.online = false;
                serverPlayers.remove(this);
                return;
            }

            load(player, "Adventure-Maps", category + "/" + map, getMapVersion(new File(dir + "/" + getPluginFolderPrefix(dir) + "/serverconfig.yml")));
        } else {
            Component component = Component.text("Du brauchst mindestens die Version ", Color.RED).append(Component.text(mapVersion, Color.BLUE).append(Component.text(" um die Map zu starten!", Color.RED)));
            plugin.getComponentUtil().sendMessage(player, component);
        }
    }

    public void load(Player p, String serverTypeDir, String targetDir, String ServerVersion) {
        plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
            File serverFolder = new File(plugin.getServerFolderPath().toFile(), this.dir);
            File configs = new File(serverFolder, "/plugins/" + getPluginFolderPrefix(new File(serverFolder, "/plugins")));
            File end = new File(serverFolder, "/world_the_end");
            File nether = new File(serverFolder, "/world_nether");
            File world = new File(serverFolder, "/world");
            File mlgworld = new File(serverFolder, "/mlg_challenge");
            File serverJar = new File(serverFolder, "/paper.jar");
            File saveServerJar = new File(plugin.getServerJarsPath().toFile(), ServerVersion + "/paper.jar");
            File saveend;
            File savenether;
            File saveworld;
            File saveconfigs;


            if (!serverTypeDir.equals("Adventure-Maps")) {
                saveend = new File(plugin.getChallengeSavePath().toFile(), targetDir + "/world_the_end");
                savenether = new File(plugin.getChallengeSavePath().toFile(), targetDir + "/world_nether");
                saveworld = new File(plugin.getChallengeSavePath().toFile(), targetDir + "/world");
                saveconfigs = new File(plugin.getChallengeSavePath().toFile(), targetDir + "/" + getPluginFolderPrefix(new File(plugin.getChallengeSavePath().toFile(), targetDir)));
            } else {
                saveend = new File(plugin.getAdventureMapsPath().toFile(), targetDir + "/world_the_end");
                savenether = new File(plugin.getAdventureMapsPath().toFile(), targetDir + "/world_nether");
                saveworld = new File(plugin.getAdventureMapsPath().toFile(), targetDir + "/world");
                saveconfigs = new File(plugin.getAdventureMapsPath().toFile(), targetDir + "/" + getPluginFolderPrefix(new File(plugin.getChallengeSavePath().toFile(), targetDir)));
            }

            plugin.getComponentUtil().sendNormalMessage(p, "Versuche Map zu laden!");
            try {
                if (world.isDirectory()) {
                    FileUtils.deleteDirectory(world);
                    FileUtils.deleteDirectory(end);
                    FileUtils.deleteDirectory(nether);
                }
                if (mlgworld.isDirectory()) {
                    FileUtils.deleteDirectory(mlgworld);
                }
                if (serverJar.exists()) {
                    FileUtils.delete(serverJar);
                }
                if (configs.isDirectory()) {
                    FileUtils.deleteDirectory(configs);
                }

                HashMap<File, File> copyMap = new HashMap<>();
                copyMap.put(saveServerJar, serverJar);
                copyMap.put(saveconfigs, configs);
                copyMap.put(saveworld, world);
                copyMap.put(savenether, nether);
                copyMap.put(saveend, end);
                moveFolderWithProgress(copyMap, p);


                File serverConfigFile = new File(plugin.getServerFolderPath().toFile(), this.dir + "/plugins/" + getPluginFolderPrefix(new File(plugin.getServerFolderPath().toFile(), this.dir + "/plugins")) + "/serverconfig.yml");
                YamlConfiguration serverConfig = new YamlConfiguration();
                serverConfig.load(serverConfigFile);

                String tempServerType = serverConfig.getString("servertype");
                if (tempServerType == null || tempServerType.equals("CHALLENGE")) {
                    serverConfig.set("servertype", "CHALLENGE_LOAD");
                    serverConfig.save(serverConfigFile);
                    Lobby.getPlugin().getLogger().info(serverConfigFile.getAbsolutePath());
                }

                if (tempServerType != null && serverConfig.getString("servertype").equals("ADVENTURE")) {
                    setServerVersion(ProtocolVersion.getClosest(serverConfig.getString("serverversion")).getVersion());
                }

            } catch (IOException | InvalidConfigurationException e) {
                Lobby.getPlugin().getLogger().log(Level.SEVERE, "Error while handling files", e);
                plugin.getComponentUtil().sendErrorMessage(p, "Map konnte nicht geladen werden!");
                this.online = false;
                serverPlayers.remove(this);
                return;
            }
            plugin.getComponentUtil().sendNormalMessage(p, "Map wurde geladen! Server wird nun gestartet!");
            start(p);
        });
    }

    public static void moveFolderWithProgress(HashMap<File, File> copyMap, Player player) throws IOException {
        final long[] totalBytes = {0};
        final long[] copiedBytes = {0};
        AtomicReference<Double> progress = new AtomicReference<>(0.0);

        for (File sourceFolder : copyMap.keySet()) {
            Files.walk(sourceFolder.toPath()).forEach(source -> {
                if (!Files.isDirectory(source)) {
                    totalBytes[0] += source.toFile().length();
                }
            });
        }

        for (File sourceFolder : copyMap.keySet()) {
            Files.walk(sourceFolder.toPath()).forEach(source -> {
                try {
                    File target = new File(copyMap.get(sourceFolder).toPath().resolve(sourceFolder.toPath().relativize(source)).toString());
                    if (Files.isDirectory(source)) {
                        target.mkdir();
                    } else {
                        Files.copy(source, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
                        copiedBytes[0] += source.toFile().length();
                        progress.set((double) copiedBytes[0] / totalBytes[0] * 100);
                        player.sendActionBar(Component.text("Kopiere Welt: ", Color.GREEN).append(getProgressBar(progress.get())));
                    }
                } catch (IOException e) {
                    Lobby.getPlugin().getLogger().log(Level.SEVERE, "Error while copy Map", e);
                }
            });
        }
    }

    public static Component getProgressBar(double value) {
        int progress = (int) (value / 100 * 40);

        Component progressBar = Component.text("[", Color.RED);
        for (int i = 0; i < 40; i++) {
            if (i < progress) {
                progressBar = progressBar.append(Component.text("|", Color.PINK));
            } else {
                progressBar = progressBar.append(Component.text("|", Color.GREEN));
            }
        }
        progressBar = progressBar.append(Component.text("] ", Color.RED).append(Component.text(String.format("%.2f", value) + "%", Color.PINK)));
        return progressBar;
    }

    public void start(Player player) {
        ProcessBuilder processBuilder = new ProcessBuilder();
        boolean eventServer = false;
        if (this.serverType == ServerType.ADVENTURE && plugin.getEventServerPlayerList().contains(player.getUniqueId())) {
            processBuilder.command("screen", "-AmdS", player.getName(), "./event.sh").directory(new File(plugin.getServerFolderPath().toFile(), this.dir));
            plugin.getEventServerPlayerList().remove(player.getUniqueId());
            eventServer = true;
        } else {
            processBuilder.command("screen", "-AmdS", player.getName(), "./start.sh").directory(new File(plugin.getServerFolderPath().toFile(), this.dir));
        }

        try {
            processBuilder.start();
            Lobby.getPlugin().getLogger().info(this.serverType.toString().toLowerCase() + (eventServer ? " Event Server: " : " Server: ") + getServerfromPlayer(player).gPLocation + " wurde von " + player.getName() + " gestartet!");
        } catch (IOException e) {
            Lobby.getPlugin().getLogger().log(Level.SEVERE, "Error while starting Server", e);
        }
    }

    public void spawnPiglin(Player player) {
        this.plugin.spawnPiglin(this.piglinLocation, this.name, this.serverVersion, this.gPLocation, player.getName(), false);
    }

    public void despawnPiglin() {
        this.plugin.despawnPiglin(this.name);
    }

    public String getMapVersion(File config) {
        String serverVersion;
        YamlConfiguration serverConfiguration = new YamlConfiguration();
        if (!config.exists()) {
            serverVersion = "latest";
            return serverVersion;
        }
        try {
            serverConfiguration.load(config);
        } catch (IOException | InvalidConfigurationException e) {
            Lobby.getPlugin().getLogger().log(Level.SEVERE, "Error while load server Config", e);
        }
        String configServerVersion = serverConfiguration.getString("serverversion");
        if (configServerVersion != null) {
            File serverversionfolder = new File(plugin.getServerJarsPath().toFile(), configServerVersion);
            if (serverversionfolder.isDirectory()) {
                serverVersion = configServerVersion;
            } else {
                serverVersion = "latest";
            }
        } else {
            serverVersion = "latest";
        }
        return serverVersion;
    }

    private static String getPluginFolderPrefix(File saveSlot) {
        String challengeFolder = null;
        File challenges = new File(saveSlot, "/Challenges");
        File challenge = new File(saveSlot, "/Challenge");
        File adventure = new File(saveSlot, "/Adventure");
        if (challenges.isDirectory()) {
            challengeFolder = "Challenges";
        } else if (challenge.isDirectory()) {
            challengeFolder = "Challenge";
        } else if (adventure.isDirectory()) {
            challengeFolder = "Adventure";
        }

        return challengeFolder;
    }
}