Skip to content

Commit 233188b

Browse files
committed
new: neoforge mixin remap + fml remap
1 parent 991b5d4 commit 233188b

7 files changed

Lines changed: 324 additions & 0 deletions

File tree

src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import net.fabricmc.tinyremapper.TinyRemapper;
4040

4141
import org.relativitymc.neoloom.neoforge.NFRTMergedMinecraftProvider;
42+
import org.relativitymc.neoloom.neoforge.remap.FMLRemap;
4243

4344
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.LegacyMergedImpl, IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.NeoForgeMergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl {
4445
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
@@ -207,5 +208,11 @@ public List<MinecraftJar> getMinecraftJars() {
207208
return List.of(getMergedJar(), getNeoForgeUniversalJar());
208209
}
209210
}
211+
212+
@Override
213+
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
214+
super.configureRemapper(remappedJars, tinyRemapperBuilder);
215+
FMLRemap.configureRemapper(tinyRemapperBuilder);
216+
}
210217
}
211218
}

src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import java.util.List;
2828

29+
import net.fabricmc.tinyremapper.extension.mixin.MixinExtension;
30+
2931
import org.gradle.api.Project;
3032

3133
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
@@ -40,6 +42,7 @@
4042
import net.fabricmc.tinyremapper.TinyRemapper;
4143

4244
import org.relativitymc.neoloom.neoforge.NFRTMergedMinecraftProvider;
45+
import org.relativitymc.neoloom.neoforge.remap.FMLRemap;
4346

4447
public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> {
4548
public NamedMinecraftProvider(Project project, M minecraftProvider) {
@@ -238,5 +241,18 @@ public List<MinecraftJar> getMinecraftJars() {
238241
return List.of(getMergedJar(), getNeoForgeUniversalJar());
239242
}
240243
}
244+
245+
@Override
246+
protected void configureRemapper(RemappedJars remappedJars, TinyRemapper.Builder tinyRemapperBuilder) {
247+
super.configureRemapper(remappedJars, tinyRemapperBuilder);
248+
249+
if (remappedJars.outputJar().getType() == MinecraftJar.Type.FML) {
250+
FMLRemap.configureRemapper(tinyRemapperBuilder);
251+
}
252+
253+
if (remappedJars.outputJar().getType() == MinecraftJar.Type.NEOFORGE_UNIVERSAL) {
254+
tinyRemapperBuilder.extension(new MixinExtension()); // Remap mixins in neoforge
255+
}
256+
}
241257
}
242258
}

src/main/java/org/relativitymc/neoloom/neoforge/NFRTMinecraftLibraryProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,15 @@ public Path resolveFMLJar() {
142142
attributes.attribute(MinecraftDistribution.ATTRIBUTE, project.getObjects().named(MinecraftDistribution.ATTRIBUTE.getType(), MinecraftDistribution.CLIENT));
143143
attributes.attribute(OperatingSystem.ATTRIBUTE, project.getObjects().named(OperatingSystem.ATTRIBUTE.getType(), OperatingSystem.getCurrent()));
144144
});
145+
145146
for (ResolvedArtifact artifact : gameLib.getResolvedConfiguration().getResolvedArtifacts()) {
146147
ModuleVersionIdentifier id = artifact.getModuleVersion().getId();
147148

148149
if (isFML(id)) {
149150
return artifact.getFile().toPath();
150151
}
151152
}
153+
152154
throw new GradleException("No FML in neoforge dependencies");
153155
}
154156

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* This file is part of fabric-loom, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2026 FabricMC
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package org.relativitymc.neoloom.neoforge.remap;
26+
27+
import net.fabricmc.tinyremapper.TinyRemapper;
28+
import net.fabricmc.tinyremapper.api.TrRemapper;
29+
30+
public class FMLRemap {
31+
private static final String FORGE_OBJECT_HOLDER = "net/minecraftforge/fml/common/asm/ObjectHolderDefinalize";
32+
private static final String FORGE_MOD_DIR_TRANSFORMER_DISCOVERER = "net/minecraftforge/fml/loading/ModDirTransformerDiscoverer";
33+
private static final String NEOFORGE_OBJECT_HOLDER = "net/neoforged/fml/common/asm/ObjectHolderDefinalize";
34+
private static final String NEOFORGE_LAUNCH_HANDLER = "net/neoforged/fml/loading/targets/CommonUserdevLaunchHandler";
35+
private static final String NEOFORGE_LOADER = "net/neoforged/fml/loading/FMLLoader";
36+
private static final String NEOFORGE_GAME_LOCATOR = "net/neoforged/fml/loading/moddiscovery/locators/GameLocator";
37+
private static final String NEOFORGE_REQUIRED_SYSTEM_FILES = "net/neoforged/fml/loading/moddiscovery/locators/RequiredSystemFiles";
38+
39+
public static void configureRemapper(TinyRemapper.Builder tinyRemapperBuilder) {
40+
tinyRemapperBuilder.extraPostApplyVisitor((cls, next) -> {
41+
TrRemapper remapper = cls.getEnvironment().getRemapper();
42+
43+
if (cls.getName().equals(FORGE_OBJECT_HOLDER) || cls.getName().equals(NEOFORGE_OBJECT_HOLDER)) {
44+
return new RemapObjectHolderVisitor(next, remapper);
45+
}
46+
47+
if (cls.getName().equals(FORGE_MOD_DIR_TRANSFORMER_DISCOVERER)) {
48+
// TODO
49+
}
50+
51+
if (cls.getName().equals(NEOFORGE_LAUNCH_HANDLER)) {
52+
return StringConstantPatcher.forUserdevLaunchHandler(next);
53+
}
54+
55+
if (cls.getName().equals(NEOFORGE_LOADER)) {
56+
return StringConstantPatcher.forFmlLoader(next, remapper);
57+
}
58+
59+
if (cls.getName().equals(NEOFORGE_GAME_LOCATOR)) {
60+
return StringConstantPatcher.forGameLocator(next, remapper);
61+
}
62+
63+
if (cls.getName().equals(NEOFORGE_REQUIRED_SYSTEM_FILES)) {
64+
return StringConstantPatcher.forRequiredSystemFiles(next, remapper);
65+
}
66+
67+
return next;
68+
});
69+
}
70+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* This file is part of fabric-loom, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022 FabricMC
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package org.relativitymc.neoloom.neoforge.remap;
26+
27+
import org.objectweb.asm.ClassVisitor;
28+
import org.objectweb.asm.MethodVisitor;
29+
30+
import net.fabricmc.tinyremapper.api.TrRemapper;
31+
import net.fabricmc.loom.util.Constants;
32+
33+
public class RemapObjectHolderVisitor extends ClassVisitor {
34+
private final TrRemapper remapper;
35+
36+
public RemapObjectHolderVisitor(ClassVisitor next, TrRemapper remapper) {
37+
super(Constants.ASM_VERSION, next);
38+
this.remapper = remapper;
39+
}
40+
41+
@Override
42+
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
43+
MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
44+
45+
if ("<clinit>".equals(name) && "()V".equals(descriptor)) {
46+
return new MethodVisitor(api, methodVisitor) {
47+
@Override
48+
public void visitLdcInsn(Object value) {
49+
if (value instanceof String str && str.startsWith("net.minecraft.")) {
50+
value = remapper.map(str.replace('.', '/')).replace('/', '.');
51+
}
52+
53+
super.visitLdcInsn(value);
54+
}
55+
};
56+
}
57+
58+
return methodVisitor;
59+
}
60+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* This file is part of fabric-loom, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2026 FabricMC
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package org.relativitymc.neoloom.neoforge.remap;
26+
27+
import java.util.HashMap;
28+
import java.util.Map;
29+
30+
import org.jspecify.annotations.Nullable;
31+
import org.objectweb.asm.ClassVisitor;
32+
import org.objectweb.asm.MethodVisitor;
33+
34+
import net.fabricmc.tinyremapper.api.TrRemapper;
35+
import net.fabricmc.loom.util.Constants;
36+
37+
/**
38+
* A class visitor that replaces a set of string constants in the processed class file(s).
39+
*/
40+
public final class StringConstantPatcher extends ClassVisitor {
41+
private final Map<String, String> constantChanges;
42+
43+
private static final String LAUNCH_HANDLER_INPUT_CLASS_FILE = "net/minecraft/client/Minecraft.class";
44+
private static final String LAUNCH_HANDLER_OUTPUT_CLASS_FILE = "net/minecraft/client/main/Main.class";
45+
46+
private static final String DETECTED_VERSION = "net/minecraft/DetectedVersion";
47+
private static final String MINECRAFT = "net/minecraft/client/Minecraft";
48+
49+
private StringConstantPatcher(ClassVisitor next, Map<String, String> constantChanges) {
50+
super(Constants.ASM_VERSION, next);
51+
this.constantChanges = constantChanges;
52+
}
53+
54+
private StringConstantPatcher(ClassVisitor next, String from, String to) {
55+
this(next, Map.of(from, to));
56+
}
57+
58+
/**
59+
* Patches the Minecraft.class check in FML's CommonUserdevLaunchHandler
60+
* to refer to a class that is found in any mapping set (Main.class).
61+
*
62+
* <p>See <a href="https://github.com/architectury/architectury-loom/issues/212">issue #212</a>
63+
*/
64+
public static ClassVisitor forUserdevLaunchHandler(ClassVisitor next) {
65+
return new StringConstantPatcher(next, LAUNCH_HANDLER_INPUT_CLASS_FILE, LAUNCH_HANDLER_OUTPUT_CLASS_FILE);
66+
}
67+
68+
private static ClassVisitor forRemapping(ClassVisitor next, TrRemapper remapper, String... names) {
69+
final Map<String, String> constantChanges = new HashMap<>();
70+
71+
for (String name : names) {
72+
final @Nullable String target = remapper.map(name);
73+
74+
if (target == null || name.equals(target)) {
75+
continue;
76+
}
77+
78+
constantChanges.put(name + ".class", target + ".class");
79+
}
80+
81+
if (!constantChanges.isEmpty()) {
82+
return new StringConstantPatcher(next, constantChanges);
83+
} else {
84+
return next;
85+
}
86+
}
87+
88+
/**
89+
* Patches the DetectedVersion.class check in FML's FMLLoader
90+
* to remap that reference to the current deobfuscated ns.
91+
*
92+
* <p>See <a href="https://github.com/architectury/architectury-loom/issues/299">issue #299</a>
93+
*/
94+
public static ClassVisitor forFmlLoader(ClassVisitor next, TrRemapper remapper) {
95+
return forRemapping(next, remapper, DETECTED_VERSION);
96+
}
97+
98+
/**
99+
* Patches the Minecraft.class check in FML's GameLocator
100+
* to remap that reference to the current deobfuscated ns.
101+
*
102+
* <p>See <a href="https://github.com/architectury/architectury-loom/issues/299">issue #299</a>
103+
*/
104+
public static ClassVisitor forGameLocator(ClassVisitor next, TrRemapper remapper) {
105+
return forRemapping(next, remapper, MINECRAFT);
106+
}
107+
108+
/**
109+
* Patches the class checks in FML's RequiredSystemFiles
110+
* to remap that reference to the current deobfuscated ns.
111+
*
112+
* <p>See <a href="https://github.com/architectury/architectury-loom/issues/299">issue #299</a>
113+
*/
114+
public static ClassVisitor forRequiredSystemFiles(ClassVisitor next, TrRemapper remapper) {
115+
return forRemapping(next, remapper, DETECTED_VERSION, MINECRAFT);
116+
}
117+
118+
@Override
119+
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
120+
return new MethodPatcher(super.visitMethod(access, name, descriptor, signature, exceptions));
121+
}
122+
123+
private final class MethodPatcher extends MethodVisitor {
124+
MethodPatcher(MethodVisitor next) {
125+
super(Constants.ASM_VERSION, next);
126+
}
127+
128+
@Override
129+
public void visitLdcInsn(Object value) {
130+
if (value instanceof String key) {
131+
final @Nullable String target = constantChanges.get(key);
132+
133+
if (target != null) {
134+
value = target;
135+
}
136+
}
137+
138+
super.visitLdcInsn(value);
139+
}
140+
}
141+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* This file is part of fabric-loom, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2026 FabricMC
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
@NullMarked
26+
package org.relativitymc.neoloom.neoforge.remap;
27+
28+
import org.jspecify.annotations.NullMarked;

0 commit comments

Comments
 (0)