This commit is contained in:
bbldrizzy committed 2026-10-23 00:28:57 +01:00
1 parent 83aea53e57
commit aa4f6b6ddc
842 files changed
+47284 -91563

No files matched your search

@@ -0,0 +1,118 @@
package dev.zprestige.prestige.inject;
import dev.zprestige.prestige.client.Prestige;
import dev.zprestige.prestige.engine.EnginePlugin;
import dev.zprestige.prestige.engine.EngineState;
import dev.zprestige.prestige.hooks.Definer;
import dev.zprestige.prestige.ui.mc.Entry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.ToIntBiFunction;
import net.fabricmc.loader.api.FabricLoader;
import net.lenni0451.classtransform.TransformerManager;
import net.minecraft.client.MinecraftClient;
/**
* Entry point of the injected payload. prestige_native.dll appends this jar to the Fabric (Knot) class path, registers the
* {@link NativeBridge} natives and calls {@link #start()}. Everything Fabric would normally do at launch for the Prestige mod
* (Mixin anchors, entrypoints) is done here instead: the ClassTransform hooks are applied to the loaded classes with
* {@link InPlaceTransformer} + JVMTI redefinition, then the mod entrypoints run on the client thread.
*/
public final class Bootstrap {
private static boolean started;
private Bootstrap() {}
/** Called by the native loader on its worker thread once Minecraft is up. */
public static synchronized void start() {
if (started) return;
started = true;
try {
log("waiting for the Minecraft client");
waitForClient();
Report report = install(NativeBridge::classBytes, NativeBridge::redefine);
log("hooks installed: " + report.redefined + " classes, " + report.moved + " handlers moved" + (report.failed.isEmpty() ? "" : ", FAILED " + report.failed));
if (!report.failed.isEmpty()) throw new IllegalStateException("could not hook " + report.failed);
log("initialising Prestige on the client thread");
MinecraftClient.getInstance().execute(Bootstrap::initClient);
} catch (Throwable t) {
log("start failed: " + t);
t.printStackTrace(System.out);
}
}
/** The loader may inject while the game is still starting: wait until the client and its window exist. */
private static void waitForClient() throws InterruptedException {
for (int i = 0; i < 6000; i++) {
MinecraftClient client = MinecraftClient.getInstance();
if (client != null && client.getWindow() != null) return;
Thread.sleep(50);
}
throw new IllegalStateException("Minecraft client did not start");
}
public static final class Report {
public int redefined, moved;
public final List<String> failed = new ArrayList<>();
}
/**
* Applies all injection-mode hooks. The byte source and the redefiner are parameters so the transformation can be exercised
* without the native library.
*/
public static Report install(Function<Class<?>, byte[]> classBytes, ToIntBiFunction<Class<?>, byte[]> redefine) throws Exception {
String namespace = FabricLoader.getInstance().getMappingResolver().getCurrentRuntimeNamespace();
List<String> transformers = new ArrayList<>(EnginePlugin.lines("prestige-engine/transformers.list"));
transformers.addAll(EnginePlugin.lines("prestige-engine/inject-transformers.list"));
TransformerManager manager = EnginePlugin.createManager(namespace, transformers);
ClassLoader loader = Bootstrap.class.getClassLoader();
InPlaceTransformer transformer = new InPlaceTransformer(manager, loader);
EngineState.installed = true;
Report report = new Report();
int total = manager.getTransformedClasses().size(), done = 0;
log("transforming " + total + " hook targets");
for (String target : manager.getTransformedClasses()) {
if (done > 0 && done % 10 == 0) log("transformed " + done + "/" + total);
done++;
try {
Class<?> type = Class.forName(target, false, loader);
byte[] current = classBytes.apply(type);
if (current == null) throw new IllegalStateException("no class bytes");
InPlaceTransformer.Result result = transformer.transform(target, current);
for (byte[] helper : result.helpers().values()) Definer.define(helper);
int code = redefine.applyAsInt(type, result.target());
if (code != 0) throw new IllegalStateException("redefine returned JVMTI error " + code);
report.redefined++;
report.moved += result.movedMethods();
} catch (Throwable t) {
report.failed.add(target);
log("hook failed for " + target + ": " + t);
t.printStackTrace(System.out);
}
}
return report;
}
private static void initClient() {
try {
new Prestige().onInitialize();
new Entry().onInitializeClient();
log("client initialised");
} catch (Throwable t) {
log("client init failed: " + t);
t.printStackTrace(System.out);
}
}
private static void log(String message) {
System.out.println("[Prestige-Inject] " + message);
try {
NativeBridge.log(message);
} catch (UnsatisfiedLinkError ignored) {
// not injected (dev run): the console line above is enough
}
}
}