diff options
author | shedaniel <daniel@shedaniel.me> | 2021-08-30 14:10:32 +0800 |
---|---|---|
committer | shedaniel <daniel@shedaniel.me> | 2021-08-30 14:10:32 +0800 |
commit | 9366d42baa22b53b16ad8b21b843576ec8c964c7 (patch) | |
tree | a83f8a0b0b4f1b78fc5d293aeccac27dfc9f4c19 | |
parent | d819b1cc47b26572ab6af85258e54d5737bead69 (diff) | |
download | architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.tar.gz architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.tar.bz2 architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.zip |
Start work on porting 0.7.4 over
Signed-off-by: shedaniel <daniel@shedaniel.me>
42 files changed, 1214 insertions, 811 deletions
diff --git a/build.gradle b/build.gradle index c377e0ef..73226e3a 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,7 @@ dependencies { // tinyfile management implementation ('dev.architectury:tiny-remapper:1.1.0') - implementation ('dev.architectury:mappings-layers-core:1.3.8') + implementation ('dev.architectury:mappings-layers-core:1.4.9') implementation ('net.fabricmc:tiny-mappings-parser:0.3.0+build.17') implementation 'net.fabricmc:access-widener:1.1.0' @@ -135,6 +135,7 @@ dependencies { compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21') // Forge patches + implementation ('net.minecraftforge:installertools:1.2.0') implementation ('net.minecraftforge:binarypatcher:1.1.1') implementation ('org.cadixdev:lorenz:0.5.3') implementation ('org.cadixdev:lorenz-asm:0.5.3') diff --git a/forge-runtime/.gitignore b/forge-runtime/.gitignore deleted file mode 100644 index 31ecb657..00000000 --- a/forge-runtime/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Ignore everything -/* - -!/src -!/build.gradle -!/.gitignore diff --git a/forge-runtime/build.gradle b/forge-runtime/build.gradle deleted file mode 100644 index 388db8e3..00000000 --- a/forge-runtime/build.gradle +++ /dev/null @@ -1,93 +0,0 @@ -plugins { - id 'java' - id 'maven-publish' - id 'checkstyle' - id 'com.github.johnrengelman.shadow' version '7.0.0' - id "com.diffplug.spotless" -} - -group = rootProject.group -archivesBaseName = 'architectury-loom-forge-runtime' -version = rootProject.version - -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_1_8 - -configurations { - include - compileOnly.extendsFrom include -} - -tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" - it.options.release = 8 -} - -repositories { - mavenCentral() - maven { url "https://maven.fabricmc.net/" } - maven { - url "https://maven.minecraftforge.net/" - content { - excludeGroupByRegex "org\\.eclipse\\.?.*" - } - } -} - -dependencies { - // shadowed - include ('net.fabricmc:tiny-mappings-parser:0.3.0+build.17') - - // guaranteed to be there at runtime - compileOnly ('cpw.mods:modlauncher:6.1.3') - compileOnly ('org.spongepowered:mixin:0.8.2') - compileOnly ('com.google.code.gson:gson:2.8.6') - compileOnly ('com.google.guava:guava:21.0') - compileOnly ('org.apache.logging.log4j:log4j-api:2.11.2') -} - -jar { - archiveClassifier = "slim" -} - -shadowJar { - archiveClassifier = "" - configurations = [project.configurations.include] - relocate "net.fabricmc.mapping", "dev.architectury.loom.forgeruntime.shadow.mapping" - relocate "net.fabricmc.mappings", "dev.architectury.loom.forgeruntime.shadow.mappings" -} - -assemble.dependsOn shadowJar - -spotless { - java { - licenseHeaderFile(rootProject.file("HEADER")).yearSeparator("-") - targetExclude("**/loom/forgeruntime/mixin/MixinIntermediaryDevRemapper.java") - } -} - -checkstyle { - configFile = rootProject.checkstyle.configFile - toolVersion = rootProject.checkstyle.toolVersion -} - -publishing { - publications { - maven(MavenPublication) { - artifactId = 'architectury-loom-forge-runtime' - shadow.component it - } - } - - repositories { - if (System.getenv("MAVEN_PASS") != null) { - maven { - url = "https://deploy.shedaniel.me/" - credentials { - username = "shedaniel" - password = System.getenv("MAVEN_PASS") - } - } - } - } -} diff --git a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/YarnNamingService.java b/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/YarnNamingService.java deleted file mode 100644 index 6a291de3..00000000 --- a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/YarnNamingService.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2020-2021 FabricMC - * - * 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.loom.forgeruntime; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.AbstractMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.Predicate; - -import cpw.mods.modlauncher.api.INameMappingService; - -import net.fabricmc.mapping.tree.TinyMappingFactory; -import net.fabricmc.mapping.tree.TinyTree; - -public class YarnNamingService implements INameMappingService { - private static final String PATH_TO_MAPPINGS = "fabric.yarnWithSrg.path"; - private TinyTree mappings = null; - - @Override - public String mappingName() { - return "srgtoyarn"; - } - - @Override - public String mappingVersion() { - return "1"; - } - - @Override - public Map.Entry<String, String> understanding() { - return new AbstractMap.SimpleImmutableEntry<>("srg", "mcp"); - } - - @Override - public BiFunction<Domain, String, String> namingFunction() { - return this::remap; - } - - private TinyTree getMappings() { - if (mappings != null) { - return mappings; - } - - String pathStr = System.getProperty(PATH_TO_MAPPINGS); - if (pathStr == null) throw new RuntimeException("Missing system property '" + PATH_TO_MAPPINGS + "'!"); - Path path = Paths.get(pathStr); - - try (BufferedReader reader = Files.newBufferedReader(path)) { - mappings = TinyMappingFactory.loadWithDetection(reader); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return mappings; - } - - private String remap(Domain domain, String name) { - TinyTree mappings = getMappings(); - - switch (domain) { - case CLASS: - boolean dot = name.contains("."); - return find(mappings.getClasses(), def -> maybeReplace(dot, def.getName("srg"), '/', '.').equals(name)) - .map(def -> maybeReplace(dot, def.getName("named"), '/', '.')) - .orElse(name); - case METHOD: - return mappings.getClasses().stream() - .flatMap(def -> def.getMethods().stream()) - .filter(def -> def.getName("srg").equals(name)) - .findAny() - .map(def -> def.getName("named")) - .orElse(name); - case FIELD: - return mappings.getClasses().stream() - .flatMap(def -> def.getFields().stream()) - .filter(def -> def.getName("srg").equals(name)) - .findAny() - .map(def -> def.getName("named")) - .orElse(name); - default: - return name; - } - } - - // From CollectionUtil - private static <E> Optional<E> find(Iterable<? extends E> collection, Predicate<? super E> filter) { - for (E e : collection) { - if (filter.test(e)) { - return Optional.of(e); - } - } - - return Optional.empty(); - } - - private static String maybeReplace(boolean run, String s, char from, char to) { - return run ? s.replace(from, to) : s; - } -} diff --git a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/ForgeLoomMixinRemapperInjectorService.java b/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/ForgeLoomMixinRemapperInjectorService.java deleted file mode 100644 index 8b1839fb..00000000 --- a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/ForgeLoomMixinRemapperInjectorService.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2021 FabricMC - * - * 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.loom.forgeruntime.mixin; - -import java.io.BufferedReader; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import cpw.mods.modlauncher.api.IEnvironment; -import cpw.mods.modlauncher.api.ITransformationService; -import cpw.mods.modlauncher.api.ITransformer; -import cpw.mods.modlauncher.api.IncompatibleEnvironmentException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.spongepowered.asm.mixin.MixinEnvironment; - -import net.fabricmc.mapping.tree.TinyMappingFactory; -import net.fabricmc.mapping.tree.TinyTree; - -public class ForgeLoomMixinRemapperInjectorService implements ITransformationService { - private static final Logger LOGGER = LogManager.getLogger("ForgeLoomRemapperInjector"); - - @Override - public String name() { - return "ForgeLoomMixinRemapperInjector"; - } - - @Override - public void initialize(IEnvironment environment) { - } - - @Override - public void beginScanning(IEnvironment environment) { - LOGGER.debug("We will be injecting our remapper."); - - try { - MixinEnvironment.getDefaultEnvironment().getRemappers().add(new MixinIntermediaryDevRemapper(Objects.requireNonNull(resolveMappings()), "intermediary", "named")); - LOGGER.debug("We have successfully injected our remapper."); - } catch (Exception e) { - LOGGER.debug("We have failed to inject our remapper.", e); - } - } - - @Override - public void onLoad(IEnvironment env, Set<String> otherServices) throws IncompatibleEnvironmentException { - } - - @Override - public List<ITransformer> transformers() { - return Collections.emptyList(); - } - - private static TinyTree resolveMappings() { - try { - String srgNamedProperty = System.getProperty("mixin.forgeloom.inject.mappings.srg-named"); - Path path = Paths.get(srgNamedProperty); - - try (BufferedReader reader = Files.newBufferedReader(path)) { - return TinyMappingFactory.loadWithDetection(reader); - } - } catch (Throwable throwable) { - throwable.printStackTrace(); - return null; - } - } -} diff --git a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/MixinIntermediaryDevRemapper.java b/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/MixinIntermediaryDevRemapper.java deleted file mode 100644 index f331a9ca..00000000 --- a/forge-runtime/src/main/java/dev/architectury/loom/forgeruntime/mixin/MixinIntermediaryDevRemapper.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2016 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dev.architectury.loom.forgeruntime.mixin; - -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Queue; -import java.util.Set; - -import org.spongepowered.asm.mixin.transformer.ClassInfo; - -import net.fabricmc.mapping.tree.ClassDef; -import net.fabricmc.mapping.tree.Descriptored; -import net.fabricmc.mapping.tree.TinyTree; -import net.fabricmc.mapping.util.MixinRemapper; - -public class MixinIntermediaryDevRemapper extends MixinRemapper { - private static final String ambiguousName = "<ambiguous>"; // dummy value for ambiguous mappings - needs querying with additional owner and/or desc info - - private final Set<String> allPossibleClassNames = new HashSet<>(); - private final Map<String, String> nameFieldLookup = new HashMap<>(); - private final Map<String, String> nameMethodLookup = new HashMap<>(); - private final Map<String, String> nameDescFieldLookup = new HashMap<>(); - private final Map<String, String> nameDescMethodLookup = new HashMap<>(); - - public MixinIntermediaryDevRemapper(TinyTree mappings, String from, String to) { - super(mappings, from, to); - - for (ClassDef classDef : mappings.getClasses()) { - allPossibleClassNames.add(classDef.getName(from)); - allPossibleClassNames.add(classDef.getName(to)); - - putMemberInLookup(from, to, classDef.getFields(), nameFieldLookup, nameDescFieldLookup); - putMemberInLookup(from, to, classDef.getMethods(), nameMethodLookup, nameDescMethodLookup); - } - } - - private <T extends Descriptored> void putMemberInLookup(String from, String to, Collection<T> descriptored, Map<String, String> nameMap, Map<String, String> nameDescMap) { - for (T field : descriptored) { - String nameFrom = field.getName(from); - String descFrom = field.getDescriptor(from); - String nameTo = field.getName(to); - - String prev = nameMap.putIfAbsent(nameFrom, nameTo); - - if (prev != null && prev != ambiguousName && !prev.equals(nameTo)) { - nameDescMap.put(nameFrom, ambiguousName); - } - - String key = getNameDescKey(nameFrom, descFrom); - prev = nameDescMap.putIfAbsent(key, nameTo); - - if (prev != null && prev != ambiguousName && !prev.equals(nameTo)) { - nameDescMap.put(key, ambiguousName); - } - } - } - - private void throwAmbiguousLookup(String type, String name, String desc) { - throw new RuntimeException("Ambiguous Mixin: " + type + " lookup " + name + " " + desc + " is not unique"); - } - - private String mapMethodNameInner(String owner, String name, String desc) { - String result = super.mapMethodName(owner, name, desc); - - if (result.equals(name)) { - String otherClass = unmap(owner); - return super.mapMethodName(otherClass, name, unmapDesc(desc)); - } else { - return result; - } - } - - private String mapFieldNameInner(String owner, String name, String desc) { - String result = super.mapFieldName(owner, name, desc); - - if (result.equals(name)) { - String otherClass = unmap(owner); - return super.mapFieldName(otherClass, name, unmapDesc(desc)); - } else { - return result; - } - } - - @Override - public String mapMethodName(String owner, String name, String desc) { - // handle unambiguous values early - if (owner == null || allPossibleClassNames.contains(owner)) { - String newName; - - if (desc == null) { - newName = nameMethodLookup.get(name); - } else { - newName = nameDescMethodLookup.get(getNameDescKey(name, desc)); - } - - if (newName != null) { - if (newName == ambiguousName) { - if (owner == null) { - throwAmbiguousLookup("method", name, desc); - } - } else { - return newName; - } - } else if (owner == null) { - return name; - } else { - // FIXME: this kind of namespace mixing shouldn't happen.. - // TODO: this should not repeat more than once - String unmapOwner = unmap(owner); - String unmapDesc = unmapDesc(desc); - - if (!unmapOwner.equals(owner) || !unmapDesc.equals(desc)) { - return mapMethodName(unmapOwner, name, unmapDesc); - } else { - // take advantage of the fact allPossibleClassNames - // and nameDescLookup cover all sets; if none are present, - // we don't have a mapping for it. - return name; - } - } - } - - Queue<ClassInfo> classInfos = new ArrayDeque<>(); - classInfos.add(ClassInfo.forName(owner)); - - while (!classInfos.isEmpty()) { - ClassInfo c = classInfos.remove(); - String ownerO = unmap(c.getName()); - String s; - - if (!(s = mapMethodNameInner(ownerO, name, desc)).equals(name)) { - return s; - } - - if (!c.getSuperName().startsWith("java/")) { - ClassInfo cSuper = c.getSuperClass(); - - if (cSuper != null) { - classInfos.add(cSuper); - } - } - - for (String itf : c.getInterfaces()) { - if (itf.startsWith("java/")) { - continue; - } - - ClassInfo cItf = ClassInfo.forName(itf); - - if (cItf != null) { - classInfos.add(cItf); - } - } - } - - return name; - } - - @Override - public String mapFieldName(String owner, String name, String desc) { - // handle unambiguous values early - if (owner == null || allPossibleClassNames.contains(owner)) { - String newName = nameDescFieldLookup.get(getNameDescKey(name, desc)); - - if (newName != null) { - if (newName == ambiguousName) { - if (owner == null) { - throwAmbiguousLookup("field", name, desc); - } - } else { - return newName; - } - } else if (owner == null) { - return name; - } else { - // FIXME: this kind of namespace mixing shouldn't happen.. - // TODO: this should not repeat more than once - String unmapOwner = unmap(owner); - String unmapDesc = unmapDesc(desc); - - if (!unmapOwner.equals(owner) || !unmapDesc.equals(desc)) { - return mapFieldName(unmapOwner, name, unmapDesc); - } else { - // take advantage of the fact allPossibleClassNames - // and nameDescLookup cover all sets; if none are present, - // we don't have a mapping for it. - return name; - } - } - } - - ClassInfo c = ClassInfo.forName(map(owner)); - - while (c != null) { - String nextOwner = unmap(c.getName()); - String s; - - if (!(s = mapFieldNameInner(nextOwner, name, desc)).equals(name)) { - return s; - } - - if (c.getSuperName().startsWith("java/")) { - break; - } - - c = c.getSuperClass(); - } - - return name; - } - - private static String getNameDescKey(String name, String descriptor) { - return name + ";;" + descriptor; - } -} diff --git a/forge-runtime/src/main/java/mcp/MethodsReturnNonnullByDefault.java b/forge-runtime/src/main/java/mcp/MethodsReturnNonnullByDefault.java deleted file mode 100644 index bfa2d691..00000000 --- a/forge-runtime/src/main/java/mcp/MethodsReturnNonnullByDefault.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2020-2021 FabricMC - * - * 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 mcp; - -/** - * A dummy class, required for some Forge classes to load - * because {@code MethodsReturnNonnullByDefault} in MCP has runtime retention. - * - * @deprecated Don't use this in your mods. JetBrains annotations are there for you. - */ -@Deprecated -public @interface MethodsReturnNonnullByDefault { -} diff --git a/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService b/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService deleted file mode 100644 index ec41d220..00000000 --- a/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.INameMappingService +++ /dev/null @@ -1 +0,0 @@ -dev.architectury.loom.forgeruntime.YarnNamingService diff --git a/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService b/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService deleted file mode 100644 index 679794d7..00000000 --- a/forge-runtime/src/main/resources/META-INF/services/cpw.mods.modlauncher.api.ITransformationService +++ /dev/null @@ -1 +0,0 @@ -dev.architectury.loom.forgeruntime.mixin.ForgeLoomMixinRemapperInjectorService
\ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 0b542936..0dfb5fc9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,2 @@ rootProject.name = "architectury-loom" include "bootstrap" -include "forge-runtime" diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 6c3541e9..63ad8974 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -122,6 +122,16 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { return getDependencyManager().getProvider(McpConfigProvider.class); } + @Override + default boolean isForgeAndOfficial() { + return isForge() && getMcpConfigProvider().isOfficial(); + } + + @Override + default boolean isForgeAndNotOfficial() { + return isForge() && !getMcpConfigProvider().isOfficial(); + } + default SrgProvider getSrgProvider() { return getDependencyManager().getProvider(SrgProvider.class); } diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 3d39cd51..ab5db4a8 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -195,6 +195,10 @@ public interface LoomGradleExtensionAPI { return getPlatform().get() == ModPlatform.FORGE; } + boolean isForgeAndOfficial(); + + boolean isForgeAndNotOfficial(); + boolean supportsInclude(); void setGenerateSrgTiny(Boolean generateSrgTiny); diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index e6589da5..d23072f6 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -83,8 +83,9 @@ public final class CompileConfiguration { extension.createLazyConfiguration(Constants.Configurations.FORGE_USERDEV).configure(configuration -> configuration.setTransitive(false)); extension.createLazyConfiguration(Constants.Configurations.FORGE_INSTALLER).configure(configuration -> configuration.setTransitive(false)); extension.createLazyConfiguration(Constants.Configurations.FORGE_UNIVERSAL).configure(configuration -> configuration.setTransitive(false)); - extension.createLazyConfiguration(Constants.Configurations.FORGE_DEPENDENCIES).configure(configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.FORGE_DEPENDENCIES); extension.createLazyConfiguration(Constants.Configurations.FORGE_NAMED).configure(configuration -> configuration.setTransitive(false)); + extension.createLazyConfiguration(Constants.Configurations.FORGE_EXTRA).configure(configuration -> configuration.setTransitive(false)); extension.createLazyConfiguration(Constants.Configurations.MCP_CONFIG).configure(configuration -> configuration.setTransitive(false)); extendsFrom(Constants.Configurations.MINECRAFT_DEPENDENCIES, Constants.Configurations.FORGE_DEPENDENCIES, project); @@ -93,6 +94,10 @@ public final class CompileConfiguration { extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); extendsFrom(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); + extendsFrom(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_EXTRA, project); + extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_EXTRA, project); + extendsFrom(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_EXTRA, project); + extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_EXTRA, project); } if (extension.supportsInclude()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java index a8d77353..e630939c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfig.java @@ -24,21 +24,15 @@ package net.fabricmc.loom.configuration.ide; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; import java.util.Objects; -import java.util.UUID; import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; @@ -132,23 +126,6 @@ public class RunConfig { runConfig.mainClass = "net.fabricmc.devlaunchinjector.Main"; runConfig.vmArgs = "-Dfabric.dli.config=" + encodeEscaped(extension.getFiles().getDevLauncherConfig().getAbsolutePath()) + " -Dfabric.dli.env=" + environment.toLowerCase(); - - if (extension.isForge()) { - List<String> modClasses = new ArrayList<>(); - - for (Supplier<SourceSet> sourceSetSupplier : extension.getForgeLocalMods()) { - SourceSet sourceSet = sourceSetSupplier.get(); - String sourceSetName = sourceSet.getName() + "_" + UUID.randomUUID().toString().replace("-", "").substring(0, 7); - - Stream.concat( - Stream.of(sourceSet.getOutput().getResourcesDir().getAbsolutePath()), - StreamSupport.stream(sourceSet.getOutput().getClassesDirs().spliterator(), false) - .map(File::getAbsolutePath) - ).map(s -> sourceSetName + "%%" + s).collect(Collectors.toCollection(() -> modClasses)); - } - - runConfig.envVariables.put("MOD_CLASSES", String.join(File.pathSeparator, modClasses)); - } } // Turns camelCase/PascalCase into Capital Case @@ -162,6 +139,7 @@ public class RunConfig { } public static RunConfig runConfig(Project project, RunConfigSettings settings) { + settings.evaluateNow(); LoomGradleExtension extension = LoomGradleExtension.get(project); String name = settings.getName(); @@ -195,6 +173,7 @@ public class RunConfig { } RunConfig runConfig = new RunConfig(); + runConfig.envVariables.putAll(settings.envVariables); runConfig.configName = configName; populate(project, extension, runConfig, environment); runConfig.ideaModuleName = getIdeaModuleName(project, sourceSet); diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java index 28f2f2f6..c7c0792f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/RunConfigSettings.java @@ -28,6 +28,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -36,6 +37,7 @@ import org.gradle.api.Named; import org.gradle.api.Project; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; +import org.jetbrains.annotations.ApiStatus; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.util.Constants; @@ -96,6 +98,8 @@ public final class RunConfigSettings implements Named { private final Project project; private final LoomGradleExtension extension; + public final Map<String, String> envVariables = new HashMap<>(); + private List<Runnable> evaluateLater = new ArrayList<>(); public RunConfigSettings(Project project, String baseName) { this.baseName = baseName; @@ -107,6 +111,20 @@ public final class RunConfigSettings implements Named { runDir("run"); } + @ApiStatus.Internal + public void evaluateLater(Runnable runnable) { + this.evaluateLater.add(runnable); + } + + @ApiStatus.Internal + public void evaluateNow() { + for (Runnable runnable : this.evaluateLater) { + runnable.run(); + } + + this.evaluateLater.clear(); + } + public Project getProject() { return project; } diff --git a/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java b/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java index db815e94..52006eaa 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java +++ b/src/main/java/net/fabricmc/loom/configuration/ide/SetupIntelijRunConfigs.java @@ -46,13 +46,13 @@ public class SetupIntelijRunConfigs { } try { - generate(project); + generate(project, false); } catch (IOException e) { throw new RuntimeException("Failed to generate run configs", e); } } - private static void generate(Project project) throws IOException { + public static void generate(Project project, boolean override) throws IOException { Project rootProject = project.getRootProject(); LoomGradleExtension extension = LoomGradleExtension.get(project); @@ -82,6 +82,10 @@ public class SetupIntelijRunConfigs { File runConfigs = new File(runConfigsDir, name + projectPath + ".xml"); String runConfigXml = config.fromDummy("idea_run_config_template.xml"); + if (runConfigs.exists() && override) { + runConfigs.delete(); + } + if (!runConfigs.exists()) { FileUtils.writeStringToFile(runConfigs, runConfigXml, StandardCharsets.UTF_8); } diff --git a/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java b/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java index 3a0c8eca..0ac814b5 100644 --- a/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java +++ b/src/main/java/net/fabricmc/loom/configuration/launch/LaunchProviderSettings.java @@ -33,11 +33,13 @@ import java.util.Map; import org.gradle.api.Named; import org.gradle.api.Project; +import org.jetbrains.annotations.ApiStatus; public class LaunchProviderSettings implements Named { private final String name; private List<Map.Entry<String, String>> properties = new ArrayList<>(); private List<String> arguments = new ArrayList<>(); + private List<Runnable> evaluateLater = new ArrayList<>(); public LaunchProviderSettings(Project project, String name) { this.name = name; @@ -48,6 +50,20 @@ public class LaunchProviderSettings implements Named { return name; } + @ApiStatus.Internal + public void evaluateLater(Runnable runnable) { + this.evaluateLater.add(runnable); + } + + @ApiStatus.Internal + public void evaluateNow() { + for (Runnable runnable : this.evaluateLater) { + runnable.run(); + } + + this.evaluateLater.clear(); + } + public void arg(String argument) { this.arguments.add(argument); } diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java index b7b37506..46d2e2ae 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java @@ -164,7 +164,7 @@ public class ModProcessor { remapper.readClassPathAsync(mc); - if (extension.isForge()) { + if (extension.isForgeAndNotOfficial()) { remapper.readClassPathAsync(mappedProvider.getForgeSrgJar().toPath()); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java index 9fc55c0f..af90c480 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java @@ -60,31 +60,21 @@ public class LaunchProvider extends DependencyProvider { .property("log4j.configurationFile", getAllLog4JConfigFiles()) .property("client", "java.library.path", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) - .property("client", "org.lwjgl.librarypath", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) + .property("client", "org.lwjgl.librarypath", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()); - .argument("client", "--assetIndex") - .argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) - .argument("client", "--assetsDir") - .argument("client", new File(getDirectories().getUserCache(), "assets").getAbsolutePath()); + if (!getExtension().isForge()) { + launchConfig + .argument("client", "--assetIndex") + .argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) + .argument("client", "--assetsDir") + .argument("client", new File(getDirectories().getUserCache(), "assets").getAbsolutePath()); + } if (getExtension().isForge()) { launchConfig // Should match YarnNamingService.PATH_TO_MAPPINGS in forge-runtime .property("fabric.yarnWithSrg.path", getExtension().getMappingsProvider().tinyMappingsWithSrg.toAbsolutePath().toString()) - .argument("--fml.mcVersion") - .argument(getExtension().getMinecraftProvider().minecraftVersion()) - .argument("--fml.forgeVersion") - .argument(getExtension().getForgeProvider().getVersion().getForgeVersion()) - - .argument("client", "--launchTarget") - .argument("client", "fmluserdevclient") - - .argument("server", "--launchTarget") - .argument("server", "fmluserdevserver") - - .argument("data", "--launchTarget") - .argument("data", "fmluserdevdata") .argument("data", "--all") .argument("data", "--mod") .argument("data", String.join(",", getExtension().getDataGenMods())) @@ -109,7 +99,18 @@ public class LaunchProvider extends DependencyProvider { } } + addDependency(Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES); + addDependency(Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES); + addDependency(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); + + if (getExtension().isForge()) { + addDependency(Constants.Dependencies.FORGE_RUNTIME + Constants.Dependencies.Versions.FORGE_RUNTIME, Constants.Configurations.FORGE_EXTRA); + addDependency(Constants.Dependencies.JAVAX_ANNOTATIONS + Constants.Dependencies.Versions.JAVAX_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); + } + for (LaunchProviderSettings settings : getExtension().getLaunchConfigs()) { + settings.evaluateNow(); + for (String argument : settings.getArguments()) { launchConfig.argument(settings.getName(), argument); } @@ -129,16 +130,6 @@ public class LaunchProvider extends DependencyProvider { writeLog4jConfig(); FileUtils.writeStringToFile(getDirectories().getDevLauncherConfig(), launchConfig.asString(), StandardCharsets.UTF_8); - addDependency(Constants.Dependencies.DEV_LAUNCH_INJECTOR + Constants.Dependencies.Versions.DEV_LAUNCH_INJECTOR, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES); - addDependency(Constants.Dependencies.TERMINAL_CONSOLE_APPENDER + Constants.Dependencies.Versions.TERMINAL_CONSOLE_APPENDER, Constants.Configurations.LOOM_DEVELOPMENT_DEPENDENCIES); - addDependency(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); - - if (getExtension().isForge()) { - addDependency(Constants.Dependencies.FORGE_RUNTIME + Constants.Dependencies.Versions.FORGE_RUNTIME, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); - addDependency(Constants.Dependencies.FORGE_RUNTIME + Constants.Dependencies.Versions.FORGE_RUNTIME, JavaPlugin.RUNTIME_ONLY_CONFIGURATION_NAME); - addDependency(Constants.Dependencies.JAVAX_ANNOTATIONS + Constants.Dependencies.Versions.JAVAX_ANNOTATIONS, JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME); - } - postPopulationScheduler.accept(this::writeRemapClassPath); } @@ -178,7 +169,7 @@ public class LaunchProvider extends DependencyProvider { remapClasspath.add(getExtension().getMinecraftMappedProvider().getIntermediaryJar()); - if (getExtension().isForge()) { + if (getExtension().isForgeAndNotOfficial()) { remapClasspath.add(getExtension().getMinecraftMappedProvider().getForgeIntermediaryJar()); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/FieldMigratedMappingsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/FieldMigratedMappingsProvider.java index 518398df..2440f526 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/FieldMigratedMappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/FieldMigratedMappingsProvider.java @@ -103,7 +103,7 @@ public class FieldMigratedMappingsProvider extends MappingsProviderImpl { @Override protected String createMappingsIdentifier(String mappingsName, String version, String classifier) { - return super.createMappingsIdentifier(mappingsName, version, classifier) + "-forge-" + getExtension().getPatchProvider().forgeVersion; + return super.createMappingsIdentifier(mappingsName, version, classifier) + "-forge-" + getExtension().getForgeProvider().getVersion().getCombined(); } @Override @@ -116,7 +116,7 @@ public class FieldMigratedMappingsProvider extends MappingsProviderImpl { if (getExtension().shouldGenerateSrgTiny()) { if (Files.notExists(rawTinyMappingsWithSrg) || isRefreshDeps()) { // Merge tiny mappings with srg - SrgMerger.mergeSrg(getExtension().getSrgProvider().getSrg().toPath(), rawTinyMappings, rawTinyMappingsWithSrg, true); + SrgMerger.mergeSrg(this::getMojmapSrgFileIfPossible, getRawSrgFile(), rawTinyMappings, rawTinyMappingsWithSrg, true); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeProvider.java index 50f6f82c..f9e1b9ef 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeProvider.java @@ -55,10 +55,13 @@ public class ForgeProvider extends DependencyProvider { } public static final class ForgeVersion { + private final String combined; private final String minecraftVersion; private final String forgeVersion; public ForgeVersion(String combined) { + this.combined = combined; + if (combined == null) { this.minecraftVersion = "NO_VERSION"; this.forgeVersion = "NO_VERSION"; @@ -76,6 +79,10 @@ public class ForgeProvider extends DependencyProvider { } } + public String getCombined() { + return combined; + } + public String getMinecraftVersion() { return minecraftVersion; } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeUserdevProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeUserdevProvider.java index 26add71e..2dd91d9d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeUserdevProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeUserdevProvider.java @@ -25,6 +25,7 @@ package net.fabricmc.loom.configuration.providers.forge; import java.io.File; +import java.io.IOException; import java.io.Reader; import java.net.URI; import java.nio.file.FileSystem; @@ -32,19 +33,46 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ModuleDependency; +import org.gradle.api.artifacts.transform.InputArtifact; +import org.gradle.api.artifacts.transform.TransformAction; +import org.gradle.api.artifacts.transform.TransformOutputs; +import org.gradle.api.artifacts.transform.TransformParameters; +import org.gradle.api.artifacts.type.ArtifactTypeDefinition; +import org.gradle.api.attributes.Attribute; +import org.gradle.api.file.FileSystemLocation; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.SourceSet; import net.fabricmc.loom.configuration.DependencyProvider; +import net.fabricmc.loom.configuration.ide.RunConfigSettings; +import net.fabricmc.loom.configuration.launch.LaunchProviderSettings; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.DependencyDownloader; +import net.fabricmc.loom.util.FileSystemUtil; public class ForgeUserdevProvider extends DependencyProvider { private File userdevJar; + private JsonObject json; + private Consumer<Runnable> postPopulationScheduler; public ForgeUserdevProvider(Project project) { super(project); @@ -52,6 +80,18 @@ public class ForgeUserdevProvider extends DependencyProvider { @Override public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception { + this.postPopulationScheduler = postPopulationScheduler; + Attribute<Boolean> transformed = Attribute.of("architectury-loom-forge-dependencies-transformed", Boolean.class); + + getProject().getDependencies().registerTransform(RemoveNameProvider.class, spec -> { + spec.getFrom().attribute(transformed, false); + spec.getTo().attribute(transformed, true); + }); + + for (ArtifactTypeDefinition type : getProject().getDependencies().getArtifactTypes()) { + type.getAttributes().attribute(transformed, false); + } + userdevJar = new File(getDirectories().getProjectPersistentCache(), "forge-" + dependency.getDependency().getVersion() + "-userdev.jar"); Path configJson = getDirectories() @@ -68,8 +108,6 @@ public class ForgeUserdevProvider extends DependencyProvider { } } - JsonObject json; - try (Reader reader = Files.newBufferedReader(configJson)) { json = new Gson().fromJson(reader, JsonObject.class); } @@ -79,19 +117,199 @@ public class ForgeUserdevProvider extends DependencyProvider { addDependency(json.get("universal").getAsString(), Constants.Configurations.FORGE_UNIVERSAL); for (JsonElement lib : json.get("libraries").getAsJsonArray()) { + Dependency dep = null; + if (lib.getAsString().startsWith("org.spongepowered:mixin:")) { if (getExtension().isUseFabricMixin()) { - addDependency("net.fabricmc:sponge-mixin:0.8.2+build.24", Constants.Configurations.FORGE_DEPENDENCIES); - continue; + dep = addDependency("net.fabricmc:sponge-mixin:0.8.2+build.24", Constants.Configurations.FORGE_DEPENDENCIES); } } - addDependency(lib.getAsString(), Constants.Configurations.FORGE_DEPENDENCIES); + if (dep == null) { + dep = addDependency(lib.getAsString(), Constants.Configurations.FORGE_DEPENDENCIES); + } + + if (lib.getAsString().split(":").length < 4) { + ((ModuleDependency) dep).attributes(attributes -> { + attributes.attribute(transformed, true); + }); + } } // TODO: Read launch configs from the JSON too // TODO: Should I copy the patches from here as well? // That'd require me to run the "MCP environment" fully up to merging. + for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject("runs").entrySet()) { + LaunchProviderSettings launchSettings = getExtension().getLaunchConfigs().findByName(entry.getKey()); + RunConfigSettings settings = getExtension().getRunConfigs().findByName(entry.getKey()); + JsonObject value = entry.getValue().getAsJsonObject(); + + if (launchSettings != null) { + launchSettings.evaluateLater(() -> { + if (value.has("args")) { + launchSettings.arg(StreamSupport.stream(value.getAsJsonArray("args").spliterator(), false) + .map(JsonElement::getAsString) + .map(this::processTemplates) + .collect(Collectors.toList())); + } + + if (value.has("props")) { + for (Map.Entry<String, JsonElement> props : value.getAsJsonObject("props").entrySet()) { + String string = processTemplates(props.getValue().getAsString()); + + launchSettings.property(props.getKey(), string); + } + } + }); + } + + if (settings != null) { + settings.evaluateLater(() -> { + settings.defaultMainClass(value.getAsJsonPrimitive("main").getAsString()); + settings.vmArgs(StreamSupport.stream(value.getAsJsonArray("jvmArgs").spliterator(), false) + .map(JsonElement::getAsString) + .map(this::processTemplates) + .collect(Collectors.toList())); + for (Map.Entry<String, JsonElement> env : value.getAsJsonObject("env").entrySet()) { + String string = processTemplates(env.getValue().getAsString()); + + settings.envVariables.put(env.getKey(), string); + } + }); + } + } + } + + public abstract static class RemoveNameProvider implements TransformAction<TransformParameters.None> { + @InputArtifact + public abstract Provider<FileSystemLocation> getInput(); + + @Override + public void transform(TransformOutputs outputs) { + try { + File input = getInput().get().getAsFile(); + //architectury-loom-forge-dependencies-transformed + File output = outputs.file(input.getName() + "-alfd-transformed.jar"); + Files.copy(input.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING); + + try (FileSystemUtil.FileSystemDelegate fs = FileSystemUtil.getJarFileSystem(output, false)) { + Path path = fs.get().getPath("META-INF/services/cpw.mods.modlauncher.api.INameMappingService"); + Files.deleteIfExists(path); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public String processTemplates(String string) { + if (string.startsWith("{")) { + String key = string.substring(1, string.length() - 1); + + // TODO: Look into ways to not hardcode + if (key.equals("runtime_classpath")) { + string = runtimeClasspath().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + } else if (key.equals("minecraft_classpath")) { + string = minecraftClasspath().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining(File.pathSeparator)); + } else if (key.equals("runtime_classpath_file")) { + Path path = getDirectories().getProjectPersistentCache().toPath().resolve("forge_runtime_classpath.txt"); + + postPopulationScheduler.accept(() -> { + try { + Files.writeString(path, runtimeClasspath().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining("\n")), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + string = path.toAbsolutePath().toString(); + } else if (key.equals("minecraft_classpath_file")) { + Path path = getDirectories().getProjectPersistentCache().toPath().resolve("forge_minecraft_classpath.txt"); + + postPopulationScheduler.accept(() -> { + try { + Files.writeString(path, minecraftClasspath().stream() + .map(File::getAbsolutePath) + .collect(Collectors.joining("\n")), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + string = path.toAbsolutePath().toString(); + } else if (key.equals("asset_index")) { + string = getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()); + } else if (key.equals("assets_root")) { + string = new File(getDirectories().getUserCache(), "assets").getAbsolutePath(); + } else if (key.equals("natives")) { + string = getMinecraftProvider().nativesDir().getAbsolutePath(); + } else if (key.equals("source_roots")) { + List<String> modClasses = new ArrayList<>(); + + for (Supplier<SourceSet> sourceSetSupplier : getExtension().getForgeLocalMods()) { + SourceSet sourceSet = sourceSetSupplier.get(); + String sourceSetName = sourceSet.getName() + "_" + UUID.randomUUID().toString().replace("-", "").substring(0, 7); + + Stream.concat( + Stream.of(sourceSet.getOutput().getResourcesDir().getAbsolutePath()), + StreamSupport.stream(sourceSet.getOutput().getClassesDirs().spliterator(), false) + .map(File::getAbsolutePath) + ).map(s -> sourceSetName + "%%" + s).collect(Collectors.toCollection(() -> modClasses)); + } + + string = String.join(File.pathSeparator, modClasses); + } else if (json.has(key)) { + JsonElement element = json.get(key); + + if (element.isJsonArray()) { + string = StreamSupport.stream(element.getAsJsonArray().spliterator(), false) + .map(JsonElement::getAsString) + .flatMap(str -> { + if (str.contains(":")) { + return DependencyDownloader.download(getProject(), str, false, false).getFiles().stream() + .map(File::getAbsolutePath) + .filter(dep -> !dep.contains("bootstraplauncher")); // TODO: Hack + } + + return Stream.of(str); + }) + .collect(Collectors.joining(File.pathSeparator)); + } else { + string = element.toString(); + } + } else { + getProject().getLogger().warn("Unrecognized template! " + string); + } + } + + return string; + } + + private Set<File> runtimeClasspath() { + // Should we actually include the runtime classpath here? Forge doesn't seem to be using this property anyways + Set<File> mcLibs = DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_DEPENDENCIES), true); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_EXTRA), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_NAMED), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_NAMED), false)); + return mcLibs; + } + + private Set<File> minecraftClasspath() { + Set<File> mcLibs = DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_DEPENDENCIES), true); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_EXTRA), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_NAMED), false)); + mcLibs.addAll(DependencyDownloader.resolveFiles(getProject().getConfigurations().getByName(Constants.Configurations.FORGE_NAMED), false)); + return mcLibs; } public File getUserdevJar() { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/McpConfigProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/McpConfigProvider.java index 78375240..c8d7b0c0 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/McpConfigProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/McpConfigProvider.java @@ -24,19 +24,33 @@ package net.fabricmc.loom.configuration.providers.forge; +import java.io.BufferedWriter; import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.util.function.Consumer; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import org.apache.commons.io.IOUtils; import org.gradle.api.Project; +import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.configuration.DependencyProvider; import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.FileSystemUtil; public class McpConfigProvider extends DependencyProvider { private File mcp; + private Path configJson; + private Path mappings; + private Boolean official; + private String mappingsPath; public McpConfigProvider(Project project) { super(project); @@ -46,25 +60,63 @@ public class McpConfigProvider extends DependencyProvider { public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception { init(dependency.getDependency().getVersion()); - if (mcp.exists() && !isRefreshDeps()) { - return; // No work for us to do here - } - Path mcpZip = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve MCPConfig")).toPath(); - if (!mcp.exists() || isRefreshDeps()) { + if (!mcp.exists() || !Files.exists(configJson) || isRefreshDeps()) { Files.copy(mcpZip, mcp.toPath(), StandardCopyOption.REPLACE_EXISTING); + + try (FileSystemUtil.FileSystemDelegate fs = FileSystemUtil.getJarFileSystem(mcp, false)) { + Files.copy(fs.get().getPath("config.json"), configJson, StandardCopyOption.REPLACE_EXISTING); + } } + + JsonObject json; + + try (Reader reader = Files.newBufferedReader(configJson)) { + json = new Gson().fromJson(reader, JsonObject.class); + } + + official = json.has("official") && json.getAsJsonPrimitive("official").getAsBoolean(); + mappingsPath = json.get("data").getAsJsonObject().get("mappings").getAsString(); } - private void init(String version) { - mcp = new File(getDirectories().getUserCache(), "mcp-" + version + ".zip"); + private void init(String version) throws IOException { + File dir = getMinecraftProvider().dir("mcp/" + version); + mcp = new File(dir, "mcp.zip"); + configJson = dir.toPath().resolve("mcp-config.json"); + mappings = dir.toPath().resolve("mcp-config-mappings.txt"); + + if (isRefreshDeps()) { + Files.deleteIfExists(mappings); + } + } + + public Path getMappings() { + if (Files.notExists(mappings)) { + if (!ZipUtil.handle(getMcp(), getMappingsPath(), (in, zipEntry) -> { + try (BufferedWriter writer = Files.newBufferedWriter(mappings, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + IOUtils.copy(in, writer, StandardCharsets.UTF_8); + } + })) { + throw new IllegalStateException("Failed to find mappings '" + getMappingsPath() + "' in " + getMcp().getAbsolutePath() + "!"); + } + } + + return mappings; } public File getMcp() { return mcp; } + public boolean isOfficial() { + return official; + } + + public String getMappingsPath() { + return mappingsPath; + } + @Override public String getTargetConfig() { return Constants.Configurations.MCP_CONFIG; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java index e4d60816..ae988155 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java @@ -29,7 +29,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.UncheckedIOException; @@ -55,47 +54,63 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.jar.Attributes; import java.util.jar.Manifest; +import java.util.regex.Pattern; import java.util.stream.Stream; import com.google.common.base.Preconditions; -import com.google.common.base.Predicates; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; -import com.google.gson.JsonParser; import de.oceanlabs.mcp.mcinjector.adaptors.ParameterAnnotationFixer; +import dev.architectury.mappingslayers.api.mutable.MutableClassDef; +import dev.architectury.mappingslayers.api.mutable.MutableMethodDef; +import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; +import dev.architectury.mappingslayers.api.utils.MappingsUtils; import dev.architectury.tinyremapper.InputTag; import dev.architectury.tinyremapper.OutputConsumerPath; import dev.architectury.tinyremapper.TinyRemapper; import net.minecraftforge.binarypatcher.ConsoleTool; -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.output.NullOutputStream; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.LogLevel; import org.gradle.api.logging.Logger; +import org.gradle.api.logging.configuration.ShowStacktrace; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.tasks.SourceSet; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; import org.zeroturnaround.zip.ZipUtil; +import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.configuration.DependencyProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProvider; import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; +import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; +import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace; +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingLayer; +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DependencyDownloader; import net.fabricmc.loom.util.FileSystemUtil; +import net.fabricmc.loom.util.MappingsProviderVerbose; import net.fabricmc.loom.util.ThreadingUtils; import net.fabricmc.loom.util.TinyRemapperMappingsHelper; import net.fabricmc.loom.util.function.FsPathConsumer; import net.fabricmc.loom.util.srg.InnerClassRemapper; import net.fabricmc.loom.util.srg.SpecialSourceExecutor; +import net.fabricmc.loom.util.srg.Tsrg2Utils; import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.mappingio.MappingVisitor; public class MinecraftPatchedProvider extends DependencyProvider { private static final String LOOM_PATCH_VERSION_KEY = "Loom-Patch-Version"; @@ -115,11 +130,14 @@ public class MinecraftPatchedProvider extends DependencyProvider { // Step 5: Remap Patched AT & Forge to Official (global or project) private File minecraftMergedPatchedJar; private File forgeMergedJar; + private File minecraftClientExtra; private File projectAtHash; private Set<File> projectAts = new HashSet<>(); private boolean atDirty = false; private boolean filesDirty = false; + private Path mcpConfigMappings; + private Path[] mergedMojangTsrg2Files; public MinecraftPatchedProvider(Project project) { super(project); @@ -161,34 +179,29 @@ public class MinecraftPatchedProvider extends DependencyProvider { MinecraftProviderImpl minecraftProvider = getExtension().getMinecraftProvider(); PatchProvider patchProvider = getExtension().getPatchProvider(); String minecraftVersion = minecraftProvider.minecraftVersion(); - String patchId = "forge-" + patchProvider.forgeVersion; - - if (getExtension().isUseFabricMixin()) { - patchId += "-fabric-mixin"; - } + String patchId = "forge-" + getExtension().getForgeProvider().getVersion().getCombined(); minecraftProvider.setJarSuffix(patchId); - File globalCache = getDirectories().getUserCache(); + File globalCache = getMinecraftProvider().dir("forge/" + getExtension().getForgeProvider().getVersion().getCombined()); File cache = usesProjectCache() ? getDirectories().getProjectPersistentCache() : globalCache; - File globalDir = new File(globalCache, patchId); - File projectDir = new File(cache, patchId); - globalDir.mkdirs(); + File projectDir = new File(cache, "forge/" + getExtension().getForgeProvider().getVersion().getCombined()); projectDir.mkdirs(); - minecraftClientSrgJar = new File(globalCache, "minecraft-" + minecraftVersion + "-client-srg.jar"); - minecraftServerSrgJar = new File(globalCache, "minecraft-" + minecraftVersion + "-server-srg.jar"); - minecraftClientPatchedSrgJar = new File(globalDir, "client-srg-patched.jar"); - minecraftServerPatchedSrgJar = new File(globalDir, "server-srg-patched.jar"); - minecraftMergedPatchedSrgJar = new File(globalDir, "merged-srg-patched.jar"); - forgeMergedJar = new File(globalDir, "forge-official.jar"); + minecraftClientSrgJar = new File(globalCache, "minecraft-client-srg.jar"); + minecraftServerSrgJar = new File(globalCache, "minecraft-server-srg.jar"); + minecraftClientPatchedSrgJar = new File(globalCache, "client-srg-patched.jar"); + minecraftServerPatchedSrgJar = new File(globalCache, "server-srg-patched.jar"); + minecraftMergedPatchedSrgJar = new File(globalCache, "merged-srg-patched.jar"); + forgeMergedJar = getExtension().isForgeAndOfficial() ? null : new File(globalCache, "forge-official.jar"); minecraftMergedPatchedSrgAtJar = new File(projectDir, "merged-srg-at-patched.jar"); minecraftMergedPatchedJar = new File(projectDir, "merged-patched.jar"); + minecraftClientExtra = new File(globalCache, "forge-client-extra.jar"); - if (isRefreshDeps() || Stream.of(getGlobalCaches()).anyMatch(Predicates.not(File::exists)) + if (isRefreshDeps() || Stream.of(getGlobalCaches()).anyMatch(((Predicate<File>) File::exists).negate()) || !isPatchedJarUpToDate(minecraftMergedPatchedJar)) { cleanAllCache(); - } else if (atDirty || Stream.of(getProjectCache()).anyMatch(Predicates.not(File::exists))) { + } else if (atDirty || Stream.of(getProjectCache()).anyMatch(((Predicate<File>) File::exists).negate())) { cleanProjectCache(); } } @@ -213,14 +226,21 @@ public class MinecraftPatchedProvider extends DependencyProvider { } private File[] getGlobalCaches() { - return new File[] { + File[] files = { minecraftClientSrgJar, minecraftServerSrgJar, minecraftClientPatchedSrgJar, minecraftServerPatchedSrgJar, minecraftMergedPatchedSrgJar, - forgeMergedJar, + minecraftClientExtra, }; + + if (forgeMergedJar != null) { + Arrays.copyOf(files, files.length + 1); + files[files.length - 1] = forgeMergedJar; + } + + return files; } public void cleanProjectCache() { @@ -270,7 +290,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { accessTransformForge(getProject().getLogger()); } - if (!forgeMergedJar.exists()) { + if (forgeMergedJar != null && !forgeMergedJar.exists()) { this.dirty = true; } @@ -278,10 +298,25 @@ public class MinecraftPatchedProvider extends DependencyProvider { if (dirty) { remapPatchedJar(input, getProject().getLogger()); + + if (getExtension().isForgeAndOfficial()) { + fillClientExtraJar(); + } } this.filesDirty = dirty; this.dirty = false; + + if (getExtension().isForgeAndOfficial()) { + addDependency(minecraftClientExtra, Constants.Configurations.FORGE_EXTRA); + } + } + + private void fillClientExtraJar() throws IOException { + Files.deleteIfExists(minecraftClientExtra.toPath()); + FileSystemUtil.getJarFileSystem(minecraftClientExtra, true).close(); + + copyNonClassFiles(getExtension().getMinecraftProvider().minecraftClientJar, minecraftClientExtra); } private TinyRemapper buildRemapper(Path input) throws IOException { @@ -291,12 +326,16 @@ public class MinecraftPatchedProvider extends DependencyProvider { .logger(getProject().getLogger()::lifecycle) .logUnknownInvokeDynamic(false) .withMappings(TinyRemapperMappingsHelper.create(mappingsWithSrg, "srg", "official", true)) - .withMappings(InnerClassRemapper.of(input, mappingsWithSrg, "srg", "official")) + .withMappings(InnerClassRemapper.of(InnerClassRemapper.readClassNames(input), mappingsWithSrg, "srg", "official")) .renameInvalidLocals(true) .rebuildSourceFilenames(true) .fixPackageAccess(true) .build(); + if (getProject().getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { + MappingsProviderVerbose.saveFile(remapper); + } + remapper.readClassPath(libraries); remapper.prepareClasses(); return remapper; @@ -309,39 +348,105 @@ public class MinecraftPatchedProvider extends DependencyProvider { } private void createSrgJars(Logger logger) throws Exception { - McpConfigProvider mcpProvider = getExtension().getMcpConfigProvider(); - MinecraftProviderImpl minecraftProvider = getExtension().getMinecraftProvider(); + String dep = getExtension().isForgeAndOfficial() ? Constants.Dependencies.VIGNETTE + Constants.Dependencies.Versions.VIGNETTE + : Constants.Dependencies.SPECIAL_SOURCE + Constants.Dependencies.Versions.SPECIAL_SOURCE + ":shaded"; + FileCollection classpath = DependencyDownloader.download(getProject(), dep, true, true); + produceSrgJar(getExtension().isForgeAndOfficial(), minecraftProvider.minecraftClientJar.toPath(), minecraftProvider.minecraftServerJar.toPath(), classpath); + } - String[] mappingsPath = {null}; + private void produceSrgJar(boolean official, Path clientJar, Path serverJar, FileCollection classpath) throws IOException { + Path tmpSrg = getToSrgMappings(); + Set<File> mcLibs = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).resolve(); - if (!ZipUtil.handle(mcpProvider.getMcp(), "config.json", (in, zipEntry) -> { - mappingsPath[0] = JsonParser.parseReader(new InputStreamReader(in)).getAsJsonObject().get("data").getAsJsonObject().get("mappings").getAsString(); - })) { - throw new IllegalStateException("Failed to find 'config.json' in " + mcpProvider.getMcp().getAbsolutePath() + "!"); + ThreadingUtils.run(() -> { + Files.copy(SpecialSourceExecutor.produceSrgJar(getProject(), "client", classpath, clientJar, tmpSrg), minecraftClientSrgJar.toPath()); + }, () -> { + Files.copy(SpecialSourceExecutor.produceSrgJar(getProject(), "server", classpath, serverJar, tmpSrg), minecraftServerSrgJar.toPath()); + }); + } + + private Path getToSrgMappings() throws IOException { + if (getExtension().isForgeAndOfficial()) { + return getMergedMojangTsrg2(true); + } else { + return getExtension().getMcpConfigProvider().getMappings(); } + } - Path[] tmpSrg = {null}; + private static void visitMojmap(MappingVisitor visitor, LoomGradleExtension extension) { + GradleMappingContext context = new GradleMappingContext(extension.getForgeProvider().getProject(), "tmp-mojmap"); + + try { + FileUtils.deleteDirectory(context.workingDirectory("/")); + MojangMappingLayer layer = new MojangMappingsSpec(() -> true).createLayer(context); + layer.visit(visitor); + } catch (IOException e) { + throw new UncheckedIOException(e); + } finally { + try { + FileUtils.deleteDirectory(context.workingDirectory("/")); + } catch (IOException e) { + e.printStackTrace(); + } + } + } - if (!ZipUtil.handle(mcpProvider.getMcp(), mappingsPath[0], (in, zipEntry) -> { - tmpSrg[0] = Files.createTempFile(null, null); + public static Path getMojmapTsrg(LoomGradleExtension extension) throws IOException { + Path path = extension.getMinecraftProvider().dir("forge").toPath().resolve("mojmap.tsrg"); - try (BufferedWriter writer = Files.newBufferedWriter(tmpSrg[0])) { - IOUtils.copy(in, writer, StandardCharsets.UTF_8); + if (Files.notExists(path)) { + try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + Tsrg2Utils.writeTsrg(visitor -> visitMojmap(visitor, extension), + MappingNamespace.NAMED.stringValue(), false, writer); } - })) { - throw new IllegalStateException("Failed to find mappings '" + mappingsPath[0] + "' in " + mcpProvider.getMcp().getAbsolutePath() + "!"); } - String atDependency = Constants.Dependencies.SPECIAL_SOURCE + Constants.Dependencies.Versions.SPECIAL_SOURCE + ":shaded"; - // Do getFiles() to resolve it before multithreading it - FileCollection classpath = getProject().files(DependencyDownloader.download(getProject(), atDependency).getFiles()); + return path; + } - ThreadingUtils.run(() -> { - Files.copy(SpecialSourceExecutor.produceSrgJar(getProject(), "client", classpath, minecraftProvider.minecraftClientJar.toPath(), tmpSrg[0]), minecraftClientSrgJar.toPath()); - }, () -> { - Files.copy(SpecialSourceExecutor.produceSrgJar(getProject(), "server", classpath, minecraftProvider.minecraftServerJar.toPath(), tmpSrg[0]), minecraftServerSrgJar.toPath()); + public static Path getMojmapTsrg2(LoomGradleExtension extension) throws IOException { + Path path = extension.getMinecraftProvider().dir("forge").toPath().resolve("mojmap.tsrg"); + + if (Files.notExists(path)) { + try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + Tsrg2Utils.writeTsrg2(visitor -> visitMojmap(visitor, extension), writer); + } + } + + return path; + } + + public Path getMergedMojangTsrg2(boolean hasParameters) throws IOException { + if (mergedMojangTsrg2Files == null) { + Path out = Files.createTempFile("merged-mojang-tsrg2", null); + Path outTrimmed = Files.createTempFile("merged-mojang-tsrg2-trimmed", null); + net.minecraftforge.installertools.ConsoleTool.main(new String[]{ + "--task", + "MERGE_MAPPING", + "--left", + getExtension().getMcpConfigProvider().getMappings().toAbsolutePath().toString(), + "--right", + getMojmapTsrg(getExtension()).toAbsolutePath().toString(), + "--classes", + "--output", + out.toAbsolutePath().toString() }); + + MutableTinyTree mappings = MappingsUtils.deserializeFromTsrg2(FileUtils.readFileToString(out.toFile(), StandardCharsets.UTF_8)); + + for (MutableClassDef classDef : mappings.getClassesMutable()) { + for (MutableMethodDef methodDef : classDef.getMethodsMutable()) { + methodDef.getParametersMutable().clear(); + } + } + + Files.writeString(outTrimmed, MappingsUtils.serializeToTsrg2(mappings), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + + mergedMojangTsrg2Files = new Path[]{out, outTrimmed}; + } + + return mergedMojangTsrg2Files[hasParameters ? 0 : 1]; } private void fixParameterAnnotation(File jarFile) throws Exception { @@ -378,6 +483,60 @@ public class MinecraftPatchedProvider extends DependencyProvider { getProject().getLogger().info(":fixing parameter annotations for " + jarFile.getAbsolutePath() + " in " + stopwatch); } + private void deleteParameterNames(File jarFile) throws Exception { + getProject().getLogger().info(":deleting parameter names for " + jarFile.getAbsolutePath()); + Stopwatch stopwatch = Stopwatch.createStarted(); + + try (FileSystem fs = FileSystems.newFileSystem(new URI("jar:" + jarFile.toURI()), ImmutableMap.of("create", false))) { + ThreadingUtils.TaskCompleter completer = ThreadingUtils.taskCompleter(); + Pattern vignetteParameters = Pattern.compile("p_\\d+_"); + + for (Path file : (Iterable<? extends Path>) Files.walk(fs.getPath("/"))::iterator) { + if (!file.toString().endsWith(".class")) continue; + + completer.add(() -> { + byte[] bytes = Files.readAllBytes(file); + ClassReader reader = new ClassReader(bytes); + ClassWriter writer = new ClassWriter(0); + + reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { + @Override + public void visitParameter(String name, int access) { + if (vignetteParameters.matcher(name).matches()) { + super.visitParameter(null, access); + } else { + super.visitParameter(name, access); + } + } + + @Override + public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) { + if (!vignetteParameters.matcher(name).matches()) { + super.visitLocalVariable(name, descriptor, signature, start, end, index); + } + } + }; + } + }, 0); + + byte[] out = writer.toByteArray(); + + if (!Arrays.equals(bytes, out)) { + Files.delete(file); + Files.write(file, out); + } + }); + } + + completer.complete(); + } + + getProject().getLogger().info(":deleting parameter names for " + jarFile.getAbsolutePath() + " in " + stopwatch); + } + private File getForgeJar() { return getExtension().getForgeUniversalProvider().getForge(); } @@ -453,8 +612,10 @@ public class MinecraftPatchedProvider extends DependencyProvider { spec.setClasspath(classpath); // if running with INFO or DEBUG logging - if (getProject().getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { + if (getProject().getGradle().getStartParameter().getShowStacktrace() != ShowStacktrace.INTERNAL_EXCEPTIONS + || getProject().getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { spec.setStandardOutput(System.out); + spec.setErrorOutput(System.err); } else { spec.setStandardOutput(NullOutputStream.NULL_OUTPUT_STREAM); spec.setErrorOutput(NullOutputStream.NULL_OUTPUT_STREAM); @@ -529,7 +690,12 @@ public class MinecraftPatchedProvider extends DependencyProvider { ThreadingUtils.run(Environment.values(), environment -> { copyMissingClasses(environment.srgJar.apply(this), environment.patchedSrgJar.apply(this)); - fixParameterAnnotation(environment.patchedSrgJar.apply(this)); + + if (getExtension().isForgeAndNotOfficial()) { + fixParameterAnnotation(environment.patchedSrgJar.apply(this)); + } else { + deleteParameterNames(environment.patchedSrgJar.apply(this)); + } }); logger.lifecycle(":patched jars in " + stopwatch.stop()); @@ -565,9 +731,12 @@ public class MinecraftPatchedProvider extends DependencyProvider { logger.lifecycle(":copying resources"); // Copy resources - MinecraftProviderImpl minecraftProvider = getExtension().getMinecraftProvider(); - copyNonClassFiles(minecraftProvider.minecraftClientJar, minecraftMergedPatchedSrgJar); - copyNonClassFiles(minecraftProvider.minecraftServerJar, minecraftMergedPatchedSrgJar); + if (getExtension().isForgeAndNotOfficial()) { + // Copy resources + MinecraftProviderImpl minecraftProvider = getExtension().getMinecraftProvider(); + copyNonClassFiles(minecraftProvider.minecraftClientJar, minecraftMergedPatchedSrgJar); + copyNonClassFiles(minecraftProvider.minecraftServerJar, minecraftMergedPatchedSrgJar); + } } private void walkFileSystems(File source, File target, Predicate<Path> filter, Function<FileSystem, Iterable<Path>> toWalk, FsPathConsumer action) @@ -576,6 +745,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { FileSystemUtil.FileSystemDelegate targetFs = FileSystemUtil.getJarFileSystem(target, false)) { for (Path sourceDir : toWalk.apply(sourceFs.get())) { Path dir = sourceDir.toAbsolutePath(); + if (!Files.exists(dir)) continue; Files.walk(dir) .filter(Files::isRegularFile) .filter(filter) @@ -616,9 +786,12 @@ public class MinecraftPatchedProvider extends DependencyProvider { } private void copyNonClassFiles(File source, File target) throws IOException { - Predicate<Path> filter = file -> { + Predicate<Path> filter = getExtension().isForgeAndOfficial() ? file -> { String s = file.toString(); return !s.endsWith(".class"); + } : file -> { + String s = file.toString(); + return !s.endsWith(".class") || (s.startsWith("META-INF") && !s.startsWith("META-INF/services")); }; walkFileSystems(source, target, filter, this::copyReplacing); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/PatchProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/PatchProvider.java index 2d6d8f46..d49ae8b4 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/PatchProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/PatchProvider.java @@ -43,7 +43,6 @@ import net.fabricmc.loom.util.Constants; public class PatchProvider extends DependencyProvider { public Path clientPatches; public Path serverPatches; - public String forgeVersion; public Path projectCacheFolder; public PatchProvider(Project project) { @@ -67,8 +66,7 @@ public class PatchProvider extends DependencyProvider { } private void init(String forgeVersion) { - this.forgeVersion = forgeVersion; - projectCacheFolder = getDirectories().getProjectPersistentCache().toPath().resolve(forgeVersion); + projectCacheFolder = getMinecraftProvider().dir("forge/" + forgeVersion).toPath(); clientPatches = projectCacheFolder.resolve("patches-client.lzma"); serverPatches = projectCacheFolder.resolve("patches-server.lzma"); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java index 047d75af..e62e9e91 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java @@ -25,9 +25,7 @@ package net.fabricmc.loom.configuration.providers.mappings; import java.io.File; -import java.io.IOException; -import org.apache.commons.io.FileUtils; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.logging.Logger; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java index 878a37e4..ff48a5cf 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java @@ -35,8 +35,19 @@ import java.util.Collections; import java.util.Objects; import java.util.Set; +import org.gradle.api.Action; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ExternalDependency; +import org.gradle.api.artifacts.ExternalModuleDependency; +import org.gradle.api.artifacts.ModuleIdentifier; +import org.gradle.api.artifacts.ModuleVersionIdentifier; +import org.gradle.api.artifacts.MutableVersionConstraint; import org.gradle.api.artifacts.SelfResolvingDependency; +import org.gradle.api.artifacts.VersionConstraint; +import org.gradle.api.internal.artifacts.DefaultModuleIdentifier; +import org.gradle.api.internal.artifacts.ModuleVersionSelectorStrictSpec; +import org.gradle.api.internal.artifacts.dependencies.AbstractModuleDependency; +import org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint; import org.gradle.api.tasks.TaskDependency; import org.zeroturnaround.zip.ByteSource; import org.zeroturnaround.zip.ZipEntrySource; @@ -48,7 +59,7 @@ import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.format.Tiny2Writer; import net.fabricmc.mappingio.tree.MemoryMappingTree; -public class LayeredMappingsDependency implements SelfResolvingDependency { +public class LayeredMappingsDependency extends AbstractModuleDependency implements SelfResolvingDependency, ExternalModuleDependency { private static final String GROUP = "loom"; private static final String MODULE = "mappings"; @@ -57,6 +68,7 @@ public class LayeredMappingsDependency implements SelfResolvingDependency { private final String version; public LayeredMappingsDependency(MappingContext mappingContext, LayeredMappingSpec layeredMappingSpec, String version) { + super(null); this.mappingContext = mappingContext; this.layeredMappingSpec = layeredMappingSpec; this.version = version; @@ -119,6 +131,21 @@ public class LayeredMappingsDependency implements SelfResolvingDependency { } @Override + public VersionConstraint getVersionConstraint() { + return new DefaultMutableVersionConstraint(getVersion()); + } + + @Override + public boolean matchesStrictly(ModuleVersionIdentifier identifier) { + return new ModuleVersionSelectorStrictSpec(this).isSatisfiedBy(identifier); + } + + @Override + public ModuleIdentifier getModule() { + return DefaultModuleIdentifier.newId(GROUP, MODULE); + } + + @Override public boolean contentEquals(Dependency dependency) { if (dependency instanceof LayeredMappingsDependency layeredMappingsDependency) { return Objects.equals(layeredMappingsDependency.getVersion(), this.getVersion()); @@ -128,11 +155,35 @@ public class LayeredMappingsDependency implements SelfResolvingDependency { } @Override - public Dependency copy() { + public boolean isChanging() { + return false; + } + + @Override + public ExternalModuleDependency setChanging(boolean b) { + return this; + } + + @Override + public boolean isForce() { + return false; + } + + @Override + public ExternalDependency setForce(boolean b) { + return this; + } + + @Override + public ExternalModuleDependency copy() { return new LayeredMappingsDependency(mappingContext, layeredMappingSpec, version); } @Override + public void version(Action<? super MutableVersionConstraint> action) { + } + + @Override public String getReason() { return null; } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java index edddf340..eb6343cc 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java @@ -27,6 +27,7 @@ package net.fabricmc.loom.configuration.providers.mappings; import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystem; @@ -151,7 +152,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings if (getExtension().shouldGenerateSrgTiny()) { if (Files.notExists(tinyMappingsWithSrg) || isRefreshDeps()) { // Merge tiny mappings with srg - SrgMerger.mergeSrg(getExtension().getSrgProvider().getSrg().toPath(), tinyMappings, tinyMappingsWithSrg, true); + SrgMerger.mergeSrg(this::getMojmapSrgFileIfPossible, getRawSrgFile(), tinyMappings, tinyMappingsWithSrg, true); } } @@ -216,7 +217,27 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings mappedProvider.provide(dependency, postPopulationScheduler); } - public void manipulateMappings(Path mappingsJar) throws IOException { } + protected Path getRawSrgFile() throws IOException { + LoomGradleExtension extension = getExtension(); + + if (extension.isForgeAndOfficial()) { + return patchedProvider.getMergedMojangTsrg2(false); + } + + return extension.getSrgProvider().getSrg().toPath(); + } + + protected Path getMojmapSrgFileIfPossible() { + try { + LoomGradleExtension extension = getExtension(); + return MinecraftPatchedProvider.getMojmapTsrg2(extension); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public void manipulateMappings(Path mappingsJar) throws IOException { + } private String getMappingsClassifier(DependencyInfo dependency, boolean isV2) { String[] depStringSplit = dependency.getDepString().split(":"); @@ -248,7 +269,8 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings } } - private void storeMappings(Project project, MinecraftProviderImpl minecraftProvider, Path yarnJar, Consumer<Runnable> postPopulationScheduler) throws IOException { + private void storeMappings(Project project, MinecraftProviderImpl minecraftProvider, Path yarnJar, Consumer<Runnable> postPopulationScheduler) + throws IOException { project.getLogger().info(":extracting " + yarnJar.getFileName()); if (isMCP(yarnJar)) { @@ -298,7 +320,7 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings provider.provide(DependencyInfo.create(getProject(), configuration.getDependencies().iterator().next(), configuration), postPopulationScheduler); } - Path srgPath = provider.getSrg().toPath(); + Path srgPath = getRawSrgFile(); TinyFile file = new MCPReader(intermediaryTinyPath, srgPath).read(mcpJar); TinyV2Writer.write(file, tinyMappings); } @@ -426,20 +448,20 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings try { Command command = new CommandMergeTinyV2(); runCommand(command, intermediaryMappings.toAbsolutePath().toString(), - yarnMappings.toAbsolutePath().toString(), - newMergedMappings.toAbsolutePath().toString(), - "intermediary", "official"); + yarnMappings.toAbsolutePath().toString(), + newMergedMappings.toAbsolutePath().toString(), + "intermediary", "official"); } catch (Exception e) { throw new RuntimeException("Could not merge mappings from " + intermediaryMappings.toString() - + " with mappings from " + yarnMappings, e); + + " with mappings from " + yarnMappings, e); } } private void suggestFieldNames(MinecraftProviderImpl minecraftProvider, Path oldMappings, Path newMappings) { Command command = new CommandProposeFieldNames(); runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(), - oldMappings.toAbsolutePath().toString(), - newMappings.toAbsolutePath().toString()); + oldMappings.toAbsolutePath().toString(), + newMappings.toAbsolutePath().toString()); } private void runCommand(Command command, String... args) { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java index a396e5b4..1407511e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java @@ -101,7 +101,7 @@ public class MinecraftMappedProvider extends DependencyProvider { needToRemap = true; } - if (getExtension().isForge() && (!getForgeMappedJar().exists() || !getForgeIntermediaryJar().exists() || !getForgeSrgJar().exists() || isRefreshDeps() || isForgeAtDirty)) { + if (getExtension().isForgeAndNotOfficial() && (!getForgeMappedJar().exists() || !getForgeIntermediaryJar().exists() || !getForgeSrgJar().exists() || isRefreshDeps() || isForgeAtDirty)) { needToRemap = true; } @@ -120,7 +120,7 @@ public class MinecraftMappedProvider extends DependencyProvider { minecraftSrgJar.delete(); } - if (getExtension().isForge()) { + if (getExtension().isForgeAndNotOfficial()) { if (getForgeMappedJar().exists()) { getForgeMappedJar().delete(); } @@ -158,16 +158,18 @@ public class MinecraftMappedProvider extends DependencyProvider { addDependencies(dependency, postPopulationScheduler); - if (getExtension().isForge()) { + if (getExtension().isForgeAndNotOfficial()) { getProject().getRepositories().flatDir(repository -> repository.dir(new File(getJarDirectory(getDirectories().getUserCache(), "mapped"), "forge"))); getProject().getDependencies().add(Constants.Configurations.FORGE_NAMED, - getProject().getDependencies().module("net.minecraftforge-loom:forge:" + getJarVersionString("mapped"))); + getProject().getDependencies().module("net.minecraftforge-loom:forge-mapped:" + getMinecraftProvider().minecraftVersion() + "/" + getExtension().getMappingsProvider().mappingsIdentifier() + "/forge")); + } + if (getExtension().isForge()) { getProject().afterEvaluate(project -> { if (!OperatingSystem.isCIBuild()) { try { - ForgeSourcesRemapper.addBaseForgeSources(project); + ForgeSourcesRemapper.addBaseForgeSources(project, getExtension().isForgeAndOfficial()); } catch (IOException e) { e.printStackTrace(); } @@ -241,13 +243,13 @@ public class MinecraftMappedProvider extends DependencyProvider { forgeAssets.toFile().deleteOnExit(); Info vanilla = new Info(vanillaAssets, input, outputMapped, outputIntermediary, outputSrg); - Info forge = getExtension().isForge() ? new Info(forgeAssets, inputForge, forgeOutputMapped, forgeOutputIntermediary, forgeOutputSrg) : null; + Info forge = getExtension().isForgeAndNotOfficial() ? new Info(forgeAssets, inputForge, forgeOutputMapped, forgeOutputIntermediary, forgeOutputSrg) : null; TinyRemapper remapper = remapperArray[0] = buildRemapper(); assetsOut(input, vanillaAssets); - if (getExtension().isForge()) { + if (getExtension().isForgeAndNotOfficial()) { assetsOut(inputForge, forgeAssets); } @@ -271,6 +273,8 @@ public class MinecraftMappedProvider extends DependencyProvider { } public void remap(TinyRemapper remapper, Info vanilla, @Nullable Info forge, String fromM) throws IOException { + Set<String> classNames = getExtension().isForge() ? InnerClassRemapper.readClassNames(vanilla.input) : null; + for (String toM : getExtension().isForge() ? Arrays.asList("intermediary", "srg", "named") : Arrays.asList("intermediary", "named")) { Path output = "named".equals(toM) ? vanilla.outputMapped : "srg".equals(toM) ? vanilla.outputSrg : vanilla.outputIntermediary; Path outputForge = forge == null ? null : "named".equals(toM) ? forge.outputMapped : "srg".equals(toM) ? forge.outputSrg : forge.outputIntermediary; @@ -285,7 +289,7 @@ public class MinecraftMappedProvider extends DependencyProvider { remapper.readInputs(forgeTag, forge.input); } - remapper.replaceMappings(getMappings(vanilla.input, fromM, toM)); + remapper.replaceMappings(getMappings(classNames, fromM, toM)); OutputRemappingHandler.remap(remapper, vanilla.assets, output, null, vanillaTag); if (forge != null) { @@ -325,13 +329,13 @@ public class MinecraftMappedProvider extends DependencyProvider { return builder.build(); } - public Set<IMappingProvider> getMappings(@Nullable Path fromJar, String fromM, String toM) throws IOException { + public Set<IMappingProvider> getMappings(@Nullable Set<String> fromClassNames, String fromM, String toM) throws IOException { Set<IMappingProvider> providers = new HashSet<>(); providers.add(TinyRemapperMappingsHelper.create(getExtension().isForge() ? getExtension().getMappingsProvider().getMappingsWithSrg() : getExtension().getMappingsProvider().getMappings(), fromM, toM, true)); if (getExtension().isForge()) { - if (fromJar != null) { - providers.add(InnerClassRemapper.of(fromJar, getExtension().getMappingsProvider().getMappingsWithSrg(), fromM, toM)); + if (fromClassNames != null) { + providers.add(InnerClassRemapper.of(fromClassNames, getExtension().getMappingsProvider().getMappingsWithSrg(), fromM, toM)); } } else { providers.add(out -> JSR_TO_JETBRAINS.forEach(out::acceptClass)); @@ -357,11 +361,16 @@ public class MinecraftMappedProvider extends DependencyProvider { minecraftMappedJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "minecraft-mapped.jar"); inputJar = getExtension().isForge() ? mappingsProvider.patchedProvider.getMergedJar() : minecraftProvider.getMergedJar(); - if (getExtension().isForge()) { + if (getExtension().isForgeAndNotOfficial()) { inputForgeJar = mappingsProvider.patchedProvider.getForgeMergedJar(); - forgeIntermediaryJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge-intermediary.jar"); - forgeSrgJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge-srg.jar"); + forgeIntermediaryJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-intermediary.jar"); + forgeSrgJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-srg.jar"); forgeMappedJar = new File(getExtension().getMappingsProvider().mappingsWorkingDir().toFile(), "forge/forge-mapped.jar"); + } else { + inputForgeJar = null; + forgeIntermediaryJar = null; + forgeSrgJar = null; + forgeMappedJar = null; } } diff --git a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java index db56ae5e..0e204eb4 100644 --- a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java +++ b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java @@ -58,8 +58,8 @@ import net.fabricmc.loom.util.ThreadingUtils; import net.fabricmc.lorenztiny.TinyMappingsReader; public class ForgeSourcesRemapper { - public static void addBaseForgeSources(Project project) throws IOException { - Path sourcesJar = GenerateSourcesTask.getMappedJarFileWithSuffix(project, "-sources.jar", true).toPath(); + public static void addBaseForgeSources(Project project, boolean isOfficial) throws IOException { + Path sourcesJar = GenerateSourcesTask.getMappedJarFileWithSuffix(project, "-sources.jar", !isOfficial).toPath(); if (!Files.exists(sourcesJar)) { addForgeSources(project, sourcesJar); @@ -185,7 +185,11 @@ public class ForgeSourcesRemapper { // Distinct and add the srg jar at the top, so it gets prioritized mercury.getClassPath().add(0, extension.getMinecraftMappedProvider().getSrgJar().toPath()); - mercury.getClassPath().add(0, extension.getMinecraftMappedProvider().getForgeSrgJar().toPath()); + + if (extension.isForgeAndNotOfficial()) { + mercury.getClassPath().add(0, extension.getMinecraftMappedProvider().getForgeSrgJar().toPath()); + } + List<Path> newClassPath = mercury.getClassPath().stream() .distinct() .filter(Files::isRegularFile) diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 5feeafbe..1f274f12 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -367,6 +367,16 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA } @Override + public boolean isForgeAndOfficial() { + throw new RuntimeException("Yeah... something is really wrong"); + } + + @Override + public boolean isForgeAndNotOfficial() { + throw new RuntimeException("Yeah... something is really wrong"); + } + + @Override protected String getMinecraftVersion() { throw new RuntimeException("Yeah... something is really wrong"); } diff --git a/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java b/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java index 2921b451..5550cb8a 100644 --- a/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/extension/MinecraftGradleExtension.java @@ -161,6 +161,18 @@ public class MinecraftGradleExtension implements LoomGradleExtensionAPI { } @Override + public boolean isForgeAndOfficial() { + reportDeprecation(); + return parent.isForgeAndOfficial(); + } + + @Override + public boolean isForgeAndNotOfficial() { + reportDeprecation(); + return parent.isForgeAndNotOfficial(); + } + + @Override public boolean supportsInclude() { reportDeprecation(); return parent.supportsInclude(); diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 883169f8..5f41b03e 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -25,6 +25,8 @@ package net.fabricmc.loom.task; import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; import com.google.common.base.Preconditions; import org.gradle.api.Project; @@ -33,6 +35,7 @@ import org.gradle.api.tasks.TaskContainer; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.configuration.ide.RunConfigSettings; +import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler; import net.fabricmc.loom.util.Constants; @@ -86,6 +89,19 @@ public final class LoomTasks { t.dependsOn("downloadAssets"); t.setGroup(Constants.TaskGroup.IDE); }); + + tasks.register("genIntelliJRuns", AbstractLoomTask.class, t -> { + t.setDescription("Generates IntelliJ IDEA launch configurations."); + t.dependsOn("downloadAssets"); + t.setGroup("ide"); + t.doLast(task -> { + try { + SetupIntelijRunConfigs.generate(task.getProject(), true); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + }); } private static void registerRunTasks(TaskContainer tasks, Project project) { diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 6febed33..84cee1c9 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -187,9 +187,12 @@ public class MigrateMappingsTask extends AbstractLoomTask { if (extension.isForge()) { mercury.getClassPath().add(minecraftMappedProvider.getSrgJar().toPath()); - mercury.getClassPath().add(minecraftMappedProvider.getForgeMappedJar().toPath()); - mercury.getClassPath().add(minecraftMappedProvider.getForgeIntermediaryJar().toPath()); - mercury.getClassPath().add(minecraftMappedProvider.getForgeSrgJar().toPath()); + + if (extension.isForgeAndNotOfficial()) { + mercury.getClassPath().add(minecraftMappedProvider.getForgeMappedJar().toPath()); + mercury.getClassPath().add(minecraftMappedProvider.getForgeIntermediaryJar().toPath()); + mercury.getClassPath().add(minecraftMappedProvider.getForgeSrgJar().toPath()); + } } mercury.getProcessors().add(MercuryRemapper.create(mappingSet)); diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index f53dbf50..f3f0bf5a 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -79,6 +79,7 @@ public class Constants { public static final String FORGE_UNIVERSAL = "forgeUniversal"; public static final String FORGE_DEPENDENCIES = "forgeDependencies"; public static final String FORGE_NAMED = "forgeNamed"; + public static final String FORGE_EXTRA = "forgeExtra"; public static final String MAPPING_CONSTANTS = "mappingsConstants"; public static final String UNPICK_CLASSPATH = "unpick"; @@ -95,9 +96,10 @@ public class Constants { public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:"; public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:"; public static final String JAVAX_ANNOTATIONS = "com.google.code.findbugs:jsr305:"; // I hate that I have to add these. - public static final String FORGE_RUNTIME = "dev.architectury:architectury-loom-forge-runtime:"; + public static final String FORGE_RUNTIME = "dev.architectury:architectury-loom-runtime:"; public static final String ACCESS_TRANSFORMERS = "net.minecraftforge:accesstransformers:"; public static final String SPECIAL_SOURCE = "net.md-5:SpecialSource:"; + public static final String VIGNETTE = "net.minecraftforge.lex:vignette:"; private Dependencies() { } @@ -111,9 +113,10 @@ public class Constants { public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0"; public static final String JETBRAINS_ANNOTATIONS = "19.0.0"; public static final String JAVAX_ANNOTATIONS = "3.0.2"; - public static final String FORGE_RUNTIME = "$LOOM_VERSION"; // replaced with current version at build time - public static final String ACCESS_TRANSFORMERS = "2.2.0"; + public static final String FORGE_RUNTIME = "1.0.1"; + public static final String ACCESS_TRANSFORMERS = "3.0.1"; public static final String SPECIAL_SOURCE = "1.8.3"; + public static final String VIGNETTE = "0.2.0.10"; private Versions() { } diff --git a/src/main/java/net/fabricmc/loom/util/DependencyDownloader.java b/src/main/java/net/fabricmc/loom/util/DependencyDownloader.java index a7201cbb..85bcbe00 100644 --- a/src/main/java/net/fabricmc/loom/util/DependencyDownloader.java +++ b/src/main/java/net/fabricmc/loom/util/DependencyDownloader.java @@ -24,7 +24,14 @@ package net.fabricmc.loom.util; +import java.io.File; +import java.util.LinkedHashSet; +import java.util.Set; + import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ModuleDependency; import org.gradle.api.file.FileCollection; /** @@ -41,8 +48,40 @@ public final class DependencyDownloader { * @return the resolved files */ public static FileCollection download(Project project, String dependencyNotation) { - var dependency = project.getDependencies().create(dependencyNotation); - var config = project.getConfigurations().detachedConfiguration(dependency); - return config.fileCollection(dep -> true); + return download(project, dependencyNotation, true, false); + } + + public static FileCollection download(Project project, String dependencyNotation, boolean transitive, boolean resolve) { + Dependency dependency = project.getDependencies().create(dependencyNotation); + + if (dependency instanceof ModuleDependency) { + ((ModuleDependency) dependency).setTransitive(transitive); + } + + Configuration config = project.getConfigurations().detachedConfiguration(dependency); + config.setTransitive(transitive); + FileCollection files = config.fileCollection(dep -> true); + + if (resolve) { + files = project.files(files.getFiles()); + } + + return files; + } + + private static Set<File> resolve(Configuration configuration, boolean transitive) { + Configuration copy = configuration.copy(); + copy.setTransitive(transitive); + Set<File> files = new LinkedHashSet<>(copy.resolve()); + + for (Configuration extendsForm : configuration.getExtendsFrom()) { + files.addAll(resolve(extendsForm, transitive)); + } + + return files; + } + + public static Set<File> resolveFiles(Configuration configuration, boolean transitive) { + return resolve(configuration, transitive); } } diff --git a/src/main/java/net/fabricmc/loom/util/MappingsProviderVerbose.java b/src/main/java/net/fabricmc/loom/util/MappingsProviderVerbose.java new file mode 100644 index 00000000..6bdb7932 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/MappingsProviderVerbose.java @@ -0,0 +1,71 @@ +package net.fabricmc.loom.util; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; + +import dev.architectury.mappingslayers.api.mutable.MutableTinyMetadata; +import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; +import dev.architectury.mappingslayers.api.utils.MappingsUtils; +import dev.architectury.tinyremapper.IMappingProvider; +import dev.architectury.tinyremapper.TinyRemapper; + +public class MappingsProviderVerbose { + public static void saveFile(TinyRemapper providers) throws IOException { + try { + Field field = TinyRemapper.class.getDeclaredField("mappingProviders"); + field.setAccessible(true); + Set<IMappingProvider> mappingProviders = (Set<IMappingProvider>) field.get(providers); + saveFile(mappingProviders); + } catch (IllegalAccessException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public static void saveFile(Iterable<IMappingProvider> providers) throws IOException { + MutableTinyTree tree = MappingsUtils.create(MutableTinyMetadata.create(2, 0, Arrays.asList("from", "to"), new HashMap<>())); + + for (IMappingProvider provider : providers) { + provider.load(new IMappingProvider.MappingAcceptor() { + @Override + public void acceptClass(String from, String to) { + tree.getOrCreateClass(from).setName(1, to); + } + + @Override + public void acceptMethod(IMappingProvider.Member from, String to) { + tree.getOrCreateClass(from.owner).getOrCreateMethod(from.name, from.desc) + .setName(1, to); + } + + @Override + public void acceptMethodArg(IMappingProvider.Member from, int lvIndex, String to) { + tree.getOrCreateClass(from.owner).getOrCreateMethod(from.name, from.desc) + .getOrCreateParameter(lvIndex, "") + .setName(1, to); + } + + @Override + public void acceptMethodVar(IMappingProvider.Member from, int i, int i1, int i2, String s) { + // NO-OP + } + + @Override + public void acceptField(IMappingProvider.Member from, String to) { + tree.getOrCreateClass(from.owner).getOrCreateField(from.name, from.desc) + .setName(1, to); + } + }); + } + + Path check = Files.createTempFile("CHECK", null); + Files.writeString(check, MappingsUtils.serializeToString(tree), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + System.out.println("Saved debug check mappings to " + check); + } +} diff --git a/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java b/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java index 1949c55d..edc7e263 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java @@ -27,11 +27,14 @@ package net.fabricmc.loom.util.srg; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashSet; import java.util.Iterator; -import java.util.Map; +import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import dev.architectury.tinyremapper.IMappingProvider; import net.fabricmc.loom.util.FileSystemUtil; @@ -40,22 +43,16 @@ import net.fabricmc.mapping.tree.ClassDef; import net.fabricmc.mapping.tree.TinyTree; public class InnerClassRemapper { - public static IMappingProvider of(Path fromJar, TinyTree mappingsWithSrg, String from, String to) throws IOException { + public static IMappingProvider of(Set<String> fromClassNames, TinyTree mappingsWithSrg, String from, String to) throws IOException { return sink -> { - remapInnerClass(fromJar, mappingsWithSrg, from, to, sink::acceptClass); + remapInnerClass(fromClassNames, mappingsWithSrg, from, to, sink::acceptClass); }; } - private static void remapInnerClass(Path fromJar, TinyTree mappingsWithSrg, String from, String to, BiConsumer<String, String> action) { - try (FileSystemDelegate system = FileSystemUtil.getJarFileSystem(fromJar, false)) { - Map<String, String> availableClasses = mappingsWithSrg.getClasses().stream() - .collect(Collectors.groupingBy(classDef -> classDef.getName(from), - Collectors.<ClassDef, String>reducing( - null, - classDef -> classDef.getName(to), - (first, last) -> last - )) - ); + public static Set<String> readClassNames(Path jar) { + Set<String> set = new HashSet<>(); + + try (FileSystemDelegate system = FileSystemUtil.getJarFileSystem(jar, false)) { Iterator<Path> iterator = Files.walk(system.get().getPath("/")).iterator(); while (iterator.hasNext()) { @@ -65,21 +62,42 @@ public class InnerClassRemapper { if (!Files.isDirectory(path) && name.contains("$") && name.endsWith(".class")) { String className = name.substring(0, name.length() - 6); + set.add(className); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } - if (!availableClasses.containsKey(className)) { - String parentName = className.substring(0, className.indexOf('$')); - String childName = className.substring(className.indexOf('$') + 1); - String remappedParentName = availableClasses.getOrDefault(parentName, parentName); - String remappedName = remappedParentName + "$" + childName; + return set; + } + + private static void remapInnerClass(Set<String> classNames, TinyTree mappingsWithSrg, String from, String to, BiConsumer<String, String> action) { + BiMap<String, String> availableClasses = HashBiMap.create(mappingsWithSrg.getClasses().stream() + .collect(Collectors.groupingBy(classDef -> classDef.getName(from), + Collectors.<ClassDef, String>reducing( + null, + classDef -> classDef.getName(to), + (first, last) -> last + )) + )); + + for (String className : classNames) { + if (!availableClasses.containsKey(className)) { + String parentName = className.substring(0, className.indexOf('$')); + String childName = className.substring(className.indexOf('$') + 1); + String remappedParentName = availableClasses.getOrDefault(parentName, parentName); + String remappedName = remappedParentName + "$" + childName; - if (!className.equals(remappedName)) { - action.accept(className, remappedName); - } + if (!className.equals(remappedName)) { + if (availableClasses.containsValue(remappedName)) { + // https://github.com/MinecraftForge/MinecraftForge/blob/b027a92dd287d6810a9fdae4d4b1e1432d7dc9cc/patches/minecraft/net/minecraft/Util.java.patch#L8 + action.accept(className, remappedName + "_UNBREAK"); + } else { + action.accept(className, remappedName); } } } - } catch (IOException e) { - throw new RuntimeException(e); } } } diff --git a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java index 8d5e7738..327825d3 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java +++ b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java @@ -39,6 +39,7 @@ import org.apache.commons.io.output.NullOutputStream; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.LogLevel; +import org.gradle.api.logging.configuration.ShowStacktrace; import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; @@ -87,8 +88,10 @@ public class SpecialSourceExecutor { spec.setMain("net.md_5.specialsource.SpecialSource"); // if running with INFO or DEBUG logging - if (project.getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { + if (project.getGradle().getStartParameter().getShowStacktrace() != ShowStacktrace.INTERNAL_EXCEPTIONS + || project.getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { spec.setStandardOutput(System.out); + spec.setErrorOutput(System.err); } else { spec.setStandardOutput(NullOutputStream.NULL_OUTPUT_STREAM); spec.setErrorOutput(NullOutputStream.NULL_OUTPUT_STREAM); diff --git a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java b/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java index 39a2b57c..e2cf730f 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java +++ b/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java @@ -27,15 +27,20 @@ package net.fabricmc.loom.util.srg; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; +import com.google.common.base.MoreObjects; import dev.architectury.mappingslayers.api.mutable.MutableClassDef; +import dev.architectury.mappingslayers.api.mutable.MutableDescriptored; import dev.architectury.mappingslayers.api.mutable.MutableFieldDef; import dev.architectury.mappingslayers.api.mutable.MutableMethodDef; import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; @@ -56,6 +61,7 @@ import net.fabricmc.mapping.tree.FieldDef; import net.fabricmc.mapping.tree.MethodDef; import net.fabricmc.mapping.tree.TinyMappingFactory; import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.mappingio.format.TsrgReader; import net.fabricmc.stitch.commands.tinyv2.TinyClass; import net.fabricmc.stitch.commands.tinyv2.TinyField; import net.fabricmc.stitch.commands.tinyv2.TinyFile; @@ -80,8 +86,9 @@ public final class SrgMerger { * @throws MappingException if the input tiny tree's default namespace is not 'official' * or if an element mentioned in the SRG file does not have tiny mappings */ - public static void mergeSrg(Path srg, Path tiny, Path out, boolean lenient) throws IOException, MappingException { - MappingSet arr = readSrg(srg); + public static void mergeSrg(Supplier<Path> mojmap, Path srg, Path tiny, Path out, boolean lenient) throws IOException, MappingException { + Map<String, List<MutableDescriptored>> addRegardlessSrgs = new HashMap<>(); + MappingSet arr = readSrg(srg, mojmap, addRegardlessSrgs); TinyTree foss; try (BufferedReader reader = Files.newBufferedReader(tiny)) { @@ -100,19 +107,19 @@ public final class SrgMerger { List<TinyClass> classes = new ArrayList<>(); for (TopLevelClassMapping klass : arr.getTopLevelClassMappings()) { - classToTiny(foss, namespaces, klass, classes::add, lenient); + classToTiny(addRegardlessSrgs, foss, namespaces, klass, classes::add, lenient); } TinyFile file = new TinyFile(header, classes); TinyV2Writer.write(file, out); } - private static MappingSet readSrg(Path srg) throws IOException { + private static MappingSet readSrg(Path srg, Supplier<Path> mojmap, Map<String, List<MutableDescriptored>> addRegardlessSrgs) throws IOException { try (BufferedReader reader = Files.newBufferedReader(srg)) { String content = IOUtils.toString(reader); if (content.startsWith("tsrg2")) { - return readTsrg2(content); + return readTsrg2(content, mojmap, addRegardlessSrgs); } else { try (TSrgReader srgReader = new TSrgReader(new StringReader(content))) { return srgReader.read(); @@ -121,31 +128,45 @@ public final class SrgMerger { } } - private static MappingSet readTsrg2(String content) { - MappingSet set = MappingSet.create(); - MutableTinyTree tree = MappingsUtils.deserializeFromTsrg2(content); - int obfIndex = tree.getMetadata().index("obf"); - int srgIndex = tree.getMetadata().index("srg"); + private static MappingSet readTsrg2(String content, Supplier<Path> mojmap, Map<String, List<MutableDescriptored>> addRegardlessSrgs) throws IOException { + MappingSet set; - for (MutableClassDef classDef : tree.getClassesMutable()) { - ClassMapping<?, ?> classMapping = set.getOrCreateClassMapping(classDef.getName(obfIndex)); - classMapping.setDeobfuscatedName(classDef.getName(srgIndex)); + try (Tsrg2Utils.MappingsIO2LorenzWriter lorenzWriter = new Tsrg2Utils.MappingsIO2LorenzWriter(0, false)) { + TsrgReader.read(new StringReader(content), lorenzWriter); + set = lorenzWriter.read(); + MutableTinyTree mojmapTree = readTsrg2ToTinyTree(mojmap.get()); - for (MutableFieldDef fieldDef : classDef.getFieldsMutable()) { - FieldMapping fieldMapping = classMapping.getOrCreateFieldMapping(fieldDef.getName(obfIndex)); - fieldMapping.setDeobfuscatedName(fieldDef.getName(srgIndex)); - } + for (MutableClassDef classDef : mojmapTree.getClassesMutable()) { + for (MutableMethodDef methodDef : classDef.getMethodsMutable()) { + String name = methodDef.getName(0); + + if (name.indexOf('<') != 0 && name.equals(methodDef.getName(1))) { + addRegardlessSrgs.computeIfAbsent(classDef.getName(0), $ -> new ArrayList<>()).add(methodDef); + } + } - for (MutableMethodDef methodDef : classDef.getMethodsMutable()) { - MethodMapping methodMapping = classMapping.getOrCreateMethodMapping(methodDef.getName(obfIndex), methodDef.getDescriptor(obfIndex)); - methodMapping.setDeobfuscatedName(methodDef.getName(srgIndex)); + for (MutableFieldDef fieldDef : classDef.getFieldsMutable()) { + if (fieldDef.getName(0).equals(fieldDef.getName(1))) { + addRegardlessSrgs.computeIfAbsent(classDef.getName(0), $ -> new ArrayList<>()).add(fieldDef); + } + } } } return set; } - private static void classToTiny(TinyTree foss, List<String> namespaces, ClassMapping<?, ?> klass, Consumer<TinyClass> classConsumer, boolean lenient) { + private static MutableTinyTree readTsrg2ToTinyTree(Path path) throws IOException { + MutableTinyTree tree; + + try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + tree = MappingsUtils.deserializeFromTsrg2(IOUtils.toString(reader)); + } + + return tree; + } + + private static void classToTiny(Map<String, List<MutableDescriptored>> addRegardlessSrgs, TinyTree foss, List<String> namespaces, ClassMapping<?, ?> klass, Consumer<TinyClass> classConsumer, boolean lenient) { String obf = klass.getFullObfuscatedName(); String srg = klass.getFullDeobfuscatedName(); ClassDef classDef = foss.getDefaultNamespaceClassMap().get(obf); @@ -170,9 +191,17 @@ public final class SrgMerger { MethodDef def = CollectionUtil.find( classDef.getMethods(), m -> m.getName("official").equals(method.getObfuscatedName()) && m.getDescriptor("official").equals(method.getObfuscatedDescriptor()) - ).orElse(nullOrThrow(lenient, () -> new MappingException("Missing method: " + method.getFullObfuscatedName() + " (srg: " + method.getFullDeobfuscatedName() + ")"))); + ).orElse(null); - if (def == null) continue; + if (def == null) { + if (tryMatchRegardlessSrgs(addRegardlessSrgs, namespaces, obf, methods, method)) continue; + + if (!lenient) { + throw new MappingException("Missing method: " + method.getFullObfuscatedName() + " (srg: " + method.getFullDeobfuscatedName() + ")"); + } + + continue; + } List<String> methodNames = CollectionUtil.map( namespaces, @@ -207,8 +236,34 @@ public final class SrgMerger { classConsumer.accept(tinyClass); for (InnerClassMapping innerKlass : klass.getInnerClassMappings()) { - classToTiny(foss, namespaces, innerKlass, classConsumer, lenient); + classToTiny(addRegardlessSrgs, foss, namespaces, innerKlass, classConsumer, lenient); + } + } + + private static boolean tryMatchRegardlessSrgs(Map<String, List<MutableDescriptored>> addRegardlessSrgs, List<String> namespaces, String obf, + List<TinyMethod> methods, MethodMapping method) { + List<MutableDescriptored> mutableDescriptoredList = addRegardlessSrgs.get(obf); + + if (!method.getDeobfuscatedName().equals(method.getObfuscatedName())) { + for (MutableDescriptored descriptored : MoreObjects.firstNonNull(mutableDescriptoredList, Collections.<MutableDescriptored>emptyList())) { + if (descriptored.isMethod() && descriptored.getName(0).equals(method.getObfuscatedName()) && descriptored.getDescriptor(0).equals(method.getObfuscatedDescriptor())) { + List<String> methodNames = CollectionUtil.map( + namespaces, + namespace -> "srg".equals(namespace) ? method.getDeobfuscatedName() : method.getObfuscatedName() + ); + + methods.add(new TinyMethod( + method.getObfuscatedDescriptor(), methodNames, + /* parameters */ Collections.emptyList(), + /* locals */ Collections.emptyList(), + /* comments */ Collections.emptyList() + )); + return true; + } + } } + + return false; } @Nullable diff --git a/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java b/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java new file mode 100644 index 00000000..e6ddf578 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java @@ -0,0 +1,209 @@ +package net.fabricmc.loom.util.srg; + +import java.io.IOException; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import dev.architectury.mappingslayers.api.mutable.MutableClassDef; +import dev.architectury.mappingslayers.api.mutable.MutableFieldDef; +import dev.architectury.mappingslayers.api.mutable.MutableMethodDef; +import dev.architectury.mappingslayers.api.mutable.MutableParameterDef; +import dev.architectury.mappingslayers.api.mutable.MutableTinyMetadata; +import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; +import dev.architectury.mappingslayers.api.utils.MappingsUtils; +import org.cadixdev.lorenz.MappingSet; +import org.cadixdev.lorenz.io.srg.tsrg.TSrgWriter; +import org.cadixdev.lorenz.model.ClassMapping; +import org.cadixdev.lorenz.model.MethodMapping; + +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; +import net.fabricmc.mappingio.format.TsrgReader; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public class Tsrg2Utils { + public static void convert(Reader reader, Writer writer) throws IOException { + writeTsrg(visitor -> { + try { + TsrgReader.read(reader, visitor); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }, "srg", false, writer); + } + + public static void writeTsrg(Consumer<MappingVisitor> visitorConsumer, String dstNamespace, boolean applyParameterMappings, Writer writer) + throws IOException { + MappingSet set; + + try (MappingsIO2LorenzWriter lorenzWriter = new MappingsIO2LorenzWriter(dstNamespace, applyParameterMappings)) { + visitorConsumer.accept(lorenzWriter); + set = lorenzWriter.read(); + } + + try (TSrgWriter w = new TSrgWriter(writer)) { + w.write(set); + } + } + + public static void writeTsrg2(Consumer<MappingVisitor> visitorConsumer, Writer writer) + throws IOException { + MutableTinyTree tree; + + try (MappingsIO2MappingsUtils w = new MappingsIO2MappingsUtils()) { + visitorConsumer.accept(w); + tree = w.read(); + } + + writer.write(MappingsUtils.serializeToTsrg2(tree)); + } + + // TODO Move this elsewhere + public abstract static class MappingsIO2Others extends ForwardingMappingVisitor implements MappingWriter { + public MappingsIO2Others() { + super(new MemoryMappingTree()); + } + + public MappingTree tree() { + return (MappingTree) next; + } + + @Override + public void close() throws IOException { + MappingTree tree = tree(); + List<String> names = new ArrayList<>(); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + names.add(aClass.getSrcName()); + } + + for (String name : names) { + tree.removeClass(name); + } + } + } + + public static class MappingsIO2LorenzWriter extends MappingsIO2Others { + private final Object dstNamespaceUnresolved; + private int dstNamespace; + private boolean applyParameterMappings; + + public MappingsIO2LorenzWriter(int dstNamespace, boolean applyParameterMappings) { + this.dstNamespaceUnresolved = dstNamespace; + this.applyParameterMappings = applyParameterMappings; + } + + public MappingsIO2LorenzWriter(String dstNamespace, boolean applyParameterMappings) { + this.dstNamespaceUnresolved = dstNamespace; + this.applyParameterMappings = applyParameterMappings; + } + + @Override + public void visitNamespaces(String srcNamespace, List<String> dstNamespaces) throws IOException { + super.visitNamespaces(srcNamespace, dstNamespaces); + this.dstNamespace = dstNamespaceUnresolved instanceof Integer ? (Integer) dstNamespaceUnresolved : dstNamespaces.indexOf((String) dstNamespaceUnresolved); + } + + public MappingSet read() throws IOException { + return this.read(MappingSet.create()); + } + + public MappingSet read(final MappingSet mappings) throws IOException { + MappingTree tree = tree(); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + ClassMapping<?, ?> lClass = mappings.getOrCreateClassMapping(aClass.getSrcName()) + .setDeobfuscatedName(aClass.getDstName(dstNamespace)); + + for (MappingTree.FieldMapping aField : aClass.getFields()) { + String srcDesc = aField.getSrcDesc(); + + if (srcDesc == null || srcDesc.isEmpty()) { + lClass.getOrCreateFieldMapping(aField.getSrcName()) + .setDeobfuscatedName(aField.getDstName(dstNamespace)); + } else { + lClass.getOrCreateFieldMapping(aField.getSrcName(), srcDesc) + .setDeobfuscatedName(aField.getDstName(dstNamespace)); + } + } + + for (MappingTree.MethodMapping aMethod : aClass.getMethods()) { + MethodMapping lMethod = lClass.getOrCreateMethodMapping(aMethod.getSrcName(), aMethod.getSrcDesc()) + .setDeobfuscatedName(aMethod.getDstName(dstNamespace)); + + if (applyParameterMappings) { + for (MappingTree.MethodArgMapping aArg : aMethod.getArgs()) { + lMethod.getOrCreateParameterMapping(aArg.getLvIndex()) + .setDeobfuscatedName(aArg.getDstName(dstNamespace)); + } + } + } + } + + return mappings; + } + } + + public static class MappingsIO2MappingsUtils extends MappingsIO2Others { + public MutableTinyTree read() { + MappingTree tree = tree(); + int dstNamesSize = tree.getDstNamespaces().size(); + List<String> namespaces = new ArrayList<>(); + namespaces.add(tree.getSrcNamespace()); + namespaces.addAll(tree.getDstNamespaces()); + Map<String, String> properties = new HashMap<>(); + + for (Map.Entry<String, String> entry : tree.getMetadata()) { + properties.put(entry.getKey(), entry.getValue()); + } + + MutableTinyTree out = MappingsUtils.create(MutableTinyMetadata.create(2, 0, namespaces, properties)); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + MutableClassDef classDef = out.getOrCreateClass(aClass.getSrcName()); + classDef.setComment(aClass.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + classDef.setName(i + 1, aClass.getDstName(i)); + } + + for (MappingTree.MethodMapping aMethod : aClass.getMethods()) { + MutableMethodDef methodDef = classDef.getOrCreateMethod(aMethod.getSrcName(), aMethod.getSrcDesc()); + methodDef.setComment(aMethod.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + methodDef.setName(i + 1, aMethod.getDstName(i)); + } + + for (MappingTree.MethodArgMapping aMethodArg : aMethod.getArgs()) { + MutableParameterDef parameterDef = methodDef.getOrCreateParameter(aMethodArg.getLvIndex(), aMethodArg.getSrcName()); + parameterDef.setComment(aMethodArg.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + parameterDef.setName(i + 1, aMethodArg.getDstName(i)); + } + } + } + + for (MappingTree.FieldMapping aField : aClass.getFields()) { + MutableFieldDef fieldDef = classDef.getOrCreateField(aField.getSrcName(), aField.getSrcDesc()); + fieldDef.setComment(aField.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + fieldDef.setName(i + 1, aField.getDstName(i)); + } + } + } + + return out; + } + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy index 5c087a9d..64a37b5f 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy @@ -109,11 +109,6 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay } @Override - File workingDirectory() { - return tempDir - } - - @Override File workingDirectory(String name) { return new File(tempDir, name) } |