fix: Accidental hard dependency on sodium in mixins

This commit is contained in:
Linnea Gräf
2025-04-12 14:49:41 +02:00
parent a3b3ec6490
commit c3bf4a82a2
11 changed files with 256 additions and 109 deletions

View File

@@ -8,7 +8,6 @@
import com.google.common.hash.Hashing
import com.google.devtools.ksp.gradle.KspAATask
import com.google.devtools.ksp.gradle.KspTaskJvm
import com.google.gson.Gson
import com.google.gson.JsonObject
import moe.nea.licenseextractificator.LicenseDiscoveryTask
@@ -16,7 +15,6 @@ import moe.nea.mcautotranslations.gradle.CollectTranslations
import net.fabricmc.loom.LoomGradleExtension
import org.apache.tools.ant.taskdefs.condition.Os
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.nio.charset.StandardCharsets
import java.util.Base64
@@ -166,6 +164,7 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabl
extendsFrom(getByName(mainSS.annotationProcessorConfigurationName))
}
(mainSS.runtimeOnlyConfigurationName) {
if (isEnabled)
extendsFrom(getByName(ss.runtimeClasspathConfigurationName))
}
("ksp$upperName") {
@@ -173,6 +172,7 @@ fun createIsolatedSourceSet(name: String, path: String = "compat/$name", isEnabl
}
}
dependencies {
if (isEnabled)
runtimeOnly(ss.output)
(ss.implementationConfigurationName)(project.files(tasks.compileKotlin.map { it.destinationDirectory }))
(ss.implementationConfigurationName)(project.files(tasks.compileJava.map { it.destinationDirectory }))
@@ -337,6 +337,7 @@ loom {
File(it.output.classesDirs.asPath).absolutePath
})
property("mixin.debug.export", "true")
property("mixin.debug", "true")
parseEnvFile(file(".env")).forEach { (t, u) ->
environmentVariable(t, u)

View File

@@ -15,11 +15,13 @@ import java.util.stream.Collectors;
public class MixinPlugin implements IMixinConfigPlugin {
AutoDiscoveryPlugin autoDiscoveryPlugin = new AutoDiscoveryPlugin();
public static String mixinPackage;
public static List<MixinPlugin> instances = new ArrayList<>();
public String mixinPackage;
@Override
public void onLoad(String mixinPackage) {
MixinExtrasBootstrap.init();
MixinPlugin.mixinPackage = mixinPackage;
instances.add(this);
this.mixinPackage = mixinPackage;
autoDiscoveryPlugin.setMixinPackage(mixinPackage);
}
@@ -52,7 +54,7 @@ public class MixinPlugin implements IMixinConfigPlugin {
}
public static List<String> appliedMixins = new ArrayList<>();
public List<String> appliedMixins = new ArrayList<>();
@Override
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {

View File

@@ -5,6 +5,7 @@ import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.block.BlockRenderManager;
import net.minecraft.client.render.chunk.SectionBuilder;
import net.minecraft.client.render.model.BlockStateModel;
import net.minecraft.util.math.BlockPos;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@@ -26,8 +27,8 @@ public class SectionBuilderRiser extends RiserUtils {
String BlockRenderManager;
@IntermediaryName(BlockState.class)
String BlockState;
// @IntermediaryName(BakedModel.class)
// String BakedModel;
@IntermediaryName(BlockStateModel.class)
String BlockStateModel;
String CustomBlockTextures = "moe.nea.firmament.features.texturepack.CustomBlockTextures";
Type getModelDesc = Type.getMethodType(
@@ -39,8 +40,7 @@ public class SectionBuilderRiser extends RiserUtils {
Intermediary.<BlockRenderManager>className(),
Intermediary.methodName(net.minecraft.client.render.block.BlockRenderManager::getModel),
Type.getMethodDescriptor(
// TODO: fix this riser
// getTypeForClassName(Intermediary.<BakedModel>className()),
getTypeForClassName(Intermediary.<BlockStateModel>className()),
getTypeForClassName(Intermediary.<BlockState>className())
)
);
@@ -52,6 +52,7 @@ public class SectionBuilderRiser extends RiserUtils {
}
private void handle(ClassNode classNode) {
System.out.println("AVAST! "+ getModel);
for (MethodNode method : classNode.methods) {
if ((method.name.endsWith("$fabric-renderer-indigo$hookBuildRenderBlock")
|| method.name.endsWith("$fabric-renderer-indigo$hookChunkBuildTessellate")) &&
@@ -105,8 +106,8 @@ public class SectionBuilderRiser extends RiserUtils {
getTypeForClassName(CustomBlockTextures).getInternalName(),
"patchIndigo",
Type.getMethodDescriptor(
// getTypeForClassName(BakedModel),
// getTypeForClassName(BakedModel),
getTypeForClassName(BlockStateModel),
getTypeForClassName(BlockStateModel),
getTypeForClassName(BlockPos),
getTypeForClassName(BlockState)),
false

View File

@@ -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

View File

@@ -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,15 +314,17 @@ fun firmamentCommand() = literal("firmament") {
}
thenLiteral("mixins") {
thenExecute {
source.sendFeedback(Text.translatable("firmament.mixins.start"))
MixinPlugin.appliedMixins
.map { it.removePrefix(MixinPlugin.mixinPackage) }
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") {
thenExecute {
source.sendFeedback(tr("firmament.repo.info.ref", "Repo Upstream: ${RepoManager.getRepoRef()}"))

View File

@@ -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

View 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
}
}

View File

@@ -316,6 +316,15 @@ object CustomBlockTextures {
)
}
/**
* Used by [moe.nea.firmament.init.SectionBuilderRiser]
*/
@JvmStatic
fun patchIndigo(original: BlockStateModel, pos: BlockPos?, state: BlockState): BlockStateModel {
return getReplacementModel(state, pos) ?: original
}
@JvmStatic
fun collectExtraModels(modelsCollector: ReferencedModelsCollector) {
preparationFuture.join().collectAllReplacements()

View File

@@ -26,7 +26,6 @@ public class PatchLegacyTexturePathsIntoArmorLayers {
// legacy format: "assets/{identifier.namespace}/textures/models/armor/{identifier.path}_layer_{isLegs ? 2 : 1}{suffix}.png"
// suffix is sadly not available to us here. this means leather armor will look a bit shite
var legacyIdentifier = this.textureId.withPath((textureName) -> {
String var10000 = layerType.asString();
return "textures/models/armor/" + textureName + "_layer_" +
(layerType == EquipmentModel.LayerType.HUMANOID_LEGGINGS ? 2 : 1)
+ ".png";

View File

@@ -26,7 +26,7 @@ public class ReplaceItemModelPatch implements IntrospectableItemModelManager {
private Function<Identifier, ItemModel> modelGetter;
@WrapOperation(
method = "update(Lnet/minecraft/client/render/item/ItemRenderState;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ModelTransformationMode;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;I)V",
method = "update",
at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;get(Lnet/minecraft/component/ComponentType;)Ljava/lang/Object;"))
private Object replaceItemModelByIdentifier(ItemStack instance, ComponentType componentType, Operation<Object> original) {
var override = CustomItemModelEvent.getModelIdentifier(instance, this);

View File

@@ -301,7 +301,6 @@
"firmament.inventory-buttons.save-preset": "Save Preset",
"firmament.key.category": "Firmament",
"firmament.keybinding.external": "%s",
"firmament.mixins.start": "Applied firmament mixins:",
"firmament.modapi.event": "Received mod API event: %s",
"firmament.poweruser.entity.armor": "Entity Armor:",
"firmament.poweruser.entity.armor.item": " - %s",