From 4c1c3aafdb5418edefa50ff5026eaf29d7595b6a Mon Sep 17 00:00:00 2001 From: Jonathing Date: Tue, 16 Sep 2025 15:13:30 -0400 Subject: [PATCH] Deprecate JS CoreMods, remove Forge's usages of them (#10659) --- build_forge.gradle | 3 +- .../fml/loading/moddiscovery/ModFile.java | 5 +- forge-transformers/build.gradle | 73 +++++++++ .../FieldToMethodTransformer.java | 78 ++++++++++ .../transformers/ForgeModTransformers.java | 35 +++++ .../forge/transformers/MethodRedirector.java | 142 ++++++++++++++++++ ...ods.modlauncher.api.ITransformationService | 1 + .../coremods/finalize_spawn_targets.json | 0 settings.gradle | 1 + .../client/FramePassManager.java | 1 + .../client/event/AddFramePassEvent.java | 1 + .../client/gui/overlay/ForgeLayer.java | 5 + src/main/resources/META-INF/coremods.json | 4 - .../resources/coremods/field_to_method.js | 62 -------- .../resources/coremods/method_redirector.js | 114 -------------- .../debug/client/RenderFrameLayerTest.java | 1 + 16 files changed, 344 insertions(+), 182 deletions(-) create mode 100644 forge-transformers/build.gradle create mode 100644 forge-transformers/src/main/java/net/minecraftforge/forge/transformers/FieldToMethodTransformer.java create mode 100644 forge-transformers/src/main/java/net/minecraftforge/forge/transformers/ForgeModTransformers.java create mode 100644 forge-transformers/src/main/java/net/minecraftforge/forge/transformers/MethodRedirector.java create mode 100644 forge-transformers/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService rename {src => forge-transformers/src}/main/resources/coremods/finalize_spawn_targets.json (100%) delete mode 100644 src/main/resources/META-INF/coremods.json delete mode 100644 src/main/resources/coremods/field_to_method.js delete mode 100644 src/main/resources/coremods/method_redirector.js diff --git a/build_forge.gradle b/build_forge.gradle index bdaf06dc71..f7bfab8ec4 100644 --- a/build_forge.gradle +++ b/build_forge.gradle @@ -142,6 +142,7 @@ dependencies { installer(project(':javafmllanguage')) installer(project(':lowcodelanguage')) installer(project(':mclanguage')) + installer(project(':forge-transformers')) installerextra("${MCP_ARTIFACT.group}:${MCP_ARTIFACT.name}:${MCP_ARTIFACT.version}:srg2off") @@ -997,7 +998,7 @@ if (project.hasProperty('UPDATE_MAPPINGS')) { tasks.named('javadoc', Javadoc).configure { description 'Generates the combined javadocs for the FML projects and the main Forge project' - var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage' ] + var includedProjects = [ ':fmlcore', ':fmlloader', ':javafmllanguage', ':mclanguage', ':forge-transformers' ] source includedProjects.collect { project(it).sourceSets.main.allJava } classpath = classpath + files(includedProjects.collect { project(it).sourceSets.main.compileClasspath }) diff --git a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java index 90baa56ae8..6869e1d121 100644 --- a/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java +++ b/fmlloader/src/main/java/net/minecraftforge/fml/loading/moddiscovery/ModFile.java @@ -100,7 +100,10 @@ public class ModFile implements IModFile { if (this.modFileInfo == null) return this.getType() != Type.MOD; LOGGER.debug(LogMarkers.LOADING,"Loading mod file {} with languages {}", this.getFilePath(), this.modFileInfo.requiredLanguageLoaders()); this.coreMods = ModFileParser.getCoreMods(this); - this.coreMods.forEach(mi-> LOGGER.debug(LogMarkers.LOADING,"Found coremod {}", mi.getPath())); + if (!this.coreMods.isEmpty()) + LOGGER.warn("Mod file {} contains javascript coremods! JS CoreMods are deprecated and will be removed in a future release. Consider using Mixin or ModLauncher transformers.", this.getFileName()); + for (var mi : this.coreMods) + LOGGER.debug(LogMarkers.LOADING, "Found coremod {}", mi.getPath()); this.accessTransformer = findResource("META-INF", "accesstransformer.cfg"); return true; } diff --git a/forge-transformers/build.gradle b/forge-transformers/build.gradle new file mode 100644 index 0000000000..e48c65d900 --- /dev/null +++ b/forge-transformers/build.gradle @@ -0,0 +1,73 @@ +import net.minecraftforge.gradleutils.PomUtils + +plugins { + id 'java-library' + id 'maven-publish' + id 'net.minecraftforge.licenser' + id 'net.minecraftforge.gradleutils' + alias(libs.plugins.apt) +} + +apply from: rootProject.file('build_shared.gradle') + +configurations.forEach{ it.transitive = false } + +dependencies { + compileOnly(libs.jetbrains.annotations) + + implementation(libs.bundles.asm) // Needed by all the black magic + implementation(libs.log4j.api) + implementation(libs.gson) + implementation(libs.modlauncher) + implementation(libs.coremods) // Used for ASMAPI (for now) + + testCompileOnly(libs.jetbrains.annotations) +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(JAVA_VERSION) + withSourcesJar() +} + +tasks.named('jar', Jar) { + manifest { + attributes([ + 'Automatic-Module-Name': 'net.minecraftforge.forge.transformers', + 'Forge-Module-Layer': 'boot' + ] as LinkedHashMap) + attributes([ + 'Specification-Title': 'Forge Transformers', + 'Specification-Vendor': 'Forge Development LLC', + 'Specification-Version': '1', + 'Implementation-Title': 'Forge Transformers', + 'Implementation-Vendor': 'Forge Development LLC', + 'Implementation-Version': FORGE_VERSION + ] as LinkedHashMap, 'net/minecraftforge/forge/transformers/') + } +} + +tasks.withType(JavaCompile).configureEach { + options.compilerArgs << '-Xlint:unchecked' +} + +license { + header = rootProject.file('LICENSE-header.txt') +} + +publishing { + publications.register('mavenJava', MavenPublication) { + from components.java + artifactId = 'forge-transformers' + pom { + name = project.name + description = 'Forge-specific transformers unrelated to the FML project.' + url = 'https://github.com/MinecraftForge/MinecraftForge' + PomUtils.setGitHubDetails(pom, 'MinecraftForge') + license PomUtils.Licenses.LGPLv2_1 + } + } + + repositories { + maven gradleutils.publishingForgeMaven + } +} diff --git a/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/FieldToMethodTransformer.java b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/FieldToMethodTransformer.java new file mode 100644 index 0000000000..3415744140 --- /dev/null +++ b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/FieldToMethodTransformer.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.forge.transformers; + +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ITransformerVotingContext; +import cpw.mods.modlauncher.api.TransformerVoteResult; +import net.minecraftforge.coremod.api.ASMAPI; +import org.jetbrains.annotations.NotNull; +import org.objectweb.asm.tree.ClassNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +record FieldToMethodTransformer(String className, Map fields) implements ITransformer { + // TODO [Forge][Transformer] Make this properly data driven or configurable. + // It was hard-coded like this before when using JS CoreMods, though. + static final Map> TARGETS = Map.of( + "net.minecraft.world.level.biome.Biome", + Map.of( + "climateSettings", "getModifiedClimateSettings", + "specialEffects", "getModifiedSpecialEffects" + ), + + "net.minecraft.world.effect.MobEffectInstance", + Map.of( + "effect", "getEffect" + ), + + "net.minecraft.world.level.block.LiquidBlock", + Map.of( + "fluid", "getFluid" + ), + + "net.minecraft.world.item.BucketItem", + Map.of( + "content", "getFluid" + ), + + "net.minecraft.world.level.block.FlowerPotBlock", + Map.of( + "potted", "getPotted" + ) + ); + + @SuppressWarnings("rawtypes") + static List getAll() { + var ret = new ArrayList(TARGETS.size()); + for (var entry : TARGETS.entrySet()) { + ret.add(new FieldToMethodTransformer(entry.getKey(), entry.getValue())); + } + return ret; + } + + @Override + public @NotNull ClassNode transform(ClassNode input, ITransformerVotingContext context) { + for (var entry : this.fields.entrySet()) { + ASMAPI.redirectFieldToMethod(input, entry.getKey(), entry.getValue()); + } + + return input; + } + + @Override + public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) { + return TransformerVoteResult.YES; + } + + @Override + public @NotNull Set targets() { + return Set.of(Target.targetClass(this.className)); + } +} diff --git a/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/ForgeModTransformers.java b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/ForgeModTransformers.java new file mode 100644 index 0000000000..48b32c3e1f --- /dev/null +++ b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/ForgeModTransformers.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.forge.transformers; + +import cpw.mods.modlauncher.api.IEnvironment; +import cpw.mods.modlauncher.api.ITransformationService; +import cpw.mods.modlauncher.api.ITransformer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public record ForgeModTransformers(String name) implements ITransformationService { + public ForgeModTransformers() { + this("forge"); + } + + @Override + public void initialize(IEnvironment environment) { } + + @Override + public void onLoad(IEnvironment env, Set otherServices) { } + + @Override + @SuppressWarnings("rawtypes") + public @NotNull List transformers() { + List transformers = FieldToMethodTransformer.getAll(); + transformers.add(new MethodRedirector()); + return transformers; + } +} diff --git a/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/MethodRedirector.java b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/MethodRedirector.java new file mode 100644 index 0000000000..58f13fb406 --- /dev/null +++ b/forge-transformers/src/main/java/net/minecraftforge/forge/transformers/MethodRedirector.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.forge.transformers; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; +import cpw.mods.modlauncher.api.ITransformer; +import cpw.mods.modlauncher.api.ITransformerVotingContext; +import cpw.mods.modlauncher.api.TransformerVoteResult; +import net.minecraftforge.coremod.api.ASMAPI; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodInsnNode; + +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; + +// NOTE: THIS IS A SINGLETON! +record MethodRedirector() implements ITransformer { + private static final Logger LOGGER = LogManager.getLogger(); + private static final Gson GSON = new Gson(); + + private static final Replacement[] REPLACEMENTS = { + new Replacement( + // finalizeSpawn redirection to ForgeEventFactory.onFinalizeSpawn + ASMAPI.MethodType.VIRTUAL, + "finalizeSpawn", + "(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;", + GSON.fromJson(new InputStreamReader(sneak(() -> MethodRedirector.class.getModule().getResourceAsStream("coremods/finalize_spawn_targets.json"))), Target[].class), + insn -> ASMAPI.buildMethodCall( + ASMAPI.MethodType.STATIC, + "net/minecraftforge/event/ForgeEventFactory", + "onFinalizeSpawn", + "(Lnet/minecraft/world/entity/Mob;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;" + ) + ) + }; + + private static T sneak(Callable callable) { + try { + return callable.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + record Replacement( + ASMAPI.MethodType type, + String name, + String desc, + Target[] targets, + UnaryOperator factory + ) { } + + record Target( + @SerializedName("class") String className, + String[] methods + ) { } + + @Override + public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) { + return TransformerVoteResult.YES; + } + + @Override + public @NotNull Set targets() { + return Arrays + .stream(REPLACEMENTS) + .map(Replacement::targets) + .flatMap(Arrays::stream) + .map(Target::className) + .map(ITransformer.Target::targetClass) + .collect(Collectors.toUnmodifiableSet()); + } + + @Override + public @NotNull ClassNode transform(ClassNode clazz, ITransformerVotingContext context) { + for (var replacement : REPLACEMENTS) { + for (var methodString : getClassTargetMethods(clazz, replacement)) { + // cut up the string since we've put both the name and desc as the target + var splitPos = methodString.indexOf('('); + var methodName = methodString.substring(0, splitPos); + var methodDesc = methodString.substring(splitPos); + var method = ASMAPI.findMethodNode(clazz, methodName, methodDesc); + + if (method == null) { + LOGGER.error("Failed to redirect method call for {}! Method {} not found in class {}! This is a Forge bug, and is likely due to a Minecraft update changing something.", replacement.name, methodString, clazz.name); + continue; + } + + for (var insn : method.instructions) { + if (!shouldReplace(insn, replacement)) continue; + + var methodInsn = (MethodInsnNode) insn; + var redirection = replacement.factory.apply(methodInsn); + LOGGER.debug("Redirecting method call {}{} to {}{} inside of {}.{}", methodInsn.name, methodInsn.desc, redirection.name, redirection.desc, clazz.name, method.name); + ASMAPI.insertInsn(method, methodInsn, redirection, ASMAPI.InsertMode.REMOVE_ORIGINAL); + } + } + } + + return clazz; + } + + private static boolean shouldReplace(AbstractInsnNode insn, Replacement replacement) { + return insn.getOpcode() == replacement.type.toOpcode() + && replacement.name.equals(((MethodInsnNode) insn).name) + && replacement.desc.equals(((MethodInsnNode) insn).desc); + } + + private static List getClassTargetMethods(ClassNode clazz, Replacement replacement) { + for (var t : replacement.targets) { + if (!t.className.equals(clazz.name)) continue; + + // declared methods + var targets = new ArrayList<>(Arrays.asList(t.methods)); + + // synthetic methods + for (var method : clazz.methods) { + if ((method.access & Opcodes.ACC_SYNTHETIC) != 0) + targets.add(method.name + method.desc); + } + + return targets; + } + + return List.of(); + } +} diff --git a/forge-transformers/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService b/forge-transformers/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService new file mode 100644 index 0000000000..02bb9e26ec --- /dev/null +++ b/forge-transformers/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService @@ -0,0 +1 @@ +net.minecraftforge.forge.transformers.ForgeModTransformers \ No newline at end of file diff --git a/src/main/resources/coremods/finalize_spawn_targets.json b/forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json similarity index 100% rename from src/main/resources/coremods/finalize_spawn_targets.json rename to forge-transformers/src/main/resources/coremods/finalize_spawn_targets.json diff --git a/settings.gradle b/settings.gradle index 4545965c48..47c26d59eb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -117,6 +117,7 @@ include 'mclanguage' include 'javafmllanguage' include 'lowcodelanguage' include 'fmlearlydisplay' +include 'forge-transformers' include ':mcp' project(":mcp").projectDir = file("projects/mcp") diff --git a/src/main/java/net/minecraftforge/client/FramePassManager.java b/src/main/java/net/minecraftforge/client/FramePassManager.java index 37188003dc..1330764962 100644 --- a/src/main/java/net/minecraftforge/client/FramePassManager.java +++ b/src/main/java/net/minecraftforge/client/FramePassManager.java @@ -2,6 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ + package net.minecraftforge.client; import com.mojang.blaze3d.framegraph.FrameGraphBuilder; diff --git a/src/main/java/net/minecraftforge/client/event/AddFramePassEvent.java b/src/main/java/net/minecraftforge/client/event/AddFramePassEvent.java index 5749771334..02d323a59e 100644 --- a/src/main/java/net/minecraftforge/client/event/AddFramePassEvent.java +++ b/src/main/java/net/minecraftforge/client/event/AddFramePassEvent.java @@ -2,6 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ + package net.minecraftforge.client.event; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/net/minecraftforge/client/gui/overlay/ForgeLayer.java b/src/main/java/net/minecraftforge/client/gui/overlay/ForgeLayer.java index c5ae37ee6e..a33c799ee0 100644 --- a/src/main/java/net/minecraftforge/client/gui/overlay/ForgeLayer.java +++ b/src/main/java/net/minecraftforge/client/gui/overlay/ForgeLayer.java @@ -1,3 +1,8 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + package net.minecraftforge.client.gui.overlay; import net.minecraft.client.DeltaTracker; diff --git a/src/main/resources/META-INF/coremods.json b/src/main/resources/META-INF/coremods.json deleted file mode 100644 index d6ef083372..0000000000 --- a/src/main/resources/META-INF/coremods.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "field_to_method": "coremods/field_to_method.js", - "method_redirector": "coremods/method_redirector.js" -} diff --git a/src/main/resources/coremods/field_to_method.js b/src/main/resources/coremods/field_to_method.js deleted file mode 100644 index e437a336ee..0000000000 --- a/src/main/resources/coremods/field_to_method.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI') - -function initializeCoreMod() { - return { - 'biome': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.biome.Biome' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'climateSettings', 'getModifiedClimateSettings') - ASMAPI.redirectFieldToMethod(classNode, 'specialEffects', 'getModifiedSpecialEffects') - return classNode; - } - }, - 'potion': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.effect.MobEffectInstance' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'effect', 'getEffect') - return classNode; - } - }, - 'flowing_fluid_block': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.block.LiquidBlock' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'fluid', 'getFluid') - return classNode; - } - }, - 'bucketitem': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.item.BucketItem' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'content', 'getFluid') - return classNode; - } - }, - 'flowerpotblock': { - 'target': { - 'type': 'CLASS', - 'name': 'net.minecraft.world.level.block.FlowerPotBlock' - }, - 'transformer': function(classNode) { - ASMAPI.redirectFieldToMethod(classNode, 'potted', 'getPotted') - return classNode; - } - } - } -} diff --git a/src/main/resources/coremods/method_redirector.js b/src/main/resources/coremods/method_redirector.js deleted file mode 100644 index 41b1f5f51e..0000000000 --- a/src/main/resources/coremods/method_redirector.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) Forge Development LLC and contributors - * SPDX-License-Identifier: LGPL-2.1-only - */ - -'use strict'; - -const ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI'); -const Opcodes = Java.type('org.objectweb.asm.Opcodes'); - -// we can't run ASMAPI.loadData in the global context, so we do it here -// this function is called inside of initializeCoreMod -const replacements = []; -function initReplacements() { - ASMAPI.log('DEBUG', 'Gathering Forge method redirector replacements'); - replacements.push({ - // finalizeSpawn redirection to ForgeEventFactory.onFinalizeSpawn - 'type': ASMAPI.MethodType.VIRTUAL, - 'name': 'finalizeSpawn', - 'desc': '(Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;', - 'targets': ASMAPI.loadData('coremods/finalize_spawn_targets.json'), - 'factory': function(insn) { - return ASMAPI.buildMethodCall( - ASMAPI.MethodType.STATIC, - 'net/minecraftforge/event/ForgeEventFactory', - 'onFinalizeSpawn', - '(Lnet/minecraft/world/entity/Mob;Lnet/minecraft/world/level/ServerLevelAccessor;Lnet/minecraft/world/DifficultyInstance;Lnet/minecraft/world/entity/EntitySpawnReason;Lnet/minecraft/world/entity/SpawnGroupData;)Lnet/minecraft/world/entity/SpawnGroupData;'); - } - }); -} - -function initializeCoreMod() { - initReplacements(); - - return { - 'forge_method_redirector': { - 'target': { - 'type': 'CLASS', - 'names': getTargets - }, - 'transformer': applyMethodRedirects - } - } -} - -function getTargets(classes) { - const mergedTargets = []; - for (let replacement of replacements) { - for (let target of replacement.targets) { - mergedTargets.push(target.class); - } - } - - return mergedTargets; -} - -function applyMethodRedirects(clazz) { - for (let replacement of replacements) { - for (let methodString of getClassTargetMethods(clazz, replacement)) { - // cut up the string since we've put both the name and desc as the target - const splitPos = methodString.indexOf('('); - const methodName = methodString.substring(0, splitPos); - const methodDesc = methodString.substring(splitPos); - const method = ASMAPI.findMethodNode(clazz, methodName, methodDesc); - - // if we can't find the method, get out now! - if (method === null) { - ASMAPI.log('ERROR', 'Failed to redirect method call for {}! Method {} not found in class {}! This is a Forge bug, and is likely due to a Minecraft update changing something.', replacement.name, methodString, clazz.name); - continue; - } - - for (let insn of method.instructions) { - if (shouldReplace(insn, replacement)) { - const redirection = replacement.factory(insn); - ASMAPI.log('DEBUG', 'Redirecting method call {}{} to {}{} inside of {}.{}', insn.name, insn.desc, redirection.name, redirection.desc, clazz.name, method.name); - ASMAPI.insertInsn(method, insn, redirection, ASMAPI.InsertMode.REMOVE_ORIGINAL); - } - } - } - } - - return clazz; -} - - -/* HELPER FUNCTIONS FOR TARGET SEARCHING */ - -function shouldReplace(insn, replacement) { - return insn.getOpcode() === replacement.type.toOpcode() - && insn.name === replacement.name - && insn.desc === replacement.desc; -} - -function getClassTargetMethods(clazz, replacement) { - for (let t of replacement.targets) { - if (t.class === clazz.name) { - const targets = []; - - // declared methods - for (let method of t.methods) { - targets.push(method); - } - - // synthetic methods - for (let method of clazz.methods) { - if ((method.access & Opcodes.ACC_SYNTHETIC) != 0) { - targets.push(method.name + method.desc); - } - } - - return targets; - } - } -} diff --git a/src/test/java/net/minecraftforge/debug/client/RenderFrameLayerTest.java b/src/test/java/net/minecraftforge/debug/client/RenderFrameLayerTest.java index f2af636133..5ad401bde8 100644 --- a/src/test/java/net/minecraftforge/debug/client/RenderFrameLayerTest.java +++ b/src/test/java/net/minecraftforge/debug/client/RenderFrameLayerTest.java @@ -2,6 +2,7 @@ * Copyright (c) Forge Development LLC and contributors * SPDX-License-Identifier: LGPL-2.1-only */ + package net.minecraftforge.debug.client; import net.minecraft.client.renderer.LevelTargetBundle;