diff --git a/src/main/java/dev/architectury/transformer/transformers/GenerateFakeNeoForgeMod.java b/src/main/java/dev/architectury/transformer/transformers/GenerateFakeNeoForgeMod.java new file mode 100644 index 0000000..9d79786 --- /dev/null +++ b/src/main/java/dev/architectury/transformer/transformers/GenerateFakeNeoForgeMod.java @@ -0,0 +1,68 @@ +/* + * This file is licensed under the MIT License, part of architectury-transformer. + * Copyright (c) 2020, 2021, 2022 architectury + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.architectury.transformer.transformers; + +import dev.architectury.transformer.input.FileAccess; +import dev.architectury.transformer.transformers.base.edit.TransformerContext; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Generates a fake neoforge mod. + */ +public class GenerateFakeNeoForgeMod extends AbstractFakeMod { + @Override + public void doEdit(TransformerContext context, FileAccess output) throws Exception { + String fakeModId = generateModId(); + output.addFile("META-INF/mods.toml", + "modLoader = \"javafml\"\n" + + "loaderVersion = \"[1,)\"\n" + + "license = \"Generated\"\n" + + "[[mods]]\n" + + "modId = \"" + fakeModId + "\"\n"); + output.addFile("pack.mcmeta", + "{\"pack\":{\"description\":\"Generated\",\"pack_format\":" + System.getProperty(BuiltinProperties.MCMETA_VERSION, "4") + "}}"); + output.addFile("generated" + fakeModId + "/" + fakeModId + ".class", generateClass(fakeModId)); + } + + private byte[] generateClass(String fakeModId) { + ClassWriter writer = new ClassWriter(0); + writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "generated" + fakeModId + "/" + fakeModId, null, "java/lang/Object", null); + AnnotationVisitor modAnnotation = writer.visitAnnotation("Lnet/neoforged/fml/common/Mod;", false); + modAnnotation.visit("value", fakeModId); + modAnnotation.visitEnd(); + { + MethodVisitor method = writer.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, new String[0]); + method.visitVarInsn(Opcodes.ALOAD, 0); + method.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); + method.visitInsn(Opcodes.RETURN); + method.visitMaxs(1, 1); + method.visitEnd(); + } + writer.visitEnd(); + return writer.toByteArray(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/architectury/transformer/transformers/TransformExpectPlatform.java b/src/main/java/dev/architectury/transformer/transformers/TransformExpectPlatform.java index 272f6b9..5af98c3 100644 --- a/src/main/java/dev/architectury/transformer/transformers/TransformExpectPlatform.java +++ b/src/main/java/dev/architectury/transformer/transformers/TransformExpectPlatform.java @@ -128,6 +128,7 @@ private static String getPlatformClass(String lookupClass) { String platform = System.getProperty(BuiltinProperties.PLATFORM_NAME); Preconditions.checkNotNull(platform, BuiltinProperties.PLATFORM_NAME + " is not present!"); if (platform.equals("quilt")) platform = "fabric"; + if (platform.equals("neoforge")) platform = "forge"; String lookupType = lookupClass.replace("$", "") + "Impl"; return lookupType.substring(0, lookupType.lastIndexOf('/')) + "/" + platform + "/" + diff --git a/src/main/java/dev/architectury/transformer/transformers/TransformForgeAnnotations.java b/src/main/java/dev/architectury/transformer/transformers/TransformForgeAnnotations.java index 6b4fa03..daeed12 100644 --- a/src/main/java/dev/architectury/transformer/transformers/TransformForgeAnnotations.java +++ b/src/main/java/dev/architectury/transformer/transformers/TransformForgeAnnotations.java @@ -23,110 +23,19 @@ package dev.architectury.transformer.transformers; -import dev.architectury.transformer.transformers.base.ClassEditTransformer; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.*; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.stream.Collectors; - /** * Handle @ForgeEvent and @ForgeEventCancellable and promote @Environment from being an invisible annotation to being an visible annotation. */ -public class TransformForgeAnnotations implements ClassEditTransformer { +public class TransformForgeAnnotations extends TransformForgeLikeAnnotations { public static final String FORGE_EVENT_LEGACY = "Lme/shedaniel/architectury/ForgeEvent;"; public static final String FORGE_EVENT = "Ldev/architectury/annotations/ForgeEvent;"; public static final String FORGE_EVENT_CANCELLABLE_LEGACY = "Lme/shedaniel/architectury/ForgeEventCancellable;"; public static final String FORGE_EVENT_CANCELLABLE = "Ldev/architectury/annotations/ForgeEventCancellable;"; public static final String CANCELABLE = "Lnet/minecraftforge/eventbus/api/Cancelable;"; - private static final String ENVIRONMENT = "net/fabricmc/api/Environment"; private static final String ONLY_IN = "net/minecraftforge/api/distmarker/OnlyIn"; - @Override - public ClassNode doEdit(String name, ClassNode node) { - if ((node.access & Opcodes.ACC_INTERFACE) == 0) { - if (node.visibleAnnotations != null && node.visibleAnnotations.stream().anyMatch( - annotation -> Objects.equals(annotation.desc, FORGE_EVENT) || Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE) - || Objects.equals(annotation.desc, FORGE_EVENT_LEGACY) || Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE_LEGACY) - )) { - node.superName = "net/minecraftforge/eventbus/api/Event"; - for (MethodNode method : node.methods) { - if (Objects.equals(method.name, "")) { - for (AbstractInsnNode insnNode : method.instructions) { - if (insnNode.getOpcode() == Opcodes.INVOKESPECIAL) { - MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; - if (Objects.equals(methodInsnNode.name, "") && Objects.equals(methodInsnNode.owner, "java/lang/Object")) { - methodInsnNode.owner = "net/minecraftforge/eventbus/api/Event"; - break; - } - } - } - } - } - if (node.signature != null) { - int index = node.signature.lastIndexOf('L'); - String s = index == -1 ? node.signature : node.signature.substring(0, index); - node.signature = s + "Lnet/minecraftforge/eventbus/api/Event;"; - } - // if @ForgeEventCancellable, add the cancellable annotation from forge - if ((node.visibleAnnotations.stream().anyMatch(annotation -> Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE_LEGACY)) - || node.visibleAnnotations.stream().anyMatch(annotation -> Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE))) && - node.visibleAnnotations.stream().noneMatch(annotation -> Objects.equals(annotation.desc, CANCELABLE))) { - node.visibleAnnotations.add(new AnnotationNode(CANCELABLE)); - } - } - } - if (node.visibleAnnotations == null) { - node.visibleAnnotations = new ArrayList<>(); - } - { - Collection invisibleEnvironments; - if (node.invisibleAnnotations != null) { - invisibleEnvironments = node.invisibleAnnotations.stream() - .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + ONLY_IN + ";")) - .collect(Collectors.toList()); - node.invisibleAnnotations.removeAll(invisibleEnvironments); - } else { - invisibleEnvironments = Collections.emptyList(); - } - node.visibleAnnotations.addAll(invisibleEnvironments); - } - for (FieldNode field : node.fields) { - if (field.visibleAnnotations == null) { - field.visibleAnnotations = new ArrayList<>(); - } - - Collection invisibleEnvironments; - if (field.invisibleAnnotations != null) { - invisibleEnvironments = field.invisibleAnnotations.stream() - .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + ONLY_IN + ";")) - .collect(Collectors.toList()); - field.invisibleAnnotations.removeAll(invisibleEnvironments); - } else { - invisibleEnvironments = Collections.emptyList(); - } - field.visibleAnnotations.addAll(invisibleEnvironments); - } - for (MethodNode method : node.methods) { - if (method.visibleAnnotations == null) { - method.visibleAnnotations = new ArrayList<>(); - } - - Collection invisibleEnvironments; - if (method.invisibleAnnotations != null) { - invisibleEnvironments = method.invisibleAnnotations.stream() - .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + ONLY_IN + ";")) - .collect(Collectors.toList()); - method.invisibleAnnotations.removeAll(invisibleEnvironments); - } else { - invisibleEnvironments = Collections.emptyList(); - } - method.visibleAnnotations.addAll(invisibleEnvironments); - } - return node; + public TransformForgeAnnotations() { + super(ONLY_IN); } } \ No newline at end of file diff --git a/src/main/java/dev/architectury/transformer/transformers/TransformForgeLikeAnnotations.java b/src/main/java/dev/architectury/transformer/transformers/TransformForgeLikeAnnotations.java new file mode 100644 index 0000000..64daaa0 --- /dev/null +++ b/src/main/java/dev/architectury/transformer/transformers/TransformForgeLikeAnnotations.java @@ -0,0 +1,139 @@ +/* + * This file is licensed under the MIT License, part of architectury-transformer. + * Copyright (c) 2020, 2021, 2022 architectury + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.architectury.transformer.transformers; + +import dev.architectury.transformer.transformers.base.ClassEditTransformer; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Handle @ForgeEvent and @ForgeEventCancellable and promote @Environment from being an invisible annotation to being an visible annotation. + */ +public class TransformForgeLikeAnnotations implements ClassEditTransformer { + public static final String FORGE_EVENT_LEGACY = "Lme/shedaniel/architectury/ForgeEvent;"; + public static final String FORGE_EVENT = "Ldev/architectury/annotations/ForgeEvent;"; + public static final String FORGE_EVENT_CANCELLABLE_LEGACY = "Lme/shedaniel/architectury/ForgeEventCancellable;"; + public static final String FORGE_EVENT_CANCELLABLE = "Ldev/architectury/annotations/ForgeEventCancellable;"; + public static final String CANCELABLE = "Lnet/minecraftforge/eventbus/api/Cancelable;"; + + private static final String ENVIRONMENT = "net/fabricmc/api/Environment"; + private static final String FORGE_ONLY_IN = "net/minecraftforge/api/distmarker/OnlyIn"; + protected static final String NEOFORGE_ONLY_IN = "net/neoforged/api/distmarker/OnlyIn"; + + private final String onlyIn; + + public TransformForgeLikeAnnotations(String onlyIn) { + this.onlyIn = onlyIn; + } + + @Override + public ClassNode doEdit(String name, ClassNode node) { + if ((node.access & Opcodes.ACC_INTERFACE) == 0) { + if (node.visibleAnnotations != null && node.visibleAnnotations.stream().anyMatch( + annotation -> Objects.equals(annotation.desc, FORGE_EVENT) || Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE) + || Objects.equals(annotation.desc, FORGE_EVENT_LEGACY) || Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE_LEGACY) + )) { + node.superName = "net/minecraftforge/eventbus/api/Event"; + for (MethodNode method : node.methods) { + if (Objects.equals(method.name, "")) { + for (AbstractInsnNode insnNode : method.instructions) { + if (insnNode.getOpcode() == Opcodes.INVOKESPECIAL) { + MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode; + if (Objects.equals(methodInsnNode.name, "") && Objects.equals(methodInsnNode.owner, "java/lang/Object")) { + methodInsnNode.owner = "net/minecraftforge/eventbus/api/Event"; + break; + } + } + } + } + } + if (node.signature != null) { + int index = node.signature.lastIndexOf('L'); + String s = index == -1 ? node.signature : node.signature.substring(0, index); + node.signature = s + "Lnet/minecraftforge/eventbus/api/Event;"; + } + // if @ForgeEventCancellable, add the cancellable annotation from forge + if ((node.visibleAnnotations.stream().anyMatch(annotation -> Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE_LEGACY)) + || node.visibleAnnotations.stream().anyMatch(annotation -> Objects.equals(annotation.desc, FORGE_EVENT_CANCELLABLE))) && + node.visibleAnnotations.stream().noneMatch(annotation -> Objects.equals(annotation.desc, CANCELABLE))) { + node.visibleAnnotations.add(new AnnotationNode(CANCELABLE)); + } + } + } + if (node.visibleAnnotations == null) { + node.visibleAnnotations = new ArrayList<>(); + } + { + Collection invisibleEnvironments; + if (node.invisibleAnnotations != null) { + invisibleEnvironments = node.invisibleAnnotations.stream() + .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + onlyIn + ";")) + .collect(Collectors.toList()); + node.invisibleAnnotations.removeAll(invisibleEnvironments); + } else { + invisibleEnvironments = Collections.emptyList(); + } + node.visibleAnnotations.addAll(invisibleEnvironments); + } + for (FieldNode field : node.fields) { + if (field.visibleAnnotations == null) { + field.visibleAnnotations = new ArrayList<>(); + } + + Collection invisibleEnvironments; + if (field.invisibleAnnotations != null) { + invisibleEnvironments = field.invisibleAnnotations.stream() + .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + onlyIn + ";")) + .collect(Collectors.toList()); + field.invisibleAnnotations.removeAll(invisibleEnvironments); + } else { + invisibleEnvironments = Collections.emptyList(); + } + field.visibleAnnotations.addAll(invisibleEnvironments); + } + for (MethodNode method : node.methods) { + if (method.visibleAnnotations == null) { + method.visibleAnnotations = new ArrayList<>(); + } + + Collection invisibleEnvironments; + if (method.invisibleAnnotations != null) { + invisibleEnvironments = method.invisibleAnnotations.stream() + .filter(annotation -> Objects.equals(annotation.desc, "L" + ENVIRONMENT + ";") || Objects.equals(annotation.desc, "L" + onlyIn + ";")) + .collect(Collectors.toList()); + method.invisibleAnnotations.removeAll(invisibleEnvironments); + } else { + invisibleEnvironments = Collections.emptyList(); + } + method.visibleAnnotations.addAll(invisibleEnvironments); + } + return node; + } +} \ No newline at end of file diff --git a/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeAnnotations.java b/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeAnnotations.java new file mode 100644 index 0000000..0f69333 --- /dev/null +++ b/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeAnnotations.java @@ -0,0 +1,33 @@ +/* + * This file is licensed under the MIT License, part of architectury-transformer. + * Copyright (c) 2020, 2021, 2022 architectury + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.architectury.transformer.transformers; + +/** + * Handle @ForgeEvent and @ForgeEventCancellable and promote @Environment from being an invisible annotation to being an visible annotation. + */ +public class TransformNeoForgeAnnotations extends TransformForgeLikeAnnotations { + public TransformNeoForgeAnnotations() { + super(NEOFORGE_ONLY_IN); + } +} \ No newline at end of file diff --git a/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeEnvironment.java b/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeEnvironment.java new file mode 100644 index 0000000..d1a70ee --- /dev/null +++ b/src/main/java/dev/architectury/transformer/transformers/TransformNeoForgeEnvironment.java @@ -0,0 +1,53 @@ +/* + * This file is licensed under the MIT License, part of architectury-transformer. + * Copyright (c) 2020, 2021, 2022 architectury + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.architectury.transformer.transformers; + +import dev.architectury.tinyremapper.IMappingProvider; +import dev.architectury.transformer.transformers.base.TinyRemapperTransformer; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class TransformNeoForgeEnvironment implements TinyRemapperTransformer { + @Override + public List collectMappings() throws Exception { + return new ArrayList<>(Collections.singletonList(remapEnvironment())); + } + + private IMappingProvider remapEnvironment() { + return sink -> { + // Stop shadow plugin from relocating this + // net/fabricmc/api + String fabricLoaderApiPackage = new String(new byte[]{0x6e, 0x65, 0x74, 0x2f, 0x66, 0x61, 0x62, 0x72, 0x69, 0x63, 0x6d, 0x63, 0x2f, 0x61, 0x70, 0x69}, StandardCharsets.UTF_8); + sink.acceptClass(fabricLoaderApiPackage + "/Environment", "net/neoforged/api/distmarker/OnlyIn"); + sink.acceptClass(fabricLoaderApiPackage + "/EnvType", "net/neoforged/api/distmarker/Dist"); + sink.acceptField( + new IMappingProvider.Member(fabricLoaderApiPackage + "/EnvType", "SERVER", "L" + fabricLoaderApiPackage + "/EnvType" + ";"), + "DEDICATED_SERVER" + ); + }; + } +} \ No newline at end of file