Newer
Older
ChallengeSystem / src / main / java / de / fanta / challenges / utils / SaveWorldUtils.java
@fanta fanta on 6 Jun 2024 11 KB save saveTime in serverConfig
package de.fanta.challenges.utils;

import de.cubeside.nmsutils.NMSUtils;
import de.fanta.challenges.Challenges;
import de.fanta.challenges.SaveSlot;
import de.fanta.challenges.ServerType;
import de.fanta.challenges.events.ChallengeEventStatusChangedEvent;
import de.fanta.challenges.events.EventStatusChangedEvent;
import de.fanta.challenges.events.ServerStatusChangedEvent;
import net.kyori.adventure.text.Component;
import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;

import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;

public class SaveWorldUtils {

    private static final Challenges plugin = Challenges.getPlugin();

    public static boolean isSavingWorld = false;
    public static boolean isCopyWorld = false;
    private static boolean isServerRestartRequested = false;
    private static boolean restart = false;
    private static String restartSeed = null;
    public static double progress = 0.0;

    public static void saveWorld(String saveID, SaveSlot saveSlot) {
        saveWorld(null, saveID, saveSlot);
    }

    public static void saveWorld(@Nullable Player player, String saveID, SaveSlot saveSlot) {
        plugin.getLogger().info("Try Save world slot: " + saveSlot.getSlot());
        try {
            if (isSavingWorld) {
                if (player != null) {
                    ChatUtil.sendErrorMessage(player, "Diese Welt wird aktuell gespeichert. Bitte warte bis der Vorgang abgeschlossen ist. Dies kann einige Minuten dauern.");
                }
                return;
            }
            if (plugin.getServerType() == ServerType.CHALLENGE_EVENT) {
                if (player != null) {
                    ChatUtil.sendErrorMessage(player, "Challenge Events können nicht gespeichert werden.");
                }
                return;
            }
            isSavingWorld = true;
            plugin.getServerConfig().set("saveTime", System.currentTimeMillis());
            plugin.saveServerConfig();
            Config.setValue("timertime", Challenges.getPlugin().getTimer().getTime());
            Config.setValue("backpack_size", Challenges.getPlugin().getBackpack().getSize() / 9);
            Challenges.getPlugin().getBackpack().saveInventoryToConfig();

            for (Player p : Bukkit.getOnlinePlayers()) {
                p.saveData();
            }
            NMSUtils nms = plugin.getNMSUtils();
            if (nms != null) {
                for (World world : Bukkit.getWorlds()) {
                    nms.getWorldUtils().saveWorldNow(world);
                }
                copyWorldAsync(player, saveID, saveSlot);
            }
        } catch (Exception ex) {
            plugin.getLogger().log(Level.SEVERE, "Welt konnte nicht gespeichert werden", ex);
        }
    }

