Created
January 27, 2020 16:28
-
-
Save comp500/7b5dc81981751cbc32d9fac707dd682b to your computer and use it in GitHub Desktop.
Cursed classloader magic (why load fabric from java when you can load fabric from fabric???)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package link.infra.borderlessmining; | |
import net.fabricmc.api.ClientModInitializer; | |
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; | |
import net.fabricmc.loader.discovery.ModResolver; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.net.URL; | |
import java.net.URLClassLoader; | |
import java.nio.file.FileSystem; | |
import java.util.HashMap; | |
public class BorderlessMining implements ClientModInitializer, PreLaunchEntrypoint { | |
@Override | |
public void onInitializeClient() { | |
// TODO: is anything needed here? | |
} | |
private static class AlreadyJumpedFlag { | |
public AlreadyJumpedFlag() {} | |
} | |
private static class FunkyClassLoader extends URLClassLoader { | |
public FunkyClassLoader(URL[] urls) { | |
super(urls, getSystemClassLoader()); | |
} | |
private HashMap<String, Class<?>> cachedClasses = new HashMap<>(); | |
// kinda quirky hack i found in the depths of stack overflow | |
@Override | |
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { | |
// if (!name.contains("net.fabricmc.loader") && !name.contains("org.spongepowered.asm")) { | |
// System.out.println(name + " delegating to parent"); | |
// } else { | |
// System.out.println(name + " funky hacking"); | |
// } | |
//if (!name.contains("net.fabricmc.loader") && !name.contains("org.spongepowered.asm")) return super.loadClass(name, resolve); | |
if (name.startsWith("java") || name.startsWith("sun") || name.startsWith("org.xml") || name.startsWith("org.w3c")) return super.loadClass(name, resolve); | |
Class<?> cachedClass = cachedClasses.get(name); | |
if (cachedClass != null) { | |
return cachedClass; | |
} | |
InputStream classStream = getResourceAsStream(name.replace('.', '/') + ".class"); | |
if (classStream == null) { | |
return null; | |
} | |
ByteArrayOutputStream result = new ByteArrayOutputStream(); | |
try { | |
byte[] buffer = new byte[1024]; | |
int length; | |
while ((length = classStream.read(buffer)) != -1) { | |
result.write(buffer, 0, length); | |
} | |
} catch (IOException e) { | |
return null; | |
} | |
byte[] resultBytes = result.toByteArray(); | |
//System.out.println(result.toString()); | |
Class<?> newClass = defineClass(name, resultBytes,0, resultBytes.length, getClass().getProtectionDomain().getCodeSource()); | |
if (resolve) { | |
resolveClass(newClass); | |
} | |
cachedClasses.put(name, newClass); | |
return newClass; | |
} | |
} | |
@Override | |
public void onPreLaunch() { | |
if ("infinity".equals(System.getProperty("bm.jumpyhax"))) { | |
System.out.println("Jumpy hax done!!!"); | |
return; | |
} | |
System.setProperty("bm.jumpyhax", "infinity"); | |
System.out.println("Jumpy hax time!!!"); | |
// Attempt to close the current in-memory file system for jar-in-jars | |
try { | |
Field jimfs = ModResolver.class.getDeclaredField("inMemoryFs"); | |
jimfs.setAccessible(true); | |
FileSystem fs = (FileSystem) jimfs.get(null); | |
fs.close(); | |
} catch (NoSuchFieldException | IllegalAccessException | IOException e) { | |
e.printStackTrace(); | |
} | |
//ClassLoader parent = BorderlessMining.class.getClassLoader(); | |
URLClassLoader newLoader = new FunkyClassLoader(new URL[0]); | |
Thread.currentThread().setContextClassLoader(newLoader); | |
Class<?> knotClient = null; | |
try { | |
knotClient = newLoader.loadClass("net.fabricmc.loader.launch.knot.KnotClient"); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} | |
if (knotClient != null) { | |
try { | |
Method main = knotClient.getMethod("main", String[].class); | |
main.invoke(null, new Object[] {new String[0]}); | |
} catch (NoSuchMethodException | IllegalAccessException e) { | |
e.printStackTrace(); | |
} catch (InvocationTargetException e) { | |
e.getTargetException().printStackTrace(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment