update
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownSettings">
|
||||
<option name="previewPanelProviderInfo">
|
||||
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@@ -10,11 +10,9 @@ import net.bytebuddy.description.method.*
|
||||
import net.bytebuddy.asm.Advice
|
||||
import java.lang.instrument.*
|
||||
import java.util.jar.JarFile
|
||||
import java.nio.file.Path
|
||||
import java.io.File
|
||||
|
||||
@Suppress("unused") object Agent {
|
||||
private const val KNOT = "net.fabricmc.loader.impl.launch.knot"
|
||||
@JvmStatic fun premain(args: String?, inst: Instrumentation?) = attach(inst!!)
|
||||
@JvmStatic fun agentmain(args: String?, inst: Instrumentation?) = attach(inst!!)
|
||||
val injections = listOf(Tick::class, Render::class, Gui::class)
|
||||
@@ -32,27 +30,11 @@ import java.io.File
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKnotDelegate(): Any? {
|
||||
val base = Class.forName("$KNOT.KnotClassLoader")
|
||||
val delegate = base.getDeclaredField("delegate")
|
||||
val threads = Thread.getAllStackTraces().keys
|
||||
val loaders = threads.mapNotNull { it.contextClassLoader }
|
||||
val knot = loaders.firstOrNull { it.javaClass == base }
|
||||
return delegate.apply { isAccessible = true }.get(knot)
|
||||
}
|
||||
|
||||
private fun exposeToKnot(jar: Path) {
|
||||
val delegate = getKnotDelegate()
|
||||
val base = Class.forName("$KNOT.KnotClassDelegate")
|
||||
val source = base.getMethod("addCodeSource", Path::class.java)
|
||||
source.apply { isAccessible = true }.invoke(delegate, jar)
|
||||
}
|
||||
|
||||
private fun attach(inst: Instrumentation) {
|
||||
val domain = Client::class.java.protectionDomain
|
||||
val location = File(domain.codeSource.location.toURI())
|
||||
inst.appendToSystemClassLoaderSearch(JarFile(location))
|
||||
runCatching { exposeToKnot(location.toPath()) }
|
||||
Knot(location.toPath()).register(inst)
|
||||
|
||||
var builder: AgentBuilder = Default()
|
||||
builder = builder.disableClassFormatChanges()
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package dev.zerozipp.loader
|
||||
|
||||
import java.lang.instrument.*
|
||||
import java.security.ProtectionDomain
|
||||
import java.nio.file.Path
|
||||
|
||||
class Knot(private val jar: Path) : ClassFileTransformer {
|
||||
private val knot = "net.fabricmc.loader.impl.launch.knot"
|
||||
private var registry = mutableSetOf<Instrumentation>()
|
||||
override fun transform(classLoader: ClassLoader, className: String,
|
||||
redefined: Class<*>, domain: ProtectionDomain, bytes: ByteArray
|
||||
): ByteArray? = null.also { load(classLoader) }
|
||||
|
||||
fun register(inst: Instrumentation) {
|
||||
val result = runCatching { expose(jar) }
|
||||
if(result.isSuccess) return
|
||||
inst.addTransformer(this)
|
||||
registry.add(inst)
|
||||
}
|
||||
|
||||
private fun delegate() = run {
|
||||
val base = Class.forName("$knot.KnotClassLoader")
|
||||
val delegate = base.getDeclaredField("delegate")
|
||||
val threads = Thread.getAllStackTraces().keys
|
||||
val loaders = threads.mapNotNull { it.contextClassLoader }
|
||||
val knot = loaders.firstOrNull { it.javaClass == base }
|
||||
delegate.apply { isAccessible = true }.get(knot)
|
||||
}
|
||||
|
||||
private fun expose(jar: Path) = delegate().let {
|
||||
val base = Class.forName("$knot.KnotClassDelegate")
|
||||
val source = base.getMethod("addCodeSource", Path::class.java)
|
||||
source.apply { isAccessible = true }.invoke(it, jar)
|
||||
}
|
||||
|
||||
private fun load(loader: ClassLoader) {
|
||||
val knotLoader = "$knot.KnotClassLoader"
|
||||
if(loader.javaClass.name != knotLoader) return
|
||||
registry.forEach { it.removeTransformer(this) }
|
||||
runCatching { expose(jar) }
|
||||
registry.clear()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user