diff --git a/build.gradle.kts b/build.gradle.kts index 0fc3c341..83622e5f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,15 +6,15 @@ import net.neoforged.moddevgradle.internal.RunGameTask plugins { java `maven-publish` - id("net.neoforged.moddev") version "2.0.78" - id("com.gradleup.shadow") version "9.0.0-beta12" apply false + id("net.neoforged.moddev") version "2.0.140" + id("com.gradleup.shadow") version "9.3.1" apply false id("me.modmuss50.mod-publish-plugin") version "0.5.+" - id("net.neoforged.gradleutils") version "3.0.0" + id("net.neoforged.gradleutils") version "5.1.0" id("org.sinytra.adapter.userdev") version "1.2.1-SNAPSHOT" } val versionConnector: String by project -val versionAdapterDefinition: String by project +val versionAdapterCore: String by project val versionAdapterRuntime: String by project val versionMc: String by project val versionNeoForge: String by project @@ -131,7 +131,7 @@ dependencies { shade(group = "org.sinytra", name = "forgified-fabric-loader", version = versionForgifiedFabricLoader) shade(group = "net.fabricmc", name = "access-widener", version = versionAccessWidener) { isTransitive = false } shade(group = "org.sinytra", name = "ForgeAutoRenamingTool", version = versionForgeAutoRenamingTool) { isTransitive = false } - shade(group = "org.sinytra.adapter", name = "definition", version = versionAdapterDefinition) { isTransitive = false } + shade(group = "org.sinytra.adapter", name = "core", version = versionAdapterCore) { isTransitive = false } shade(project(":transformer")) { isTransitive = false } jarJar(implementation(group = "org.sinytra.adapter", name = "runtime", version = versionAdapterRuntime)) @@ -141,7 +141,7 @@ dependencies { "modCompileOnly"(sourceSets.main.get().output) - implementation("curse.maven:connector-extras-913445:5618470") +// implementation("curse.maven:connector-extras-913445:5618470") } val modJar: Jar by tasks.creating(Jar::class) { diff --git a/gradle.properties b/gradle.properties index 147b958c..d8f473aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,18 +7,18 @@ org.gradle.caching=true #org.gradle.configuration-cache=true # Versions -versionConnector=2.0.0-beta.12 -versionAdapterDefinition=1.13.58+1.21.1 +versionConnector=2.0.0-beta.13 +versionAdapterCore=2.0.25+1.21.1 versionAdapterRuntime=1.0.0+1.21.1 versionMc=1.21.1 -versionNeoForge=21.1.208 +versionNeoForge=21.1.219 versionParchmentMc=1.21.1 versionParchment=2024.11.17 versionForgeAutoRenamingTool=1.0.14 -versionForgifiedFabricLoader=2.5.55+0.17.2+1.21.1 +versionForgifiedFabricLoader=2.5.68+0.18.4+1.21.1 versionAccessWidener=2.1.0 -versionForgifiedFabricApi=0.115.6+2.1.1+1.21.1 +versionForgifiedFabricApi=0.116.7+2.2.1+1.21.1 # Publishing curseForgeId=890127 diff --git a/src/main/java/org/sinytra/connector/ConnectorCoremods.java b/src/main/java/org/sinytra/connector/ConnectorCoremods.java index 7734d29d..1453229d 100644 --- a/src/main/java/org/sinytra/connector/ConnectorCoremods.java +++ b/src/main/java/org/sinytra/connector/ConnectorCoremods.java @@ -20,7 +20,7 @@ import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; -import org.sinytra.adapter.patch.analysis.locals.LocalVariableLookup; +import org.sinytra.adapter.analysis.locals.LocalVariableLookup; import org.slf4j.Logger; import java.util.List; diff --git a/src/main/java/org/sinytra/connector/ConnectorEarlyLoader.java b/src/main/java/org/sinytra/connector/ConnectorEarlyLoader.java index e621fea6..60c17afd 100644 --- a/src/main/java/org/sinytra/connector/ConnectorEarlyLoader.java +++ b/src/main/java/org/sinytra/connector/ConnectorEarlyLoader.java @@ -14,6 +14,7 @@ import org.sinytra.connector.util.ConnectorUtil; import org.slf4j.Logger; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -25,6 +26,7 @@ public class ConnectorEarlyLoader { // A list of modids that use the connector language provider private static final Set CONNECTOR_MODIDS = new HashSet<>(); private static final List CONNECTOR_MODS = new ArrayList<>(); + private static final List CONNECTOR_MOD_PATHS = new ArrayList<>(); // If we encounter an exception during setup/load, we store it here and throw it later during FML mod loading, // so that it is propagated to the forge error screen. private static final List LOADING_EXCEPTIONS = new ArrayList<>(); @@ -90,6 +92,14 @@ public static ModLoadingIssue createLoadingIssue(Throwable original, String mess return new ModLoadingIssue(ModLoadingIssue.Severity.ERROR, message, Arrays.asList(args), keepOriginal ? original : null, null, null, null); } + public static void addConnectorModPath(Path path) { + CONNECTOR_MOD_PATHS.add(path); + } + + public static boolean isConnectorMod(Path path) { + return CONNECTOR_MOD_PATHS.contains(path); + } + /** * Run initial fabric loader setup. Any exceptions thrown are ignored and re-thrown later during FML load. * diff --git a/src/main/java/org/sinytra/connector/locator/ConnectorFabricModMetadata.java b/src/main/java/org/sinytra/connector/locator/ConnectorFabricModMetadata.java index 592282e2..fe605570 100644 --- a/src/main/java/org/sinytra/connector/locator/ConnectorFabricModMetadata.java +++ b/src/main/java/org/sinytra/connector/locator/ConnectorFabricModMetadata.java @@ -41,7 +41,7 @@ public ConnectorFabricModMetadata(LoaderModMetadata wrapped) { * Adjust version to accomodate Java Module System requirements */ private static String normalizeVersion(String version) { - return version.replace("+", ""); + return version.replace("+", "_"); } public String getNormalizedVersion() { @@ -74,8 +74,8 @@ public Collection getMixinConfigs(EnvType type) { } @Override - public String getAccessWidener() { - return this.wrapped.getAccessWidener(); + public String getClassTweaker() { + return this.wrapped.getClassTweaker(); } @Override diff --git a/src/main/java/org/sinytra/connector/locator/ConnectorLocator.java b/src/main/java/org/sinytra/connector/locator/ConnectorLocator.java index 3ca726d9..3db45cc9 100644 --- a/src/main/java/org/sinytra/connector/locator/ConnectorLocator.java +++ b/src/main/java/org/sinytra/connector/locator/ConnectorLocator.java @@ -63,6 +63,7 @@ public void scanMods(List loadedMods, IDiscoveryPipeline pipeline) { LocationResult results = locateFabricMods(loadedMods); if (results != null) { results.mods().forEach(pipeline::addModFile); + results.originalPaths().forEach(ConnectorEarlyLoader::addConnectorModPath); // Create mod file for generated adapter mixins jar Path generatedAdapterJar = results.generatedJarPath(); @@ -163,7 +164,8 @@ private LocationResult locateFabricMods(List discoveredMods) { List moduleSafeJars = SplitPackageMerger.mergeSplitPackages(transformed.stream().map(JarTransformer.TransformedFabricModPath::output).toList(), loadedModFiles, ignoredModFiles); List loadedMods = moduleSafeJars.stream().map(ConnectorLocator::createConnectorModFile).toList(); - return new LocationResult(loadedMods, environment.getGeneratedJarPath()); + List originalPaths = transformed.stream().map(JarTransformer.TransformedFabricModPath::input).toList(); + return new LocationResult(loadedMods, originalPaths, environment.getGeneratedJarPath()); } private static IModFile createConnectorModFile(SplitPackageMerger.FilteredModPath modPath) { @@ -276,5 +278,5 @@ private static void loadEmbeddedJars(IDiscoveryPipeline pipeline) throws Excepti private record SimpleModInfo(String modid, ArtifactVersion version, boolean library, @Nullable IModFile origin, @Nullable String moduleName) { } - private record LocationResult(List mods, Path generatedJarPath) {} + private record LocationResult(List mods, List originalPaths, Path generatedJarPath) {} } diff --git a/src/main/java/org/sinytra/connector/locator/DependencyResolver.java b/src/main/java/org/sinytra/connector/locator/DependencyResolver.java index 3e704829..855aef15 100644 --- a/src/main/java/org/sinytra/connector/locator/DependencyResolver.java +++ b/src/main/java/org/sinytra/connector/locator/DependencyResolver.java @@ -5,8 +5,10 @@ import com.google.common.collect.HashBiMap; import com.google.common.collect.Multimap; import com.mojang.logging.LogUtils; +import cpw.mods.jarhandling.SecureJar; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.Version; import net.fabricmc.loader.api.VersionParsingException; import net.fabricmc.loader.api.metadata.ModDependency; import net.fabricmc.loader.api.metadata.ModMetadata; @@ -17,28 +19,21 @@ import net.fabricmc.loader.impl.discovery.ModResolutionException; import net.fabricmc.loader.impl.discovery.ModResolver; import net.fabricmc.loader.impl.game.GameProvider; -import net.fabricmc.loader.impl.metadata.BuiltinModMetadata; -import net.fabricmc.loader.impl.metadata.DependencyOverrides; -import net.fabricmc.loader.impl.metadata.LoaderModMetadata; -import net.fabricmc.loader.impl.metadata.ModDependencyImpl; -import net.fabricmc.loader.impl.metadata.VersionOverrides; +import net.fabricmc.loader.impl.metadata.*; import net.fabricmc.loader.impl.util.version.VersionParser; import net.neoforged.fml.ModLoadingException; import net.neoforged.fml.loading.FMLPaths; import net.neoforged.neoforgespi.locating.IModFile; +import org.jetbrains.annotations.Nullable; import org.sinytra.connector.ConnectorEarlyLoader; import org.sinytra.connector.transformer.jar.JarTransformer; import org.sinytra.connector.util.ConnectorConfig; import org.slf4j.Logger; +import java.lang.module.ModuleDescriptor; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -46,6 +41,7 @@ import static cpw.mods.modlauncher.api.LambdaExceptionUtils.uncheck; public final class DependencyResolver { + private static final String MIXINEXTRAS_MODID = "mixinextras"; private static final Logger LOGGER = LogUtils.getLogger(); public static final VersionOverrides VERSION_OVERRIDES = new VersionOverrides(); public static final Supplier DEPENDENCY_OVERRIDES = Suppliers.memoize(() -> loadConfigFile("fabric_loader_dependencies.json", () -> new DependencyOverrides(FMLPaths.CONFIGDIR.get()))); @@ -60,7 +56,8 @@ public static List resolveDependencies(Collecti Stream forgeCandidates = loadedMods.stream() .flatMap(modFile -> modFile.getModFileInfo() != null ? modFile.getModInfos().stream() : Stream.empty()) .map(modInfo -> ModCandidateImpl.createPlain(List.of(modInfo.getOwningFile().getFile().getFilePath()), new BuiltinMetadataWrapper(new FMLModMetadata(modInfo)), false, List.of())); - Stream builtinCandidates = Stream.of(createJavaMod(), createFabricLoaderMod()); + Stream builtinCandidates = Stream.of(createJavaMod(), createFabricLoaderMod(), createMixinExtrasMod(loadedMods)) + .filter(Objects::nonNull); // Merge List allCandidates = Stream.of(candidates.stream(), forgeCandidates, builtinCandidates).flatMap(Function.identity()).toList(); @@ -135,21 +132,36 @@ private static ModCandidateImpl createFabricLoaderMod() { final String[] components = version.split("\\."); version = components[0] + "." + components[1] + ".*"; } - ModMetadata metadata; - - try { - metadata = new BuiltinModMetadata.Builder("fabricloader", VersionParser.parse(version, true)) - .setName("Fabric Loader") - .build(); - } catch (VersionParsingException e) { - throw new RuntimeException(e); - } + ModMetadata metadata = new BuiltinModMetadata.Builder("fabricloader", parseVersionUnchecked(version)) + .setName("Fabric Loader") + .build(); GameProvider.BuiltinMod builtinMod = new GameProvider.BuiltinMod(Collections.singletonList(Path.of(uncheck(() -> FabricLoader.class.getProtectionDomain().getCodeSource().getLocation().toURI()))), metadata); return ModCandidateImpl.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES.get()); } + @Nullable + private static ModCandidateImpl createMixinExtrasMod(Collection loadedMods) { + SecureJar mixinExJar = loadedMods.stream() + .map(IModFile::getSecureJar) + .filter(j -> j.name().contains(MIXINEXTRAS_MODID)) + .findFirst() + .orElse(null); + if (mixinExJar == null) return null; + + String version = mixinExJar.moduleDataProvider().descriptor().version() + .map(ModuleDescriptor.Version::toString) + .orElse(null); + + ModMetadata metadata = new BuiltinModMetadata.Builder(MIXINEXTRAS_MODID, parseVersionUnchecked(version)) + .setName(mixinExJar.name()) + .build(); + GameProvider.BuiltinMod builtinMod = new GameProvider.BuiltinMod(List.of(mixinExJar.getPrimaryPath()), metadata); + + return ModCandidateImpl.createBuiltin(builtinMod, VERSION_OVERRIDES, DEPENDENCY_OVERRIDES.get()); + } + private static T loadConfigFile(String name, Supplier supplier) { try { return supplier.get(); @@ -157,4 +169,12 @@ private static T loadConfigFile(String name, Supplier supplier) { throw new ModLoadingException(ConnectorEarlyLoader.createGenericLoadingIssue(t, "Invalid config file " + name)); } } + + private static Version parseVersionUnchecked(String str) { + try { + return VersionParser.parse(str, true); + } catch (VersionParsingException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/org/sinytra/connector/locator/MixinTransformSafeguard.java b/src/main/java/org/sinytra/connector/locator/MixinTransformSafeguard.java index ce293ba1..86e61fcf 100644 --- a/src/main/java/org/sinytra/connector/locator/MixinTransformSafeguard.java +++ b/src/main/java/org/sinytra/connector/locator/MixinTransformSafeguard.java @@ -4,7 +4,7 @@ import net.neoforged.fml.ModLoadingException; import net.neoforged.fml.ModLoadingIssue; import net.neoforged.fml.loading.progress.StartupNotificationManager; -import org.sinytra.adapter.patch.api.PatchAuditTrail; +import org.sinytra.adapter.env.ctx.AuditTrail; import org.sinytra.connector.transformer.jar.JarTransformer; import org.sinytra.connector.util.ConnectorConfig; import org.sinytra.connector.util.PriorityModLoadingException; @@ -35,7 +35,7 @@ public static void trigger(List failing failing.forEach(p -> { builder.append("Mod file §e").append(p.input().getFileName().toString()).append("§r has failing mixins:\n"); - for (PatchAuditTrail.Candidate failed : p.auditTrail().getFailingMixins()) { + for (AuditTrail.Candidate failed : p.auditTrail().getFailingMixins()) { String[] parts = failed.classNode().name.split("/"); builder.append("- §c").append(parts[parts.length - 1]).append("§7#§3").append(failed.methodNode().name).append("§r\n"); } diff --git a/src/main/java/org/sinytra/connector/locator/filter/ForgeModPackageFilter.java b/src/main/java/org/sinytra/connector/locator/filter/ForgeModPackageFilter.java index e39785e7..de793fde 100644 --- a/src/main/java/org/sinytra/connector/locator/filter/ForgeModPackageFilter.java +++ b/src/main/java/org/sinytra/connector/locator/filter/ForgeModPackageFilter.java @@ -64,7 +64,7 @@ private static void injectUFSFilter(UnionFileSystem ufs, UnionPathFilter filter) UnionPathFilter merged = existing != null ? (a, b) -> existing.test(a, b) && filter.test(a, b) : filter; // Inject filter into UFS - UPFS_FILTER.set(ufs, merged); // TODO TEST + UPFS_FILTER.set(ufs, merged); } private static void forceRecomputeJarPackages(Jar jar) { diff --git a/src/main/java/org/sinytra/connector/locator/filter/SplitPackageMerger.java b/src/main/java/org/sinytra/connector/locator/filter/SplitPackageMerger.java index fd133c55..91e094ea 100644 --- a/src/main/java/org/sinytra/connector/locator/filter/SplitPackageMerger.java +++ b/src/main/java/org/sinytra/connector/locator/filter/SplitPackageMerger.java @@ -10,7 +10,7 @@ import cpw.mods.niofs.union.UnionPathFilter; import net.neoforged.neoforgespi.locating.IModFile; import org.jetbrains.annotations.Nullable; -import org.sinytra.connector.transformer.jar.JarTransformer; +import org.sinytra.connector.transformer.jar.FabricModFileMetadata; import org.sinytra.connector.transformer.jar.JarTransformer.FabricModPath; import org.slf4j.Logger; @@ -148,7 +148,7 @@ private static void analyzeJar(Map swap, JarMergeInfo mast List additionalPaths = others.stream() .flatMap(pair -> { SecureJar sj = pair.getFirst(); - JarTransformer.FabricModFileMetadata metadata = pair.getSecond().metadata(); + FabricModFileMetadata metadata = pair.getSecond().metadata(); JarContents jarContents = new JarContentsBuilder().paths(sj.getPrimaryPath()).pathFilter(singlePackageFilter(pkg)).build(); SecureJar singlePackage = SecureJar.from(jarContents); JarMergeInfo jarInfo = swap.computeIfAbsent(sj.name(), name -> new JarMergeInfo(sj, metadata)); @@ -187,11 +187,11 @@ private static UnionPathFilter mergeANDFilter(UnionPathFilter left, @Nullable Un * @param additionalPaths additional paths to include in the jar * @param excludedPackages packages to exlude from the jar */ - private record JarMergeInfo(SecureJar jar, JarTransformer.FabricModFileMetadata metadata, Set additionalPaths, Set excludedPackages) { - public JarMergeInfo(SecureJar jar, JarTransformer.FabricModFileMetadata metadata) { + private record JarMergeInfo(SecureJar jar, FabricModFileMetadata metadata, Set additionalPaths, Set excludedPackages) { + public JarMergeInfo(SecureJar jar, FabricModFileMetadata metadata) { this(jar, metadata, new HashSet<>(), new HashSet<>()); } } - public record FilteredModPath(Path[] paths, @Nullable UnionPathFilter filter, JarTransformer.FabricModFileMetadata metadata) {} + public record FilteredModPath(Path[] paths, @Nullable UnionPathFilter filter, FabricModFileMetadata metadata) {} } diff --git a/src/main/java/org/sinytra/connector/locator/transform/ConnectorTransformerEnvironment.java b/src/main/java/org/sinytra/connector/locator/transform/ConnectorTransformerEnvironment.java index 04b288d1..ef09acfa 100644 --- a/src/main/java/org/sinytra/connector/locator/transform/ConnectorTransformerEnvironment.java +++ b/src/main/java/org/sinytra/connector/locator/transform/ConnectorTransformerEnvironment.java @@ -17,8 +17,8 @@ import net.neoforged.fml.loading.progress.StartupNotificationManager; import net.neoforged.neoforgespi.locating.IModFile; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.provider.ClassLookup; -import org.sinytra.adapter.patch.util.provider.ZipClassLookup; +import org.sinytra.adapter.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ZipClassLookup; import org.sinytra.connector.ConnectorEarlyLoader; import org.sinytra.connector.locator.ConnectorFabricModMetadata; import org.sinytra.connector.locator.DependencyResolver; diff --git a/src/main/java/org/sinytra/connector/service/ConnectorLoaderService.java b/src/main/java/org/sinytra/connector/service/ConnectorLoaderService.java index e2103707..e5cfea5c 100644 --- a/src/main/java/org/sinytra/connector/service/ConnectorLoaderService.java +++ b/src/main/java/org/sinytra/connector/service/ConnectorLoaderService.java @@ -21,6 +21,7 @@ import java.lang.invoke.VarHandle; import java.lang.reflect.Field; +import java.nio.file.Path; import java.util.*; import java.util.function.*; import java.util.stream.Stream; @@ -105,7 +106,11 @@ public void onLoad(IEnvironment env, Set otherServices) { @Override public List completeScan(IModuleLayerManager layerManager) { // Ignore default Fabric mod locator warnings - LoadingModList.get().getModLoadingIssues().removeIf(issue -> issue.translationKey().equals("fml.modloadingissue.brokenfile.fabric")); + LoadingModList.get().getModLoadingIssues() + .removeIf(issue -> { + Path path = issue.affectedPath(); + return ConnectorEarlyLoader.isConnectorMod(path) && issue.translationKey().startsWith("fml.modloadingissue.brokenfile."); + }); // Add our loading errors LoadingModList.get().getModLoadingIssues().addAll(ConnectorEarlyLoader.getLoadingExceptions()); diff --git a/src/mod/java/org/sinytra/connector/mod/mixin/item/ItemStackMixin.java b/src/mod/java/org/sinytra/connector/mod/mixin/item/ItemStackMixin.java index deda69f0..9a915e01 100644 --- a/src/mod/java/org/sinytra/connector/mod/mixin/item/ItemStackMixin.java +++ b/src/mod/java/org/sinytra/connector/mod/mixin/item/ItemStackMixin.java @@ -17,7 +17,6 @@ @Mixin(value = ItemStack.class, priority = 500) public abstract class ItemStackMixin implements ItemStackExtensions { - // TODO Make sure name is the same in prod @Inject(method = "lambda$useOn$16", at = @At("HEAD"), cancellable = true) private void appyUseOn(UseOnContext pContext, UseOnContext c, CallbackInfoReturnable cir) { InteractionResult result = connector_useOn(c); diff --git a/transformer/build.gradle.kts b/transformer/build.gradle.kts index f693a48c..b64701a1 100644 --- a/transformer/build.gradle.kts +++ b/transformer/build.gradle.kts @@ -11,7 +11,7 @@ plugins { group = "org.sinytra.connector" version = rootProject.version -val versionAdapterDefinition: String by rootProject +val versionAdapterCore: String by rootProject val versionForgeAutoRenamingTool: String by rootProject val versionForgifiedFabricLoader: String by rootProject val versionAccessWidener: String by rootProject @@ -49,7 +49,7 @@ dependencies { implementation(platform("org.apache.logging.log4j:log4j-bom:2.24.3")) implementation("org.apache.logging.log4j:log4j-core") implementation("org.apache.logging.log4j:log4j-slf4j2-impl") - implementation("org.sinytra.adapter:definition:$versionAdapterDefinition") + implementation("org.sinytra.adapter:core:$versionAdapterCore") implementation("org.sinytra:ForgeAutoRenamingTool:$versionForgeAutoRenamingTool") { isTransitive = false } @@ -85,7 +85,6 @@ tasks { configurations = project.configurations.named("runtimeClasspath").map { listOf(it, shade) } from(sourceSets.main.map { it.output }, runner.output) - manifest.inheritFrom(jar.get().manifest) mergeServiceFiles() transform(Log4JConfigTransformer(runner.output.resourcesDir)) } @@ -127,4 +126,54 @@ class Log4JConfigTransformer(private val resourcesDir: File?) : ResourceTransfor override fun transform(context: TransformerContext) {} override fun hasTransformedResource(): Boolean = true override fun modifyOutputStream(os: ZipOutputStream, preserveFileTimestamps: Boolean) {} -} \ No newline at end of file +} + +/* + // parameter instance + // parameter item + // parameter original + @Lcom/llamalad7/mixinextras/injector/wrapoperation/WrapOperation;(method={"useItemOn"}, at={@Lorg/spongepowered/asm/mixin/injection/At;(value="INVOKE", target="Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z")}) + L0 + LINENUMBER 25 L0 + ALOAD 3 + ICONST_2 + ANEWARRAY java/lang/Object + DUP + ICONST_0 + ALOAD 1 + AASTORE + DUP + ICONST_1 + ALOAD 2 + AASTORE + INVOKEINTERFACE com/llamalad7/mixinextras/injector/wrapoperation/Operation.call ([Ljava/lang/Object;)Ljava/lang/Object; (itf) + CHECKCAST java/lang/Boolean + INVOKEVIRTUAL java/lang/Boolean.booleanValue ()Z + IFNE L1 + ALOAD 2 + GETSTATIC net/minecraft/world/item/Items.SHEARS : Lnet/minecraft/world/item/Item; + IF_ACMPNE L2 + ALOAD 1 + INVOKESTATIC org/betterx/bclib/items/tool/BaseShearsItem.isShear (Lnet/minecraft/world/item/ItemStack;)Z + IFEQ L2 + L1 + FRAME SAME + ICONST_1 + GOTO L3 + L2 + FRAME SAME + ICONST_0 + L3 + FRAME SAME1 I + IRETURN + L4 + LOCALVARIABLE this Lorg/betterx/bclib/mixin/common/shears/PumpkinBlockMixin; L0 L4 0 + LOCALVARIABLE instance Lnet/minecraft/world/item/ItemStack; L0 L4 1 + LOCALVARIABLE item Lnet/minecraft/world/item/Item; L0 L4 2 + LOCALVARIABLE original Lcom/llamalad7/mixinextras/injector/wrapoperation/Operation; L0 L4 3 + // signature Lcom/llamalad7/mixinextras/injector/wrapoperation/Operation; + // declaration: original extends com.llamalad7.mixinextras.injector.wrapoperation.Operation + MAXSTACK = 5 + MAXLOCALS = 4 + + */ \ No newline at end of file diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/TransformerEnvironment.java b/transformer/src/main/java/org/sinytra/connector/transformer/TransformerEnvironment.java index 41b3b41e..6d4a9c9c 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/TransformerEnvironment.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/TransformerEnvironment.java @@ -7,7 +7,7 @@ import net.fabricmc.loader.impl.metadata.VersionOverrides; import net.minecraftforge.fart.api.ClassProvider; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ClassLookup; import org.sinytra.connector.transformer.transform.TransformProgressMeter; import java.io.IOException; diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/BytecodeFixerUpperFrontend.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/BytecodeFixerUpperFrontend.java index c19d1077..2db3127f 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/jar/BytecodeFixerUpperFrontend.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/BytecodeFixerUpperFrontend.java @@ -6,10 +6,10 @@ import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.TypeInsnNode; -import org.sinytra.adapter.patch.fixes.BytecodeFixerUpper; -import org.sinytra.adapter.patch.fixes.SimpleTypeAdapter; -import org.sinytra.adapter.patch.fixes.TypeAdapter; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.types.SimpleTypeAdapter; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.provider.ClassLookup; import org.sinytra.connector.transformer.TransformerEnvironment; import org.sinytra.connector.transformer.transform.TransformerUtil; @@ -19,7 +19,7 @@ import java.util.List; import java.util.jar.Attributes; -import static org.sinytra.adapter.patch.util.AdapterUtil.insnList; +import static org.sinytra.adapter.util.AdapterUtil.insnList; public class BytecodeFixerUpperFrontend { private static final List FIELD_TYPE_ADAPTERS = List.of( diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricJarReader.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricJarReader.java new file mode 100644 index 00000000..b834171b --- /dev/null +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricJarReader.java @@ -0,0 +1,139 @@ +package org.sinytra.connector.transformer.jar; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.mojang.logging.LogUtils; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.metadata.CustomValue; +import net.fabricmc.loader.impl.metadata.*; +import org.sinytra.connector.transformer.TransformerEnvironment; +import org.sinytra.connector.transformer.transform.TransformerUtil; +import org.slf4j.Logger; + +import java.io.*; +import java.util.*; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; + +public class FabricJarReader { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final String LOOM_GENERATED_PROPERTY = "fabric-loom:generated"; + private static final String LOOM_REMAP_ATTRIBUTE = "Fabric-Loom-Remap"; + + public static FabricModFileMetadata readModMetadata(File input, TransformerEnvironment environment) throws IOException { + try (JarFile jarFile = new JarFile(input)) { + LoaderModMetadata metadata; + Set allConfigs; + Set configs; + try (InputStream ins = jarFile.getInputStream(jarFile.getEntry(TransformerUtil.FABRIC_MOD_JSON))) { + VersionOverrides versionOverrides = environment.getVersionOverrides(); + DependencyOverrides dependencyOverrides = environment.getDependencyOverrides().get(); + LoaderModMetadata rawMetadata = ModMetadataParser.parseMetadata( + ins, + "", + Collections.emptyList(), + versionOverrides, + dependencyOverrides, + false + ); + metadata = environment.wrapModMetadata(rawMetadata); + + Map> envMixinConfigs = Map.of( + EnvType.CLIENT, metadata.getMixinConfigs(EnvType.CLIENT), + EnvType.SERVER, metadata.getMixinConfigs(EnvType.SERVER) + ); + allConfigs = envMixinConfigs.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + configs = new HashSet<>(envMixinConfigs.get(environment.getEnvType())); + } catch (ParseMetadataException e) { + throw new RuntimeException(e); + } + boolean containsAT = jarFile.getEntry(TransformerUtil.AT_PATH) != null; + + Set refmaps = new HashSet<>(); + Set mixinPackages = new HashSet<>(); + Set mixinClasses = new HashSet<>(); + for (String configName : configs) { + ZipEntry entry = jarFile.getEntry(configName); + if (entry != null) { + readMixinConfigPackages(input, jarFile, entry, refmaps, mixinPackages, mixinClasses); + } + } + + // Find additional configs that may not be listed in mod metadata + jarFile.stream() + .forEach(entry -> { + String name = entry.getName(); + // Already discovered and ignored due to env setting + if (allConfigs.contains(name)) { + return; + } + if ((name.endsWith(".mixins.json") || name.startsWith("mixins.") && name.endsWith(".json")) && configs.add(name)) { + readMixinConfigPackages(input, jarFile, entry, refmaps, mixinPackages, mixinClasses); + } + }); + + Attributes manifestAttributes = Optional.ofNullable(jarFile.getManifest()) + .map(Manifest::getMainAttributes) + .orElseGet(Attributes::new); + boolean generated = isGeneratedLibraryJarMetadata(manifestAttributes, metadata); + + return new FabricModFileMetadata( + metadata, + Set.copyOf(configs), + configs, + refmaps, + mixinPackages, + mixinClasses, + manifestAttributes, + containsAT, + generated + ); + } + } + + private static void readMixinConfigPackages(File input, JarFile jarFile, ZipEntry entry, Set refmaps, Set packages, Set mixinClasses) { + try (Reader reader = new InputStreamReader(jarFile.getInputStream(entry))) { + JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); + if (json.has("refmap")) { + String refmap = json.get("refmap").getAsString(); + refmaps.add(refmap); + } + if (json.has("package")) { + String pkg = json.get("package").getAsString(); + if (!pkg.isEmpty()) { + String pkgPath = pkg.replace('.', '/') + '/'; + packages.add(pkgPath); + } + for (String type : List.of("mixins", "client", "server")) { + if (json.has(type)) { + for (JsonElement mixin : json.getAsJsonArray(type)) { + if (mixin.isJsonPrimitive()) { + String className = pkg + "." + mixin.getAsString(); + mixinClasses.add(className.replace('.', '/')); + } + } + } + } + } + } catch (Throwable t) { + LOGGER.error("Error reading mixin config entry {} in file {}", entry.getName(), input.getAbsolutePath()); + throw new RuntimeException(t); + } + } + + private static boolean isGeneratedLibraryJarMetadata(Attributes manifestAttributes, LoaderModMetadata metadata) { + CustomValue generatedValue = metadata.getCustomValue(LOOM_GENERATED_PROPERTY); + if (generatedValue != null && generatedValue.getType() == CustomValue.CvType.BOOLEAN && generatedValue.getAsBoolean()) { + String loomRemapAttribute = manifestAttributes.getValue(LOOM_REMAP_ATTRIBUTE); + return loomRemapAttribute == null || !loomRemapAttribute.equals("true"); + } + return false; + } + +} diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricModFileMetadata.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricModFileMetadata.java new file mode 100644 index 00000000..89436f62 --- /dev/null +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/FabricModFileMetadata.java @@ -0,0 +1,20 @@ +package org.sinytra.connector.transformer.jar; + +import net.fabricmc.loader.impl.metadata.LoaderModMetadata; + +import java.util.Collection; +import java.util.Set; +import java.util.jar.Attributes; + +public record FabricModFileMetadata( + LoaderModMetadata modMetadata, + Collection visibleMixinConfigs, + Collection mixinConfigs, + Set refmaps, + Set mixinPackages, + Set mixinClasses, + Attributes manifestAttributes, + boolean containsAT, + boolean generated +) { +} diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformInstance.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformInstance.java index ce89d062..3b585a99 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformInstance.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformInstance.java @@ -9,10 +9,10 @@ import net.minecraftforge.fart.internal.EnhancedRemapper; import net.minecraftforge.srgutils.IMappingFile; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.api.PatchAuditTrail; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import org.sinytra.adapter.patch.util.provider.ClassLookup; -import org.sinytra.adapter.patch.util.provider.MixinClassLookup; +import org.sinytra.adapter.env.ctx.AuditTrail; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.MixinClassLookup; import org.sinytra.connector.transformer.TransformerEnvironment; import org.sinytra.connector.transformer.patch.ClassAnalysingTransformer; import org.sinytra.connector.transformer.patch.ClassNodeTransformer; @@ -41,7 +41,7 @@ public class JarTransformInstance { private final EnhancedRemapper enhancedRemapper; private final ClassLookup cleanClassLookup; private final List libs; - private final PatchAuditTrail auditTrail; + private final AuditTrail auditTrail; private final TransformerEnvironment environment; public JarTransformInstance(TransformerEnvironment environment, ClassProvider classProvider, List libs) { @@ -58,7 +58,7 @@ public JarTransformInstance(TransformerEnvironment environment, ClassProvider cl this.cleanClassLookup = environment.getCleanClassLookup(); this.bfu = new BytecodeFixerUpperFrontend(this.cleanClassLookup, MixinClassLookup.INSTANCE, this.environment); this.libs = libs; - this.auditTrail = PatchAuditTrail.create(); + this.auditTrail = AuditTrail.create(); } public BytecodeFixerUpperFrontend getBfu() { @@ -66,7 +66,7 @@ public BytecodeFixerUpperFrontend getBfu() { } @Nullable - public PatchAuditTrail transformJar(File input, Path output, JarTransformer.FabricModFileMetadata metadata) throws IOException { + public AuditTrail transformJar(File input, Path output, FabricModFileMetadata metadata) throws IOException { Stopwatch stopwatch = Stopwatch.createStarted(); if (metadata.generated()) { @@ -83,34 +83,33 @@ public PatchAuditTrail transformJar(File input, Path output, JarTransformer.Fabr RefmapRemapper.RefmapFiles refmap = RefmapRemapper.processRefmaps(input.toPath(), metadata.refmaps(), this.remapper, this.libs); IMappingFile srgToIntermediary = resolver.getMap(JarTransformer.OBF_NAMESPACE, JarTransformer.SOURCE_NAMESPACE); IMappingFile intermediaryToSrg = resolver.getCurrentMap(JarTransformer.SOURCE_NAMESPACE); - AccessorRedirectTransformer accessorRedirectTransformer = new AccessorRedirectTransformer(srgToIntermediary); + AccessorRedirectTransformer accessorRedirectTransformer = new AccessorRedirectTransformer(); - PatchAuditTrail jarTrail = PatchAuditTrail.create(); + AuditTrail jarTrail = AuditTrail.create(); ConnectorRefmapHolder refmapHolder = new ConnectorRefmapHolder(refmap.merged(), refmap.files()); int fabricLVTCompatibility = this.environment.getFabricMixinCompatibility(metadata.modMetadata()); PatchEnvironment environment = PatchEnvironment.create(refmapHolder, this.cleanClassLookup, this.bfu.unwrap(), fabricLVTCompatibility, jarTrail); - MixinPatchTransformer patchTransformer = new MixinPatchTransformer(this.environment, environment, AccessorRedirectTransformer.PATCHES); - RefmapRemapper refmapRemapper = new RefmapRemapper(refmap.files()); + MixinPatchTransformer patchTransformer = new MixinPatchTransformer(this.environment, environment, accessorRedirectTransformer.getPatches()); + Renamer.Builder builder = Renamer.builder() .add(new JarSignatureStripper()) .add(new ClassNodeTransformer( - new FieldToMethodTransformer(metadata.modMetadata().getAccessWidener(), srgToIntermediary), - accessorRedirectTransformer, - new ReflectionRenamingTransformer(intermediaryToSrg, IntermediateMapping.get(JarTransformer.SOURCE_NAMESPACE)) + new FieldToMethodTransformer(metadata.modMetadata().getClassTweaker(), srgToIntermediary), + new ReflectionRenamingTransformer(intermediaryToSrg, IntermediateMapping.get(JarTransformer.SOURCE_NAMESPACE)), + new ClassAnalysingTransformer() )) .add(new OptimizedRenamingTransformer(this.enhancedRemapper, false, metadata.refmaps().isEmpty())) - .add(new ClassNodeTransformer(new ClassAnalysingTransformer())) .add(patchTransformer) - .add(refmapRemapper) + .add(new ClassNodeTransformer(accessorRedirectTransformer)) + .add(new RefmapRemapper(refmap.files())) .logger(s -> LOGGER.trace(JarTransformer.TRANSFORM_MARKER, s)) .debug(s -> LOGGER.trace(JarTransformer.TRANSFORM_MARKER, s)) .ignoreJarPathPrefix("assets/", "data/"); if (!metadata.containsAT()) { - builder.add(new AccessWidenerTransformer(metadata.modMetadata().getAccessWidener(), resolver, IntermediateMapping.get(JarTransformer.SOURCE_NAMESPACE))); + builder.add(new AccessWidenerTransformer(metadata.modMetadata().getClassTweaker(), resolver, IntermediateMapping.get(JarTransformer.SOURCE_NAMESPACE))); } - try (Renamer renamer = builder.build()) { - accessorRedirectTransformer.analyze(input, metadata.mixinPackages(), environment); + try (Renamer renamer = builder.build()) { renamer.run(input, output.toFile()); try (FileSystem zipFile = FileSystems.newFileSystem(output)) { diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformer.java index 76a6c214..196ce6e5 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/JarTransformer.java @@ -1,22 +1,15 @@ package org.sinytra.connector.transformer.jar; import com.google.common.base.Stopwatch; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import cpw.mods.jarhandling.JarContents; import cpw.mods.jarhandling.JarContentsBuilder; import cpw.mods.jarhandling.JarMetadata; import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; -import net.fabricmc.loader.api.metadata.CustomValue; -import net.fabricmc.loader.impl.metadata.LoaderModMetadata; -import net.fabricmc.loader.impl.metadata.ModMetadataParser; -import net.fabricmc.loader.impl.metadata.ParseMetadataException; import net.minecraftforge.fart.api.ClassProvider; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.api.PatchAuditTrail; +import org.sinytra.adapter.env.ctx.AuditTrail; import org.sinytra.connector.transformer.TransformerEnvironment; import org.sinytra.connector.transformer.transform.TransformProgressMeter; import org.sinytra.connector.transformer.transform.TransformerUtil; @@ -25,20 +18,20 @@ import org.slf4j.MarkerFactory; import org.spongepowered.asm.mixin.transformer.ClassInfo; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.zip.ZipEntry; import static cpw.mods.modlauncher.api.LambdaExceptionUtils.uncheck; @@ -46,8 +39,6 @@ public final class JarTransformer { public static final String SOURCE_NAMESPACE = "intermediary"; public static final String OBF_NAMESPACE = "mojang"; public static final Marker TRANSFORM_MARKER = MarkerFactory.getMarker("TRANSFORM"); - private static final String LOOM_GENERATED_PROPERTY = "fabric-loom:generated"; - private static final String LOOM_REMAP_ATTRIBUTE = "Fabric-Loom-Remap"; private static final Logger LOGGER = LogUtils.getLogger(); private final TransformerEnvironment environment; @@ -82,7 +73,7 @@ public TransformableJar cacheTransformableJar(File input) throws IOException { String name = input.getName().split("\\.(?!.*\\.)")[0]; Path output = this.environment.createCachedJarPath(name); - FabricModFileMetadata metadata = readModMetadata(input); + FabricModFileMetadata metadata = FabricJarReader.readModMetadata(input, this.environment); FabricModPath path = new FabricModPath(output, metadata); TransformerUtil.CacheFile cacheFile = TransformerUtil.getCached(input.toPath(), output, this.environment.getJarCacheVersion()); String moduleName = getModuleName(input.toPath()); @@ -104,10 +95,10 @@ private List transformJars(List path initProgress.complete(); } ExecutorService executorService = Executors.newFixedThreadPool(paths.size()); - List>>> futures = paths.stream() + List>>> futures = paths.stream() .map(jar -> { - Future> future = executorService.submit(() -> { - Pair pair = jar.transform(transformInstance); + Future> future = executorService.submit(() -> { + Pair pair = jar.transform(transformInstance); progress.increment(); return pair; }); @@ -121,7 +112,7 @@ private List transformJars(List path List results = futures.stream() .map(pair -> { try { - Pair result = pair.getSecond().get(); + Pair result = pair.getSecond().get(); return new TransformedFabricModPath(pair.getFirst().toPath(), result.getFirst(), result.getSecond()); } catch (Throwable t) { throw this.environment.onTransformationError("Error transforming file " + pair.getFirst().getName(), t); @@ -142,82 +133,6 @@ private List transformJars(List path } } - private FabricModFileMetadata readModMetadata(File input) throws IOException { - try (JarFile jarFile = new JarFile(input)) { - LoaderModMetadata metadata; - Set configs; - try (InputStream ins = jarFile.getInputStream(jarFile.getEntry(TransformerUtil.FABRIC_MOD_JSON))) { - LoaderModMetadata rawMetadata = ModMetadataParser.parseMetadata(ins, "", Collections.emptyList(), this.environment.getVersionOverrides(), this.environment.getDependencyOverrides().get(), false); - metadata = this.environment.wrapModMetadata(rawMetadata); - - configs = new HashSet<>(metadata.getMixinConfigs(this.environment.getEnvType())); - } catch (ParseMetadataException e) { - throw new RuntimeException(e); - } - boolean containsAT = jarFile.getEntry(TransformerUtil.AT_PATH) != null; - - Set refmaps = new HashSet<>(); - Set mixinPackages = new HashSet<>(); - Set mixinClasses = new HashSet<>(); - for (String configName : configs) { - ZipEntry entry = jarFile.getEntry(configName); - if (entry != null) { - readMixinConfigPackages(input, jarFile, entry, refmaps, mixinPackages, mixinClasses); - } - } - // Find additional configs that may not be listed in mod metadata - jarFile.stream() - .forEach(entry -> { - String name = entry.getName(); - if ((name.endsWith(".mixins.json") || name.startsWith("mixins.") && name.endsWith(".json")) && configs.add(name)) { - readMixinConfigPackages(input, jarFile, entry, refmaps, mixinPackages, mixinClasses); - } - }); - Attributes manifestAttributes = Optional.ofNullable(jarFile.getManifest()).map(Manifest::getMainAttributes).orElseGet(Attributes::new); - boolean generated = isGeneratedLibraryJarMetadata(manifestAttributes, metadata); - return new FabricModFileMetadata(metadata, Set.copyOf(configs), configs, refmaps, mixinPackages, mixinClasses, manifestAttributes, containsAT, generated); - } - } - - private static boolean isGeneratedLibraryJarMetadata(Attributes manifestAttributes, LoaderModMetadata metadata) { - CustomValue generatedValue = metadata.getCustomValue(LOOM_GENERATED_PROPERTY); - if (generatedValue != null && generatedValue.getType() == CustomValue.CvType.BOOLEAN && generatedValue.getAsBoolean()) { - String loomRemapAttribute = manifestAttributes.getValue(LOOM_REMAP_ATTRIBUTE); - return loomRemapAttribute == null || !loomRemapAttribute.equals("true"); - } - return false; - } - - private static void readMixinConfigPackages(File input, JarFile jarFile, ZipEntry entry, Set refmaps, Set packages, Set mixinClasses) { - try (Reader reader = new InputStreamReader(jarFile.getInputStream(entry))) { - JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); - if (json.has("refmap")) { - String refmap = json.get("refmap").getAsString(); - refmaps.add(refmap); - } - if (json.has("package")) { - String pkg = json.get("package").getAsString(); - if (!pkg.isEmpty()) { - String pkgPath = pkg.replace('.', '/') + '/'; - packages.add(pkgPath); - } - for (String type : List.of("mixins", "client", "server")) { - if (json.has(type)) { - for (JsonElement mixin : json.getAsJsonArray(type)) { - if (mixin.isJsonPrimitive()) { - String className = pkg + "." + mixin.getAsString(); - mixinClasses.add(className.replace('.', '/')); - } - } - } - } - } - } catch (Throwable t) { - LOGGER.error("Error reading mixin config entry {} in file {}", entry.getName(), input.getAbsolutePath()); - throw new RuntimeException(t); - } - } - @SuppressWarnings("unchecked") private void cleanupEnvironment() { this.environment.setGlobalBytecodeLoader(null); @@ -251,14 +166,12 @@ private static String getModuleName(Path path) { public record FabricModPath(Path path, FabricModFileMetadata metadata) {} - public record TransformedFabricModPath(Path input, FabricModPath output, @Nullable PatchAuditTrail auditTrail) {} - - public record FabricModFileMetadata(LoaderModMetadata modMetadata, Collection visibleMixinConfigs, Collection mixinConfigs, Set refmaps, Set mixinPackages, Set mixinClasses, Attributes manifestAttributes, boolean containsAT, boolean generated) {} + public record TransformedFabricModPath(Path input, FabricModPath output, @Nullable AuditTrail auditTrail) {} public record TransformableJar(File input, FabricModPath modPath, TransformerUtil.CacheFile cacheFile, String moduleName) { - public Pair transform(JarTransformInstance transformInstance) throws IOException { + public Pair transform(JarTransformInstance transformInstance) throws IOException { Files.deleteIfExists(this.modPath.path); - PatchAuditTrail audit = transformInstance.transformJar(this.input, this.modPath.path, this.modPath.metadata()); + AuditTrail audit = transformInstance.transformJar(this.input, this.modPath.path, this.modPath.metadata()); this.cacheFile.save(); return Pair.of(this.modPath, audit); } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/jar/SimpleClassLookup.java b/transformer/src/main/java/org/sinytra/connector/transformer/jar/SimpleClassLookup.java index 79657ba5..d1f32f72 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/jar/SimpleClassLookup.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/jar/SimpleClassLookup.java @@ -3,7 +3,7 @@ import net.minecraftforge.fart.api.ClassProvider; import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ClassLookup; import java.util.Map; import java.util.Optional; diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/AccessorToInvokerTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/AccessorToInvokerTransformer.java new file mode 100644 index 00000000..890d67f8 --- /dev/null +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/AccessorToInvokerTransformer.java @@ -0,0 +1,36 @@ +package org.sinytra.connector.transformer.patch; + +import com.mojang.logging.LogUtils; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.env.ctx.MixinContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.config.Configuration; +import org.sinytra.adapter.transform.MethodTransformer; +import org.slf4j.Logger; + +import static org.sinytra.adapter.util.AdapterUtil.MIXINPATCH; + +public record AccessorToInvokerTransformer(String value) implements MethodTransformer { + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public PatchResult apply(MixinContext context, Configuration config) { + if (!context.methodAnnotation().matchesDesc(MixinAnnotations.ACCESSOR)) + return PatchResult.PASS; + + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + AnnotationVisitor visitor = methodNode.visitAnnotation(MixinAnnotations.INVOKER, true); + visitor.visit("value", this.value); + visitor.visitEnd(); + + methodNode.visibleAnnotations.remove(context.methodAnnotation().unwrap()); + + LOGGER.info(MIXINPATCH, "Redirecting accessor {}.{} to invoke method {}", classNode.name, methodNode.name, this.value); + + return PatchResult.APPLY; + } +} diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java index 0bff6187..c1e14c1f 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassAnalysingTransformer.java @@ -5,8 +5,8 @@ import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.util.MethodQualifier; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.util.MethodQualifier; import java.util.Map; @@ -20,7 +20,7 @@ public class ClassAnalysingTransformer implements ClassNodeTransformer.ClassProc ); @Override - public Patch.Result process(ClassNode node) { + public PatchResult process(ClassNode node) { boolean applied = false; for (MethodNode method : node.methods) { for (AbstractInsnNode insn : method.instructions) { @@ -35,6 +35,6 @@ public Patch.Result process(ClassNode node) { } } } - return applied ? Patch.Result.APPLY : Patch.Result.PASS; + return applied ? PatchResult.APPLY : PatchResult.PASS; } } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassNodeTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassNodeTransformer.java index 164888e5..dfd6b178 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassNodeTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ClassNodeTransformer.java @@ -4,7 +4,7 @@ import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.env.ctx.PatchResult; import java.util.List; @@ -17,7 +17,7 @@ public ClassNodeTransformer(ClassProcessor... processors) { @Override public ClassEntry process(ClassEntry entry) { - Patch.Result patchResult = Patch.Result.PASS; + PatchResult patchResult = PatchResult.PASS; ClassReader reader = new ClassReader(entry.getData()); ClassNode node = new ClassNode(); @@ -27,8 +27,8 @@ public ClassEntry process(ClassEntry entry) { patchResult = patchResult.or(processor.process(node)); } - if (patchResult != Patch.Result.PASS) { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | (patchResult == Patch.Result.COMPUTE_FRAMES ? ClassWriter.COMPUTE_FRAMES : 0)); + if (patchResult != PatchResult.PASS) { + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | (patchResult == PatchResult.COMPUTE_FRAMES ? ClassWriter.COMPUTE_FRAMES : 0)); node.accept(writer); return ClassEntry.create(entry.getName(), entry.getTime(), writer.toByteArray()); } @@ -44,7 +44,7 @@ public ResourceEntry process(ResourceEntry entry) { } public interface ClassProcessor { - Patch.Result process(ClassNode node); + PatchResult process(ClassNode node); default ResourceEntry process(ResourceEntry entry) { return entry; diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ConnectorRefmapHolder.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ConnectorRefmapHolder.java index e026d441..bf2b8f51 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ConnectorRefmapHolder.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ConnectorRefmapHolder.java @@ -1,7 +1,7 @@ package org.sinytra.connector.transformer.patch; +import org.sinytra.adapter.env.ctx.RefmapHolder; import org.sinytra.connector.transformer.transform.MappingAwareReferenceMapper; -import org.sinytra.adapter.patch.api.RefmapHolder; import java.util.HashSet; import java.util.Map; diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java index 5129ba2b..057f742b 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java @@ -8,17 +8,18 @@ import org.objectweb.asm.Handle; import org.objectweb.asm.Type; import org.objectweb.asm.tree.*; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.env.ann.ClassTarget; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.transform.ClassTransformer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -public class EnvironmentStripperTransformer implements ClassTransform { +public class EnvironmentStripperTransformer implements ClassTransformer { private static final String ENVIRONMENT_ANNOTATION = Type.getDescriptor(Environment.class); private static final String ENVIRONMENT_INTERFACE_DESCRIPTOR = Type.getDescriptor(EnvironmentInterface.class); private static final String ENVIRONMENT_INTERFACES_DESCRIPTOR = Type.getDescriptor(EnvironmentInterfaces.class); @@ -31,7 +32,7 @@ public EnvironmentStripperTransformer(EnvType envType) { } @Override - public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context) { + public PatchResult apply(ClassNode classNode, ClassTarget classTarget, PatchContext context) { boolean applied = stripEnvironmentInterface(classNode.interfaces, classNode.invisibleAnnotations); List removeMethods = new ArrayList<>(); @@ -50,7 +51,7 @@ public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle getMethodLambdas(ClassNode cls, MethodNode method) { diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/RedirectAccessorToMethod.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/RedirectAccessorToMethod.java deleted file mode 100644 index e9eacc20..00000000 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/RedirectAccessorToMethod.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.sinytra.connector.transformer.patch; - -import com.mojang.logging.LogUtils; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodNode; -import org.sinytra.adapter.patch.api.*; -import org.slf4j.Logger; - -import java.util.Collection; -import java.util.Set; - -import static org.sinytra.adapter.patch.PatchInstance.MIXINPATCH; - -public record RedirectAccessorToMethod(String value) implements MethodTransform { - private static final Logger LOGGER = LogUtils.getLogger(); - - @Override - public Collection getAcceptedAnnotations() { - return Set.of(MixinConstants.ACCESSOR); - } - - @Override - public Patch.Result apply(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - AnnotationVisitor visitor = methodNode.visitAnnotation(MixinConstants.INVOKER, true); - visitor.visit("value", this.value); - visitor.visitEnd(); - - methodNode.visibleAnnotations.remove(methodContext.methodAnnotation().unwrap()); - - LOGGER.info(MIXINPATCH, "Redirecting accessor {}.{} to invoke method {}", classNode.name, methodNode.name, this.value); - - return Patch.Result.APPLY; - } -} diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ReflectionRenamingTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ReflectionRenamingTransformer.java index 63d0a764..6fb905cb 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/patch/ReflectionRenamingTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/patch/ReflectionRenamingTransformer.java @@ -7,9 +7,9 @@ import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.analysis.SourceInterpreter; import org.objectweb.asm.tree.analysis.SourceValue; +import org.sinytra.adapter.analysis.method.MethodAnalyzer; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.connector.transformer.jar.IntermediateMapping; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -import org.sinytra.adapter.patch.api.Patch; import java.util.Collection; import java.util.HashSet; @@ -25,14 +25,14 @@ public ReflectionRenamingTransformer(IMappingFile mappingFile, IntermediateMappi } @Override - public Patch.Result process(ClassNode node) { + public PatchResult process(ClassNode node) { boolean applied = false; for (MethodNode method : node.methods) { ReflectionRemapperInterpreter interpreter = new ReflectionRemapperInterpreter(Opcodes.ASM9, this.mappingFile, this.flatMappings); - MethodCallAnalyzer.analyzeInterpretMethod(method, interpreter); + MethodAnalyzer.analyzeInterpretMethod(method, interpreter); applied |= interpreter.remapApplied(); } - return applied ? Patch.Result.APPLY : Patch.Result.PASS; + return applied ? PatchResult.APPLY : PatchResult.PASS; } private static class ReflectionRemapperInterpreter extends SourceInterpreter { diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/AccessorRedirectTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/AccessorRedirectTransformer.java index c0891e92..34e0166f 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/AccessorRedirectTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/AccessorRedirectTransformer.java @@ -1,81 +1,49 @@ package org.sinytra.connector.transformer.transform; -import net.minecraftforge.srgutils.IMappingFile; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.transform.patch.MethodPatch; +import org.sinytra.connector.transformer.patch.AccessorToInvokerTransformer; import org.sinytra.connector.transformer.patch.ClassNodeTransformer; -import org.sinytra.connector.transformer.patch.RedirectAccessorToMethod; -import org.sinytra.adapter.patch.api.MethodContext; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.api.PatchEnvironment; -import java.io.File; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import static cpw.mods.modlauncher.api.LambdaExceptionUtils.rethrowConsumer; public class AccessorRedirectTransformer implements ClassNodeTransformer.ClassProcessor { private static final String PREFIX = "connector$redirect$"; - public static final List PATCHES = FieldToMethodTransformer.REPLACEMENTS.entrySet().stream() + + private final Map> methodRenames = new HashMap<>(); + private final List patches = FieldToMethodTransformer.REPLACEMENTS.entrySet().stream() .flatMap(entry -> entry.getValue().values().stream() - .map(s -> Patch.interfaceBuilder() + .map(s -> MethodPatch.builder() .targetClass(entry.getKey().replace('.', '/')) .targetField(s) - .transform(new RedirectAccessorToMethod(s)) - .transform((classNode, methodNode, methodContext, patchContext) -> { - methodNode.name = PREFIX + methodNode.name; - return Patch.Result.APPLY; + .transform(new AccessorToInvokerTransformer(s)) + .transform((context, configuration) -> { + ClassNode classNode = context.classNode(); + MethodNode methodNode = context.methodNode(); + + // Add prefix to invoker + String newName = PREFIX + methodNode.name; + this.methodRenames.computeIfAbsent(classNode.name, a -> new HashMap<>()) + .put(methodNode.name + methodNode.desc, newName); + methodNode.name = newName; + + return PatchResult.APPLY; }) .build())) .toList(); - private final IMappingFile mappings; - private final Map> methodRenames = new HashMap<>(); - - public AccessorRedirectTransformer(IMappingFile mappings) { - this.mappings = mappings; - } - - public void analyze(File input, Set mixinPackages, PatchEnvironment environment) throws IOException { - List accessorAnalysisPatches = FieldToMethodTransformer.REPLACEMENTS.entrySet().stream() - .flatMap(entry -> entry.getValue().keySet().stream() - .map(s -> Patch.interfaceBuilder() - .targetClass(this.mappings.remapClass(entry.getKey().replace('.', '/'))) - .targetField(s) - .transform(this::analyzeAccessor) - .build())) - .toList(); - - try (FileSystem fs = FileSystems.newFileSystem(input.toPath(), Map.of())) { - for (String pkg : mixinPackages) { - Path packageRoot = fs.getPath(pkg); - if (Files.notExists(packageRoot)) { - continue; - } - try (Stream stream = Files.walk(packageRoot)) { - stream - .filter(path -> path.getFileName().toString().endsWith(".class")) - .forEach(rethrowConsumer(path -> analyzeClass(path, accessorAnalysisPatches, environment))); - } - } - } + public List getPatches() { + return this.patches; } @Override - public Patch.Result process(ClassNode node) { + public PatchResult process(ClassNode node) { boolean applied = false; for (MethodNode method : node.methods) { for (AbstractInsnNode insn : method.instructions) { @@ -91,23 +59,6 @@ public Patch.Result process(ClassNode node) { } } } - return applied ? Patch.Result.APPLY : Patch.Result.PASS; - } - - private void analyzeClass(Path path, List accessorAnalysisPatches, PatchEnvironment environment) throws IOException { - byte[] bytes = Files.readAllBytes(path); - ClassReader reader = new ClassReader(bytes); - ClassNode node = new ClassNode(); - reader.accept(node, ClassReader.SKIP_CODE); - - for (Patch patch : accessorAnalysisPatches) { - patch.apply(node, environment); - } - } - - private Patch.Result analyzeAccessor(ClassNode classNode, MethodNode methodNode, MethodContext methodContext, PatchContext context) { - this.methodRenames.computeIfAbsent(classNode.name, s -> new HashMap<>()) - .put(methodNode.name + methodNode.desc, PREFIX + methodNode.name); - return Patch.Result.PASS; + return applied ? PatchResult.APPLY : PatchResult.PASS; } } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/FieldToMethodTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/FieldToMethodTransformer.java index 16748e7c..a43f1212 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/FieldToMethodTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/FieldToMethodTransformer.java @@ -10,8 +10,8 @@ import net.minecraftforge.srgutils.IMappingFile; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.env.ctx.PatchResult; import org.sinytra.connector.transformer.patch.ClassNodeTransformer; -import org.sinytra.adapter.patch.api.Patch; import org.slf4j.Logger; import java.util.Collection; @@ -49,8 +49,8 @@ public FieldToMethodTransformer(String accessWidenerResource, IMappingFile mappi } @Override - public Patch.Result process(ClassNode node) { - return processClass(node) ? Patch.Result.APPLY : Patch.Result.PASS; + public PatchResult process(ClassNode node) { + return processClass(node) ? PatchResult.APPLY : PatchResult.PASS; } @Override diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/InheritingClassWriter.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/InheritingClassWriter.java new file mode 100644 index 00000000..070482f9 --- /dev/null +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/InheritingClassWriter.java @@ -0,0 +1,86 @@ +package org.sinytra.connector.transformer.transform; + +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Type; +import org.sinytra.adapter.env.ctx.PatchEnvironment; + +import java.lang.reflect.Modifier; +import java.util.*; + +public class InheritingClassWriter extends ClassWriter { + private final PatchEnvironment environment; + + public InheritingClassWriter(int flags, PatchEnvironment environment) { + super(flags); + this.environment = environment; + } + + // This method is a relative reimplementation of the super method that relies on reading transformable classes without loading them through the class provider + @Override + protected String getCommonSuperClass(String type1, String type2) { + var t1Info = getClassInfo(type1); + var t2Info = getClassInfo(type2); + + var t1Inh = getParents(t1Info); + var t2Inh = getParents(t2Info); + + // First check if type2 inherits from type1 + if (t2Inh.contains(type1)) { + return type1; + } + // Then check if type1 inherits from type2 + else if (t1Inh.contains(type2)) { + return type2; + } + + // If either is an interface and one isn't a superinterface of the other, we have to use Object + if (t1Info.isInterface() || t2Info.isInterface()) { + return "java/lang/Object"; + } else { + // So find the most direct parent of type1 that is a parent of type2 too. + // This vaguely resembles the last set of logic from the super method. + for (var t1Parent : t1Inh) { + if (t2Inh.contains(t1Parent)) { + return t1Parent; + } + } + + // If all fails, fallback to ASM's built-in logic + return super.getCommonSuperClass(type1, type2); + } + } + + private record ClassInfo(boolean isInterface, @Nullable String superClass, List interfaces) { + } + + private ClassInfo getClassInfo(String className) { + var asmNode = this.environment.cleanClassLookup().getClass(className); + if (asmNode.isPresent()) { + var node = asmNode.get(); + return new ClassInfo(Modifier.isInterface(node.access), node.superName, Objects.requireNonNullElse(node.interfaces, List.of())); + } + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + var clazz = Class.forName(className.replace('/', '.'), false, classLoader); + return new ClassInfo(clazz.isInterface(), clazz.getSuperclass() == null ? null : Type.getInternalName(clazz.getSuperclass()), Arrays.stream(clazz.getInterfaces()) + .map(Type::getInternalName).toList()); + } catch (ClassNotFoundException e) { + throw new TypeNotPresentException(className, e); + } + } + + private Set getParents(ClassInfo info) { + var parents = new LinkedHashSet(); + if (info.superClass() != null) { + parents.add(info.superClass()); + parents.addAll(getParents(getClassInfo(info.superClass()))); + } + for (var itf : info.interfaces()) { + if (parents.add(itf)) { + parents.addAll(getParents(getClassInfo(itf))); + } + } + return parents; + } +} diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatchTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatchTransformer.java index 0780418d..9e19c881 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatchTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatchTransformer.java @@ -1,21 +1,22 @@ package org.sinytra.connector.transformer.transform; -import com.google.common.collect.ImmutableList; import com.google.gson.*; import com.mojang.logging.LogUtils; import net.minecraftforge.fart.api.Transformer; -import org.jetbrains.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; -import org.sinytra.adapter.next.PipelineLegacyMethodTransformer; -import org.sinytra.adapter.patch.api.*; -import org.sinytra.adapter.patch.fixes.FieldTypePatchTransformer; -import org.sinytra.adapter.patch.fixes.FieldTypeUsageTransformer; -import org.sinytra.adapter.patch.transformer.dynamic.*; -import org.sinytra.adapter.patch.transformer.dynfix.DynamicInjectionPointPatch; +import org.sinytra.adapter.env.ctx.MixinClassGenerator; +import org.sinytra.adapter.env.ctx.PatchContext; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.patch.DynamicPatches; +import org.sinytra.adapter.patch.Patcher; +import org.sinytra.adapter.transform.ClassTransformer; +import org.sinytra.adapter.transform.patch.MethodPatch; +import org.sinytra.adapter.types.FieldTypeUsageTransformer; import org.sinytra.connector.transformer.TransformerEnvironment; import org.sinytra.connector.transformer.patch.EnvironmentStripperTransformer; import org.slf4j.Logger; @@ -23,7 +24,6 @@ import java.io.IOException; import java.io.Reader; import java.io.UncheckedIOException; -import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -33,47 +33,31 @@ import static cpw.mods.modlauncher.api.LambdaExceptionUtils.rethrowConsumer; public class MixinPatchTransformer implements Transformer { - private static final List PRIORITY_PATCHES = MixinPatches.getPriorityPatches(); - private static final List PATCHES = MixinPatches.getPatches(); + private static final List PRIORITY_PATCHES = MixinPatches.getPriorityPatches(); + private static final List PATCHES = MixinPatches.getPatches(); private static final Logger LOGGER = LogUtils.getLogger(); - // Applied to non-mixins - private final List classTransforms; + private final PatchEnvironment environment; + + // Applied to all classes including non-mixins + private final List classTransforms; // Applied to mixins only - private final Patch classPatch; + private final Patcher patcher; - private final PatchEnvironment environment; - private final List patches; + public MixinPatchTransformer(TransformerEnvironment runtimeEnvironment, PatchEnvironment environment, List extraPatches) { + this.environment = environment; - public MixinPatchTransformer(TransformerEnvironment runtimeEnvironment, PatchEnvironment environment, List extraPatches) { this.classTransforms = List.of( new EnvironmentStripperTransformer(runtimeEnvironment.getEnvType()), new FieldTypeUsageTransformer() ); - this.classPatch = Patch.builder() - .transform(classTransforms) - .build(); - this.environment = environment; - this.patches = ImmutableList.builder() - .addAll(PRIORITY_PATCHES) - .addAll(extraPatches) - .addAll(PATCHES) - .add( - Patch.builder() - .transform(new DynamicInjectorOrdinalPatch()) - .transform(new DynamicLVTPatch()) - .transform(new DynamicAnonClassIndexPatch()) - .transform(new DynamicAnonymousShadowFieldTypePatch()) - .transform(new DynamicModifyVarAtReturnPatch()) - .transform(new DynamicInheritedInjectionPointPatch()) - .transform(new DynamicInjectionPointPatch()) - .transform(new PipelineLegacyMethodTransformer()) - .build(), - Patch.interfaceBuilder() - .transform(new FieldTypePatchTransformer()) - .build() - ) + List allPatches = Stream.of(PRIORITY_PATCHES, extraPatches, PATCHES) + .flatMap(Collection::stream) + .toList(); + this.patcher = Patcher.builder(this.environment) + .classTransformers(DynamicPatches.CLASS_PATCHES) + .methodTransformers(DynamicPatches.methodTransformers(allPatches)) .build(); } @@ -161,7 +145,7 @@ private Map getMixinsInPackage(Strin @Override public ClassEntry process(ClassEntry entry) { - Patch.Result patchResult = Patch.Result.PASS; + PatchResult patchResult = PatchResult.PASS; ClassReader reader = new ClassReader(entry.getData()); ClassNode node = new ClassNode(); @@ -170,107 +154,29 @@ public ClassEntry process(ClassEntry entry) { // Some mods generate their mixin configs at runtime, therefore we must scan all classes // regardless of whether they're listed in present config files (see Andromeda) if (isMixinClass(node)) { - patchResult = patchResult.or(classPatch.apply(node, this.environment)); - - for (Patch patch : this.patches) { - patchResult = patchResult.or(patch.apply(node, this.environment)); - } + PatchResult txResult = this.patcher.process(node); + patchResult = patchResult.or(txResult); } else { - for (ClassTransform transform : classTransforms) { + for (ClassTransformer transform : this.classTransforms) { patchResult = patchResult.or(transform.apply(node, null, PatchContext.create(node, List.of(), this.environment))); } } // TODO if a mixin method is extracted, roll back the status from compute frames to apply, // Alternatively, change the order of patches so that extractmixin comes first - if (patchResult != Patch.Result.PASS) { - ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | (patchResult == Patch.Result.COMPUTE_FRAMES ? ClassWriter.COMPUTE_FRAMES : 0)) { - // This method is a relative reimplementation of the super method that relies on reading transformable classes without loading them through the class provider - @Override - protected String getCommonSuperClass(String type1, String type2) { - var t1Info = getClassInfo(type1); - var t2Info = getClassInfo(type2); - - var t1Inh = getParents(t1Info); - var t2Inh = getParents(t2Info); - - // First check if type2 inherits from type1 - if (t2Inh.contains(type1)) { - return type1; - } - // Then check if type1 inherits from type2 - else if (t1Inh.contains(type2)) { - return type2; - } - - // If either is an interface and one isn't a superinterface of the other, we have to use Object - if (t1Info.isInterface() || t2Info.isInterface()) { - return "java/lang/Object"; - } else { - // So find the most direct parent of type1 that is a parent of type2 too. - // This vaguely resembles the last set of logic from the super method. - for (var t1Parent : t1Inh) { - if (t2Inh.contains(t1Parent)) { - return t1Parent; - } - } - - // If all fails, fallback to ASM's built-in logic - return super.getCommonSuperClass(type1, type2); - } - } - }; + if (patchResult != PatchResult.PASS) { + ClassWriter writer = new InheritingClassWriter(ClassWriter.COMPUTE_MAXS | (patchResult == PatchResult.COMPUTE_FRAMES ? ClassWriter.COMPUTE_FRAMES : 0), this.environment); node.accept(writer); return ClassEntry.create(entry.getName(), entry.getTime(), writer.toByteArray()); } return entry; } - private Set getParents(ClassInfo info) { - var parents = new LinkedHashSet(); - if (info.superClass() != null) { - parents.add(info.superClass()); - parents.addAll(getParents(getClassInfo(info.superClass()))); - } - for (var itf : info.interfaces()) { - if (parents.add(itf)) { - parents.addAll(getParents(getClassInfo(itf))); - } - } - return parents; - } - - private ClassInfo getClassInfo(String className) { - var asmNode = environment.cleanClassLookup().getClass(className); - if (asmNode.isPresent()) { - var node = asmNode.get(); - return new ClassInfo(Modifier.isInterface(node.access), node.superName, Objects.requireNonNullElse(node.interfaces, List.of())); - } - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - try { - var clazz = Class.forName(className.replace('/', '.'), false, classLoader); - return new ClassInfo(clazz.isInterface(), clazz.getSuperclass() == null ? null : Type.getInternalName(clazz.getSuperclass()), Arrays.stream(clazz.getInterfaces()) - .map(Type::getInternalName).toList()); - } catch (ClassNotFoundException e) { - throw new TypeNotPresentException(className, e); - } - } - - private record ClassInfo(boolean isInterface, @Nullable String superClass, List interfaces) {} - @Override public Collection getExtras() { List entries = new ArrayList<>(); - List patches = ImmutableList.builder() - .add( - Patch.builder() - .transform(new DynamicInheritedInjectionPointPatch()) - .build() - ).build(); this.environment.classGenerator().getGeneratedMixinClasses().forEach((name, cls) -> { - for (Patch patch : patches) { - patch.apply(cls.node(), this.environment); - } + this.patcher.process(cls.node()); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cls.node().accept(writer); @@ -283,7 +189,7 @@ public Collection getExtras() { private static boolean isMixinClass(ClassNode classNode) { if (classNode.invisibleAnnotations != null) { for (AnnotationNode annotation : classNode.invisibleAnnotations) { - if (annotation.desc.equals(MixinConstants.MIXIN)) { + if (annotation.desc.equals(MixinAnnotations.MIXIN)) { return true; } } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatches.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatches.java index 0604a03e..8364c762 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatches.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/MixinPatches.java @@ -5,34 +5,32 @@ import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; -import org.sinytra.adapter.patch.api.MixinConstants; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.transformer.operation.unit.ModifyMethodAccess; -import org.sinytra.adapter.patch.transformer.operation.param.ParamTransformTarget; +import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.env.ctx.PatchResult; +import org.sinytra.adapter.env.util.MixinAnnotations; +import org.sinytra.adapter.transform.patch.MethodPatch; import java.util.List; -import java.util.ListIterator; import java.util.stream.Collectors; import java.util.stream.Stream; -@SuppressWarnings("deprecation") public class MixinPatches { - public static List getPriorityPatches() { + public static List getPriorityPatches() { return List.of( - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/item/ItemStack") .targetMethod("useOn") .targetInjectionPoint("INVOKE", "Lnet/minecraft/world/item/ItemStack;getItem()Lnet/minecraft/world/item/Item;") .modifyTarget("connector_useOn") - .modifyInjectionPoint("RETURN", "", true) + .replaceInjectionPoint("RETURN", null) .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/Minecraft") .targetMethod("") .targetInjectionPoint("Lnet/fabricmc/loader/impl/game/minecraft/Hooks;startClient(Ljava/io/File;Ljava/lang/Object;)V") .modifyInjectionPoint("Ljava/lang/Thread;currentThread()Ljava/lang/Thread;") .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/server/Main") .targetMethod("main([Ljava/lang/String;)V") .targetInjectionPoint("Lnet/fabricmc/loader/impl/game/minecraft/Hooks;startServer(Ljava/io/File;Ljava/lang/Object;)V") @@ -42,34 +40,40 @@ public static List getPriorityPatches() { // We not only have to extract the mixin but we also have to retarget it to a method we inject // as the NeoForge extension method accepts a LevelReader rather than a Level so our // injected method will handle a safe cast and reordering the locals (swap the beacon pos and the block pos) - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/level/block/entity/BeaconBlockEntity") .targetMethod("tick") .targetInjectionPoint("INVOKE", "Lnet/minecraft/world/item/DyeColor;getTextureDiffuseColor()I") - .modifyMethodAccess(new ModifyMethodAccess.AccessChange(false, Opcodes.ACC_STATIC)) + .modifyStatic(false) .extractMixin("net/neoforged/neoforge/common/extensions/IBlockExtension") .modifyTarget("connector_getTextureDiffuseColor") .build() ); } - public static List getPatches() { + public static List getPatches() { final List patches = List.of( // ======= Necessary manual patches - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/KeyMapping") .targetMethod("set") - .targetInjectionPoint("TAIL", "") - .modifyInjectionPoint("Lnet/minecraft/client/KeyMapping;setDown(Z)V") + .targetInjectionPoint("TAIL", null) + .modifyInjectionPoint("INVOKE", "Lnet/minecraft/client/KeyMapping;setDown(Z)V") .build(), - Patch.builder() + MethodPatch.builder() + .targetClass("net/minecraft/client/KeyMapping") + .targetMethod("click") + .targetInjectionPoint("TAIL", null) + .modifyInjectionPoint("FIELD", "Lnet/minecraft/client/KeyMapping;clickCount:I") + .build(), + MethodPatch.builder() .targetClass("net/minecraft/world/level/block/piston/PistonStructureResolver") .targetMethod("isSticky") .modifyTarget("canStickTo(Lnet/minecraft/world/level/block/state/BlockState;)Z") - .modifyMethodAccess(new ModifyMethodAccess.AccessChange(false, Opcodes.ACC_STATIC)) // TODO Should be automatic + .modifyStatic(false) // TODO Should be automatic .extractMixin("net/neoforged/neoforge/common/extensions/IBlockStateExtension") .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/LivingEntity") .targetMethod("baseTick") .targetInjectionPoint("Lnet/minecraft/world/entity/LivingEntity;isEyeInFluid(Lnet/minecraft/tags/TagKey;)Z") @@ -77,14 +81,14 @@ public static List getPatches() { .modifyInjectionPoint("Lnet/neoforged/neoforge/fluids/FluidType;isAir()Z") .extractMixin("net/neoforged/neoforge/common/CommonHooks") .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/LivingEntity") .targetMethod("goDownInWater()V") .targetConstant(-0.03999999910593033D) .extractMixin("net/neoforged/neoforge/common/extensions/ILivingEntityExtension") .modifyTarget("sinkInFluid(Lnet/neoforged/neoforge/fluids/FluidType;)V") .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/LivingEntity") .targetMethod("updateFallFlying") .targetInjectionPoint("INVOKE", "Lnet/minecraft/world/item/ItemStack;hurtAndBreak(ILnet/minecraft/world/entity/LivingEntity;Ljava/util/function/Consumer;)V") @@ -92,24 +96,19 @@ public static List getPatches() { .modifyTarget("elytraFlightTick(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;I)Z") .build(), // Move redirectors of Map.put to KeyMappingLookup.put - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/KeyMapping") .targetMethod("resetMapping()V") .targetInjectionPoint("Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") .modifyInjectionPoint("Lnet/minecraftforge/client/settings/KeyMappingLookup;put(Lcom/mojang/blaze3d/platform/InputConstants$Key;Lnet/minecraft/client/KeyMapping;)V") - .targetMixinType(MixinConstants.REDIRECT) - .modifyParams(builder -> builder - .replace(0, Type.getObjectType("net/minecraftforge/client/settings/KeyMappingLookup")) - .replace(1, Type.getObjectType("com/mojang/blaze3d/platform/InputConstants$Key")) - .replace(2, Type.getObjectType("net/minecraft/client/KeyMapping"))) - .transform((classNode, methodNode, methodContext, patchContext) -> { - for (ListIterator iterator = methodNode.instructions.iterator(); iterator.hasNext(); ) { - AbstractInsnNode insn = iterator.next(); + .targetMixinType(MixinAnnotations.REDIRECT) + .transform((context, configuration) -> { + MethodNode methodNode = context.methodNode(); + for (AbstractInsnNode insn : methodNode.instructions) { if (insn.getOpcode() == Opcodes.ARETURN) { methodNode.instructions.insertBefore(insn, new InsnNode(Opcodes.POP)); methodNode.instructions.set(insn, new InsnNode(Opcodes.RETURN)); - } - else if (insn instanceof MethodInsnNode minsn && minsn.name.equals("put") && minsn.desc.equals("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) { + } else if (insn instanceof MethodInsnNode minsn && minsn.name.equals("put") && minsn.desc.equals("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) { minsn.desc = "(Lcom/mojang/blaze3d/platform/InputConstants$Key;Lnet/minecraft/client/KeyMapping;)V"; minsn.itf = false; minsn.setOpcode(Opcodes.INVOKEVIRTUAL); @@ -117,51 +116,53 @@ public static List getPatches() { } } methodNode.desc = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getArgumentTypes(methodNode.desc)); - return Patch.Result.APPLY; + return PatchResult.APPLY; }) .build(), // NeoForge moves this behaviour out completely with no viable replacement, so we disable it for now - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/animal/SnowGolem", "net/minecraft/world/entity/animal/Sheep", "net/minecraft/world/entity/animal/MushroomCow") .targetMethod("mobInteract") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z") .disable() .build(), // ======= Rendering patches - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/renderer/ShaderInstance", "net/minecraft/client/renderer/EffectInstance") .targetMethod("", "getOrCreate") .targetInjectionPoint("Lnet/minecraft/resources/ResourceLocation;withDefaultNamespace(Ljava/lang/String;)Lnet/minecraft/resources/ResourceLocation;") + // Axiom-specific (broken) target we still want to match + .targetInjectionPoint("Lnet/minecraft/resources/ResourceLocation;withDefaultNamespace(Ljava/lang/String;)Lnet/minecraft/resources/Identifier;") .disable() .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/renderer/PostChain") .targetMethod("parsePassNode") // TODO update these .targetInjectionPoint("NEW", "net/minecraft/resources/ResourceLocation") .targetInjectionPoint("NEW", "(Ljava/lang/String;)Lnet/minecraft/resources/ResourceLocation;") - .targetMixinType(MixinConstants.REDIRECT) + .targetMixinType(MixinAnnotations.REDIRECT) .disable() .build(), // Disable potential duplicate attempts at making shaders IDs namespace aware - Neo already does this for us. // Attempts at doing so again will fail. - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/renderer/EffectInstance") .targetMethod("", "getOrCreate") .targetInjectionPoint("Lnet/minecraft/resources/ResourceLocation;withDefaultNamespace(Ljava/lang/String;)Lnet/minecraft/resources/ResourceLocation;") - .targetMixinType(MixinConstants.REDIRECT) + .targetMixinType(MixinAnnotations.REDIRECT) .disable() .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/renderer/entity/layers/ElytraLayer") .targetMethod("render(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/LivingEntity;FFFFFF)V") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z") - .targetMixinType(MixinConstants.REDIRECT) - .modifyParams(builder -> builder - .insert(0, Type.getObjectType("net/minecraft/client/renderer/entity/layers/ElytraLayer")) - .replace(2, Type.getObjectType("net/minecraft/world/entity/LivingEntity")) - .targetType(ParamTransformTarget.INJECTION_POINT) - .ignoreOffset()) + .targetMixinType(MixinAnnotations.REDIRECT) +// .modifyParams(builder -> builder +// .insert(0, Type.getObjectType("net/minecraft/client/renderer/entity/layers/ElytraLayer")) +// .replace(2, Type.getObjectType("net/minecraft/world/entity/LivingEntity")) +// .targetType(ParamTransformTarget.INJECTION_POINT) +// .ignoreOffset()) .divertRedirector(adapter -> { adapter.visitVarInsn(Opcodes.ALOAD, 1); adapter.visitVarInsn(Opcodes.ALOAD, 2); @@ -171,57 +172,53 @@ public static List getPatches() { .modifyInjectionPoint("Lnet/minecraft/client/renderer/entity/layers/ElytraLayer;shouldRender(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;)Z") .build(), // ======= TODO Handle in adapter - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/vehicle/Boat") .targetMethod("m_38394_", "m_38393_", "m_38371_", "m_7840_") .targetInjectionPoint("Lnet/minecraft/world/level/material/FluidState;is(Lnet/minecraft/tags/TagKey;)Z") - .targetMixinType(MixinConstants.REDIRECT) + .targetMixinType(MixinAnnotations.REDIRECT) .modifyInjectionPoint("Lnet/minecraft/world/entity/vehicle/Boat;canBoatInFluid(Lnet/minecraft/world/level/material/FluidState;)Z") - .modifyParams(b -> b - .targetType(ParamTransformTarget.INJECTION_POINT) - .ignoreOffset() - .insert(0, Type.getObjectType("net/minecraft/world/entity/vehicle/Boat")) - .inline(2, i -> i.getstatic("net/minecraft/tags/FluidTags", "WATER", "Lnet/minecraft/tags/TagKey;"))) +// .modifyParams(b -> b +// .targetType(ParamTransformTarget.INJECTION_POINT) +// .ignoreOffset() +// .insert(0, Type.getObjectType("net/minecraft/world/entity/vehicle/Boat")) +// .inline(2, i -> i.getstatic("net/minecraft/tags/FluidTags", "WATER", "Lnet/minecraft/tags/TagKey;"))) .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/entity/player/Player") .targetMethod("hurtCurrentlyUsedShield(F)V") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z") - .targetMixinType(MixinConstants.WRAP_OPERATION) + .targetMixinType(MixinAnnotations.WRAP_OPERATION) .modifyInjectionPoint("Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/minecraftforge/common/ToolAction;)Z") - .modifyParams(builder -> builder.replace(1, Type.getObjectType("net/minecraftforge/common/ToolAction"))) .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/client/renderer/entity/FishingHookRenderer") .targetMethod("render(Lnet/minecraft/world/entity/projectile/FishingHook;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;m_150930_(Lnet/minecraft/world/item/Item;)Z") - .targetMixinType(MixinConstants.WRAP_OPERATION) + .targetMixinType(MixinAnnotations.WRAP_OPERATION) .modifyInjectionPoint("Lnet/minecraft/world/item/ItemStack;canPerformAction(Lnet/minecraftforge/common/ToolAction;)Z") - .modifyParams(builder -> builder.replace(1, Type.getObjectType("net/minecraftforge/common/ToolAction"))) .build(), - Patch.builder() + MethodPatch.builder() .targetClass("net/minecraft/world/level/block/PowderSnowBlock") .targetMethod("canEntityWalkOnPowderSnow(Lnet/minecraft/world/entity/Entity;)Z") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z") - .targetMixinType(MixinConstants.WRAP_OPERATION) + .targetMixinType(MixinAnnotations.WRAP_OPERATION) .modifyInjectionPoint("Lnet/minecraft/world/item/ItemStack;canWalkOnPowderedSnow(Lnet/minecraft/world/entity/LivingEntity;)Z") - .modifyParams(builder -> builder.replace(1, Type.getObjectType("net/minecraft/world/entity/LivingEntity"))) .build(), - Patch.builder() // This is the annoying instanceof CrossbowItem patch TODO see DynamicSyntheticInstanceofPatch + MethodPatch.builder() // This is the annoying instanceof CrossbowItem patch TODO see DynamicSyntheticInstanceofPatch .targetClass("net/minecraft/client/renderer/ItemInHandRenderer") .targetMethod("renderArmWithItem") .targetInjectionPoint("Lnet/minecraft/world/item/ItemStack;is(Lnet/minecraft/world/item/Item;)Z") - .targetMixinType(MixinConstants.MODIFY_ARG) - .modifyParams(builder -> builder - .replace(0, Type.getObjectType("net/minecraft/world/item/ItemStack"))) - .modifyMixinType(MixinConstants.REDIRECT, builder -> builder - .sameTarget() - .injectionPoint("INVOKE", "Lnet/minecraft/world/item/ItemStack;getItem()Lnet/minecraft/world/item/Item;")) - .build()); + .targetMixinType(MixinAnnotations.MODIFY_ARG) + .modifyMixinType(MixinAnnotations.REDIRECT) + .modifyTarget("renderArmWithItem") + .modifyInjectionPoint("INVOKE", "Lnet/minecraft/world/item/ItemStack;getItem()Lnet/minecraft/world/item/Item;") + .build() + ); return patches.stream() .flatMap(p -> p instanceof List lst ? lst.stream() : Stream.of(p)) - .map(o -> (Patch) o) + .map(o -> (MethodPatch) o) .collect(Collectors.toList()); // Mutable list } } diff --git a/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java b/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java index 477340f0..5e76d0b5 100644 --- a/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java +++ b/transformer/src/main/java/org/sinytra/connector/transformer/transform/OptimizedRenamingTransformer.java @@ -11,11 +11,11 @@ import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.tree.*; +import org.sinytra.adapter.analysis.method.MethodCallAnalyzer; +import org.sinytra.adapter.analysis.selector.AnnotationHandle; +import org.sinytra.adapter.analysis.selector.AnnotationValueHandle; +import org.sinytra.adapter.util.MethodQualifier; import org.sinytra.connector.transformer.jar.IntermediateMapping; -import org.sinytra.adapter.patch.analysis.MethodCallAnalyzer; -import org.sinytra.adapter.patch.analysis.selector.AnnotationHandle; -import org.sinytra.adapter.patch.analysis.selector.AnnotationValueHandle; -import org.sinytra.adapter.patch.util.MethodQualifier; import org.spongepowered.asm.mixin.gen.AccessorInfo; import java.io.IOException; @@ -92,8 +92,8 @@ private void avoidAmbigousMappingRecursion(ClassNode classNode, MethodNode metho if (parentMethods > 1) { for (AbstractInsnNode insn : method.instructions) { if (insn instanceof MethodInsnNode minsn && minsn.getOpcode() == Opcodes.INVOKEVIRTUAL && minsn.owner.equals(classNode.name) && minsn.name.equals(method.name) && minsn.desc.equals(method.desc)) { - List insns = MethodCallAnalyzer.findMethodCallParamInsns(method, minsn); - if (!insns.isEmpty() && insns.getFirst() instanceof VarInsnNode varInsn && varInsn.var == 0) { + List insns = MethodCallAnalyzer.getMethodCallInsns(method, minsn); + if (insns != null && !insns.isEmpty() && insns.getFirst() instanceof VarInsnNode varInsn && varInsn.var == 0) { method.instructions.set(minsn, new MethodInsnNode(Opcodes.INVOKESPECIAL, classNode.superName, minsn.name, minsn.desc, minsn.itf)); } } @@ -188,7 +188,7 @@ else if (str.matches(INTERNAL_CLASS_NAME_PATTERN)) { } } - MethodQualifier qualifier = MethodQualifier.create(str).orElse(null); + MethodQualifier qualifier = MethodQualifier.parse(str).orElse(null); if (qualifier != null && qualifier.desc() != null) { String owner = qualifier.owner() != null ? this.remapper.mapDesc(qualifier.owner()) : ""; String name = qualifier.name() != null ? this.flatMappings.mapMethodOrDefault(qualifier.name(), qualifier.desc()) : ""; diff --git a/transformer/src/runner/java/org/sinytra/connector/transformer/runner/PortableRuntimeEnvironment.java b/transformer/src/runner/java/org/sinytra/connector/transformer/runner/PortableRuntimeEnvironment.java index 27affb18..020f309b 100644 --- a/transformer/src/runner/java/org/sinytra/connector/transformer/runner/PortableRuntimeEnvironment.java +++ b/transformer/src/runner/java/org/sinytra/connector/transformer/runner/PortableRuntimeEnvironment.java @@ -7,7 +7,7 @@ import net.fabricmc.loader.impl.metadata.VersionOverrides; import net.minecraftforge.fart.api.ClassProvider; import org.jetbrains.annotations.Nullable; -import org.sinytra.adapter.patch.util.provider.ClassLookup; +import org.sinytra.adapter.util.provider.ClassLookup; import org.sinytra.connector.transformer.TransformerEnvironment; import org.sinytra.connector.transformer.jar.SimpleClassLookup; import org.sinytra.connector.transformer.runner.runtime.MixinServiceProbe;