    private static void copyWorldAsync(Player player, String saveID, SaveSlot saveSlot) {
        File dir = new File(saveID);
        File configs = new File("plugins/Challenges");
        File end = new File("world_the_end");
        File nether = new File("world_nether");
        File world = new File("world");
        File saveend = new File(saveID + "/world_the_end");
        File savenether = new File(saveID + "/world_nether");
        File saveworld = new File(saveID + "/world");
        File saveconfigs = new File(saveID + "/Challenges");
        File saveFolder;
        if (plugin.getServerType() != ServerType.ADVENTURE) {
            saveFolder = new File(plugin.getChallengeSavePath().toFile(), saveID + "/");
        } else {
            saveFolder = new File(plugin.getAdventureSavePath().toFile(), saveID + "/");
        }
        try {
            FileUtils.forceMkdir(dir);
            FileUtils.copyDirectory(configs, saveconfigs);
            FileUtils.copyDirectory(end, saveend);
            FileUtils.copyDirectory(nether, savenether);
            FileUtils.copyDirectory(world, saveworld);

            if (player != null) {
                ChatUtil.sendNormalMessage(player, "Welt wurde erfolgreich kopiert und wird nun gespeichert. Dies kann einige Minuten dauern. Du kannst aber ganz normal weiter spielen.");
            }

            CompletableFuture<Boolean> copyFuture = CompletableFuture.supplyAsync(() -> {
                try {
                    if (!saveFolder.isDirectory()) {
                        saveFolder.mkdirs();
                    }

                    File saveSlotFolder = new File(saveFolder, saveSlot.getSlot());

                    if (saveSlotFolder.isDirectory()) {
                        FileUtils.forceDelete(saveSlotFolder);
                    }
                    HashMap<File, File> copyMap = new HashMap<>();
                    copyMap.put(dir, saveSlotFolder);
                    moveFolderWithProgress(copyMap);
                    return true;
                } catch (IOException ex) {
                    plugin.getLogger().log(Level.SEVERE, "Could not save world ", ex);
                    return false;
                }
            });

            copyFuture.thenAccept(result -> {
                plugin.getServer().getScheduler().runTask(plugin, () -> {
                    plugin.getLogger().info("Save result: " + result);
                    if (result) {
                        if (player != null) {
                            ChatUtil.sendNormalMessage(player, "Welt wurde erfolgreich auf Slot " + saveSlot.getSlot() + " gespeichert!");
                        }

                        if (isServerRestartRequested) {
                            restartServerInternal(restartSeed);
                        } else if (restart) {
                            Config.setValue("World_Reset", true);
                            Bukkit.shutdown();
                        }
                    } else {
                        if (player != null) {
                            ChatUtil.sendErrorMessage(Bukkit.getPlayer(saveID), "Map konnte nicht richtig gespeichert werden, bitte versuche es noch einmal");
                        }
                    }
                    isSavingWorld = false;
                    try {
                        FileUtils.deleteDirectory(dir);
                    } catch (IOException ex) {
                        plugin.getLogger().log(Level.SEVERE, "Could not delete tempFolder ", ex);
                    }
                });
            });
        } catch (IOException ex) {
            plugin.getLogger().log(Level.SEVERE, "Could not save world ", ex);
        }
    }

    public static void restartServer(@Nullable String seed) {
        if (isSavingWorld) {
            restartSeed = seed;
            isServerRestartRequested = true;
        } else {
            restartServerInternal(seed);
        }
    }

    private static void restartServerInternal(@Nullable String seed) {
        plugin.setWaitingForShutdown(true);

        Bukkit.getPluginManager().callEvent(new EventStatusChangedEvent(false));
        Bukkit.getPluginManager().callEvent(new ChallengeEventStatusChangedEvent(false));
        Bukkit.getPluginManager().callEvent(new ServerStatusChangedEvent(false));

        for (Player p : Bukkit.getOnlinePlayers()) {
            plugin.portPlayerToLobby(p);
        }

        Config.setValue("editsettings", true, false);

        setSeedInServerProperties(seed);

        plugin.getTimer().stopTimer();

        for (String key : Config.getConfigurationSection("Saved_Locations").getKeys(false)) {
            Config.setValue("Saved_Locations." + key, null, false);
        }

        plugin.saveConfig();
        plugin.getBackpack().saveInventoryToConfig();

        if (Config.getBoolean("firsttimerstart") && plugin.getFirstEditor() != null && plugin.getServerType() != ServerType.CHALLENGE_EVENT) {
            restart = true;
            SaveWorldUtils.saveWorld(plugin.getFirstEditor().getUniqueId().toString(), SaveSlot.SLOT_AUTO);
        } else {
            Config.setValue("World_Reset", true);
            Bukkit.shutdown();
        }

    }

    private static void setSeedInServerProperties(@Nullable String seed) {
        try {
            BufferedReader in = new BufferedReader(new FileReader("server.properties"));
            Properties props = new Properties();
            props.load(in);
            in.close();
            if (seed != null) {
                props.setProperty("level-seed", seed);
                Config.setValue("resetwithseed", true, false);
            } else {
                props.setProperty("level-seed", "");
            }
            FileOutputStream out = new FileOutputStream("server.properties");
            props.store(out, null);
            out.close();
        } catch (IOException e) {
            plugin.getLogger().log(Level.SEVERE, "Error while read server properties Config", e);
        }
    }

    public static void moveFolderWithProgress(HashMap<File, File> copyMap) throws IOException {
        isCopyWorld = true;
        final long[] totalBytes = {0};
        final long[] copiedBytes = {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 = (double) copiedBytes[0] / totalBytes[0] * 100;
                    }
                } catch (IOException e) {
                    plugin.getLogger().log(Level.SEVERE, "Error while copy files", e);
                }
            });
        }
        isCopyWorld = false;
    }

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

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

        return progressBar;
    }
}