mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-03 05:51:37 +01:00
Resource gatherer to extract data from Minecraft's server jar instead of distributing our own
This commit is contained in:
parent
7493a6cae7
commit
feae9f1cd3
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,6 +42,9 @@ gradle-app.setting
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# IDEA files
|
||||
.idea/
|
||||
|
||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
|
110013
registry/blocks.json
110013
registry/blocks.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -15,10 +15,13 @@ import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.registry.RegistryMain;
|
||||
import net.minestom.server.registry.ResourceGatherer;
|
||||
import net.minestom.server.scoreboard.TeamManager;
|
||||
import net.minestom.server.timer.SchedulerManager;
|
||||
import net.minestom.server.world.Difficulty;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class MinecraftServer {
|
||||
|
||||
// Threads
|
||||
@ -103,6 +106,12 @@ public class MinecraftServer {
|
||||
nettyServer = new NettyServer(packetProcessor);
|
||||
|
||||
// Registry
|
||||
try {
|
||||
ResourceGatherer.ensureResourcesArePresent(null); // TODO: provide a way to give a path override, probably via launch arguments?
|
||||
} catch (IOException e) {
|
||||
System.err.println("An error happened during resource gathering. Minestom will attempt to load anyway, but things may not work, and crashes can happen.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
RegistryMain.registerBlocks();
|
||||
RegistryMain.registerItems();
|
||||
RegistryMain.registerEntities();
|
||||
|
@ -23,12 +23,12 @@ import java.util.Set;
|
||||
|
||||
public class RegistryMain {
|
||||
|
||||
public static final String BLOCKS_PATH = "registry/blocks.json";
|
||||
public static final String ITEMS_PATH = "registry/registries.json";
|
||||
public static final String ENTITIES_PATH = "registry/registries.json";
|
||||
public static final String SOUNDS_PATH = "registry/registries.json";
|
||||
public static final String PARTICLES_PATH = "registry/registries.json";
|
||||
public static final String STATS_PATH = "registry/registries.json";
|
||||
public static final String BLOCKS_PATH = "minecraft_data/reports/blocks.json";
|
||||
public static final String ITEMS_PATH = "minecraft_data/reports/registries.json";
|
||||
public static final String ENTITIES_PATH = "minecraft_data/reports/registries.json";
|
||||
public static final String SOUNDS_PATH = "minecraft_data/reports/registries.json";
|
||||
public static final String PARTICLES_PATH = "minecraft_data/reports/registries.json";
|
||||
public static final String STATS_PATH = "minecraft_data/reports/registries.json";
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<RegistryBlock> blocks = parseBlocks(BLOCKS_PATH);
|
||||
|
164
src/main/java/net/minestom/server/registry/ResourceGatherer.java
Normal file
164
src/main/java/net/minestom/server/registry/ResourceGatherer.java
Normal file
@ -0,0 +1,164 @@
|
||||
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");
|
||||
}
|
||||
}
|
39
src/main/java/net/minestom/server/registry/VersionInfo.java
Normal file
39
src/main/java/net/minestom/server/registry/VersionInfo.java
Normal file
@ -0,0 +1,39 @@
|
||||
package net.minestom.server.registry;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class used to represent the contents of a versions/{version}/{version}.json file
|
||||
* Structured in a way that makes loading with Gson easy.
|
||||
* Only concerned with helping extracting data from the server jar, lots of features may be missing.
|
||||
*/
|
||||
class VersionInfo {
|
||||
|
||||
private Map<String, DownloadObject> downloads;
|
||||
|
||||
private VersionInfo() {
|
||||
|
||||
}
|
||||
|
||||
public Map<String, DownloadObject> getDownloadableFiles() {
|
||||
return downloads;
|
||||
}
|
||||
|
||||
class DownloadObject {
|
||||
private String url;
|
||||
private String sha1;
|
||||
private long size;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getSha1() {
|
||||
return sha1;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user