Minestom/src/main/java/net/minestom/server/registry/ResourceGatherer.java

165 lines
7.3 KiB
Java

package net.minestom.server.registry;
import com.google.gson.Gson;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.stream.Collectors;
/**
* Responsible for making sure Minestom has the necessary files to run (notably registry files)
*/
public class ResourceGatherer {
public static final File DATA_FOLDER = new File("./minecraft_data/");
private static final File TMP_FOLDER = new File("./.minestom_tmp/");
/**
* Checks if registry/ folder is present
* If it is not, download the minecraft server jar, run the data generator and extract the wanted files
* If it is already present, directly return
*/
public static void ensureResourcesArePresent(File minecraftFolderOverride) throws IOException {
if(DATA_FOLDER.exists()) {
return;
}
System.out.println(DATA_FOLDER +" folder does not exist. Minestom will now generate the necessary files.");
if(!TMP_FOLDER.exists() && !TMP_FOLDER.mkdirs()) {
throw new IOException("Failed to create tmp folder.");
}
final String version = "1.15.2"; // TODO: Do not hardcode
System.out.println("Starting download of Minecraft server jar for version "+version+" from Mojang servers...");
File minecraftFolder = getMinecraftFolder(minecraftFolderOverride);
if(!minecraftFolder.exists()) {
throw new IOException("Could not find Minecraft installation folder, attempted location "+minecraftFolder+". If this location is not the correct one, please supply the correct one as argument of ResourceGatherer#ensureResourcesArePresent");
}
File serverJar = downloadServerJar(minecraftFolder, version);
System.out.println("Download complete.");
runDataGenerator(serverJar);
moveAndCleanup(version);
System.out.println("Resource gathering done!");
}
private static void moveAndCleanup(String version) throws IOException {
Path dataFolderPath = DATA_FOLDER.toPath();
Path tmpFolderPath = TMP_FOLDER.toPath();
Path generatedFolder = tmpFolderPath.resolve("generated");
System.out.println("Data generator successful, removing server jar");
Files.delete(tmpFolderPath.resolve("server_"+version+".jar"));
System.out.println("Removal successful, now moving data to "+DATA_FOLDER);
Files.walkFileTree(tmpFolderPath, new SimpleFileVisitor<>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path relativePath = generatedFolder.relativize(dir);
if(dir.startsWith(generatedFolder)) { // don't copy logs
Path resolvedPath = dataFolderPath.resolve(relativePath);
System.out.println("> Creating sub-folder "+relativePath);
Files.createDirectories(resolvedPath);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
System.out.println("> Deleting folder "+dir);
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path relativePath = generatedFolder.relativize(file);
if(file.startsWith(generatedFolder)) { // don't copy logs
Path resolvedPath = dataFolderPath.resolve(relativePath);
System.out.println("> Moving "+relativePath);
Files.move(file, resolvedPath);
} else {
System.out.println("> Deleting "+relativePath);
Files.delete(file);
}
return FileVisitResult.CONTINUE;
}
});
}
private static void runDataGenerator(File serverJar) throws IOException {
ProcessBuilder dataGenerator = new ProcessBuilder("java", "-cp", serverJar.getName(), "net.minecraft.data.Main", "--all", "--server", "--dev");
dataGenerator.directory(TMP_FOLDER);
dataGenerator.inheritIO();
System.out.println("Now running data generator with options '--dev', '--server', '--all'");
System.out.println("Executing: "+dataGenerator.command().stream().collect(Collectors.joining(" ")));
System.out.println("Minestom will now wait for it to finish, here's its output:");
Process dataGeneratorProcess = dataGenerator.start();
try {
int resultCode = dataGeneratorProcess.waitFor();
if(resultCode != 0) {
throw new IOException("Data generator finished with non-zero return code "+resultCode);
}
} catch (InterruptedException e) {
throw new IOException("Data generator was interrupted.", e);
}
}
/**
* Finds the URL for the server jar inside the versions/ folder of the game installation and download the .jar file from there
* @param minecraftFolder
* @param version
* @return
*/
private static File downloadServerJar(File minecraftFolder, String version) throws IOException {
File versionInfoFile = new File(minecraftFolder, "versions/"+version+"/"+version+".json");
if(!versionInfoFile.exists()) {
throw new IOException("Could not find "+version+".json in your Minecraft installation. Make sure to launch this version at least once before running Minestom");
}
try(FileReader fileReader = new FileReader(versionInfoFile)) {
Gson gson = new Gson();
VersionInfo versionInfo = gson.fromJson(fileReader, VersionInfo.class);
VersionInfo.DownloadObject serverJarInfo = versionInfo.getDownloadableFiles().get("server");
String downloadURL = serverJarInfo.getUrl();
System.out.println("Found URL, starting download from "+downloadURL+"...");
return download(version, downloadURL);
}
}
private static File download(String version, String url) throws IOException {
File target = new File(TMP_FOLDER, "server_"+version+".jar");
try(BufferedInputStream in = new BufferedInputStream(new URL(url).openStream())) {
Files.copy(in, target.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new IOException("Failed to download Minecraft server jar.", e);
}
return target;
}
private static File getMinecraftFolder(File minecraftFolderOverride) {
if(minecraftFolderOverride != null) {
return minecraftFolderOverride;
}
// https://help.minecraft.net/hc/en-us/articles/360035131551-Where-are-Minecraft-files-stored-
String os = System.getProperty("os.name").toLowerCase();
if(os.contains("win")) {
String user = System.getProperty("user.name");
return new File("C:/Users/"+user+"/AppData/Roaming/.minecraft/");
}
if(os.contains("mac")) {
return new File("~/Library/Application Support/minecraft");
}
return new File("~/.minecraft");
}
}