mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
remove shuttle, useless
This commit is contained in:
4
.github/workflows/build-1218.yml
vendored
4
.github/workflows/build-1218.yml
vendored
@@ -62,8 +62,8 @@ jobs:
|
|||||||
PARALLELISM=$(($(nproc) * 2))
|
PARALLELISM=$(($(nproc) * 2))
|
||||||
./gradlew applyAllPatches --stacktrace --parallel --max-workers=$PARALLELISM --build-cache --no-daemon
|
./gradlew applyAllPatches --stacktrace --parallel --max-workers=$PARALLELISM --build-cache --no-daemon
|
||||||
|
|
||||||
- name: Build Shuttle Jar
|
- name: Build Paperclip Jar
|
||||||
run: ./gradlew createMojmapShuttleJar --stacktrace --parallel --no-daemon
|
run: ./gradlew createMojmapPaperclipJar --stacktrace --parallel --no-daemon
|
||||||
|
|
||||||
- name: Prepare Release Info
|
- name: Prepare Release Info
|
||||||
run: bash scripts/releaseInfo.sh
|
run: bash scripts/releaseInfo.sh
|
||||||
|
|||||||
6
.github/workflows/build-pr.yml
vendored
6
.github/workflows/build-pr.yml
vendored
@@ -26,11 +26,11 @@ jobs:
|
|||||||
- name: Apply Patches
|
- name: Apply Patches
|
||||||
run: ./gradlew applyAllPatches --stacktrace --no-daemon
|
run: ./gradlew applyAllPatches --stacktrace --no-daemon
|
||||||
|
|
||||||
- name: Build Shuttle Jar
|
- name: Build Paperclip Jar
|
||||||
run: ./gradlew createMojmapShuttleJar --stacktrace --no-daemon
|
run: ./gradlew createMojmapPaperclipJar --stacktrace --no-daemon
|
||||||
|
|
||||||
- name: Upload Artifacts
|
- name: Upload Artifacts
|
||||||
uses: actions/upload-artifact@main
|
uses: actions/upload-artifact@main
|
||||||
with:
|
with:
|
||||||
name: DivineMC
|
name: DivineMC
|
||||||
path: divinemc-server/build/libs/divinemc-shuttle-*-mojmap.jar
|
path: divinemc-server/build/libs/divinemc-paperclip-*-mojmap.jar
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Run the following commands in the root directory:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
> ./gradlew applyAllPatches # apply all patches
|
> ./gradlew applyAllPatches # apply all patches
|
||||||
> ./gradlew createMojmapShuttleJar # build the server jar
|
> ./gradlew createMojmapPaperclipJar # build the server jar
|
||||||
```
|
```
|
||||||
|
|
||||||
For anything else you can refer to our [contribution guide](https://bxteam.org/docs/divinemc/development/contributing).
|
For anything else you can refer to our [contribution guide](https://bxteam.org/docs/divinemc/development/contributing).
|
||||||
|
|||||||
@@ -107,76 +107,6 @@ subprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Jar>("createMojmapShuttleJar") {
|
|
||||||
dependsOn(":divinemc-server:createMojmapPaperclipJar", "shuttle:shadowJar")
|
|
||||||
|
|
||||||
outputs.upToDateWhen { false }
|
|
||||||
|
|
||||||
val paperclipJarTask = project(":divinemc-server").tasks.getByName("createMojmapPaperclipJar")
|
|
||||||
val shuttleJarTask = project(":shuttle").tasks.getByName("shadowJar")
|
|
||||||
|
|
||||||
val paperclipJar = paperclipJarTask.outputs.files.singleFile
|
|
||||||
val shuttleJar = shuttleJarTask.outputs.files.singleFile
|
|
||||||
val outputDir = paperclipJar.parentFile
|
|
||||||
val tempDir = File(outputDir, "tempJarWork")
|
|
||||||
val newJarName = "divinemc-shuttle-${properties["version"]}-mojmap.jar"
|
|
||||||
|
|
||||||
doFirst {
|
|
||||||
val time = measureTimeMillis {
|
|
||||||
println("Recompiling Paperclip with Shuttle sources...")
|
|
||||||
|
|
||||||
tempDir.deleteRecursively()
|
|
||||||
tempDir.mkdirs()
|
|
||||||
|
|
||||||
copy {
|
|
||||||
from(zipTree(paperclipJar))
|
|
||||||
into(tempDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
val oldPackagePath = "io/papermc/paperclip/"
|
|
||||||
tempDir.walkTopDown()
|
|
||||||
.filter { it.isFile && it.relativeTo(tempDir).path.startsWith(oldPackagePath) }
|
|
||||||
.forEach { it.delete() }
|
|
||||||
|
|
||||||
val shuttlePackagePath = "org/bxteam/shuttle/"
|
|
||||||
copy {
|
|
||||||
from(zipTree(shuttleJar))
|
|
||||||
include("$shuttlePackagePath**")
|
|
||||||
into(tempDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
tempDir.walkBottomUp()
|
|
||||||
.filter { it.isDirectory && it.listFiles().isNullOrEmpty() }
|
|
||||||
.forEach { it.delete() }
|
|
||||||
|
|
||||||
val metaInfDir = File(tempDir, "META-INF")
|
|
||||||
metaInfDir.mkdirs()
|
|
||||||
File(metaInfDir, "main-class").writeText("net.minecraft.server.Main")
|
|
||||||
}
|
|
||||||
println("Finished build in ${time}ms")
|
|
||||||
}
|
|
||||||
|
|
||||||
archiveFileName.set(newJarName)
|
|
||||||
destinationDirectory.set(outputDir)
|
|
||||||
from(tempDir)
|
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
"Main-Class" to "org.bxteam.shuttle.Shuttle",
|
|
||||||
"Enable-Native-Access" to "ALL-UNNAMED",
|
|
||||||
"Premain-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Launcher-Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Can-Redefine-Classes" to true,
|
|
||||||
"Can-Retransform-Classes" to true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
doLast {
|
|
||||||
tempDir.deleteRecursively()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("printMinecraftVersion") {
|
tasks.register("printMinecraftVersion") {
|
||||||
doLast {
|
doLast {
|
||||||
println(providers.gradleProperty("mcVersion").get().trim())
|
println(providers.gradleProperty("mcVersion").get().trim())
|
||||||
|
|||||||
@@ -31,29 +31,19 @@ index 97844ec1ccc986eb3d3a185d78a03ceeca49fc1a..5e40ec3fbe6e6d5f98ad98df7d4c27d6
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
|
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
|
||||||
index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef516126eb 100644
|
index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..0e07db9311d480c97251be6277f9d5d103ee9f22 100644
|
||||||
--- a/net/minecraft/server/Main.java
|
--- a/net/minecraft/server/Main.java
|
||||||
+++ b/net/minecraft/server/Main.java
|
+++ b/net/minecraft/server/Main.java
|
||||||
@@ -64,41 +64,39 @@ import org.slf4j.Logger;
|
@@ -69,36 +69,29 @@ public class Main {
|
||||||
public class Main {
|
)
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
@DontObfuscate
|
||||||
|
public static void main(final OptionSet optionSet) { // CraftBukkit - replaces main(String[] args)
|
||||||
+ public static void main(String[] arguments) {
|
+ // DivineMC start - Rebrand
|
||||||
+ OptionSet optionSet = org.bxteam.divinemc.DivineBootstrap.bootstrap(arguments);
|
|
||||||
+
|
|
||||||
+ io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo();
|
+ io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo();
|
||||||
+ if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) {
|
+ if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) {
|
||||||
+ LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName());
|
+ LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName());
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ main(optionSet);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
@SuppressForbidden(
|
|
||||||
reason = "System.out needed before bootstrap"
|
|
||||||
)
|
|
||||||
@DontObfuscate
|
|
||||||
public static void main(final OptionSet optionSet) { // CraftBukkit - replaces main(String[] args)
|
|
||||||
+ Path path2 = Paths.get("eula.txt");
|
+ Path path2 = Paths.get("eula.txt");
|
||||||
+ Eula eula = new Eula(path2);
|
+ Eula eula = new Eula(path2);
|
||||||
+ boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree");
|
+ boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree");
|
||||||
@@ -66,7 +56,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef
|
|||||||
+ LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
|
+ LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+
|
+ // DivineMC end - Rebrand
|
||||||
io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper - Improved watchdog support
|
io.papermc.paper.util.LogManagerShutdownThread.hook(); // Paper - Improved watchdog support
|
||||||
SharedConstants.tryDetectVersion();
|
SharedConstants.tryDetectVersion();
|
||||||
- /* CraftBukkit start - Replace everything
|
- /* CraftBukkit start - Replace everything
|
||||||
@@ -100,7 +90,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef
|
|||||||
Path path = (Path) optionSet.valueOf("pidFile"); // CraftBukkit
|
Path path = (Path) optionSet.valueOf("pidFile"); // CraftBukkit
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
writePidFile(path);
|
writePidFile(path);
|
||||||
@@ -124,8 +122,6 @@ public class Main {
|
@@ -124,8 +117,6 @@ public class Main {
|
||||||
DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support
|
DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support
|
||||||
dedicatedServerSettings.forceSave();
|
dedicatedServerSettings.forceSave();
|
||||||
RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression);
|
RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression);
|
||||||
@@ -109,7 +99,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef
|
|||||||
// Paper start - load config files early for access below if needed
|
// Paper start - load config files early for access below if needed
|
||||||
org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("bukkit-settings"));
|
org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("bukkit-settings"));
|
||||||
org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings"));
|
org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings"));
|
||||||
@@ -148,19 +144,6 @@ public class Main {
|
@@ -148,19 +139,6 @@ public class Main {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +120,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..c3ac5ba5d8084fefc0e9f58b09b521ef
|
|||||||
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
|
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
|
||||||
if (awtException != null) {
|
if (awtException != null) {
|
||||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
index 3de43e4edb33bb2c657a315ad2676ce44ee3bd6a..2d01252a66e59f69ff69055b83d7e881f2f3e5cd 100644
|
index b68749354f2a55e41f2b39f96ac9d1190092d672..e04be8b21514db5b7ecb2419b4b37caf29960c5a 100644
|
||||||
--- a/net/minecraft/server/MinecraftServer.java
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
+++ b/net/minecraft/server/MinecraftServer.java
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
@@ -1184,6 +1184,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
@@ -1184,6 +1184,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|||||||
@@ -114,66 +114,32 @@ index bc7e4e5560708fea89c584b1d8b471f4966f311a..6567ff18cb1c21230565c2d92caf3a7f
|
|||||||
.completer(new ConsoleCommandCompleter(this.server))
|
.completer(new ConsoleCommandCompleter(this.server))
|
||||||
.option(LineReader.Option.COMPLETE_IN_WORD, true);
|
.option(LineReader.Option.COMPLETE_IN_WORD, true);
|
||||||
diff --git a/src/main/java/io/papermc/paper/PaperBootstrap.java b/src/main/java/io/papermc/paper/PaperBootstrap.java
|
diff --git a/src/main/java/io/papermc/paper/PaperBootstrap.java b/src/main/java/io/papermc/paper/PaperBootstrap.java
|
||||||
deleted file mode 100644
|
index d543b1b107ab8d3eeb1fc3c1cadf489928d2786e..e77078e54efdfe931202ecf8c8550840b602d135 100644
|
||||||
index d543b1b107ab8d3eeb1fc3c1cadf489928d2786e..0000000000000000000000000000000000000000
|
|
||||||
--- a/src/main/java/io/papermc/paper/PaperBootstrap.java
|
--- a/src/main/java/io/papermc/paper/PaperBootstrap.java
|
||||||
+++ /dev/null
|
+++ b/src/main/java/io/papermc/paper/PaperBootstrap.java
|
||||||
@@ -1,55 +0,0 @@
|
@@ -8,7 +8,7 @@ import org.slf4j.Logger;
|
||||||
-package io.papermc.paper;
|
import org.slf4j.LoggerFactory;
|
||||||
-
|
|
||||||
-import java.util.List;
|
public final class PaperBootstrap {
|
||||||
-import joptsimple.OptionSet;
|
|
||||||
-import net.minecraft.SharedConstants;
|
|
||||||
-import net.minecraft.server.Main;
|
|
||||||
-import org.slf4j.Logger;
|
|
||||||
-import org.slf4j.LoggerFactory;
|
|
||||||
-
|
|
||||||
-public final class PaperBootstrap {
|
|
||||||
- private static final Logger LOGGER = LoggerFactory.getLogger("bootstrap");
|
- private static final Logger LOGGER = LoggerFactory.getLogger("bootstrap");
|
||||||
-
|
+ private static final Logger LOGGER = LoggerFactory.getLogger("PaperBootstrap"); // DivineMC - Rebrand
|
||||||
- private PaperBootstrap() {
|
|
||||||
- }
|
private PaperBootstrap() {
|
||||||
-
|
}
|
||||||
- public static void boot(final OptionSet options) {
|
@@ -49,7 +49,13 @@ public final class PaperBootstrap {
|
||||||
- SharedConstants.tryDetectVersion();
|
bi.brandName(),
|
||||||
-
|
bi.asString(ServerBuildInfo.StringRepresentation.VERSION_FULL),
|
||||||
- getStartupVersionMessages().forEach(LOGGER::info);
|
bi.minecraftVersionId()
|
||||||
-
|
+ ),
|
||||||
- Main.main(options);
|
+ // DivineMC start - Rebrand
|
||||||
- }
|
+ String.format(
|
||||||
-
|
+ "Running JVM args %s",
|
||||||
- private static List<String> getStartupVersionMessages() {
|
+ java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toString()
|
||||||
- final String javaSpecVersion = System.getProperty("java.specification.version");
|
)
|
||||||
- final String javaVmName = System.getProperty("java.vm.name");
|
+ // DivineMC end - Rebrand
|
||||||
- final String javaVmVersion = System.getProperty("java.vm.version");
|
);
|
||||||
- final String javaVendor = System.getProperty("java.vendor");
|
}
|
||||||
- final String javaVendorVersion = System.getProperty("java.vendor.version");
|
}
|
||||||
- final String osName = System.getProperty("os.name");
|
|
||||||
- final String osVersion = System.getProperty("os.version");
|
|
||||||
- final String osArch = System.getProperty("os.arch");
|
|
||||||
-
|
|
||||||
- final ServerBuildInfo bi = ServerBuildInfo.buildInfo();
|
|
||||||
- return List.of(
|
|
||||||
- String.format(
|
|
||||||
- "Running Java %s (%s %s; %s %s) on %s %s (%s)",
|
|
||||||
- javaSpecVersion,
|
|
||||||
- javaVmName,
|
|
||||||
- javaVmVersion,
|
|
||||||
- javaVendor,
|
|
||||||
- javaVendorVersion,
|
|
||||||
- osName,
|
|
||||||
- osVersion,
|
|
||||||
- osArch
|
|
||||||
- ),
|
|
||||||
- String.format(
|
|
||||||
- "Loading %s %s for Minecraft %s",
|
|
||||||
- bi.brandName(),
|
|
||||||
- bi.asString(ServerBuildInfo.StringRepresentation.VERSION_FULL),
|
|
||||||
- bi.minecraftVersionId()
|
|
||||||
- )
|
|
||||||
- );
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||||
index 1b0ee48e28aaa68ddb1f28c23d3c5f5f40505c98..4d3518795a238d87ca4f3df0bee074ab5bcc2734 100644
|
index 1b0ee48e28aaa68ddb1f28c23d3c5f5f40505c98..4d3518795a238d87ca4f3df0bee074ab5bcc2734 100644
|
||||||
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||||
@@ -230,98 +196,6 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..341f13e57896f03058ea3ec68e69b7cb
|
|||||||
@Override
|
@Override
|
||||||
public void executeAsync(final Runnable runnable) {
|
public void executeAsync(final Runnable runnable) {
|
||||||
MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous"));
|
MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous"));
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
index 748bd9650da4a209743b7a5dde584b2e19c5a578..3a4239d6f5768f7e2b6025477670dd2eb9f8cbc4 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
@@ -24,7 +24,7 @@ public class Main {
|
|
||||||
}
|
|
||||||
// Paper end - Reset loggers after shutdown
|
|
||||||
|
|
||||||
- public static void main(String[] args) {
|
|
||||||
+ public static OptionParser main(String[] args) { // DivineMC - Rebrand
|
|
||||||
if (System.getProperty("jdk.nio.maxCachedBufferSize") == null) System.setProperty("jdk.nio.maxCachedBufferSize", "262144"); // Paper - cap per-thread NIO cache size; https://www.evanjones.ca/java-bytebuffer-leak.html
|
|
||||||
OptionParser parser = new OptionParser() {
|
|
||||||
{
|
|
||||||
@@ -180,77 +180,6 @@ public class Main {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
- OptionSet options = null;
|
|
||||||
-
|
|
||||||
- try {
|
|
||||||
- options = parser.parse(args);
|
|
||||||
- } catch (joptsimple.OptionException ex) {
|
|
||||||
- Logger.getLogger(Main.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage());
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if ((options == null) || (options.has("?"))) {
|
|
||||||
- try {
|
|
||||||
- parser.printHelpOn(System.out);
|
|
||||||
- } catch (IOException ex) {
|
|
||||||
- Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
|
|
||||||
- }
|
|
||||||
- } else if (options.has("v")) {
|
|
||||||
- System.out.println(CraftServer.class.getPackage().getImplementationVersion());
|
|
||||||
- } else {
|
|
||||||
- // Do you love Java using + and ! as string based identifiers? I sure do!
|
|
||||||
- String path = new File(".").getAbsolutePath();
|
|
||||||
- if (path.contains("!") || path.contains("+")) {
|
|
||||||
- System.err.println("Cannot run server in a directory with ! or + in the pathname. Please rename the affected folders and try again.");
|
|
||||||
- return;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- // Paper start - Improve java version check
|
|
||||||
- boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion");
|
|
||||||
- String javaVersionName = System.getProperty("java.version");
|
|
||||||
- // J2SE SDK/JRE Version String Naming Convention
|
|
||||||
- boolean isPreRelease = javaVersionName.contains("-");
|
|
||||||
- if (isPreRelease) {
|
|
||||||
- if (!skip) {
|
|
||||||
- System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information.");
|
|
||||||
- return;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! ");
|
|
||||||
- }
|
|
||||||
- // Paper end - Improve java version check
|
|
||||||
-
|
|
||||||
- try {
|
|
||||||
- if (options.has("nojline")) {
|
|
||||||
- System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false");
|
|
||||||
- useJline = false;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (options.has("noconsole")) {
|
|
||||||
- Main.useConsole = false;
|
|
||||||
- useJline = false; // Paper
|
|
||||||
- System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (false && Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) { // Purpur - Disable outdated build check
|
|
||||||
- Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper
|
|
||||||
-
|
|
||||||
- Calendar deadline = Calendar.getInstance();
|
|
||||||
- deadline.add(Calendar.DAY_OF_YEAR, -14);
|
|
||||||
- if (buildDate.before(deadline.getTime())) {
|
|
||||||
- // Paper start - This is some stupid bullshit
|
|
||||||
- System.err.println("*** Warning, you've not updated in a while! ***");
|
|
||||||
- System.err.println("*** Please download a new build from https://papermc.io/downloads/paper ***");
|
|
||||||
- // Paper end
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows
|
|
||||||
- System.setProperty("jdk.console", "java.base"); // Paper - revert default console provider back to java.base so we can have our own jline
|
|
||||||
-
|
|
||||||
- io.papermc.paper.PaperBootstrap.boot(options);
|
|
||||||
- } catch (Throwable t) {
|
|
||||||
- t.printStackTrace();
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
+ return parser; // DivineMC - Rebrand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||||
index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..a839dbbb72f48b8f8736d9f4693c528686570732 100644
|
index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..a839dbbb72f48b8f8736d9f4693c528686570732 100644
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
package org.bxteam.divinemc;
|
|
||||||
|
|
||||||
import io.papermc.paper.ServerBuildInfo;
|
|
||||||
import joptsimple.OptionParser;
|
|
||||||
import joptsimple.OptionSet;
|
|
||||||
import net.minecraft.SharedConstants;
|
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
|
||||||
import org.bukkit.craftbukkit.Main;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DivineBootstrap {
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger("DivineBootstrap");
|
|
||||||
|
|
||||||
public static OptionSet bootstrap(String[] args) {
|
|
||||||
OptionParser parser = Main.main(args);
|
|
||||||
OptionSet options = parser.parse(args);
|
|
||||||
|
|
||||||
if ((options == null) || (options.has("?"))) {
|
|
||||||
try {
|
|
||||||
parser.printHelpOn(System.out);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOGGER.warn(ex.getMessage());
|
|
||||||
}
|
|
||||||
} else if (options.has("v")) {
|
|
||||||
System.out.println(CraftServer.class.getPackage().getImplementationVersion());
|
|
||||||
} else {
|
|
||||||
String path = new File(".").getAbsolutePath();
|
|
||||||
if (path.contains("!") || path.contains("+")) {
|
|
||||||
System.err.println("Cannot run server in a directory with ! or + in the pathname. Please rename the affected folders and try again.");
|
|
||||||
System.exit(70);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean skip = Boolean.getBoolean("Paper.IgnoreJavaVersion");
|
|
||||||
String javaVersionName = System.getProperty("java.version");
|
|
||||||
boolean isPreRelease = javaVersionName.contains("-");
|
|
||||||
if (isPreRelease) {
|
|
||||||
if (!skip) {
|
|
||||||
System.err.println("Unsupported Java detected (" + javaVersionName + "). You are running an unsupported, non official, version. Only general availability versions of Java are supported. Please update your Java version. See https://docs.papermc.io/paper/faq#unsupported-java-detected-what-do-i-do for more information.");
|
|
||||||
System.exit(70);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.err.println("Unsupported Java detected ("+ javaVersionName + "), but the check was skipped. Proceed with caution! ");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (options.has("nojline")) {
|
|
||||||
System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false");
|
|
||||||
Main.useJline = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.has("noconsole")) {
|
|
||||||
Main.useConsole = false;
|
|
||||||
Main.useJline = false;
|
|
||||||
System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
|
|
||||||
}
|
|
||||||
|
|
||||||
System.setProperty("library.jansi.version", "Paper");
|
|
||||||
System.setProperty("jdk.console", "java.base");
|
|
||||||
|
|
||||||
SharedConstants.tryDetectVersion();
|
|
||||||
getStartupVersionMessages().forEach(LOGGER::info);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
LOGGER.error("Failed to initialize the server", t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getStartupVersionMessages() {
|
|
||||||
final String javaSpecVersion = System.getProperty("java.specification.version");
|
|
||||||
final String javaVmName = System.getProperty("java.vm.name");
|
|
||||||
final String javaVmVersion = System.getProperty("java.vm.version");
|
|
||||||
final String javaVendor = System.getProperty("java.vendor");
|
|
||||||
final String javaVendorVersion = System.getProperty("java.vendor.version");
|
|
||||||
final String osName = System.getProperty("os.name");
|
|
||||||
final String osVersion = System.getProperty("os.version");
|
|
||||||
final String osArch = System.getProperty("os.arch");
|
|
||||||
|
|
||||||
final ServerBuildInfo bi = ServerBuildInfo.buildInfo();
|
|
||||||
return List.of(
|
|
||||||
String.format(
|
|
||||||
"Running Java %s (%s %s; %s %s) on %s %s (%s)",
|
|
||||||
javaSpecVersion,
|
|
||||||
javaVmName,
|
|
||||||
javaVmVersion,
|
|
||||||
javaVendor,
|
|
||||||
javaVendorVersion,
|
|
||||||
osName,
|
|
||||||
osVersion,
|
|
||||||
osArch
|
|
||||||
),
|
|
||||||
String.format(
|
|
||||||
"Loading %s %s for Minecraft %s",
|
|
||||||
bi.brandName(),
|
|
||||||
bi.asString(ServerBuildInfo.StringRepresentation.VERSION_FULL),
|
|
||||||
bi.minecraftVersionId()
|
|
||||||
),
|
|
||||||
String.format(
|
|
||||||
"Running JVM args %s",
|
|
||||||
ManagementFactory.getRuntimeMXBean().getInputArguments().toString()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,7 @@ make_latest=$([ "$experimental" = "true" ] && echo "false" || echo "true")
|
|||||||
|
|
||||||
rm -f $changelog
|
rm -f $changelog
|
||||||
|
|
||||||
mv divinemc-server/build/libs/divinemc-shuttle-"$version"-mojmap.jar "$jarName"
|
mv divinemc-server/build/libs/divinemc-paperclip-"$version"-mojmap.jar "$jarName"
|
||||||
{
|
{
|
||||||
echo "name=$divinemcid"
|
echo "name=$divinemcid"
|
||||||
echo "tag=$tagid"
|
echo "tag=$tagid"
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ if (!file(".git").exists()) {
|
|||||||
|
|
||||||
rootProject.name = "DivineMC"
|
rootProject.name = "DivineMC"
|
||||||
|
|
||||||
for (name in listOf("divinemc-api", "divinemc-server", "shuttle")) {
|
for (name in listOf("divinemc-api", "divinemc-server")) {
|
||||||
val projName = name.lowercase(Locale.ENGLISH)
|
val projName = name.lowercase(Locale.ENGLISH)
|
||||||
include(projName)
|
include(projName)
|
||||||
findProject(":$projName")!!.projectDir = file(name)
|
findProject(":$projName")!!.projectDir = file(name)
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id("java")
|
|
||||||
id("application")
|
|
||||||
id("maven-publish")
|
|
||||||
id("com.gradleup.shadow") version "8.3.8"
|
|
||||||
}
|
|
||||||
|
|
||||||
val mainClass = "org.bxteam.shuttle.Shuttle"
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("io.sigpipe:jbsdiff:1.0")
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
|
||||||
withSourcesJar()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<JavaCompile>().configureEach {
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
options.release = 21
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.jar {
|
|
||||||
val jar = tasks.named("shadowJar")
|
|
||||||
dependsOn(jar)
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
from(zipTree(jar.map { it.outputs.files.singleFile }))
|
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
"Main-Class" to mainClass,
|
|
||||||
"Enable-Native-Access" to "ALL-UNNAMED",
|
|
||||||
"Premain-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Launcher-Agent-Class" to "org.bxteam.shuttle.patch.InstrumentationManager",
|
|
||||||
"Can-Redefine-Classes" to true,
|
|
||||||
"Can-Retransform-Classes" to true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project.setProperty("mainClassName", mainClass)
|
|
||||||
|
|
||||||
tasks.shadowJar {
|
|
||||||
val prefix = "paperclip.libs"
|
|
||||||
listOf("org.apache", "org.tukaani", "io.sigpipe").forEach { pack ->
|
|
||||||
relocate(pack, "$prefix.$pack")
|
|
||||||
}
|
|
||||||
|
|
||||||
exclude("META-INF/LICENSE.txt")
|
|
||||||
exclude("META-INF/NOTICE.txt")
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
package org.bxteam.shuttle;
|
|
||||||
|
|
||||||
import org.bxteam.shuttle.logger.Logger;
|
|
||||||
import org.bxteam.shuttle.patch.LibraryLoader;
|
|
||||||
import org.bxteam.shuttle.patch.PatchBuilder;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
public final class Shuttle {
|
|
||||||
private static final String MAIN_CLASS_RESOURCE = "/META-INF/main-class";
|
|
||||||
private static final String VERSION_RESOURCE = "/version.json";
|
|
||||||
private static final String PATCH_ONLY_PROPERTY = "paperclip.patchonly";
|
|
||||||
private static final String BUNDLER_MAIN_CLASS_PROPERTY = "bundlerMainClass";
|
|
||||||
private static final String BUNDLER_REPO_DIR_PROPERTY = "bundlerRepoDir";
|
|
||||||
private static final String MAIN_THREAD_NAME = "main";
|
|
||||||
|
|
||||||
public static void main(String[] arguments) {
|
|
||||||
new Shuttle().run(arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void run(String[] arguments) {
|
|
||||||
try {
|
|
||||||
String defaultMainClassName = readMainClass();
|
|
||||||
String mainClassName = System.getProperty(BUNDLER_MAIN_CLASS_PROPERTY, defaultMainClassName);
|
|
||||||
String repoDir = System.getProperty(BUNDLER_REPO_DIR_PROPERTY, "");
|
|
||||||
|
|
||||||
setupDirectories(repoDir);
|
|
||||||
|
|
||||||
Provider<String> versionProvider = this::readVersionFromResource;
|
|
||||||
|
|
||||||
executePatchingPhase(versionProvider);
|
|
||||||
|
|
||||||
if (shouldExitAfterPatching()) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
executeLibraryLoadingPhase(versionProvider);
|
|
||||||
|
|
||||||
startTargetApplication(mainClassName, arguments);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Logger.error("Failed to extract server libraries, exiting", e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readMainClass() throws IOException {
|
|
||||||
return readResourceContent(MAIN_CLASS_RESOURCE, BufferedReader::readLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readVersionFromResource() throws IOException {
|
|
||||||
String jsonContent = readResourceContent(VERSION_RESOURCE, this::readAllLines);
|
|
||||||
return extractVersionFromJson(jsonContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T readResourceContent(String resourcePath, ResourceParser<T> parser) throws IOException {
|
|
||||||
try (InputStream inputStream = getClass().getResourceAsStream(resourcePath)) {
|
|
||||||
if (inputStream == null) {
|
|
||||||
throw new IOException("Resource not found: " + resourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (BufferedReader reader = new BufferedReader(
|
|
||||||
new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
|
||||||
return parser.parse(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readAllLines(BufferedReader reader) throws IOException {
|
|
||||||
StringBuilder content = new StringBuilder();
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
content.append(line);
|
|
||||||
}
|
|
||||||
return content.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractVersionFromJson(String jsonContent) throws IOException {
|
|
||||||
String prefix = "\"id\": \"";
|
|
||||||
int startIndex = jsonContent.indexOf(prefix);
|
|
||||||
|
|
||||||
if (startIndex == -1) {
|
|
||||||
throw new IOException("Version ID not found in JSON content");
|
|
||||||
}
|
|
||||||
|
|
||||||
startIndex += prefix.length();
|
|
||||||
int endIndex = jsonContent.indexOf("\"", startIndex);
|
|
||||||
|
|
||||||
if (endIndex == -1) {
|
|
||||||
throw new IOException("Malformed version ID in JSON content");
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonContent.substring(startIndex, endIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupDirectories(String repoDir) throws IOException {
|
|
||||||
if (!repoDir.isEmpty()) {
|
|
||||||
Path outputDir = Paths.get(repoDir);
|
|
||||||
Files.createDirectories(outputDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executePatchingPhase(Provider<String> versionProvider) throws IOException {
|
|
||||||
new PatchBuilder().start(versionProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldExitAfterPatching() {
|
|
||||||
return Boolean.getBoolean(PATCH_ONLY_PROPERTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void executeLibraryLoadingPhase(Provider<String> versionProvider) throws IOException {
|
|
||||||
new LibraryLoader().start(versionProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startTargetApplication(String mainClassName, String[] arguments) {
|
|
||||||
if (mainClassName == null || mainClassName.trim().isEmpty()) {
|
|
||||||
Logger.warn("No main class specified, exiting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.info("Starting " + mainClassName);
|
|
||||||
|
|
||||||
Thread applicationThread = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
invokeMainMethod(mainClassName, arguments);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
ExceptionHandler.INSTANCE.rethrow(e);
|
|
||||||
}
|
|
||||||
}, MAIN_THREAD_NAME);
|
|
||||||
|
|
||||||
applicationThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invokeMainMethod(String mainClassName, String[] arguments) throws Throwable {
|
|
||||||
Class<?> mainClass = Class.forName(mainClassName);
|
|
||||||
MethodHandle mainHandle = MethodHandles.lookup()
|
|
||||||
.findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class))
|
|
||||||
.asFixedArity();
|
|
||||||
|
|
||||||
mainHandle.invoke((Object) arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
private interface ResourceParser<T> {
|
|
||||||
T parse(BufferedReader reader) throws IOException;
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Provider<T> {
|
|
||||||
T get() throws IOException;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ExceptionHandler {
|
|
||||||
static final ExceptionHandler INSTANCE = new ExceptionHandler();
|
|
||||||
|
|
||||||
private ExceptionHandler() {
|
|
||||||
throw new UnsupportedOperationException("Utility class cannot be instantiated");
|
|
||||||
}
|
|
||||||
|
|
||||||
void rethrow(Throwable exception) {
|
|
||||||
throw new RuntimeException("Exception in target application", exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package org.bxteam.shuttle.logger;
|
|
||||||
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.LogRecord;
|
|
||||||
import java.util.logging.ConsoleHandler;
|
|
||||||
import java.util.logging.Formatter;
|
|
||||||
|
|
||||||
public class Logger {
|
|
||||||
private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger("Shuttle");
|
|
||||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
|
|
||||||
|
|
||||||
static {
|
|
||||||
LOGGER.setUseParentHandlers(false);
|
|
||||||
|
|
||||||
ConsoleHandler consoleHandler = new ConsoleHandler();
|
|
||||||
consoleHandler.setFormatter(new ShuttleFormatter());
|
|
||||||
consoleHandler.setLevel(Level.ALL);
|
|
||||||
LOGGER.addHandler(consoleHandler);
|
|
||||||
|
|
||||||
LOGGER.setLevel(Level.INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void info(String message) {
|
|
||||||
LOGGER.info(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void warn(String message) {
|
|
||||||
LOGGER.warning(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void error(String message) {
|
|
||||||
LOGGER.severe(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void error(String message, Throwable throwable) {
|
|
||||||
LOGGER.log(Level.SEVERE, message, throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void debug(String message) {
|
|
||||||
LOGGER.fine(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setLevel(Level level) {
|
|
||||||
LOGGER.setLevel(level);
|
|
||||||
LOGGER.getHandlers()[0].setLevel(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ShuttleFormatter extends Formatter {
|
|
||||||
@Override
|
|
||||||
public String format(LogRecord record) {
|
|
||||||
String time = LocalTime.now().format(TIME_FORMATTER);
|
|
||||||
String level = record.getLevel().getName();
|
|
||||||
String message = record.getMessage();
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("[").append(time).append(" ").append(level).append("]: ");
|
|
||||||
sb.append("[Shuttle] ");
|
|
||||||
sb.append(message);
|
|
||||||
sb.append(System.lineSeparator());
|
|
||||||
|
|
||||||
if (record.getThrown() != null) {
|
|
||||||
java.io.StringWriter sw = new java.io.StringWriter();
|
|
||||||
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
|
|
||||||
record.getThrown().printStackTrace(pw);
|
|
||||||
sb.append(sw.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package org.bxteam.shuttle.patch;
|
|
||||||
|
|
||||||
import java.lang.instrument.Instrumentation;
|
|
||||||
|
|
||||||
public final class InstrumentationManager {
|
|
||||||
private static volatile Instrumentation instrumentation;
|
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
|
|
||||||
private InstrumentationManager() {
|
|
||||||
throw new UnsupportedOperationException("Utility class cannot be instantiated");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void premain(final String agentArgs, final Instrumentation inst) {
|
|
||||||
agentmain(agentArgs, inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void agentmain(final String agentArgs, final Instrumentation inst) {
|
|
||||||
if (inst == null) {
|
|
||||||
throw new IllegalArgumentException("Instrumentation instance cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (LOCK) {
|
|
||||||
if (instrumentation == null) {
|
|
||||||
instrumentation = inst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Instrumentation getInstrumentation() {
|
|
||||||
final Instrumentation inst = instrumentation;
|
|
||||||
if (inst == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Instrumentation has not been initialized. " +
|
|
||||||
"Ensure the agent is properly loaded via -javaagent or attach mechanism."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return inst;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
package org.bxteam.shuttle.patch;
|
|
||||||
|
|
||||||
import org.bxteam.shuttle.Shuttle;
|
|
||||||
import org.bxteam.shuttle.logger.Logger;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
public class LibraryLoader {
|
|
||||||
private static final String LIBRARIES_DIR = "libraries";
|
|
||||||
private static final String CACHE_DIR = "cache";
|
|
||||||
private static final String LIBRARIES_LIST_RESOURCE = "/META-INF/libraries.list";
|
|
||||||
private static final String LIBRARIES_PREFIX = "META-INF/libraries/";
|
|
||||||
private static final String PATCH_EXTENSION = ".patch";
|
|
||||||
private static final int BUFFER_SIZE = 8192;
|
|
||||||
|
|
||||||
private static final List<String> MAVEN_REPOSITORIES = List.of(
|
|
||||||
"https://repo.papermc.io/repository/maven-public/",
|
|
||||||
"https://jitpack.io",
|
|
||||||
"https://s01.oss.sonatype.org/content/repositories/snapshots/",
|
|
||||||
"https://repo1.maven.org/maven2/",
|
|
||||||
"https://libraries.minecraft.net/"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static void copyStream(InputStream input, OutputStream output) throws IOException {
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = input.read(buffer)) != -1) {
|
|
||||||
output.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Shuttle.Provider<String> versionProvider) throws IOException {
|
|
||||||
try {
|
|
||||||
start(versionProvider.get());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Error during library loading process", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(String mcVersion) throws IOException {
|
|
||||||
if (mcVersion == null || mcVersion.trim().isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Minecraft version cannot be null or empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.info("Unpacking and linking library jars");
|
|
||||||
|
|
||||||
try {
|
|
||||||
createLibrariesDirectory();
|
|
||||||
|
|
||||||
Path currentJar = getCurrentJarPath();
|
|
||||||
extractLibrariesFromJar(currentJar);
|
|
||||||
|
|
||||||
Path vanillaBundler = Paths.get(CACHE_DIR, "vanilla-bundler-" + mcVersion + ".jar");
|
|
||||||
if (Files.exists(vanillaBundler)) {
|
|
||||||
extractLibrariesFromJar(vanillaBundler);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Failed to load libraries for version " + mcVersion, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createLibrariesDirectory() throws IOException {
|
|
||||||
Path librariesDir = Paths.get(LIBRARIES_DIR);
|
|
||||||
if (!Files.exists(librariesDir)) {
|
|
||||||
Files.createDirectories(librariesDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path getCurrentJarPath() throws IOException {
|
|
||||||
try {
|
|
||||||
return Paths.get(LibraryLoader.class.getProtectionDomain()
|
|
||||||
.getCodeSource().getLocation().toURI());
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new IOException("Failed to get current JAR path", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extractLibrariesFromJar(Path jarPath) throws IOException {
|
|
||||||
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
|
|
||||||
Enumeration<JarEntry> entries = jarFile.entries();
|
|
||||||
|
|
||||||
while (entries.hasMoreElements()) {
|
|
||||||
JarEntry entry = entries.nextElement();
|
|
||||||
|
|
||||||
if (entry.getName().startsWith(LIBRARIES_PREFIX)) {
|
|
||||||
processLibraryEntry(jarFile, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processLibraryEntry(JarFile jarFile, JarEntry entry) throws IOException {
|
|
||||||
String relativePath = entry.getName().substring(LIBRARIES_PREFIX.length());
|
|
||||||
File extractedFile = new File(LIBRARIES_DIR, relativePath);
|
|
||||||
|
|
||||||
if (entry.isDirectory()) {
|
|
||||||
Files.createDirectories(extractedFile.toPath());
|
|
||||||
} else if (entry.getName().endsWith(PATCH_EXTENSION)) {
|
|
||||||
processPatchEntry(entry);
|
|
||||||
} else {
|
|
||||||
extractLibraryFile(jarFile, entry, extractedFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extractLibraryFile(JarFile jarFile, JarEntry entry, File extractedFile) throws IOException {
|
|
||||||
File parentDir = extractedFile.getParentFile();
|
|
||||||
if (parentDir != null && !parentDir.exists()) {
|
|
||||||
parentDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream input = jarFile.getInputStream(entry);
|
|
||||||
FileOutputStream output = new FileOutputStream(extractedFile)) {
|
|
||||||
copyStream(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
addToClasspath(extractedFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processPatchEntry(JarEntry entry) throws IOException {
|
|
||||||
try (InputStream inputStream = LibraryLoader.class.getResourceAsStream(LIBRARIES_LIST_RESOURCE);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
|
||||||
|
|
||||||
if (inputStream == null) {
|
|
||||||
throw new IOException("Libraries list resource not found: " + LIBRARIES_LIST_RESOURCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
String entryDirectoryName = extractDirectoryName(entry.getName());
|
|
||||||
boolean foundArtifact = false;
|
|
||||||
String line;
|
|
||||||
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
LibraryInfo libraryInfo = parseLibraryLine(line);
|
|
||||||
if (libraryInfo == null) continue;
|
|
||||||
|
|
||||||
String libraryDirectoryName = extractDirectoryName(libraryInfo.jarPath);
|
|
||||||
|
|
||||||
if (entryDirectoryName.equalsIgnoreCase(libraryDirectoryName)) {
|
|
||||||
foundArtifact = true;
|
|
||||||
handleLibraryFromPatch(libraryInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundArtifact) {
|
|
||||||
String artifactName = extractArtifactName(entry.getName());
|
|
||||||
Logger.error("Unable to find library: " + artifactName);
|
|
||||||
throw new RuntimeException("Missing library: " + artifactName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractDirectoryName(String path) {
|
|
||||||
return path.replaceFirst("^" + LIBRARIES_PREFIX, "")
|
|
||||||
.replaceFirst("/[^/]+$", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractArtifactName(String entryName) {
|
|
||||||
String[] parts = entryName.split("/");
|
|
||||||
String fileName = parts[parts.length - 1];
|
|
||||||
return fileName.replace(PATCH_EXTENSION, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private LibraryInfo parseLibraryLine(String line) {
|
|
||||||
if (line == null || line.trim().isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] parts = line.split("\\s+");
|
|
||||||
if (parts.length < 3) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LibraryInfo(parts[1], parts[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleLibraryFromPatch(LibraryInfo libraryInfo) throws IOException {
|
|
||||||
File libraryFile = new File(LIBRARIES_DIR, libraryInfo.jarPath);
|
|
||||||
|
|
||||||
if (!libraryFile.exists()) {
|
|
||||||
File downloadedFile = downloadLibrary(libraryInfo.jarPath);
|
|
||||||
|
|
||||||
if (downloadedFile == null) {
|
|
||||||
throw new IOException("Failed to download missing library: " + libraryInfo.artifact);
|
|
||||||
}
|
|
||||||
|
|
||||||
libraryFile = downloadedFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
addToClasspath(libraryFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File downloadLibrary(String artifactPath) {
|
|
||||||
for (String repository : MAVEN_REPOSITORIES) {
|
|
||||||
try {
|
|
||||||
String downloadUrl = repository + artifactPath;
|
|
||||||
File downloadedFile = new File(LIBRARIES_DIR, artifactPath);
|
|
||||||
|
|
||||||
if (downloadFile(downloadUrl, downloadedFile)) {
|
|
||||||
return downloadedFile;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Continue trying other repositories
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean downloadFile(String urlString, File outputFile) {
|
|
||||||
try {
|
|
||||||
File parentDir = outputFile.getParentFile();
|
|
||||||
if (parentDir != null && !parentDir.exists()) {
|
|
||||||
parentDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
URL url = new URL(urlString);
|
|
||||||
URLConnection connection = url.openConnection();
|
|
||||||
connection.setConnectTimeout(30000);
|
|
||||||
connection.setReadTimeout(60000);
|
|
||||||
|
|
||||||
try (InputStream input = connection.getInputStream();
|
|
||||||
FileOutputStream output = new FileOutputStream(outputFile)) {
|
|
||||||
copyStream(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputFile.exists() && outputFile.length() > 0;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (outputFile.exists()) {
|
|
||||||
outputFile.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToClasspath(File jarFile) throws IOException {
|
|
||||||
try (JarFile jar = new JarFile(jarFile)) {
|
|
||||||
InstrumentationManager.getInstrumentation().appendToSystemClassLoaderSearch(jar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private record LibraryInfo(String artifact, String jarPath) { }
|
|
||||||
}
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
package org.bxteam.shuttle.patch;
|
|
||||||
|
|
||||||
import io.sigpipe.jbsdiff.InvalidHeaderException;
|
|
||||||
import io.sigpipe.jbsdiff.Patch;
|
|
||||||
import org.apache.commons.compress.compressors.CompressorException;
|
|
||||||
import org.bxteam.shuttle.Shuttle;
|
|
||||||
import org.bxteam.shuttle.logger.Logger;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
|
|
||||||
public class PatchBuilder {
|
|
||||||
private static final String CACHE_DIR = "cache";
|
|
||||||
private static final String VERSIONS_DIR = "versions";
|
|
||||||
private static final String META_INF_PREFIX = "/META-INF/";
|
|
||||||
private static final int BUFFER_SIZE = 8192;
|
|
||||||
|
|
||||||
private static String readResourceField(int index, String resourceName) {
|
|
||||||
final String resourcePath = META_INF_PREFIX + resourceName;
|
|
||||||
|
|
||||||
try (InputStream inputStream = PatchBuilder.class.getResourceAsStream(resourcePath);
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
|
||||||
|
|
||||||
if (inputStream == null) {
|
|
||||||
throw new IOException("Resource not found: " + resourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
String line = reader.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
throw new IOException("Empty resource file: " + resourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] parts = line.split("\\s+");
|
|
||||||
if (parts.length <= index) {
|
|
||||||
throw new IOException("Invalid resource format or index out of bounds: " + resourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts[index].trim();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Unable to read " + resourceName + " at index " + index, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String computeFileSha256(File file) throws NoSuchAlgorithmException, IOException {
|
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
|
||||||
|
|
||||||
try (FileInputStream fis = new FileInputStream(file);
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(fis)) {
|
|
||||||
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int bytesRead;
|
|
||||||
|
|
||||||
while ((bytesRead = bis.read(buffer)) != -1) {
|
|
||||||
digest.update(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] hashBytes = digest.digest();
|
|
||||||
StringBuilder hexString = new StringBuilder();
|
|
||||||
for (byte b : hashBytes) {
|
|
||||||
hexString.append(String.format("%02x", b));
|
|
||||||
}
|
|
||||||
|
|
||||||
return hexString.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(Shuttle.Provider<String> versionProvider) throws IOException {
|
|
||||||
try {
|
|
||||||
start(versionProvider.get());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Error during patch building process", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(String mcVersion) throws IOException {
|
|
||||||
if (mcVersion == null || mcVersion.trim().isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("Minecraft version cannot be null or empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.info("Loading Minecraft version " + mcVersion);
|
|
||||||
|
|
||||||
try {
|
|
||||||
createDirectories();
|
|
||||||
|
|
||||||
String sha256Hash = readResourceField(0, "download-context");
|
|
||||||
String vanillaUrl = readResourceField(1, "download-context");
|
|
||||||
|
|
||||||
Path vanillaBundler = downloadVanillaBundler(mcVersion, vanillaUrl, sha256Hash);
|
|
||||||
String patchedJarName = extractPatchedJarName();
|
|
||||||
|
|
||||||
applyPatches(mcVersion, vanillaBundler, patchedJarName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Failed to build patched jar for version " + mcVersion, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createDirectories() throws IOException {
|
|
||||||
Files.createDirectories(Paths.get(VERSIONS_DIR));
|
|
||||||
Files.createDirectories(Paths.get(CACHE_DIR));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path downloadVanillaBundler(String mcVersion, String vanillaUrl, String expectedSha256) throws IOException {
|
|
||||||
Path vanillaBundler = Paths.get(CACHE_DIR, "vanilla-bundler-" + mcVersion + ".jar");
|
|
||||||
|
|
||||||
boolean needsDownload = !Files.exists(vanillaBundler);
|
|
||||||
|
|
||||||
if (!needsDownload) {
|
|
||||||
try {
|
|
||||||
String actualSha256 = computeFileSha256(vanillaBundler.toFile());
|
|
||||||
needsDownload = !expectedSha256.equals(actualSha256);
|
|
||||||
if (needsDownload) {
|
|
||||||
Logger.info("SHA-256 mismatch, re-downloading vanilla jar");
|
|
||||||
}
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new IOException("SHA-256 algorithm not available", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsDownload) {
|
|
||||||
Logger.info("Downloading vanilla jar...");
|
|
||||||
downloadFile(vanillaUrl, vanillaBundler);
|
|
||||||
}
|
|
||||||
|
|
||||||
return vanillaBundler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads a file from a URL.
|
|
||||||
*/
|
|
||||||
private void downloadFile(String urlString, Path outputPath) throws IOException {
|
|
||||||
URL url = new URL(urlString);
|
|
||||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setRequestMethod("GET");
|
|
||||||
connection.setConnectTimeout(30000);
|
|
||||||
connection.setReadTimeout(60000);
|
|
||||||
|
|
||||||
try (BufferedInputStream in = new BufferedInputStream(connection.getInputStream());
|
|
||||||
FileOutputStream fos = new FileOutputStream(outputPath.toFile());
|
|
||||||
BufferedOutputStream out = new BufferedOutputStream(fos)) {
|
|
||||||
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = in.read(buffer)) != -1) {
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractPatchedJarName() {
|
|
||||||
String versionListEntry = readResourceField(2, "versions.list");
|
|
||||||
String[] parts = versionListEntry.split("/");
|
|
||||||
if (parts.length < 2) {
|
|
||||||
throw new RuntimeException("Invalid versions.list format");
|
|
||||||
}
|
|
||||||
return parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyPatches(String mcVersion, Path vanillaBundler, String patchedJarName) throws IOException {
|
|
||||||
Logger.info("Applying patches...");
|
|
||||||
|
|
||||||
Path vanillaJar = extractVanillaJar(mcVersion, vanillaBundler);
|
|
||||||
|
|
||||||
File patchFile = extractPatchFile(mcVersion);
|
|
||||||
|
|
||||||
Path outputJar = Paths.get(VERSIONS_DIR, mcVersion, patchedJarName);
|
|
||||||
Files.createDirectories(outputJar.getParent());
|
|
||||||
|
|
||||||
try {
|
|
||||||
applyPatch(vanillaJar.toFile(), patchFile, outputJar.toFile());
|
|
||||||
addToClasspath(outputJar.toFile());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException("Failed to apply patch", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path extractVanillaJar(String mcVersion, Path vanillaBundler) throws IOException {
|
|
||||||
Path vanillaJar = Paths.get(CACHE_DIR, "vanilla-" + mcVersion + ".jar");
|
|
||||||
|
|
||||||
try (JarFile jarFile = new JarFile(vanillaBundler.toFile())) {
|
|
||||||
JarEntry entry = jarFile.getJarEntry("META-INF/versions/" + mcVersion + "/server-" + mcVersion + ".jar");
|
|
||||||
|
|
||||||
if (entry == null) {
|
|
||||||
throw new IOException("Vanilla jar entry not found in bundler for version " + mcVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream inputStream = jarFile.getInputStream(entry)) {
|
|
||||||
Files.copy(inputStream, vanillaJar, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vanillaJar;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File extractPatchFile(String mcVersion) throws IOException {
|
|
||||||
String resourcePath = "/META-INF/versions/" + mcVersion + "/server-" + mcVersion + ".jar.patch";
|
|
||||||
return extractResourceToFile(resourcePath, CACHE_DIR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File extractResourceToFile(String resourcePath, String outputDir) throws IOException {
|
|
||||||
try (InputStream resourceStream = PatchBuilder.class.getResourceAsStream(resourcePath)) {
|
|
||||||
if (resourceStream == null) {
|
|
||||||
throw new IOException("Resource not found: " + resourcePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path outputDirectory = Paths.get(outputDir);
|
|
||||||
Files.createDirectories(outputDirectory);
|
|
||||||
|
|
||||||
String fileName = Paths.get(resourcePath).getFileName().toString();
|
|
||||||
Path outputPath = outputDirectory.resolve(fileName);
|
|
||||||
|
|
||||||
Files.copy(resourceStream, outputPath, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
return outputPath.toFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyPatch(File vanillaJar, File patchFile, File outputJar) throws IOException, CompressorException, InvalidHeaderException {
|
|
||||||
byte[] vanillaBytes = Files.readAllBytes(vanillaJar.toPath());
|
|
||||||
byte[] patchBytes = Files.readAllBytes(patchFile.toPath());
|
|
||||||
|
|
||||||
try (FileOutputStream outputStream = new FileOutputStream(outputJar)) {
|
|
||||||
Patch.patch(vanillaBytes, patchBytes, outputStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!outputJar.exists()) {
|
|
||||||
throw new IOException("Patched jar was not created successfully");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToClasspath(File jarFile) throws IOException {
|
|
||||||
try (JarFile jar = new JarFile(jarFile)) {
|
|
||||||
InstrumentationManager.getInstrumentation().appendToSystemClassLoaderSearch(jar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user