fix: Accidental hard dependency on sodium in mixins
This commit is contained in:
@@ -26,6 +26,7 @@ import net.fabricmc.loader.api.Version
|
||||
import net.fabricmc.loader.api.metadata.ModMetadata
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import org.spongepowered.asm.launch.MixinBootstrap
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
@@ -262,7 +262,8 @@ fun firmamentCommand() = literal("firmament") {
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.gametype", locrawInfo.gametype))
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.mode", locrawInfo.mode))
|
||||
source.sendFeedback(Text.stringifiedTranslatable("firmament.sbinfo.map", locrawInfo.map))
|
||||
source.sendFeedback(tr("firmament.sbinfo.custommining", "Custom Mining: ${formatBool(locrawInfo.skyblockLocation?.hasCustomMining ?: false)}"))
|
||||
source.sendFeedback(tr("firmament.sbinfo.custommining",
|
||||
"Custom Mining: ${formatBool(locrawInfo.skyblockLocation?.hasCustomMining ?: false)}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -313,13 +314,15 @@ fun firmamentCommand() = literal("firmament") {
|
||||
}
|
||||
thenLiteral("mixins") {
|
||||
thenExecute {
|
||||
source.sendFeedback(Text.translatable("firmament.mixins.start"))
|
||||
MixinPlugin.appliedMixins
|
||||
.map { it.removePrefix(MixinPlugin.mixinPackage) }
|
||||
.forEach {
|
||||
source.sendFeedback(Text.literal(" - ").withColor(0xD020F0)
|
||||
.append(Text.literal(it).withColor(0xF6BA20)))
|
||||
}
|
||||
MixinPlugin.instances.forEach { plugin ->
|
||||
source.sendFeedback(tr("firmament.mixins.start.package", "Mixins (base ${plugin.mixinPackage}):"))
|
||||
plugin.appliedMixins
|
||||
.map { it.removePrefix(plugin.mixinPackage) }
|
||||
.forEach {
|
||||
source.sendFeedback(Text.literal(" - ").withColor(0xD020F0)
|
||||
.append(Text.literal(it).withColor(0xF6BA20)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
thenLiteral("repo") {
|
||||
|
||||
@@ -3,6 +3,10 @@ package moe.nea.firmament.features.debug
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.spongepowered.asm.mixin.Mixin
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import kotlin.io.path.absolute
|
||||
import kotlin.io.path.exists
|
||||
@@ -10,11 +14,14 @@ import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.Firmament
|
||||
import moe.nea.firmament.annotations.Subscribe
|
||||
import moe.nea.firmament.events.DebugInstantiateEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
import moe.nea.firmament.init.MixinPlugin
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.TimeMark
|
||||
import moe.nea.firmament.util.asm.AsmAnnotationUtil
|
||||
import moe.nea.firmament.util.iterate
|
||||
|
||||
object DeveloperFeatures : FirmamentFeature {
|
||||
@@ -41,6 +48,42 @@ object DeveloperFeatures : FirmamentFeature {
|
||||
this.missingTranslations = missingTranslations
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun loadAllMixinClasses(event: DebugInstantiateEvent) {
|
||||
val allMixinClasses = mutableSetOf<String>()
|
||||
MixinPlugin.instances.forEach { plugin ->
|
||||
val prefix = plugin.mixinPackage + "."
|
||||
val classes = plugin.mixins.map { prefix + it }
|
||||
allMixinClasses.addAll(classes)
|
||||
for (cls in classes) {
|
||||
val targets = javaClass.classLoader.getResourceAsStream("${cls.replace(".", "/")}.class").use {
|
||||
val node = ClassNode()
|
||||
ClassReader(it).accept(node, 0)
|
||||
val mixins = mutableListOf<Mixin>()
|
||||
(node.visibleAnnotations.orEmpty() + node.invisibleAnnotations.orEmpty()).forEach {
|
||||
val annotationType = Type.getType(it.desc)
|
||||
val mixinType = Type.getType(Mixin::class.java)
|
||||
if (mixinType == annotationType) {
|
||||
mixins.add(AsmAnnotationUtil.createProxy(Mixin::class.java, it))
|
||||
}
|
||||
}
|
||||
mixins.flatMap { it.targets.toList() } + mixins.flatMap { it.value.map { it.java.name } }
|
||||
}
|
||||
for (target in targets)
|
||||
try {
|
||||
Firmament.logger.debug("Loading ${target} to force instantiate ${cls}")
|
||||
Class.forName(target, true, javaClass.classLoader)
|
||||
} catch (ex: Throwable) {
|
||||
Firmament.logger.error("Could not load class ${target} that has been mixind by $cls", ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
Firmament.logger.info("Forceloaded all Firmament mixins:")
|
||||
val applied = MixinPlugin.instances.flatMap { it.appliedMixins }.toSet()
|
||||
applied.forEach { Firmament.logger.info(" - ${it}") }
|
||||
require(allMixinClasses == applied)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun dumpMissingTranslations(tickEvent: TickEvent) {
|
||||
val toDump = missingTranslations ?: return
|
||||
|
||||
89
src/main/kotlin/util/asm/AsmAnnotationUtil.kt
Normal file
89
src/main/kotlin/util/asm/AsmAnnotationUtil.kt
Normal file
@@ -0,0 +1,89 @@
|
||||
package moe.nea.firmament.util.asm
|
||||
|
||||
import com.google.common.base.Defaults
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Proxy
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.AnnotationNode
|
||||
|
||||
object AsmAnnotationUtil {
|
||||
class AnnotationProxy(
|
||||
val originalType: Class<out Annotation>,
|
||||
val annotationNode: AnnotationNode,
|
||||
) : InvocationHandler {
|
||||
val offsets = annotationNode.values.withIndex()
|
||||
.chunked(2)
|
||||
.map { it.first() }
|
||||
.associate { (idx, value) -> value as String to idx + 1 }
|
||||
|
||||
fun nestArrayType(depth: Int, comp: Class<*>): Class<*> =
|
||||
if (depth == 0) comp
|
||||
else java.lang.reflect.Array.newInstance(nestArrayType(depth - 1, comp), 0).javaClass
|
||||
|
||||
fun unmap(
|
||||
value: Any?,
|
||||
comp: Class<*>,
|
||||
depth: Int,
|
||||
): Any? {
|
||||
value ?: return null
|
||||
if (depth > 0)
|
||||
return ((value as List<Any>)
|
||||
.map { unmap(it, comp, depth - 1) } as java.util.List<Any>)
|
||||
.toArray(java.lang.reflect.Array.newInstance(nestArrayType(depth - 1, comp), 0) as Array<*>)
|
||||
if (comp.isEnum) {
|
||||
comp as Class<out Enum<*>>
|
||||
when (value) {
|
||||
is String -> return java.lang.Enum.valueOf(comp, value)
|
||||
is List<*> -> return java.lang.Enum.valueOf(comp, value[1] as String)
|
||||
else -> error("Unknown enum variant $value for $comp")
|
||||
}
|
||||
}
|
||||
when (value) {
|
||||
is Type -> return Class.forName(value.className)
|
||||
is AnnotationNode -> return createProxy(comp as Class<out Annotation>, value)
|
||||
is String, is Boolean, is Byte, is Double, is Int, is Float, is Long, is Short, is Char -> return value
|
||||
}
|
||||
error("Unknown enum variant $value for $comp")
|
||||
}
|
||||
|
||||
fun defaultFor(fullType: Class<*>): Any? {
|
||||
if (fullType.isArray) return java.lang.reflect.Array.newInstance(fullType.componentType, 0)
|
||||
if (fullType.isPrimitive) {
|
||||
return Defaults.defaultValue(fullType)
|
||||
}
|
||||
if (fullType == String::class.java)
|
||||
return ""
|
||||
return null
|
||||
}
|
||||
|
||||
override fun invoke(
|
||||
proxy: Any,
|
||||
method: Method,
|
||||
args: Array<out Any?>?
|
||||
): Any? {
|
||||
val name = method.name
|
||||
val ret = method.returnType
|
||||
val retU = generateSequence(ret) { if (it.isArray) it.componentType else null }
|
||||
.toList()
|
||||
val arrayDepth = retU.size - 1
|
||||
val componentType = retU.last()
|
||||
|
||||
val off = offsets[name]
|
||||
if (off == null) {
|
||||
return defaultFor(ret)
|
||||
}
|
||||
return unmap(annotationNode.values[off], componentType, arrayDepth)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Annotation> createProxy(
|
||||
annotationClass: Class<T>,
|
||||
annotationNode: AnnotationNode
|
||||
): T {
|
||||
require(Type.getType(annotationClass) == Type.getType(annotationNode.desc))
|
||||
return Proxy.newProxyInstance(javaClass.classLoader,
|
||||
arrayOf(annotationClass),
|
||||
AnnotationProxy(annotationClass, annotationNode)) as T
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user