Update to Minecraft 1.18-pre5

By: md_5 <git@md-5.net>
This commit is contained in:
CraftBukkit/Spigot
2021-11-22 09:00:00 +11:00
parent a852b81a69
commit 43702a9e10
700 changed files with 10286 additions and 10098 deletions

View File

@@ -0,0 +1,168 @@
// Based on net.minecraft.bundler.Main
package org.bukkit.craftbukkit.bootstrap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] argv) {
new Main().run(argv);
}
private void run(String[] argv) {
try {
String defaultMainClassName = readResource("main-class", BufferedReader::readLine);
String mainClassName = System.getProperty("bundlerMainClass", defaultMainClassName);
String repoDir = System.getProperty("bundlerRepoDir", "bundler");
Path outputDir = Paths.get(repoDir).toAbsolutePath();
Files.createDirectories(outputDir);
System.out.println("Unbundling libraries to " + outputDir);
boolean readOnly = Boolean.getBoolean("bundlerReadOnly");
List<URL> extractedUrls = new ArrayList<>();
readAndExtractDir("versions", outputDir, extractedUrls, readOnly);
readAndExtractDir("libraries", outputDir, extractedUrls, readOnly);
if (mainClassName == null || mainClassName.isEmpty()) {
System.out.println("Empty main class specified, exiting");
System.exit(0);
}
ClassLoader maybePlatformClassLoader = getClass().getClassLoader().getParent();
URLClassLoader classLoader = new URLClassLoader(extractedUrls.toArray(new URL[0]), maybePlatformClassLoader);
System.out.println("Starting server");
Thread runThread = new Thread(() -> {
try {
Class<?> mainClass = Class.forName(mainClassName, true, classLoader);
MethodHandle mainHandle = MethodHandles.lookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
mainHandle.invoke(argv);
} catch (Throwable t) {
Thrower.INSTANCE.sneakyThrow(t);
}
}, "ServerMain");
runThread.setContextClassLoader(classLoader);
runThread.start();
} catch (Exception e) {
e.printStackTrace(System.out);
System.out.println("Failed to extract server libraries, exiting");
}
}
private <T> T readResource(String resource, ResourceParser<T> parser) throws Exception {
String fullPath = "/META-INF/" + resource;
try (InputStream is = getClass().getResourceAsStream(fullPath)) {
if (is == null) {
throw new IllegalStateException("Resource " + fullPath + " not found");
}
return parser.parse(new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)));
}
}
private void readAndExtractDir(String subdir, Path outputDir, List<URL> extractedUrls, boolean readOnly) throws Exception {
List<FileEntry> entries = readResource(subdir + ".list", reader -> reader.lines().map(FileEntry::parseLine).toList());
Path subdirPath = outputDir.resolve(subdir);
for (FileEntry entry : entries) {
if (entry.path.startsWith("minecraft-server")) {
continue;
}
Path outputFile = subdirPath.resolve(entry.path);
if (!readOnly) {
checkAndExtractJar(subdir, entry, outputFile);
}
extractedUrls.add(outputFile.toUri().toURL());
}
}
private void checkAndExtractJar(String subdir, FileEntry entry, Path outputFile) throws Exception {
if (!Files.exists(outputFile) || !checkIntegrity(outputFile, entry.hash())) {
System.out.printf("Unpacking %s (%s:%s) to %s%n", entry.path, subdir, entry.id, outputFile);
extractJar(subdir, entry.path, outputFile);
}
}
private void extractJar(String subdir, String jarPath, Path outputFile) throws IOException {
Files.createDirectories(outputFile.getParent());
try (InputStream input = getClass().getResourceAsStream("/META-INF/" + subdir + "/" + jarPath)) {
if (input == null) {
throw new IllegalStateException("Declared library " + jarPath + " not found");
}
Files.copy(input, outputFile, StandardCopyOption.REPLACE_EXISTING);
}
}
private static boolean checkIntegrity(Path file, String expectedHash) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (InputStream output = Files.newInputStream(file)) {
output.transferTo(new DigestOutputStream(OutputStream.nullOutputStream(), digest));
String actualHash = byteToHex(digest.digest());
if (actualHash.equalsIgnoreCase(expectedHash)) {
return true;
}
System.out.printf("Expected file %s to have hash %s, but got %s%n", new Object[]{file, expectedHash, actualHash});
}
return false;
}
private static String byteToHex(byte[] bytes) {
StringBuilder result = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
result.append(Character.forDigit(b >> 4 & 0xF, 16));
result.append(Character.forDigit(b >> 0 & 0xF, 16));
}
return result.toString();
}
@FunctionalInterface
private static interface ResourceParser<T> {
T parse(BufferedReader param1BufferedReader) throws Exception;
}
private static final record FileEntry(String hash, String id, String path) {
public static FileEntry parseLine(String line) {
String[] fields = line.split(" ");
if (fields.length != 2) {
throw new IllegalStateException("Malformed library entry: " + line);
}
String path = fields[1].substring(1);
return new FileEntry(fields[0], path, path);
}
}
private static class Thrower<T extends Throwable> {
private static final Thrower<RuntimeException> INSTANCE = new Thrower();
public void sneakyThrow(Throwable exception) throws T {
throw (T) exception;
}
}
}