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);
}
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;
}
}