diff --git a/gradle.properties b/gradle.properties index c02ac5ea..423f4eb0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,16 +4,16 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=true # Versions -versionConnector=1.0.0-beta.34 -versionAdapter=1.11.12-1.20.1-20240124.174344 -versionAdapterDefinition=1.11.12 +versionConnector=1.0.0-beta.35 +versionAdapter=1.11.19-1.20.1-20240126.215012 +versionAdapterDefinition=1.11.22 versionMc=1.20.1 versionForge=47.1.3 versionForgeAutoRenamingTool=1.0.9 versionFabricLoader=2.7.1+0.15.3+1.20.1 versionAccessWidener=2.1.0 -versionFabricApi=0.90.7+1.10.3+1.20.1 +versionFabricApi=0.91.0+1.10.8+1.20.1 versionMixin=0.12.5+mixin.0.8.5 versionMixinTransmog=0.4.3+1.20.1 diff --git a/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java b/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java index 1c61db84..5f2e9567 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java +++ b/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java @@ -1,5 +1,6 @@ package dev.su5ed.sinytra.connector.locator; +import com.google.common.base.Suppliers; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.Multimap; @@ -35,6 +36,7 @@ import java.util.Map; import java.util.Objects; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -43,7 +45,7 @@ public final class DependencyResolver { private static final Logger LOGGER = LogUtils.getLogger(); public static final VersionOverrides VERSION_OVERRIDES = new VersionOverrides(); - public static final DependencyOverrides DEPENDENCY_OVERRIDES = new DependencyOverrides(FMLPaths.CONFIGDIR.get()); + public static final Supplier DEPENDENCY_OVERRIDES = Suppliers.memoize(DependencyResolver::loadDependencyOverrides); private static final GlobalModAliases GLOBAL_MOD_ALIASES = new GlobalModAliases(FMLPaths.CONFIGDIR.get(), ConnectorUtil.DEFAULT_GLOBAL_MOD_ALIASES); public static List resolveDependencies(Collection keys, Multimap jars, Iterable loadedMods) { @@ -100,7 +102,7 @@ private static ModCandidate createJavaMod() { .build(); GameProvider.BuiltinMod builtinMod = new GameProvider.BuiltinMod(Collections.singletonList(Paths.get(System.getProperty("java.home"))), metadata); - return ModCandidate.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES); + return ModCandidate.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES.get()); } private static ModCandidate createFabricLoaderMod() { @@ -125,6 +127,14 @@ private static ModCandidate createFabricLoaderMod() { GameProvider.BuiltinMod builtinMod = new GameProvider.BuiltinMod(Collections.singletonList(Path.of(uncheck(() -> FabricLoader.class.getProtectionDomain().getCodeSource().getLocation().toURI()))), metadata); - return ModCandidate.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES); + return ModCandidate.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES.get()); + } + + private static DependencyOverrides loadDependencyOverrides() { + try { + return new DependencyOverrides(FMLPaths.CONFIGDIR.get()); + } catch (Exception e) { + throw ConnectorEarlyLoader.createGenericLoadingException(e, "Invalid config file fabric_loader_dependencies.json"); + } } } diff --git a/src/main/java/dev/su5ed/sinytra/connector/service/ConnectorPreLaunchPlugin.java b/src/main/java/dev/su5ed/sinytra/connector/service/ConnectorPreLaunchPlugin.java index 700a11df..3adceaba 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/service/ConnectorPreLaunchPlugin.java +++ b/src/main/java/dev/su5ed/sinytra/connector/service/ConnectorPreLaunchPlugin.java @@ -26,10 +26,10 @@ public String name() { public void initializeLaunch(ITransformerLoader transformerLoader, NamedPath[] specialPaths) { // Apply provider inheritance fix from newer SJH versions ServiceProviderInheritanceWorkaround.apply(); - // Decorate mixin config's with mod IDs, enabling method prefix functionality - FabricMixinBootstrap.init(); // Setup Fabric Loader ConnectorEarlyLoader.init(); + // Decorate mixin config's with mod IDs, enabling method prefix functionality + FabricMixinBootstrap.init(); // Apply Fabric ASM fix FabricASMFixer.injectMinecraftModuleReader(); } diff --git a/src/main/java/dev/su5ed/sinytra/connector/transformer/jar/JarTransformer.java b/src/main/java/dev/su5ed/sinytra/connector/transformer/jar/JarTransformer.java index 4d79527a..644b43bc 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/transformer/jar/JarTransformer.java +++ b/src/main/java/dev/su5ed/sinytra/connector/transformer/jar/JarTransformer.java @@ -176,7 +176,7 @@ private static FabricModFileMetadata readModMetadata(File input) throws IOExcept ConnectorLoaderModMetadata metadata; Set configs; try (InputStream ins = jarFile.getInputStream(jarFile.getEntry(ConnectorUtil.FABRIC_MOD_JSON))) { - LoaderModMetadata rawMetadata = ModMetadataParser.parseMetadata(ins, "", Collections.emptyList(), DependencyResolver.VERSION_OVERRIDES, DependencyResolver.DEPENDENCY_OVERRIDES, false); + LoaderModMetadata rawMetadata = ModMetadataParser.parseMetadata(ins, "", Collections.emptyList(), DependencyResolver.VERSION_OVERRIDES, DependencyResolver.DEPENDENCY_OVERRIDES.get(), false); metadata = new ConnectorLoaderModMetadata(rawMetadata); configs = new HashSet<>(metadata.getMixinConfigs(FabricLoader.getInstance().getEnvironmentType())); diff --git a/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java b/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java index e2639f19..2d071d76 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java +++ b/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java @@ -2,6 +2,7 @@ import dev.su5ed.sinytra.adapter.patch.analysis.MethodCallAnalyzer; import dev.su5ed.sinytra.adapter.patch.api.Patch; +import dev.su5ed.sinytra.adapter.patch.util.MethodQualifier; import dev.su5ed.sinytra.connector.transformer.jar.IntermediateMapping; import net.minecraftforge.srgutils.IMappingFile; import org.jetbrains.annotations.Nullable; @@ -15,12 +16,13 @@ import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; -import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; public class ClassAnalysingTransformer implements ClassNodeTransformer.ClassProcessor { + private static final MethodQualifier GET_RESOURCE_AS_STREAM = new MethodQualifier("Ljava/lang/Class;", "getResourceAsStream", "(Ljava/lang/String;)Ljava/io/InputStream;"); + private final IMappingFile mappings; private final IntermediateMapping fastMappings; @@ -29,19 +31,18 @@ public ClassAnalysingTransformer(IMappingFile mappings, IntermediateMapping fast this.fastMappings = fastMappings; } - record Replacement(MethodInsnNode methodInsn, AbstractInsnNode paramInsn) {} - @Override public Patch.Result process(ClassNode node) { boolean applied = false; for (MethodNode method : node.methods) { ScanningSourceInterpreter i = MethodCallAnalyzer.analyzeInterpretMethod(method, new ScanningSourceInterpreter(Opcodes.ASM9)); - applied |= i.remapApplied(); - for (Replacement replacement : i.getReplacements()) { - method.instructions.insert(replacement.paramInsn, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;")); - replacement.methodInsn.owner = "java/lang/ClassLoader"; - applied = true; + + for (AbstractInsnNode insn : method.instructions) { + if (insn instanceof MethodInsnNode minsn && GET_RESOURCE_AS_STREAM.matches(minsn)) { + method.instructions.set(insn, new MethodInsnNode(Opcodes.INVOKESTATIC, "dev/su5ed/sinytra/connector/mod/ConnectorMod", "getModResourceAsStream", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/io/InputStream;", false)); + applied = true; + } } } return applied ? Patch.Result.APPLY : Patch.Result.PASS; @@ -49,7 +50,6 @@ public Patch.Result process(ClassNode node) { private class ScanningSourceInterpreter extends SourceInterpreter { private static final Type STR_TYPE = Type.getType(String.class); - private final List replacements = new ArrayList<>(); private final Collection seen = new HashSet<>(); private boolean remapApplied = false; @@ -61,24 +61,9 @@ public boolean remapApplied() { return this.remapApplied; } - public List getReplacements() { - return this.replacements; - } - @Override public SourceValue naryOperation(AbstractInsnNode insn, List values) { if (insn instanceof MethodInsnNode methodInsn && !this.seen.contains(methodInsn)) { - if (methodInsn.owner.equals("java/lang/Class") && methodInsn.name.equals("getResourceAsStream") && methodInsn.desc.equals("(Ljava/lang/String;)Ljava/io/InputStream;")) { - SourceValue value = values.get(0); - if (value.insns.size() == 1) { - AbstractInsnNode sourceInsn = value.insns.iterator().next(); - this.replacements.add(new Replacement(methodInsn, sourceInsn)); - this.seen.add(methodInsn); - } - else { - throw new IllegalStateException("Got multiple source value insns: " + value.insns); - } - } // Try to remap reflection method call args Type[] args = Type.getArgumentTypes(methodInsn.desc); if (args.length >= 3 && STR_TYPE.equals(args[0]) && STR_TYPE.equals(args[1]) && STR_TYPE.equals(args[2]) && values.size() >= 3) { diff --git a/src/mod/java/dev/su5ed/sinytra/connector/mod/ConnectorMod.java b/src/mod/java/dev/su5ed/sinytra/connector/mod/ConnectorMod.java index 7668d476..7f8f7f20 100644 --- a/src/mod/java/dev/su5ed/sinytra/connector/mod/ConnectorMod.java +++ b/src/mod/java/dev/su5ed/sinytra/connector/mod/ConnectorMod.java @@ -14,6 +14,8 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.loading.FMLLoader; +import java.io.InputStream; + @Mod(ConnectorUtil.CONNECTOR_MODID) public class ConnectorMod { private static boolean clientLoadComplete; @@ -44,4 +46,11 @@ private static void onClientSetup(FMLClientSetupEvent event) { private static void onLoadComplete(FMLLoadCompleteEvent event) { LateSheetsInit.completeSheetsInit(); } + + // Injected into mod code by ClassAnalysingTransformer + @SuppressWarnings("unused") + public static InputStream getModResourceAsStream(Class clazz, String name) { + InputStream classRes = clazz.getResourceAsStream(name); + return classRes != null ? classRes : clazz.getClassLoader().getResourceAsStream(name); + } } diff --git a/src/mod/resources/META-INF/asm/expandLocalVarScope.js b/src/mod/resources/META-INF/asm/expandLocalVarScope.js index d5012e4a..823623f6 100644 --- a/src/mod/resources/META-INF/asm/expandLocalVarScope.js +++ b/src/mod/resources/META-INF/asm/expandLocalVarScope.js @@ -2,6 +2,7 @@ var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); var Opcodes = Java.type('org.objectweb.asm.Opcodes'); var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode'); var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode'); +var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode'); function initializeCoreMod() { return { @@ -35,6 +36,64 @@ function initializeCoreMod() { ASMAPI.log('DEBUG', 'Expanded local variable scope for LivingEntity#forceAddEffect index 3'); return node; } + }, + 'insertBooleanInjectionTarget': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraft.world.level.BaseSpawner', + 'methodName': 'm_151311_', + 'methodDesc': '(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;)V' + }, + 'transformer': function (node) { + var targetLocal = null; + for (var i = 0; i < node.localVariables.size(); i++) { + var lvn = node.localVariables.get(i); + if (lvn.desc === 'Z') { + targetLocal = lvn; + break; + } + } + + var instance = null; + for (var i = 0; i < node.localVariables.size(); i++) { + var lvn = node.localVariables.get(i); + if (lvn.index === 0) { + instance = lvn; + break; + } + } + + for (var i = 0; i < node.localVariables.size(); i++) { + var lvn = node.localVariables.get(i); + if (lvn === targetLocal) { + lvn.start = instance.start; + break; + } + } + + var endLabel = null; + for (var i = node.instructions.size() - 1; i > 0; i--) { + if (node.instructions.get(i) instanceof LabelNode) { + endLabel = node.instructions.get(i); + break; + } + } + + for (var i = 0; i < node.localVariables.size(); i++) { + var lvn = node.localVariables.get(i); + if (lvn === targetLocal) { + lvn.end = endLabel; + break; + } + } + + node.instructions.insert(instance.start, ASMAPI.listOf( + new InsnNode(Opcodes.ICONST_0), + new VarInsnNode(Opcodes.ISTORE, targetLocal.index) + )); + ASMAPI.log('DEBUG', 'Expanded local variable scope for BaseSpawner#serverTick index 3'); + return node; + } } } } \ No newline at end of file