mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-03-30 13:05:27 -05:00
Merge remote-tracking branch 'upstream/dev/0.12' into dev/0.12.0
# Conflicts: # .github/workflows/test.yml # bootstrap/test-project/build.gradle # build.gradle # src/main/java/net/fabricmc/loom/LoomGradlePlugin.java # src/main/java/net/fabricmc/loom/LoomRepositoryPlugin.java # src/main/java/net/fabricmc/loom/api/MixinExtensionAPI.java # src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java # src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java # src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java # src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/assets/MinecraftAssetsProvider.java # src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java # src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java # src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java # src/main/java/net/fabricmc/loom/task/AbstractRunTask.java # src/main/java/net/fabricmc/loom/task/RemapJarTask.java # src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java # src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java # src/main/java/net/fabricmc/loom/util/Constants.java # src/main/java/net/fabricmc/loom/util/ModUtils.java # src/main/kotlin/net/fabricmc/loom/kotlin/remapping/KotlinMetadataTinyRemapperExtensionImpl.kt # src/test/kotlin/net/fabricmc/loom/test/kotlin/KotlinClassMetadataRemappingAnnotationVisitorTest.kt # src/test/resources/projects/kotlin/build.gradle.kts
This commit is contained in:
@@ -129,10 +129,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI {
|
||||
|
||||
boolean isRootProject();
|
||||
|
||||
default String getIntermediaryUrl(String minecraftVersion) {
|
||||
return String.format(this.getIntermediaryUrl().get(), minecraftVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
MixinExtension getMixin();
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import net.fabricmc.loom.decompilers.DecompilerConfiguration;
|
||||
import net.fabricmc.loom.extension.LoomFiles;
|
||||
import net.fabricmc.loom.extension.LoomGradleExtensionImpl;
|
||||
import net.fabricmc.loom.task.LoomTasks;
|
||||
import net.fabricmc.loom.util.LibraryLocationLogger;
|
||||
|
||||
public class LoomGradlePlugin implements BootstrappedPlugin {
|
||||
public static boolean refreshDeps;
|
||||
@@ -73,6 +74,8 @@ public class LoomGradlePlugin implements BootstrappedPlugin {
|
||||
project.getLogger().lifecycle("Architectury Loom: " + LOOM_VERSION);
|
||||
}
|
||||
|
||||
LibraryLocationLogger.logLibraryVersions();
|
||||
|
||||
refreshDeps = project.getGradle().getStartParameter().isRefreshDependencies() || Boolean.getBoolean("loom.refresh");
|
||||
|
||||
if (refreshDeps) {
|
||||
|
||||
@@ -26,7 +26,9 @@ package net.fabricmc.loom;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.ArtifactRepositoryContainer;
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler;
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository;
|
||||
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
|
||||
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
|
||||
import org.gradle.api.initialization.Settings;
|
||||
@@ -75,7 +77,8 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
|
||||
repo.setName("Fabric");
|
||||
repo.setUrl(MirrorUtil.getFabricRepository(target));
|
||||
});
|
||||
repositories.maven(repo -> {
|
||||
|
||||
MavenArtifactRepository mojangRepo = repositories.maven(repo -> {
|
||||
repo.setName("Mojang");
|
||||
repo.setUrl(MirrorUtil.getLibrariesBase(target));
|
||||
|
||||
@@ -100,6 +103,16 @@ public class LoomRepositoryPlugin implements Plugin<PluginAware> {
|
||||
sources.ignoreGradleMetadataRedirection();
|
||||
});
|
||||
});
|
||||
|
||||
// If a mavenCentral repo is already defined, remove the mojang repo and add it back before the mavenCentral repo so that it will be checked first.
|
||||
// See: https://github.com/FabricMC/fabric-loom/issues/621
|
||||
ArtifactRepository mavenCentral = repositories.findByName(ArtifactRepositoryContainer.DEFAULT_MAVEN_CENTRAL_REPO_NAME);
|
||||
|
||||
if (mavenCentral != null) {
|
||||
repositories.remove(mojangRepo);
|
||||
repositories.add(repositories.indexOf(mavenCentral), mojangRepo);
|
||||
}
|
||||
|
||||
repositories.mavenCentral();
|
||||
|
||||
repositories.ivy(repo -> {
|
||||
|
||||
@@ -39,11 +39,13 @@ import org.gradle.api.publish.maven.MavenPublication;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.util.DeprecationHelper;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
@@ -75,9 +77,7 @@ public interface LoomGradleExtensionAPI {
|
||||
|
||||
ConfigurableFileCollection getLog4jConfigs();
|
||||
|
||||
default Dependency officialMojangMappings() {
|
||||
return layered(LayeredMappingSpecBuilder::officialMojangMappings);
|
||||
}
|
||||
Dependency officialMojangMappings();
|
||||
|
||||
Dependency layered(Action<LayeredMappingSpecBuilder> action);
|
||||
|
||||
@@ -89,6 +89,16 @@ public interface LoomGradleExtensionAPI {
|
||||
|
||||
void mixin(Action<MixinExtensionAPI> action);
|
||||
|
||||
/**
|
||||
* Optionally register and configure a {@link ModSettings} object. The name should match the modid.
|
||||
* This is generally only required when the mod spans across multiple classpath directories, such as when using split sourcesets.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
void mods(Action<NamedDomainObjectContainer<ModSettings>> action);
|
||||
|
||||
@ApiStatus.Experimental
|
||||
NamedDomainObjectContainer<ModSettings> getMods();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
// TODO: move this from LoomGradleExtensionAPI to LoomGradleExtension once getRefmapName & setRefmapName is removed.
|
||||
MixinExtensionAPI getMixin();
|
||||
@@ -137,6 +147,30 @@ public interface LoomGradleExtensionAPI {
|
||||
*/
|
||||
Property<Boolean> getEnableTransitiveAccessWideners();
|
||||
|
||||
/**
|
||||
* When true loom will apply mod provided javadoc from dependencies.
|
||||
*
|
||||
* @return the property controlling the mod provided javadoc
|
||||
*/
|
||||
Property<Boolean> getEnableModProvidedJavadoc();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
IntermediateMappingsProvider getIntermediateMappingsProvider();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
void setIntermediateMappingsProvider(IntermediateMappingsProvider intermediateMappingsProvider);
|
||||
|
||||
@ApiStatus.Experimental
|
||||
<T extends IntermediateMappingsProvider> void setIntermediateMappingsProvider(Class<T> clazz, Action<T> action);
|
||||
|
||||
/**
|
||||
* An Experimental option to provide empty intermediate mappings, to be used for game versions without any intermediate mappings.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
default void noIntermediateMappings() {
|
||||
setIntermediateMappingsProvider(NoOpIntermediateMappingsProvider.class, p -> { });
|
||||
}
|
||||
|
||||
/**
|
||||
* Use "%1$s" as a placeholder for the minecraft version.
|
||||
*
|
||||
@@ -152,11 +186,22 @@ public interface LoomGradleExtensionAPI {
|
||||
getMinecraftJarConfiguration().set(MinecraftJarConfiguration.SERVER_ONLY);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
default void clientOnlyMinecraftJar() {
|
||||
getMinecraftJarConfiguration().set(MinecraftJarConfiguration.CLIENT_ONLY);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
default void splitMinecraftJar() {
|
||||
getMinecraftJarConfiguration().set(MinecraftJarConfiguration.SPLIT);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
void splitEnvironmentSourceSets();
|
||||
|
||||
@ApiStatus.Experimental
|
||||
boolean areEnvironmentSourceSetsSplit();
|
||||
|
||||
Property<Boolean> getRuntimeOnlyLog4j();
|
||||
|
||||
// ===================
|
||||
|
||||
@@ -36,6 +36,8 @@ public interface MixinExtensionAPI {
|
||||
|
||||
Property<String> getDefaultRefmapName();
|
||||
|
||||
Property<String> getRefmapTargetNamespace();
|
||||
|
||||
Property<String> getLegacyRemapToNamespace();
|
||||
|
||||
/**
|
||||
|
||||
62
src/main/java/net/fabricmc/loom/api/ModSettings.java
Normal file
62
src/main/java/net/fabricmc/loom/api/ModSettings.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.api;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Named;
|
||||
import org.gradle.api.file.ConfigurableFileCollection;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* A {@link Named} object for setting mod-related values. The {@linkplain Named#getName() name} should match the mod id.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public abstract class ModSettings implements Named {
|
||||
/**
|
||||
* List of classpath directories, used to populate the `fabric.classPathGroups` Fabric Loader system property.
|
||||
*/
|
||||
public abstract ListProperty<SourceSet> getModSourceSets();
|
||||
|
||||
/**
|
||||
* List of classpath directories, or jar files used to populate the `fabric.classPathGroups` Fabric Loader system property.
|
||||
*/
|
||||
public abstract ConfigurableFileCollection getModFiles();
|
||||
|
||||
@Inject
|
||||
public ModSettings() {
|
||||
getModSourceSets().finalizeValueOnRead();
|
||||
getModFiles().finalizeValueOnRead();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a {@link SourceSet} output directories part of the named mod.
|
||||
*/
|
||||
public void sourceSet(SourceSet sourceSet) {
|
||||
getModSourceSets().add(sourceSet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.api.mappings.intermediate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.Named;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* A simple API to allow 3rd party plugins.
|
||||
* Implement by creating an abstract class overriding provide and getName
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public abstract class IntermediateMappingsProvider implements Named {
|
||||
public abstract Property<String> getMinecraftVersion();
|
||||
|
||||
/**
|
||||
* Generate or download a tinyv2 mapping file with intermediary and named namespaces.
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract void provide(Path tinyMappings) throws IOException;
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.MixinMappingsService;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
@@ -90,7 +91,7 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, mappings.toFile().getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, MixinMappingsService.getMixinMappingFile(project, sourceSet).getCanonicalPath());
|
||||
put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName));
|
||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary");
|
||||
put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:" + loom.getMixin().getRefmapTargetNamespace().get());
|
||||
put(Constants.MixinArguments.QUIET, "true");
|
||||
}};
|
||||
|
||||
@@ -104,15 +105,16 @@ public abstract class AnnotationProcessorInvoker<T extends Task> {
|
||||
public void configureMixin() {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
ConfigurationContainer configs = project.getConfigurations();
|
||||
MinecraftSourceSets minecraftSourceSets = MinecraftSourceSets.get(project);
|
||||
|
||||
if (!IdeaUtils.isIdeaSync()) {
|
||||
for (Configuration processorConfig : apConfigurations) {
|
||||
project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName());
|
||||
// Pass named MC classpath to mixin AP classpath
|
||||
processorConfig.extendsFrom(
|
||||
configs.getByName(Constants.Configurations.MINECRAFT_NAMED),
|
||||
configs.getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED),
|
||||
configs.getByName(Constants.Configurations.MAPPINGS_FINAL)
|
||||
configs.getByName(minecraftSourceSets.getCombinedSourceSetName()),
|
||||
configs.getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED),
|
||||
configs.getByName(Constants.Configurations.MAPPINGS_FINAL)
|
||||
);
|
||||
|
||||
if (extension.isForge()) {
|
||||
|
||||
@@ -27,6 +27,7 @@ package net.fabricmc.loom.configuration;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gradle.api.NamedDomainObjectProvider;
|
||||
@@ -48,6 +49,7 @@ import net.fabricmc.loom.configuration.accesstransformer.AccessTransformerJarPro
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor;
|
||||
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.mods.ModJavadocProcessor;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.forge.DependencyProviders;
|
||||
import net.fabricmc.loom.configuration.providers.forge.ForgeProvider;
|
||||
@@ -60,6 +62,7 @@ import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.SrgMinecraftProvider;
|
||||
@@ -89,7 +92,6 @@ public final class CompileConfiguration {
|
||||
|
||||
extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH, configuration -> configuration.setTransitive(true));
|
||||
extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED, configuration -> configuration.setTransitive(false));
|
||||
extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NAMED, configuration -> configuration.setTransitive(false)); // The launchers do not recurse dependencies
|
||||
NamedDomainObjectProvider<Configuration> serverDeps = extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, configuration -> configuration.setTransitive(false));
|
||||
extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_RUNTIME_DEPENDENCIES, configuration -> configuration.setTransitive(false));
|
||||
extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_DEPENDENCIES, configuration -> {
|
||||
@@ -177,13 +179,7 @@ public final class CompileConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
extendsFrom(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_NAMED, project);
|
||||
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_NAMED, project);
|
||||
extendsFrom(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_NAMED, project);
|
||||
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MINECRAFT_NAMED, project);
|
||||
|
||||
extendsFrom(Constants.Configurations.LOADER_DEPENDENCIES, Constants.Configurations.MINECRAFT_DEPENDENCIES, project);
|
||||
extendsFrom(Constants.Configurations.MINECRAFT_NAMED, Constants.Configurations.LOADER_DEPENDENCIES, project);
|
||||
|
||||
extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL, project);
|
||||
extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.MAPPINGS_FINAL, project);
|
||||
@@ -215,6 +211,8 @@ public final class CompileConfiguration {
|
||||
});
|
||||
|
||||
p.afterEvaluate(project -> {
|
||||
MinecraftSourceSets.get(project).afterEvaluate(project);
|
||||
|
||||
try {
|
||||
setupMinecraft(project);
|
||||
} catch (Exception e) {
|
||||
@@ -339,6 +337,15 @@ public final class CompileConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.getEnableModProvidedJavadoc().get()) {
|
||||
// This doesn't do any processing on the compiled jar, but it does have an effect on the generated sources.
|
||||
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(project);
|
||||
|
||||
if (javadocProcessor != null) {
|
||||
extension.getGameJarProcessors().add(javadocProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.isForge()) {
|
||||
Set<File> atFiles = AccessTransformerJarProcessor.getAccessTransformerFiles(project);
|
||||
|
||||
@@ -389,7 +396,13 @@ public final class CompileConfiguration {
|
||||
.apply(project, extension.getNamedMinecraftProvider()).afterEvaluation();
|
||||
}
|
||||
|
||||
private static void extendsFrom(String a, String b, Project project) {
|
||||
public static void extendsFrom(List<String> parents, String b, Project project) {
|
||||
for (String parent : parents) {
|
||||
extendsFrom(parent, b, project);
|
||||
}
|
||||
}
|
||||
|
||||
public static void extendsFrom(String a, String b, Project project) {
|
||||
project.getConfigurations().getByName(a, configuration -> configuration.extendsFrom(project.getConfigurations().getByName(b)));
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.w3c.dom.Node;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
@@ -115,16 +116,6 @@ public class RunConfig {
|
||||
return e;
|
||||
}
|
||||
|
||||
private static String getIdeaModuleName(Project project, SourceSet srcs) {
|
||||
String module = project.getName() + "." + srcs.getName();
|
||||
|
||||
while ((project = project.getParent()) != null) {
|
||||
module = project.getName() + "." + module;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
private static void populate(Project project, LoomGradleExtension extension, RunConfig runConfig, String environment) {
|
||||
runConfig.configName += extension.isRootProject() ? "" : " (" + project.getPath() + ")";
|
||||
runConfig.eclipseProjectName = project.getExtensions().getByType(EclipseModel.class).getProject().getName();
|
||||
@@ -183,7 +174,7 @@ public class RunConfig {
|
||||
runConfig.envVariables.putAll(settings.envVariables);
|
||||
runConfig.configName = configName;
|
||||
populate(project, extension, runConfig, environment);
|
||||
runConfig.ideaModuleName = getIdeaModuleName(project, sourceSet);
|
||||
runConfig.ideaModuleName = IdeaUtils.getIdeaModuleName(project, sourceSet);
|
||||
runConfig.runDirIdeaUrl = "file://$PROJECT_DIR$/" + runDir;
|
||||
runConfig.runDir = runDir;
|
||||
runConfig.sourceSet = sourceSet;
|
||||
|
||||
@@ -26,6 +26,9 @@ package net.fabricmc.loom.configuration.ide.idea;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
public class IdeaUtils {
|
||||
public static boolean isIdeaSync() {
|
||||
return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"));
|
||||
@@ -42,4 +45,14 @@ public class IdeaUtils {
|
||||
final int minor = Integer.parseInt(split[1]);
|
||||
return major > 2021 || (major == 2021 && minor >= 3);
|
||||
}
|
||||
|
||||
public static String getIdeaModuleName(Project project, SourceSet srcs) {
|
||||
String module = project.getName() + "." + srcs.getName();
|
||||
|
||||
while ((project = project.getParent()) != null) {
|
||||
module = project.getName() + "." + module;
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Checksum;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
@@ -314,18 +315,12 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
|
||||
private record InjectedInterface(String modId, String className, String ifaceName) {
|
||||
/**
|
||||
* Reads the injected interfaces contained in a mod jar, or returns null if there is none.
|
||||
* Reads the injected interfaces contained in a mod jar, or returns empty if there is none.
|
||||
*/
|
||||
public static List<InjectedInterface> fromModJar(Path modJarPath) {
|
||||
final byte[] modJsonBytes;
|
||||
final JsonObject jsonObject = ModUtils.getFabricModJson(modJarPath);
|
||||
|
||||
try {
|
||||
modJsonBytes = ZipUtils.unpackNullable(modJarPath, "fabric.mod.json");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to extract fabric.mod.json from " + modJarPath);
|
||||
}
|
||||
|
||||
if (modJsonBytes == null) {
|
||||
if (jsonObject == null) {
|
||||
byte[] commonJsonBytes;
|
||||
|
||||
try {
|
||||
@@ -353,12 +348,9 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final JsonObject jsonObject = LoomGradlePlugin.GSON.fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class);
|
||||
|
||||
return fromJson(jsonObject, modJarPath.toString());
|
||||
}
|
||||
|
||||
@@ -375,11 +367,11 @@ public class InterfaceInjectionProcessor implements JarProcessor, GenerateSource
|
||||
|
||||
final JsonObject custom = jsonObject.getAsJsonObject("custom");
|
||||
|
||||
if (!custom.has("loom:injected_interfaces")) {
|
||||
if (!custom.has(Constants.CustomModJsonKeys.INJECTED_INTERFACE)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final JsonObject addedIfaces = custom.getAsJsonObject("loom:injected_interfaces");
|
||||
final JsonObject addedIfaces = custom.getAsJsonObject(Constants.CustomModJsonKeys.INJECTED_INTERFACE);
|
||||
|
||||
final List<InjectedInterface> result = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.configuration.mods;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessor;
|
||||
import net.fabricmc.loom.task.GenerateSourcesTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.ModUtils;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.mappingio.MappingReader;
|
||||
import net.fabricmc.mappingio.tree.MappingTree;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class ModJavadocProcessor implements JarProcessor, GenerateSourcesTask.MappingsProcessor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ModJavadocProcessor.class);
|
||||
|
||||
private final List<ModJavadoc> javadocs;
|
||||
|
||||
private ModJavadocProcessor(List<ModJavadoc> javadocs) {
|
||||
this.javadocs = javadocs;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ModJavadocProcessor create(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final List<ModJavadoc> javadocs = new ArrayList<>();
|
||||
|
||||
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
|
||||
Set<File> artifacts = extension.getLazyConfigurationProvider(entry.sourceConfiguration())
|
||||
.get()
|
||||
.resolve();
|
||||
|
||||
for (File artifact : artifacts) {
|
||||
if (!ModUtils.isMod(artifact.toPath())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ModJavadoc modJavadoc;
|
||||
|
||||
try {
|
||||
modJavadoc = ModJavadoc.fromModJar(artifact.toPath());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to read mod jar (%s)".formatted(artifact), e);
|
||||
}
|
||||
|
||||
if (modJavadoc != null) {
|
||||
javadocs.add(modJavadoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (javadocs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModJavadocProcessor(javadocs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(MemoryMappingTree mappings) {
|
||||
for (ModJavadoc javadoc : javadocs) {
|
||||
javadoc.apply(mappings);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "loom:interface_injection:" + javadocs.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(File file) {
|
||||
// No need to actually process anything, we need to be a JarProcessor to ensure that the jar is cached correctly.
|
||||
}
|
||||
|
||||
public record ModJavadoc(String modId, MemoryMappingTree mappingTree) {
|
||||
@Nullable
|
||||
public static ModJavadoc fromModJar(Path path) throws IOException {
|
||||
JsonObject jsonObject = ModUtils.getFabricModJson(path);
|
||||
|
||||
if (jsonObject == null || !jsonObject.has("custom")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String modId = jsonObject.get("id").getAsString();
|
||||
final JsonObject custom = jsonObject.getAsJsonObject("custom");
|
||||
|
||||
if (!custom.has(Constants.CustomModJsonKeys.PROVIDED_JAVADOC)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String javaDocPath = custom.getAsJsonPrimitive(Constants.CustomModJsonKeys.PROVIDED_JAVADOC).getAsString();
|
||||
final byte[] data = ZipUtils.unpack(path, javaDocPath);
|
||||
final MemoryMappingTree mappings = new MemoryMappingTree();
|
||||
|
||||
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(data))) {
|
||||
MappingReader.read(reader, mappings);
|
||||
}
|
||||
|
||||
if (!mappings.getSrcNamespace().equals(MappingsNamespace.INTERMEDIARY.toString())) {
|
||||
throw new IllegalStateException("Javadoc provided by mod (%s) must be have an intermediary source namespace".formatted(modId));
|
||||
}
|
||||
|
||||
if (!mappings.getDstNamespaces().isEmpty()) {
|
||||
throw new IllegalStateException("Javadoc provided by mod (%s) must not contain any dst names".formatted(modId));
|
||||
}
|
||||
|
||||
return new ModJavadoc(modId, mappings);
|
||||
}
|
||||
|
||||
public void apply(MemoryMappingTree target) {
|
||||
if (!mappingTree.getSrcNamespace().equals(target.getSrcNamespace())) {
|
||||
throw new IllegalStateException("Cannot apply mappings to differing namespaces. source: %s target: %s".formatted(mappingTree.getSrcNamespace(), target.getSrcNamespace()));
|
||||
}
|
||||
|
||||
for (MappingTree.ClassMapping sourceClass : mappingTree.getClasses()) {
|
||||
final MappingTree.ClassMapping targetClass = target.getClass(sourceClass.getSrcName());
|
||||
|
||||
if (targetClass == null) {
|
||||
LOGGER.warn("Could not find provided javadoc target class {} from mod {}", sourceClass.getSrcName(), modId);
|
||||
continue;
|
||||
}
|
||||
|
||||
applyComment(sourceClass, targetClass);
|
||||
|
||||
for (MappingTree.FieldMapping sourceField : sourceClass.getFields()) {
|
||||
final MappingTree.FieldMapping targetField = targetClass.getField(sourceField.getSrcName(), sourceField.getSrcDesc());
|
||||
|
||||
if (targetField == null) {
|
||||
LOGGER.warn("Could not find provided javadoc target field {}{} from mod {}", sourceField.getSrcName(), sourceField.getSrcDesc(), modId);
|
||||
continue;
|
||||
}
|
||||
|
||||
applyComment(sourceField, targetField);
|
||||
}
|
||||
|
||||
for (MappingTree.MethodMapping sourceMethod : sourceClass.getMethods()) {
|
||||
final MappingTree.MethodMapping targetMethod = targetClass.getMethod(sourceMethod.getSrcName(), sourceMethod.getSrcDesc());
|
||||
|
||||
if (targetMethod == null) {
|
||||
LOGGER.warn("Could not find provided javadoc target method {}{} from mod {}", sourceMethod.getSrcName(), sourceMethod.getSrcDesc(), modId);
|
||||
continue;
|
||||
}
|
||||
|
||||
applyComment(sourceMethod, targetMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends MappingTree.ElementMapping> void applyComment(T source, T target) {
|
||||
String sourceComment = source.getComment();
|
||||
|
||||
if (sourceComment == null) {
|
||||
LOGGER.warn("Mod {} provided javadoc has mapping for {}, without comment", modId, source);
|
||||
return;
|
||||
}
|
||||
|
||||
String targetComment = target.getComment();
|
||||
|
||||
if (targetComment == null) {
|
||||
targetComment = "";
|
||||
} else {
|
||||
targetComment += "\n";
|
||||
}
|
||||
|
||||
targetComment += sourceComment;
|
||||
target.setComment(targetComment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.mods;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -33,6 +35,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -51,11 +54,13 @@ import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.RemappedConfigurationEntry;
|
||||
import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
|
||||
import net.fabricmc.loom.task.RemapJarTask;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.LoggerFilter;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
|
||||
import net.fabricmc.loom.util.srg.AtRemapper;
|
||||
import net.fabricmc.loom.util.srg.CoreModClassRemapper;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
@@ -159,10 +164,8 @@ public class ModProcessor {
|
||||
private void remapJars(List<ModDependencyInfo> remapList) throws IOException {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
|
||||
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
|
||||
String fromM = extension.isForge() ? MappingsNamespace.SRG.toString() : MappingsNamespace.INTERMEDIARY.toString();
|
||||
String toM = MappingsNamespace.NAMED.toString();
|
||||
|
||||
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()
|
||||
.stream().map(File::toPath).toArray(Path[]::new);
|
||||
|
||||
@@ -177,8 +180,12 @@ public class ModProcessor {
|
||||
.withMappings(TinyRemapperHelper.create(mappings, fromM, toM, false))
|
||||
.renameInvalidLocals(false);
|
||||
|
||||
if (useKotlinExtension) {
|
||||
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
|
||||
final KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
|
||||
KotlinRemapperClassloader kotlinRemapperClassloader = null;
|
||||
|
||||
if (kotlinClasspathService != null) {
|
||||
kotlinRemapperClassloader = KotlinRemapperClassloader.create(kotlinClasspathService);
|
||||
builder.extension(kotlinRemapperClassloader.getTinyRemapperExtension());
|
||||
}
|
||||
|
||||
final TinyRemapper remapper = builder.build();
|
||||
@@ -236,6 +243,10 @@ public class ModProcessor {
|
||||
}
|
||||
} finally {
|
||||
remapper.finish();
|
||||
|
||||
if (kotlinRemapperClassloader != null) {
|
||||
kotlinRemapperClassloader.close();
|
||||
}
|
||||
}
|
||||
|
||||
project.getLogger().lifecycle(":remapped " + remapList.size() + " mods (TinyRemapper, " + fromM + " -> " + toM + ") in " + stopwatch.stop());
|
||||
@@ -250,6 +261,7 @@ public class ModProcessor {
|
||||
}
|
||||
|
||||
stripNestedJars(info.getRemappedOutput());
|
||||
remapJarManifestEntries(info.getRemappedOutput().toPath());
|
||||
|
||||
if (extension.isForge()) {
|
||||
AtRemapper.remap(project.getLogger(), info.getRemappedOutput().toPath(), mappings);
|
||||
@@ -259,4 +271,16 @@ public class ModProcessor {
|
||||
info.finaliseRemapping();
|
||||
}
|
||||
}
|
||||
|
||||
private void remapJarManifestEntries(Path jar) throws IOException {
|
||||
ZipUtils.transform(jar, Map.of(RemapJarTask.MANIFEST_PATH, bytes -> {
|
||||
var manifest = new Manifest(new ByteArrayInputStream(bytes));
|
||||
|
||||
manifest.getMainAttributes().putValue(RemapJarTask.MANIFEST_NAMESPACE_KEY, toM);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
manifest.write(out);
|
||||
return out.toByteArray();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class GradleMappingContext implements MappingContext {
|
||||
|
||||
@Override
|
||||
public Supplier<MemoryMappingTree> intermediaryTree() {
|
||||
return () -> IntermediaryService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
|
||||
return () -> IntermediateMappingsService.getInstance(project, minecraftProvider()).getMemoryMappingTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,4 +82,12 @@ public class GradleMappingContext implements MappingContext {
|
||||
public Logger getLogger() {
|
||||
return project.getLogger();
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public LoomGradleExtension getExtension() {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.configuration.providers.mappings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.util.DownloadUtil;
|
||||
|
||||
public abstract class IntermediaryMappingsProvider extends IntermediateMappingsProvider {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IntermediateMappingsProvider.class);
|
||||
|
||||
public abstract Property<String> getIntermediaryUrl();
|
||||
|
||||
@Override
|
||||
public void provide(Path tinyMappings) throws IOException {
|
||||
if (Files.exists(tinyMappings) && !LoomGradlePlugin.refreshDeps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Download and extract intermediary
|
||||
final Path intermediaryJarPath = Files.createTempFile(getName(), ".jar");
|
||||
final String encodedMcVersion = UrlEscapers.urlFragmentEscaper().escape(getMinecraftVersion().get());
|
||||
final URL url = new URL(getIntermediaryUrl().get().formatted(encodedMcVersion));
|
||||
|
||||
LOGGER.info("Downloading intermediary from {}", url);
|
||||
|
||||
Files.deleteIfExists(tinyMappings);
|
||||
Files.deleteIfExists(intermediaryJarPath);
|
||||
|
||||
DownloadUtil.downloadIfChanged(url, intermediaryJarPath.toFile(), LOGGER);
|
||||
MappingsProviderImpl.extractMappings(intermediaryJarPath, tinyMappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return "intermediary-v2";
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,8 @@
|
||||
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.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -37,59 +35,52 @@ import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.net.UrlEscapers;
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.util.DownloadUtil;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
|
||||
public final class IntermediaryService implements SharedService {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IntermediaryService.class);
|
||||
|
||||
public final class IntermediateMappingsService implements SharedService {
|
||||
private final Path intermediaryTiny;
|
||||
private final Supplier<MemoryMappingTree> memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree);
|
||||
|
||||
private IntermediaryService(Path intermediaryTiny) {
|
||||
private IntermediateMappingsService(Path intermediaryTiny) {
|
||||
this.intermediaryTiny = intermediaryTiny;
|
||||
}
|
||||
|
||||
public static synchronized IntermediaryService getInstance(Project project, MinecraftProvider minecraftProvider) {
|
||||
public static synchronized IntermediateMappingsService getInstance(Project project, MinecraftProvider minecraftProvider) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftProvider.minecraftVersion());
|
||||
final String intermediaryArtifactUrl = extension.getIntermediaryUrl(encodedMinecraftVersion);
|
||||
final IntermediateMappingsProvider intermediateProvider = extension.getIntermediateMappingsProvider();
|
||||
final String id = "IntermediateMappingsService:%s:%s".formatted(intermediateProvider.getName(), intermediateProvider.getMinecraftVersion().get());
|
||||
|
||||
return SharedServiceManager.get(project).getOrCreateService("IntermediaryService:" + intermediaryArtifactUrl,
|
||||
() -> create(intermediaryArtifactUrl, minecraftProvider));
|
||||
return SharedServiceManager.get(project).getOrCreateService(id, () -> create(intermediateProvider, minecraftProvider));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static IntermediaryService create(String intermediaryUrl, MinecraftProvider minecraftProvider) {
|
||||
final Path intermediaryTiny = minecraftProvider.file("intermediary-v2.tiny").toPath();
|
||||
|
||||
if (!Files.exists(intermediaryTiny) || LoomGradlePlugin.refreshDeps) {
|
||||
// Download and extract intermediary
|
||||
File intermediaryJar = minecraftProvider.file("intermediary-v2.jar");
|
||||
public static IntermediateMappingsService create(IntermediateMappingsProvider intermediateMappingsProvider, MinecraftProvider minecraftProvider) {
|
||||
final Path intermediaryTiny = minecraftProvider.file(intermediateMappingsProvider.getName() + ".tiny").toPath();
|
||||
|
||||
try {
|
||||
intermediateMappingsProvider.provide(intermediaryTiny);
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
DownloadUtil.downloadIfChanged(new URL(intermediaryUrl), intermediaryJar, LOGGER);
|
||||
MappingsProviderImpl.extractMappings(intermediaryJar.toPath(), intermediaryTiny);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to download and extract intermediary", e);
|
||||
Files.deleteIfExists(intermediaryTiny);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
throw new UncheckedIOException("Failed to provide intermediate mappings", e);
|
||||
}
|
||||
|
||||
return new IntermediaryService(intermediaryTiny);
|
||||
return new IntermediateMappingsService(intermediaryTiny);
|
||||
}
|
||||
|
||||
private MemoryMappingTree createMemoryMappingTree() {
|
||||
@@ -102,9 +102,9 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
private UnpickMetadata unpickMetadata;
|
||||
private Map<String, String> signatureFixes;
|
||||
|
||||
private final Supplier<IntermediaryService> intermediaryService;
|
||||
private final Supplier<IntermediateMappingsService> intermediaryService;
|
||||
|
||||
protected MappingsProviderImpl(String mappingsIdentifier, Path mappingsWorkingDir, Supplier<IntermediaryService> intermediaryService) {
|
||||
protected MappingsProviderImpl(String mappingsIdentifier, Path mappingsWorkingDir, Supplier<IntermediateMappingsService> intermediaryService) {
|
||||
this.mappingsIdentifier = mappingsIdentifier;
|
||||
|
||||
this.mappingsWorkingDir = mappingsWorkingDir;
|
||||
@@ -121,7 +121,7 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
|
||||
public static synchronized MappingsProviderImpl getInstance(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider) {
|
||||
return SharedServiceManager.get(project).getOrCreateService("MappingsProvider:%s:%s".formatted(dependency.getDepString(), minecraftProvider.minecraftVersion()), () -> {
|
||||
Supplier<IntermediaryService> intermediaryService = Suppliers.memoize(() -> IntermediaryService.getInstance(project, minecraftProvider));
|
||||
Supplier<IntermediateMappingsService> intermediaryService = Suppliers.memoize(() -> IntermediateMappingsService.getInstance(project, minecraftProvider));
|
||||
return create(project, dependency, minecraftProvider, intermediaryService);
|
||||
});
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class MappingsProviderImpl implements MappingsProvider, SharedService {
|
||||
return Objects.requireNonNull(mappingTreeWithSrg, "Cannot get mappings before they have been read").get();
|
||||
}
|
||||
|
||||
private static MappingsProviderImpl create(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider, Supplier<IntermediaryService> intermediaryService) {
|
||||
private static MappingsProviderImpl create(Project project, DependencyInfo dependency, MinecraftProvider minecraftProvider, Supplier<IntermediateMappingsService> intermediaryService) {
|
||||
final String version = dependency.getResolvedVersion();
|
||||
final Path inputJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not resolve mappings: " + dependency)).toPath();
|
||||
final String mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged");
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.configuration.providers.mappings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
|
||||
/**
|
||||
* A bit of a hack, creates an empty intermediary mapping file to be used for mc versions without any intermediate mappings.
|
||||
*/
|
||||
public abstract class NoOpIntermediateMappingsProvider extends IntermediateMappingsProvider {
|
||||
private static final String HEADER = "tiny\t2\t0\tofficial\tintermediary";
|
||||
|
||||
@Override
|
||||
public void provide(Path tinyMappings) throws IOException {
|
||||
Files.writeString(tinyMappings, HEADER, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return "empty-intermediate";
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryService;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService;
|
||||
import net.fabricmc.mappingio.adapter.MappingNsCompleter;
|
||||
import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch;
|
||||
import net.fabricmc.mappingio.format.Tiny2Reader;
|
||||
@@ -49,12 +49,12 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree;
|
||||
public final class MappingsMerger {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MappingsMerger.class);
|
||||
|
||||
public static void mergeAndSaveMappings(Path from, Path out, IntermediaryService intermediaryService) throws IOException {
|
||||
public static void mergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
LOGGER.info(":merging mappings");
|
||||
|
||||
MemoryMappingTree intermediaryTree = new MemoryMappingTree();
|
||||
intermediaryService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||
intermediateMappingsService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString()));
|
||||
|
||||
try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) {
|
||||
Tiny2Reader.read(reader, intermediaryTree);
|
||||
|
||||
@@ -37,7 +37,7 @@ import net.fabricmc.loom.util.Architecture;
|
||||
import net.fabricmc.loom.util.OperatingSystem;
|
||||
|
||||
public class LWJGLVersionOverride {
|
||||
public static final String LWJGL_VERSION = "3.3.0";
|
||||
public static final String LWJGL_VERSION = "3.3.1";
|
||||
@Nullable
|
||||
public static final String NATIVE_CLASSIFIER = getNativesClassifier();
|
||||
|
||||
@@ -66,9 +66,15 @@ public class LWJGLVersionOverride {
|
||||
return false;
|
||||
}
|
||||
|
||||
return versionMeta.libraries().stream()
|
||||
.map(MinecraftVersionMeta.Library::name)
|
||||
.anyMatch(s -> s.startsWith("org.lwjgl:lwjgl:3"));
|
||||
boolean supportedLwjglVersion = versionMeta.libraries().stream()
|
||||
.anyMatch(library -> library.name().startsWith("org.lwjgl:lwjgl:3"));
|
||||
|
||||
boolean hasExistingNatives = versionMeta.libraries().stream()
|
||||
.filter(library -> library.name().startsWith("org.lwjgl:lwjgl"))
|
||||
.anyMatch(MinecraftVersionMeta.Library::hasNativesForOS);
|
||||
|
||||
// Is LWJGL 3, and doesn't have any existing compatible LWGL natives.
|
||||
return supportedLwjglVersion && !hasExistingNatives;
|
||||
}
|
||||
|
||||
public static boolean forceOverride(Project project) {
|
||||
|
||||
@@ -58,6 +58,10 @@ public class MergedMinecraftProvider extends MinecraftProvider {
|
||||
public void provide() throws Exception {
|
||||
super.provide();
|
||||
|
||||
if (!getVersionInfo().isVersionOrNewer("2012-07-25T22:00:00+00:00" /* 1.3 release date */)) {
|
||||
throw new UnsupportedOperationException("Minecraft versions 1.2.5 and older cannot be merged. Please use `loom { server/clientOnlyMinecraftJar() }`");
|
||||
}
|
||||
|
||||
if (!Files.exists(minecraftMergedJar) || isRefreshDeps()) {
|
||||
try {
|
||||
mergeJars();
|
||||
|
||||
@@ -52,14 +52,22 @@ public enum MinecraftJarConfiguration {
|
||||
List.of("client", "server")
|
||||
),
|
||||
SERVER_ONLY(
|
||||
ServerOnlyMinecraftProvider::new,
|
||||
IntermediaryMinecraftProvider.ServerOnlyImpl::new,
|
||||
NamedMinecraftProvider.ServerOnlyImpl::new,
|
||||
SingleJarMinecraftProvider::server,
|
||||
IntermediaryMinecraftProvider.SingleJarImpl::server,
|
||||
NamedMinecraftProvider.SingleJarImpl::server,
|
||||
SrgMinecraftProvider.ServerOnlyImpl::new,
|
||||
ProcessedNamedMinecraftProvider.ServerOnlyImpl::new,
|
||||
ProcessedNamedMinecraftProvider.SingleJarImpl::server,
|
||||
SingleJarDecompileConfiguration::new,
|
||||
List.of("server")
|
||||
),
|
||||
CLIENT_ONLY(
|
||||
SingleJarMinecraftProvider::client,
|
||||
IntermediaryMinecraftProvider.SingleJarImpl::client,
|
||||
NamedMinecraftProvider.SingleJarImpl::client,
|
||||
ProcessedNamedMinecraftProvider.SingleJarImpl::client,
|
||||
SingleJarDecompileConfiguration::new,
|
||||
List.of("client")
|
||||
),
|
||||
SPLIT(
|
||||
SplitMinecraftProvider::new,
|
||||
IntermediaryMinecraftProvider.SplitImpl::new,
|
||||
|
||||
@@ -60,8 +60,11 @@ public class MinecraftLibraryProvider {
|
||||
|
||||
if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) {
|
||||
// 1.4.7 contains an LWJGL version with an invalid maven pom, set the metadata sources to not use the pom for this version.
|
||||
if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(library.name())) {
|
||||
if ("org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20130708-debug3".equals(library.name()) || "org.lwjgl.lwjgl:lwjgl:2.9.1-nightly-20131017".equals(library.name())) {
|
||||
LoomRepositoryPlugin.setupForLegacyVersions(project);
|
||||
} else if (library.name().startsWith("org.ow2.asm:asm-all")) {
|
||||
// Don't want asm-all, use the modern split version.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (runtimeOnlyLog4j && library.name().startsWith("org.apache.logging.log4j")) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.Files;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
@@ -75,6 +76,14 @@ public abstract class MinecraftProvider {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
protected boolean provideClient() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean provideServer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void provide() throws Exception {
|
||||
final DependencyInfo dependency = DependencyInfo.create(getProject(), Constants.Configurations.MINECRAFT);
|
||||
minecraftVersion = dependency.getDependency().getVersion();
|
||||
@@ -94,7 +103,17 @@ public abstract class MinecraftProvider {
|
||||
}
|
||||
|
||||
if (offline) {
|
||||
if (minecraftClientJar.exists() && minecraftServerJar.exists()) {
|
||||
boolean exists = true;
|
||||
|
||||
if (provideServer() && !minecraftServerJar.exists()) {
|
||||
exists = false;
|
||||
}
|
||||
|
||||
if (provideClient() && !minecraftClientJar.exists()) {
|
||||
exists = false;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
getProject().getLogger().debug("Found client and server jars, presuming up-to-date");
|
||||
} else {
|
||||
throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists());
|
||||
@@ -103,7 +122,9 @@ public abstract class MinecraftProvider {
|
||||
downloadJars(getProject().getLogger());
|
||||
}
|
||||
|
||||
serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath());
|
||||
if (provideServer()) {
|
||||
serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath());
|
||||
}
|
||||
|
||||
libraryProvider = new MinecraftLibraryProvider();
|
||||
libraryProvider.provide(this, getProject());
|
||||
@@ -119,11 +140,17 @@ public abstract class MinecraftProvider {
|
||||
workingDir = new File(getExtension().getFiles().getUserCache(), minecraftVersion);
|
||||
workingDir.mkdirs();
|
||||
minecraftJson = file("minecraft-info.json");
|
||||
minecraftClientJar = file("minecraft-client.jar");
|
||||
minecraftServerJar = file("minecraft-server.jar");
|
||||
minecraftExtractedServerJar = file("minecraft-extracted_server.jar");
|
||||
versionManifestJson = new File(getExtension().getFiles().getUserCache(), "version_manifest.json");
|
||||
experimentalVersionsJson = new File(getExtension().getFiles().getUserCache(), "experimental_version_manifest.json");
|
||||
|
||||
if (provideClient()) {
|
||||
minecraftClientJar = file("minecraft-client.jar");
|
||||
}
|
||||
|
||||
if (provideServer()) {
|
||||
minecraftServerJar = file("minecraft-server.jar");
|
||||
minecraftExtractedServerJar = file("minecraft-extracted_server.jar");
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadMcJson(boolean offline) throws IOException {
|
||||
@@ -243,14 +270,19 @@ public abstract class MinecraftProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftVersionMeta.Download client = versionInfo.download("client");
|
||||
MinecraftVersionMeta.Download server = versionInfo.download("server");
|
||||
if (provideClient()) {
|
||||
MinecraftVersionMeta.Download client = versionInfo.download("client");
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(client.url()), minecraftClientJar, client.sha1(), logger, false);
|
||||
}
|
||||
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(client.url()), minecraftClientJar, client.sha1(), logger, false);
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false);
|
||||
if (provideServer()) {
|
||||
MinecraftVersionMeta.Download server = versionInfo.download("server");
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void extractBundledServerJar() throws IOException {
|
||||
Preconditions.checkArgument(provideServer(), "Not configured to provide server jar");
|
||||
Objects.requireNonNull(getServerBundleMetadata(), "Cannot bundled mc jar from none bundled server jar");
|
||||
|
||||
getLogger().info(":Extracting server jar from bootstrap");
|
||||
@@ -281,17 +313,20 @@ public abstract class MinecraftProvider {
|
||||
}
|
||||
|
||||
public File getMinecraftClientJar() {
|
||||
Preconditions.checkArgument(provideClient(), "Not configured to provide client jar");
|
||||
return minecraftClientJar;
|
||||
}
|
||||
|
||||
// May be null on older versions
|
||||
@Nullable
|
||||
public File getMinecraftExtractedServerJar() {
|
||||
Preconditions.checkArgument(provideServer(), "Not configured to provide server jar");
|
||||
return minecraftExtractedServerJar;
|
||||
}
|
||||
|
||||
// This may be the server bundler jar on newer versions prob not what you want.
|
||||
public File getMinecraftServerJar() {
|
||||
Preconditions.checkArgument(provideServer(), "Not configured to provide server jar");
|
||||
return minecraftServerJar;
|
||||
}
|
||||
|
||||
@@ -303,10 +338,6 @@ public abstract class MinecraftProvider {
|
||||
return versionInfo;
|
||||
}
|
||||
|
||||
public MinecraftLibraryProvider getLibraryProvider() {
|
||||
return libraryProvider;
|
||||
}
|
||||
|
||||
public String getJarPrefix() {
|
||||
return jarPrefix;
|
||||
}
|
||||
@@ -315,10 +346,6 @@ public abstract class MinecraftProvider {
|
||||
this.jarPrefix = jarSuffix;
|
||||
}
|
||||
|
||||
public String getTargetConfig() {
|
||||
return Constants.Configurations.MINECRAFT;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public BundleMetadata getServerBundleMetadata() {
|
||||
return serverBundleMetadata;
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.configuration.providers.minecraft;
|
||||
|
||||
import static net.fabricmc.loom.configuration.CompileConfiguration.extendsFrom;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.jvm.tasks.Jar;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
|
||||
public abstract sealed class MinecraftSourceSets permits MinecraftSourceSets.Single, MinecraftSourceSets.Split {
|
||||
public static MinecraftSourceSets get(Project project) {
|
||||
return LoomGradleExtension.get(project).areEnvironmentSourceSetsSplit() ? Split.INSTANCE : Single.INSTANCE;
|
||||
}
|
||||
|
||||
public abstract void applyDependencies(BiConsumer<String, String> consumer, List<String> targets);
|
||||
|
||||
public abstract String getCombinedSourceSetName();
|
||||
|
||||
public abstract String getSourceSetForEnv(String env);
|
||||
|
||||
protected abstract List<String> getAllSourceSetNames();
|
||||
|
||||
public void evaluateSplit(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
Preconditions.checkArgument(extension.areEnvironmentSourceSetsSplit());
|
||||
|
||||
Split.INSTANCE.evaluate(project);
|
||||
}
|
||||
|
||||
public abstract void afterEvaluate(Project project);
|
||||
|
||||
protected void createSourceSets(Project project) {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
|
||||
for (String name : getAllSourceSetNames()) {
|
||||
extension.createLazyConfiguration(name, configuration -> configuration.setTransitive(false));
|
||||
|
||||
// All the configurations extend the loader deps.
|
||||
extendsFrom(name, Constants.Configurations.LOADER_DEPENDENCIES, project);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when we have a single source set, either with split or merged jars.
|
||||
*/
|
||||
public static final class Single extends MinecraftSourceSets {
|
||||
private static final String MINECRAFT_NAMED = "minecraftNamed";
|
||||
|
||||
private static final Single INSTANCE = new Single();
|
||||
|
||||
@Override
|
||||
public void applyDependencies(BiConsumer<String, String> consumer, List<String> targets) {
|
||||
for (String target : targets) {
|
||||
consumer.accept(MINECRAFT_NAMED, target);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCombinedSourceSetName() {
|
||||
return MINECRAFT_NAMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceSetForEnv(String env) {
|
||||
return SourceSet.MAIN_SOURCE_SET_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAllSourceSetNames() {
|
||||
return List.of(MINECRAFT_NAMED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEvaluate(Project project) {
|
||||
// This is done in afterEvaluate as we need to be sure that split source sets was not enabled.
|
||||
createSourceSets(project);
|
||||
|
||||
// Default compile and runtime sourcesets.
|
||||
extendsFrom(List.of(
|
||||
JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||
JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME,
|
||||
JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME,
|
||||
JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME),
|
||||
MINECRAFT_NAMED, project
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when we have a split client/common source set and split jars.
|
||||
*/
|
||||
public static final class Split extends MinecraftSourceSets {
|
||||
private static final String MINECRAFT_COMMON_NAMED = "minecraftCommonNamed";
|
||||
private static final String MINECRAFT_CLIENT_ONLY_NAMED = "minecraftClientOnlyNamed";
|
||||
private static final String MINECRAFT_COMBINED_NAMED = "minecraftCombinedNamed";
|
||||
|
||||
private static final String CLIENT_ONLY_SOURCE_SET_NAME = "client";
|
||||
|
||||
private static final Split INSTANCE = new Split();
|
||||
|
||||
@Override
|
||||
public void applyDependencies(BiConsumer<String, String> consumer, List<String> targets) {
|
||||
Preconditions.checkArgument(targets.size() == 2);
|
||||
Preconditions.checkArgument(targets.contains("common"));
|
||||
Preconditions.checkArgument(targets.contains("clientOnly"));
|
||||
|
||||
consumer.accept(MINECRAFT_COMMON_NAMED, "common");
|
||||
consumer.accept(MINECRAFT_CLIENT_ONLY_NAMED, "clientOnly");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCombinedSourceSetName() {
|
||||
return MINECRAFT_COMBINED_NAMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceSetForEnv(String env) {
|
||||
return env.equals("client") ? CLIENT_ONLY_SOURCE_SET_NAME : SourceSet.MAIN_SOURCE_SET_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getAllSourceSetNames() {
|
||||
return List.of(MINECRAFT_COMMON_NAMED, MINECRAFT_CLIENT_ONLY_NAMED, MINECRAFT_COMBINED_NAMED);
|
||||
}
|
||||
|
||||
// Called during evaluation, when the loom extension method is called.
|
||||
private void evaluate(Project project) {
|
||||
createSourceSets(project);
|
||||
|
||||
// Combined extends from the 2 environments.
|
||||
extendsFrom(MINECRAFT_COMBINED_NAMED, MINECRAFT_COMMON_NAMED, project);
|
||||
extendsFrom(MINECRAFT_COMBINED_NAMED, MINECRAFT_CLIENT_ONLY_NAMED, project);
|
||||
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
final LoomGradleExtension loomExtension = LoomGradleExtension.get(project);
|
||||
|
||||
// Register our new client only source set, main becomes common only, with their respective jars.
|
||||
SourceSet mainSourceSet = javaExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
||||
SourceSet clientOnlySourceSet = javaExtension.getSourceSets().create(CLIENT_ONLY_SOURCE_SET_NAME);
|
||||
|
||||
extendsFrom(List.of(
|
||||
mainSourceSet.getCompileClasspathConfigurationName(),
|
||||
mainSourceSet.getRuntimeClasspathConfigurationName()
|
||||
), MINECRAFT_COMMON_NAMED, project
|
||||
);
|
||||
|
||||
extendsFrom(List.of(
|
||||
clientOnlySourceSet.getCompileClasspathConfigurationName(),
|
||||
clientOnlySourceSet.getRuntimeClasspathConfigurationName()
|
||||
), MINECRAFT_CLIENT_ONLY_NAMED, project
|
||||
);
|
||||
|
||||
// Client depends on common.
|
||||
extendsFrom(MINECRAFT_CLIENT_ONLY_NAMED, MINECRAFT_COMMON_NAMED, project);
|
||||
clientOnlySourceSet.setCompileClasspath(
|
||||
clientOnlySourceSet.getCompileClasspath()
|
||||
.plus(mainSourceSet.getCompileClasspath())
|
||||
.plus(mainSourceSet.getOutput())
|
||||
);
|
||||
clientOnlySourceSet.setRuntimeClasspath(
|
||||
clientOnlySourceSet.getRuntimeClasspath()
|
||||
.plus(mainSourceSet.getRuntimeClasspath())
|
||||
.plus(mainSourceSet.getOutput())
|
||||
);
|
||||
|
||||
loomExtension.mixin(mixinExtension -> {
|
||||
// Generate a refmap for mixins in the new source set.
|
||||
mixinExtension.add(clientOnlySourceSet, "client-" + mixinExtension.getDefaultRefmapName().get(), (p) -> { });
|
||||
});
|
||||
|
||||
// Include the client only output in the jars
|
||||
project.getTasks().named(mainSourceSet.getJarTaskName(), Jar.class).configure(jar -> {
|
||||
jar.from(clientOnlySourceSet.getOutput().getClassesDirs());
|
||||
jar.from(clientOnlySourceSet.getOutput().getResourcesDir());
|
||||
});
|
||||
|
||||
if (project.getTasks().findByName(mainSourceSet.getSourcesJarTaskName()) == null) {
|
||||
// No sources.
|
||||
return;
|
||||
}
|
||||
|
||||
project.getTasks().named(mainSourceSet.getSourcesJarTaskName(), Jar.class).configure(jar -> {
|
||||
jar.from(clientOnlySourceSet.getAllSource());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterEvaluate(Project project) {
|
||||
}
|
||||
|
||||
public static SourceSet getClientSourceSet(Project project) {
|
||||
Preconditions.checkArgument(LoomGradleExtension.get(project).areEnvironmentSourceSetsSplit());
|
||||
|
||||
final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
return javaExtension.getSourceSets().getByName(CLIENT_ONLY_SOURCE_SET_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.fabricmc.loom.util.Architecture;
|
||||
import net.fabricmc.loom.util.OperatingSystem;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -85,7 +86,7 @@ public record MinecraftVersionMeta(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (natives.get(OperatingSystem.CURRENT_OS) == null) {
|
||||
if (classifierForOS() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,7 +94,13 @@ public record MinecraftVersionMeta(
|
||||
}
|
||||
|
||||
public Download classifierForOS() {
|
||||
return downloads().classifier(natives.get(OperatingSystem.CURRENT_OS));
|
||||
String classifier = natives.get(OperatingSystem.CURRENT_OS);
|
||||
|
||||
if (Architecture.CURRENT.isArm()) {
|
||||
classifier += "-arm64";
|
||||
}
|
||||
|
||||
return downloads().classifier(classifier);
|
||||
}
|
||||
|
||||
public Download artifact() {
|
||||
|
||||
@@ -35,60 +35,64 @@ import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.configuration.providers.BundleMetadata;
|
||||
|
||||
public final class ServerOnlyMinecraftProvider extends MinecraftProvider {
|
||||
private Path minecraftServerOnlyJar;
|
||||
public final class SingleJarMinecraftProvider extends MinecraftProvider {
|
||||
private final Environment environment;
|
||||
|
||||
public ServerOnlyMinecraftProvider(Project project) {
|
||||
private Path minecraftEnvOnlyJar;
|
||||
|
||||
private SingleJarMinecraftProvider(Project project, Environment environment) {
|
||||
super(project);
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public static SingleJarMinecraftProvider server(Project project) {
|
||||
return new SingleJarMinecraftProvider(project, new Server());
|
||||
}
|
||||
|
||||
public static SingleJarMinecraftProvider client(Project project) {
|
||||
return new SingleJarMinecraftProvider(project, new Client());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initFiles() {
|
||||
super.initFiles();
|
||||
|
||||
minecraftServerOnlyJar = path("minecraft-server-only.jar");
|
||||
minecraftEnvOnlyJar = path("minecraft-%s-only.jar".formatted(environment.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getMinecraftJars() {
|
||||
return List.of(minecraftServerOnlyJar);
|
||||
return List.of(minecraftEnvOnlyJar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void provide() throws Exception {
|
||||
super.provide();
|
||||
|
||||
boolean requiresRefresh = isRefreshDeps() || Files.notExists(minecraftServerOnlyJar);
|
||||
boolean requiresRefresh = isRefreshDeps() || Files.notExists(minecraftEnvOnlyJar);
|
||||
|
||||
if (!requiresRefresh) {
|
||||
return;
|
||||
}
|
||||
|
||||
BundleMetadata serverBundleMetadata = getServerBundleMetadata();
|
||||
|
||||
if (serverBundleMetadata == null) {
|
||||
throw new UnsupportedOperationException("Only Minecraft versions using a bundled server jar support server only configuration, please use a merged jar setup for this version of minecraft");
|
||||
}
|
||||
|
||||
extractBundledServerJar();
|
||||
final Path serverJar = getMinecraftExtractedServerJar().toPath();
|
||||
final Path inputJar = environment.getInputJar(this);
|
||||
|
||||
TinyRemapper remapper = null;
|
||||
|
||||
try {
|
||||
remapper = TinyRemapper.newRemapper().build();
|
||||
|
||||
Files.deleteIfExists(minecraftServerOnlyJar);
|
||||
Files.deleteIfExists(minecraftEnvOnlyJar);
|
||||
|
||||
// Pass through tiny remapper to fix the meta-inf
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(minecraftServerOnlyJar).build()) {
|
||||
outputConsumer.addNonClassFiles(serverJar, NonClassCopyMode.FIX_META_INF, remapper);
|
||||
remapper.readInputs(serverJar);
|
||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(minecraftEnvOnlyJar).build()) {
|
||||
outputConsumer.addNonClassFiles(inputJar, NonClassCopyMode.FIX_META_INF, remapper);
|
||||
remapper.readInputs(inputJar);
|
||||
remapper.apply(outputConsumer);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Files.deleteIfExists(minecraftServerOnlyJar);
|
||||
throw new RuntimeException("Failed to process server only jar", e);
|
||||
Files.deleteIfExists(minecraftEnvOnlyJar);
|
||||
throw new RuntimeException("Failed to process %s only jar".formatted(environment.name()), e);
|
||||
} finally {
|
||||
if (remapper != null) {
|
||||
remapper.finish();
|
||||
@@ -96,7 +100,54 @@ public final class ServerOnlyMinecraftProvider extends MinecraftProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public Path getMinecraftServerOnlyJar() {
|
||||
return minecraftServerOnlyJar;
|
||||
@Override
|
||||
protected boolean provideClient() {
|
||||
return environment instanceof Client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean provideServer() {
|
||||
return environment instanceof Server;
|
||||
}
|
||||
|
||||
public Path getMinecraftEnvOnlyJar() {
|
||||
return minecraftEnvOnlyJar;
|
||||
}
|
||||
|
||||
private interface Environment {
|
||||
String name();
|
||||
|
||||
Path getInputJar(SingleJarMinecraftProvider provider) throws Exception;
|
||||
}
|
||||
|
||||
private static final class Server implements Environment {
|
||||
@Override
|
||||
public String name() {
|
||||
return "server";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getInputJar(SingleJarMinecraftProvider provider) throws Exception {
|
||||
BundleMetadata serverBundleMetadata = provider.getServerBundleMetadata();
|
||||
|
||||
if (serverBundleMetadata == null) {
|
||||
return provider.getMinecraftServerJar().toPath();
|
||||
}
|
||||
|
||||
provider.extractBundledServerJar();
|
||||
return provider.getMinecraftExtractedServerJar().toPath();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Client implements Environment {
|
||||
@Override
|
||||
public String name() {
|
||||
return "client";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getInputJar(SingleJarMinecraftProvider provider) throws Exception {
|
||||
return provider.getMinecraftClientJar().toPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,8 @@ public final class SplitMinecraftProvider extends MinecraftProvider {
|
||||
try (MinecraftJarSplitter jarSplitter = new MinecraftJarSplitter(clientJar, serverJar)) {
|
||||
// Required for loader to compute the version info also useful to have in both jars.
|
||||
jarSplitter.sharedEntry("version.json");
|
||||
jarSplitter.forcedClientEntry("assets/.mcassetsroot");
|
||||
jarSplitter.sharedEntry("assets/.mcassetsroot");
|
||||
jarSplitter.sharedEntry("assets/minecraft/lang/en_us.json");
|
||||
|
||||
jarSplitter.split(minecraftClientOnlyJar, minecraftCommonJar);
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -24,18 +24,38 @@
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.minecraft.assets;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public record AssetIndex(Map<String, AssetObject> objects, boolean virtual) {
|
||||
public record AssetIndex(Map<String, Entry> objects, boolean virtual, @JsonProperty("map_to_resources") boolean mapToResources) {
|
||||
public AssetIndex() {
|
||||
this(new LinkedHashMap<>(), false);
|
||||
this(new LinkedHashMap<>(), false, false);
|
||||
}
|
||||
|
||||
public Set<AssetObject> getUniqueObjects() {
|
||||
return new HashSet<>(this.objects.values());
|
||||
public Collection<Object> getObjects() {
|
||||
return objects.entrySet().stream().map(Object::new).toList();
|
||||
}
|
||||
|
||||
public record Entry(String hash, long size) {
|
||||
}
|
||||
|
||||
public record Object(String path, String hash, long size) {
|
||||
private Object(Map.Entry<String, Entry> entry) {
|
||||
this(entry.getKey(), entry.getValue().hash(), entry.getValue().size());
|
||||
}
|
||||
|
||||
public String name() {
|
||||
int end = path().lastIndexOf("/") + 1;
|
||||
|
||||
if (end > 0) {
|
||||
return path().substring(end);
|
||||
}
|
||||
|
||||
return path();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2018-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 net.fabricmc.loom.configuration.providers.minecraft.assets;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import me.tongfei.progressbar.DelegatingProgressBarConsumer;
|
||||
import me.tongfei.progressbar.ProgressBar;
|
||||
import me.tongfei.progressbar.ProgressBarBuilder;
|
||||
import me.tongfei.progressbar.ProgressBarStyle;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||
|
||||
public class MinecraftAssetsProvider {
|
||||
public static void provide(MinecraftProvider minecraftProvider, Project project) throws IOException {
|
||||
LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
boolean offline = project.getGradle().getStartParameter().isOffline();
|
||||
|
||||
MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo();
|
||||
MinecraftVersionMeta.AssetIndex assetIndex = versionInfo.assetIndex();
|
||||
|
||||
// get existing cache files
|
||||
File assets = new File(extension.getFiles().getUserCache(), "assets");
|
||||
|
||||
if (!assets.exists()) {
|
||||
assets.mkdirs();
|
||||
}
|
||||
|
||||
File assetsInfo = new File(assets, "indexes" + File.separator + assetIndex.fabricId(minecraftProvider.minecraftVersion()) + ".json");
|
||||
|
||||
project.getLogger().info(":downloading asset index");
|
||||
|
||||
if (offline) {
|
||||
if (assetsInfo.exists()) {
|
||||
//We know it's outdated but can't do anything about it, oh well
|
||||
project.getLogger().warn("Asset index outdated");
|
||||
} else {
|
||||
//We don't know what assets we need, just that we don't have any
|
||||
throw new GradleException("Asset index not found at " + assetsInfo.getAbsolutePath());
|
||||
}
|
||||
} else {
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(assetIndex.url()), assetsInfo, assetIndex.sha1(), project.getLogger(), false);
|
||||
}
|
||||
|
||||
ExecutorService executor = Executors.newFixedThreadPool(Math.min(16, Math.max(Runtime.getRuntime().availableProcessors() * 2, 1)));
|
||||
int toDownload = 0;
|
||||
|
||||
AssetIndex index;
|
||||
|
||||
try (FileReader fileReader = new FileReader(assetsInfo)) {
|
||||
index = LoomGradlePlugin.OBJECT_MAPPER.readValue(fileReader, AssetIndex.class);
|
||||
}
|
||||
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
|
||||
Map<String, AssetObject> parent = index.objects();
|
||||
|
||||
ProgressBar[] progressBar = {null};
|
||||
|
||||
try {
|
||||
for (Map.Entry<String, AssetObject> entry : parent.entrySet()) {
|
||||
AssetObject object = entry.getValue();
|
||||
String sha1 = object.hash();
|
||||
String filename = "objects" + File.separator + sha1.substring(0, 2) + File.separator + sha1;
|
||||
File file = new File(assets, filename);
|
||||
|
||||
if (offline) {
|
||||
if (file.exists()) {
|
||||
project.getLogger().warn("Outdated asset " + entry.getKey());
|
||||
} else {
|
||||
throw new GradleException("Asset " + entry.getKey() + " not found at " + file.getAbsolutePath());
|
||||
}
|
||||
} else if (HashedDownloadUtil.requiresDownload(file, sha1, project.getLogger())) {
|
||||
toDownload++;
|
||||
|
||||
synchronized (progressBar) {
|
||||
if (progressBar[0] == null) {
|
||||
progressBar[0] = new ProgressBarBuilder()
|
||||
.setConsumer(new DelegatingProgressBarConsumer(project.getLogger()::lifecycle))
|
||||
.setInitialMax(toDownload)
|
||||
.setUpdateIntervalMillis(2000)
|
||||
.setTaskName(":downloading assets")
|
||||
.setStyle(ProgressBarStyle.ASCII)
|
||||
.showSpeed()
|
||||
.build();
|
||||
}
|
||||
|
||||
progressBar[0].maxHint(toDownload);
|
||||
}
|
||||
|
||||
executor.execute(() -> {
|
||||
String assetName = entry.getKey();
|
||||
int end = assetName.lastIndexOf("/") + 1;
|
||||
|
||||
if (end > 0) {
|
||||
assetName = assetName.substring(end);
|
||||
}
|
||||
|
||||
project.getLogger().debug(":downloading asset " + assetName);
|
||||
|
||||
try {
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(MirrorUtil.getResourcesBase(project) + sha1.substring(0, 2) + "/" + sha1), file, sha1, project.getLogger(), true, false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to download: " + assetName, e);
|
||||
}
|
||||
|
||||
synchronized (progressBar) {
|
||||
progressBar[0].step();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
project.getLogger().info("Took " + stopwatch.stop() + " to iterate " + parent.size() + " asset index.");
|
||||
|
||||
//Wait for the assets to all download
|
||||
executor.shutdown();
|
||||
|
||||
try {
|
||||
if (executor.awaitTermination(2, TimeUnit.HOURS)) {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} finally {
|
||||
if (progressBar[0] != null) {
|
||||
progressBar[0].close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -27,6 +27,7 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -41,6 +42,7 @@ import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SignatureFixerApplyVisitor;
|
||||
import net.fabricmc.loom.util.TinyRemapperHelper;
|
||||
import net.fabricmc.loom.util.srg.InnerClassRemapper;
|
||||
@@ -60,8 +62,8 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
|
||||
public abstract List<RemappedJars> getRemappedJars();
|
||||
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
// Override if needed
|
||||
public List<String> getDependencyTargets() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void provide(boolean applyDependencies) throws Exception {
|
||||
@@ -79,7 +81,16 @@ public abstract class AbstractMappedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
applyDependencies((configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)));
|
||||
final List<String> dependencyTargets = getDependencyTargets();
|
||||
|
||||
if (dependencyTargets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ import org.gradle.api.Project;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
|
||||
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.ServerOnlyImpl, IntermediaryMinecraftProvider.SplitImpl {
|
||||
public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl {
|
||||
public IntermediaryMinecraftProvider(Project project, M minecraftProvider) {
|
||||
super(project, minecraftProvider);
|
||||
}
|
||||
@@ -86,16 +86,32 @@ public abstract sealed class IntermediaryMinecraftProvider<M extends MinecraftPr
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends IntermediaryMinecraftProvider<ServerOnlyMinecraftProvider> implements ServerOnly {
|
||||
public ServerOnlyImpl(Project project, ServerOnlyMinecraftProvider minecraftProvider) {
|
||||
public static final class SingleJarImpl extends IntermediaryMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final String env;
|
||||
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, String env) {
|
||||
super(project, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "server");
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "client");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftServerOnlyJar(), getServerOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,16 +65,20 @@ public interface MappedMinecraftProvider {
|
||||
}
|
||||
}
|
||||
|
||||
interface ServerOnly extends ProviderImpl {
|
||||
String SERVER_ONLY = "serverOnly";
|
||||
interface SingleJar extends ProviderImpl {
|
||||
String env();
|
||||
|
||||
default Path getServerOnlyJar() {
|
||||
return getJar(SERVER_ONLY);
|
||||
default String envName() {
|
||||
return "%sOnly".formatted(env());
|
||||
}
|
||||
|
||||
default Path getEnvOnlyJar() {
|
||||
return getJar(envName());
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Path> getMinecraftJars() {
|
||||
return List.of(getServerOnlyJar());
|
||||
return List.of(getEnvOnlyJar());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -26,7 +26,6 @@ package net.fabricmc.loom.configuration.providers.minecraft.mapped;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.gradle.api.Project;
|
||||
@@ -34,9 +33,8 @@ import org.gradle.api.Project;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
|
||||
public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extends AbstractMappedMinecraftProvider<M> {
|
||||
@@ -67,8 +65,8 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, MERGED);
|
||||
public List<String> getDependencyTargets() {
|
||||
return List.of(MERGED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,27 +91,42 @@ public abstract class NamedMinecraftProvider<M extends MinecraftProvider> extend
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, COMMON);
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, CLIENT_ONLY);
|
||||
public List<String> getDependencyTargets() {
|
||||
return List.of(CLIENT_ONLY, COMMON);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends NamedMinecraftProvider<ServerOnlyMinecraftProvider> implements ServerOnly {
|
||||
public ServerOnlyImpl(Project project, ServerOnlyMinecraftProvider minecraftProvider) {
|
||||
public static final class SingleJarImpl extends NamedMinecraftProvider<SingleJarMinecraftProvider> implements SingleJar {
|
||||
private final String env;
|
||||
|
||||
private SingleJarImpl(Project project, SingleJarMinecraftProvider minecraftProvider, String env) {
|
||||
super(project, minecraftProvider);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static SingleJarImpl server(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "server");
|
||||
}
|
||||
|
||||
public static SingleJarImpl client(Project project, SingleJarMinecraftProvider minecraftProvider) {
|
||||
return new SingleJarImpl(project, minecraftProvider, "client");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemappedJars> getRemappedJars() {
|
||||
return List.of(
|
||||
new RemappedJars(minecraftProvider.getMinecraftServerOnlyJar(), getServerOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), MappingsNamespace.OFFICIAL)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyDependencies(BiConsumer<String, String> consumer) {
|
||||
consumer.accept(Constants.Configurations.MINECRAFT_NAMED, SERVER_ONLY);
|
||||
public List<String> getDependencyTargets() {
|
||||
return List.of(envName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -36,7 +36,8 @@ import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.ServerOnlyMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider;
|
||||
|
||||
public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvider, P extends NamedMinecraftProvider<M>> extends NamedMinecraftProvider<M> {
|
||||
@@ -85,7 +86,16 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
|
||||
if (applyDependencies) {
|
||||
parentMinecraftProvider.applyDependencies((configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)));
|
||||
final List<String> dependencyTargets = parentMinecraftProvider.getDependencyTargets();
|
||||
|
||||
if (dependencyTargets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinecraftSourceSets.get(getProject()).applyDependencies(
|
||||
(configuration, name) -> getProject().getDependencies().add(configuration, getDependencyNotation(name)),
|
||||
dependencyTargets
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,14 +166,30 @@ public abstract class ProcessedNamedMinecraftProvider<M extends MinecraftProvide
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ServerOnlyImpl extends ProcessedNamedMinecraftProvider<ServerOnlyMinecraftProvider, NamedMinecraftProvider.ServerOnlyImpl> implements ServerOnly {
|
||||
public ServerOnlyImpl(NamedMinecraftProvider.ServerOnlyImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
public static final class SingleJarImpl extends ProcessedNamedMinecraftProvider<SingleJarMinecraftProvider, NamedMinecraftProvider.SingleJarImpl> implements SingleJar {
|
||||
private final String env;
|
||||
|
||||
private SingleJarImpl(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager, String env) {
|
||||
super(parentMinecraftProvide, jarProcessorManager);
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl server(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, "server");
|
||||
}
|
||||
|
||||
public static ProcessedNamedMinecraftProvider.SingleJarImpl client(NamedMinecraftProvider.SingleJarImpl parentMinecraftProvide, JarProcessorManager jarProcessorManager) {
|
||||
return new ProcessedNamedMinecraftProvider.SingleJarImpl(parentMinecraftProvide, jarProcessorManager, "client");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getServerOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getServerOnlyJar());
|
||||
public Path getEnvOnlyJar() {
|
||||
return getProcessedPath(getParentMinecraftProvider().getEnvOnlyJar());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String env() {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class FernflowerLogger extends IFernflowerLogger {
|
||||
@Override
|
||||
public void writeMessage(String message, Severity severity) {
|
||||
if (message.contains("Inconsistent inner class entries for")) return;
|
||||
if (message.contains("Inconsistent generic signature in method")) return;
|
||||
System.err.println(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,9 @@ import net.fabricmc.loom.api.ForgeExtensionAPI;
|
||||
import net.fabricmc.loom.api.InterfaceInjectionExtensionAPI;
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI;
|
||||
import net.fabricmc.loom.api.MixinExtensionAPI;
|
||||
import net.fabricmc.loom.api.ModSettings;
|
||||
import net.fabricmc.loom.api.decompilers.DecompilerOptions;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.spec.LayeredMappingSpecBuilder;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfig;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
@@ -61,6 +63,7 @@ import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.util.DeprecationHelper;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
|
||||
@@ -80,15 +83,22 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
protected final Property<String> customManifest;
|
||||
protected final Property<Boolean> setupRemappedVariants;
|
||||
protected final Property<Boolean> transitiveAccessWideners;
|
||||
protected final Property<Boolean> modProvidedJavadoc;
|
||||
protected final Property<String> intermediary;
|
||||
protected final Property<IntermediateMappingsProvider> intermediateMappingsProvider;
|
||||
private final Property<Boolean> runtimeOnlyLog4j;
|
||||
private final Property<MinecraftJarConfiguration> minecraftJarConfiguration;
|
||||
private final Property<Boolean> splitEnvironmentalSourceSet;
|
||||
private final InterfaceInjectionExtensionAPI interfaceInjectionExtension;
|
||||
|
||||
private final ModVersionParser versionParser;
|
||||
|
||||
private final NamedDomainObjectContainer<RunConfigSettings> runConfigs;
|
||||
private final NamedDomainObjectContainer<DecompilerOptions> decompilers;
|
||||
private final NamedDomainObjectContainer<ModSettings> mods;
|
||||
|
||||
// A common mistake with layered mappings is to call the wrong `officialMojangMappings` method, use this to keep track of when we are building a layered mapping spec.
|
||||
protected final ThreadLocal<Boolean> layeredSpecBuilderScope = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
// ===================
|
||||
// Architectury Loom
|
||||
@@ -115,9 +125,15 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
this.transitiveAccessWideners = project.getObjects().property(Boolean.class)
|
||||
.convention(true);
|
||||
this.transitiveAccessWideners.finalizeValueOnRead();
|
||||
this.modProvidedJavadoc = project.getObjects().property(Boolean.class)
|
||||
.convention(true);
|
||||
this.modProvidedJavadoc.finalizeValueOnRead();
|
||||
this.intermediary = project.getObjects().property(String.class)
|
||||
.convention("https://maven.fabricmc.net/net/fabricmc/intermediary/%1$s/intermediary-%1$s-v2.jar");
|
||||
|
||||
this.intermediateMappingsProvider = project.getObjects().property(IntermediateMappingsProvider.class);
|
||||
this.intermediateMappingsProvider.finalizeValueOnRead();
|
||||
|
||||
this.versionParser = new ModVersionParser(project);
|
||||
|
||||
this.deprecationHelper = new DeprecationHelper.ProjectBased(project);
|
||||
@@ -125,6 +141,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
this.runConfigs = project.container(RunConfigSettings.class,
|
||||
baseName -> new RunConfigSettings(project, baseName));
|
||||
this.decompilers = project.getObjects().domainObjectContainer(DecompilerOptions.class);
|
||||
this.mods = project.getObjects().domainObjectContainer(ModSettings.class);
|
||||
|
||||
this.minecraftJarConfiguration = project.getObjects().property(MinecraftJarConfiguration.class).convention(MinecraftJarConfiguration.MERGED);
|
||||
this.minecraftJarConfiguration.finalizeValueOnRead();
|
||||
@@ -137,6 +154,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
|
||||
this.interfaceInjectionExtension = project.getObjects().newInstance(InterfaceInjectionExtensionAPI.class);
|
||||
|
||||
this.splitEnvironmentalSourceSet = project.getObjects().property(Boolean.class).convention(false);
|
||||
this.splitEnvironmentalSourceSet.finalizeValueOnRead();
|
||||
|
||||
// Add main source set by default
|
||||
interfaceInjection(interfaceInjection -> {
|
||||
final JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
@@ -202,10 +222,23 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return jarProcessors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dependency officialMojangMappings() {
|
||||
if (layeredSpecBuilderScope.get()) {
|
||||
throw new IllegalStateException("Use `officialMojangMappings()` when configuring layered mappings, not the extension method `loom.officialMojangMappings()`");
|
||||
}
|
||||
|
||||
return layered(LayeredMappingSpecBuilder::officialMojangMappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dependency layered(Action<LayeredMappingSpecBuilder> action) {
|
||||
LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl(this);
|
||||
|
||||
layeredSpecBuilderScope.set(true);
|
||||
action.execute(builder);
|
||||
layeredSpecBuilderScope.set(false);
|
||||
|
||||
LayeredMappingSpec builtSpec = builder.build();
|
||||
return new LayeredMappingsDependency(getProject(), new GradleMappingContext(getProject(), builtSpec.getVersion().replace("+", "_").replace(".", "_")), builtSpec, builtSpec.getVersion());
|
||||
}
|
||||
@@ -257,6 +290,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return transitiveAccessWideners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property<Boolean> getEnableModProvidedJavadoc() {
|
||||
return modProvidedJavadoc;
|
||||
}
|
||||
|
||||
protected abstract Project getProject();
|
||||
|
||||
protected abstract LoomFiles getFiles();
|
||||
@@ -266,6 +304,26 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return intermediary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntermediateMappingsProvider getIntermediateMappingsProvider() {
|
||||
return intermediateMappingsProvider.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntermediateMappingsProvider(IntermediateMappingsProvider intermediateMappingsProvider) {
|
||||
this.intermediateMappingsProvider.set(intermediateMappingsProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IntermediateMappingsProvider> void setIntermediateMappingsProvider(Class<T> clazz, Action<T> action) {
|
||||
T provider = getProject().getObjects().newInstance(clazz);
|
||||
configureIntermediateMappingsProviderInternal(provider);
|
||||
action.execute(provider);
|
||||
intermediateMappingsProvider.set(provider);
|
||||
}
|
||||
|
||||
protected abstract <T extends IntermediateMappingsProvider> void configureIntermediateMappingsProviderInternal(T provider);
|
||||
|
||||
@Override
|
||||
public void disableDeprecatedPomGeneration(MavenPublication publication) {
|
||||
net.fabricmc.loom.configuration.MavenPublication.excludePublication(publication);
|
||||
@@ -281,11 +339,39 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
return runtimeOnlyLog4j;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void splitEnvironmentSourceSets() {
|
||||
splitMinecraftJar();
|
||||
|
||||
splitEnvironmentalSourceSet.set(true);
|
||||
|
||||
// We need to lock these values, as we setup the new source sets right away.
|
||||
splitEnvironmentalSourceSet.finalizeValue();
|
||||
minecraftJarConfiguration.finalizeValue();
|
||||
|
||||
MinecraftSourceSets.get(getProject()).evaluateSplit(getProject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areEnvironmentSourceSetsSplit() {
|
||||
return splitEnvironmentalSourceSet.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterfaceInjectionExtensionAPI getInterfaceInjection() {
|
||||
return interfaceInjectionExtension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mods(Action<NamedDomainObjectContainer<ModSettings>> action) {
|
||||
action.execute(getMods());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedDomainObjectContainer<ModSettings> getMods() {
|
||||
return mods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void silentMojangMappingsLicense() {
|
||||
this.silentMojangMappingsLicense = true;
|
||||
@@ -362,6 +448,11 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
|
||||
throw new RuntimeException("Yeah... something is really wrong");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends IntermediateMappingsProvider> void configureIntermediateMappingsProviderInternal(T provider) {
|
||||
throw new RuntimeException("Yeah... something is really wrong");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MixinExtension getMixin() {
|
||||
throw new RuntimeException("Yeah... something is really wrong");
|
||||
|
||||
@@ -44,12 +44,14 @@ import org.gradle.api.file.FileCollection;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.api.ForgeExtensionAPI;
|
||||
import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.InstallerData;
|
||||
import net.fabricmc.loom.configuration.LoomDependencyManager;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
|
||||
import net.fabricmc.loom.configuration.providers.forge.DependencyProviders;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider;
|
||||
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider;
|
||||
@@ -95,6 +97,13 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
this.unmappedMods = project.files();
|
||||
this.forgeExtension = Suppliers.memoize(() -> isForge() ? project.getObjects().newInstance(ForgeExtensionImpl.class, project, this) : null);
|
||||
this.supportsInclude = new LazyBool(() -> Boolean.parseBoolean(Objects.toString(project.findProperty(INCLUDE_PROPERTY))));
|
||||
|
||||
// Setup the default intermediate mappings provider.
|
||||
setIntermediateMappingsProvider(IntermediaryMappingsProvider.class, provider -> {
|
||||
provider.getIntermediaryUrl()
|
||||
.convention(getIntermediaryUrl())
|
||||
.finalizeValueOnRead();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -256,6 +265,12 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen
|
||||
transitiveAccessWideners.addAll(accessWidenerFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends IntermediateMappingsProvider> void configureIntermediateMappingsProviderInternal(T provider) {
|
||||
provider.getMinecraftVersion().set(getProject().provider(() -> getMinecraftProvider().minecraftVersion()));
|
||||
provider.getMinecraftVersion().disallowChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMinecraftVersion() {
|
||||
return getMinecraftProvider().minecraftVersion();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -36,16 +36,22 @@ import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.util.PatternSet;
|
||||
|
||||
import net.fabricmc.loom.api.MixinExtensionAPI;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
|
||||
public abstract class MixinExtensionApiImpl implements MixinExtensionAPI {
|
||||
protected final Project project;
|
||||
protected final Property<Boolean> useMixinAp;
|
||||
private final Property<String> refmapTargetNamespace;
|
||||
|
||||
public MixinExtensionApiImpl(Project project) {
|
||||
this.project = Objects.requireNonNull(project);
|
||||
this.useMixinAp = project.getObjects().property(Boolean.class)
|
||||
// .convention(project.provider(() -> LoomGradleExtension.get(project).isForge()));
|
||||
.convention(true);
|
||||
|
||||
this.refmapTargetNamespace = project.getObjects().property(String.class)
|
||||
.convention(MappingsNamespace.INTERMEDIARY.toString());
|
||||
this.refmapTargetNamespace.finalizeValueOnRead();
|
||||
}
|
||||
|
||||
protected final PatternSet add0(SourceSet sourceSet, String refmapName) {
|
||||
@@ -59,6 +65,13 @@ public abstract class MixinExtensionApiImpl implements MixinExtensionAPI {
|
||||
return useMixinAp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Property<String> getRefmapTargetNamespace() {
|
||||
if (!getUseLegacyMixinAp().get()) throw new IllegalStateException("You need to set useLegacyMixinAp = true to configure Mixin annotation processor.");
|
||||
|
||||
return refmapTargetNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(SourceSet sourceSet, String refmapName, Action<PatternSet> action) {
|
||||
PatternSet pattern = add0(sourceSet, refmapName);
|
||||
|
||||
@@ -52,7 +52,7 @@ public abstract class AbstractRunTask extends JavaExec {
|
||||
|
||||
@Override
|
||||
public void exec() {
|
||||
setWorkingDir(new File(getProject().getRootDir(), config.runDir));
|
||||
setWorkingDir(new File(getProject().getProjectDir(), config.runDir));
|
||||
environment(config.envVariables);
|
||||
|
||||
super.exec();
|
||||
|
||||
@@ -24,20 +24,179 @@
|
||||
|
||||
package net.fabricmc.loom.task;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.util.Deque;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider;
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.assets.AssetIndex;
|
||||
import net.fabricmc.loom.util.HashedDownloadUtil;
|
||||
import net.fabricmc.loom.util.MirrorUtil;
|
||||
import net.fabricmc.loom.util.gradle.ProgressLoggerHelper;
|
||||
|
||||
public abstract class DownloadAssetsTask extends AbstractLoomTask {
|
||||
@Input
|
||||
public abstract Property<String> getAssetsHash();
|
||||
|
||||
@OutputDirectory
|
||||
public abstract RegularFileProperty getAssetsDirectory();
|
||||
|
||||
@OutputDirectory
|
||||
public abstract RegularFileProperty getLegacyResourcesDirectory();
|
||||
|
||||
@Inject
|
||||
public DownloadAssetsTask() {
|
||||
final MinecraftVersionMeta versionInfo = getExtension().getMinecraftProvider().getVersionInfo();
|
||||
final File assetsDir = new File(getExtension().getFiles().getUserCache(), "assets");
|
||||
|
||||
getAssetsDirectory().set(assetsDir);
|
||||
getAssetsHash().set(versionInfo.assetIndex().sha1());
|
||||
|
||||
if (versionInfo.assets().equals("legacy")) {
|
||||
getLegacyResourcesDirectory().set(new File(assetsDir, "/legacy/" + versionInfo.id()));
|
||||
} else {
|
||||
// pre-1.6 resources
|
||||
RunConfigSettings client = Objects.requireNonNull(getExtension().getRunConfigs().findByName("client"), "Could not find client run config");
|
||||
getLegacyResourcesDirectory().set(new File(getProject().getProjectDir(), client.getRunDir() + "/resources"));
|
||||
}
|
||||
|
||||
getAssetsHash().finalizeValueOnRead();
|
||||
getAssetsDirectory().finalizeValueOnRead();
|
||||
getLegacyResourcesDirectory().finalizeValueOnRead();
|
||||
}
|
||||
|
||||
public class DownloadAssetsTask extends AbstractLoomTask {
|
||||
@TaskAction
|
||||
public void downloadAssets() throws IOException {
|
||||
Project project = this.getProject();
|
||||
LoomGradleExtension extension = getExtension();
|
||||
final Project project = this.getProject();
|
||||
final File assetsDirectory = getAssetsDirectory().get().getAsFile();
|
||||
final Deque<ProgressLoggerHelper> loggers = new ConcurrentLinkedDeque<>();
|
||||
final ExecutorService executor = Executors.newFixedThreadPool(Math.min(10, Math.max(Runtime.getRuntime().availableProcessors() / 2, 1)));
|
||||
final AssetIndex assetIndex = getAssetIndex();
|
||||
|
||||
MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project);
|
||||
if (!assetsDirectory.exists()) {
|
||||
assetsDirectory.mkdirs();
|
||||
}
|
||||
|
||||
if (assetIndex.mapToResources()) {
|
||||
getLegacyResourcesDirectory().get().getAsFile().mkdirs();
|
||||
}
|
||||
|
||||
for (AssetIndex.Object object : assetIndex.getObjects()) {
|
||||
final String path = object.path();
|
||||
final String sha1 = object.hash();
|
||||
final File file = getAssetsFile(object, assetIndex);
|
||||
|
||||
if (getProject().getGradle().getStartParameter().isOffline()) {
|
||||
if (!file.exists()) {
|
||||
throw new GradleException("Asset " + path + " not found at " + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
final Supplier<ProgressLoggerHelper> getOrCreateLogger = () -> {
|
||||
ProgressLoggerHelper logger = loggers.pollFirst();
|
||||
|
||||
if (logger == null) {
|
||||
// No logger available, create a new one
|
||||
logger = ProgressLoggerHelper.getProgressFactory(project, DownloadAssetsTask.class.getName());
|
||||
logger.start("Downloading assets...", "assets");
|
||||
}
|
||||
|
||||
return logger;
|
||||
};
|
||||
|
||||
executor.execute(() -> {
|
||||
final ProgressLoggerHelper logger = getOrCreateLogger.get();
|
||||
|
||||
try {
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(MirrorUtil.getResourcesBase(project) + sha1.substring(0, 2) + "/" + sha1), file, sha1, project.getLogger(), true, () -> {
|
||||
project.getLogger().debug("downloading asset " + object.name());
|
||||
logger.progress(String.format("%-30.30s", object.name()) + " - " + sha1);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to download: " + object.name(), e);
|
||||
}
|
||||
|
||||
// Give this logger back
|
||||
loggers.add(logger);
|
||||
});
|
||||
}
|
||||
|
||||
// Wait for the assets to all download
|
||||
try {
|
||||
executor.shutdown();
|
||||
|
||||
if (executor.awaitTermination(2, TimeUnit.HOURS)) {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
loggers.forEach(ProgressLoggerHelper::completed);
|
||||
}
|
||||
}
|
||||
|
||||
private MinecraftVersionMeta.AssetIndex getAssetIndexMeta() {
|
||||
MinecraftVersionMeta versionInfo = getExtension().getMinecraftProvider().getVersionInfo();
|
||||
return versionInfo.assetIndex();
|
||||
}
|
||||
|
||||
private AssetIndex getAssetIndex() throws IOException {
|
||||
final LoomGradleExtension extension = getExtension();
|
||||
final MinecraftProvider minecraftProvider = extension.getMinecraftProvider();
|
||||
|
||||
MinecraftVersionMeta.AssetIndex assetIndex = getAssetIndexMeta();
|
||||
File assetsInfo = new File(getAssetsDirectory().get().getAsFile(), "indexes" + File.separator + assetIndex.fabricId(minecraftProvider.minecraftVersion()) + ".json");
|
||||
|
||||
getProject().getLogger().info(":downloading asset index");
|
||||
|
||||
if (getProject().getGradle().getStartParameter().isOffline()) {
|
||||
if (assetsInfo.exists()) {
|
||||
// We know it's outdated but can't do anything about it, oh well
|
||||
getProject().getLogger().warn("Asset index outdated");
|
||||
} else {
|
||||
// We don't know what assets we need, just that we don't have any
|
||||
throw new GradleException("Asset index not found at " + assetsInfo.getAbsolutePath());
|
||||
}
|
||||
} else {
|
||||
HashedDownloadUtil.downloadIfInvalid(new URL(assetIndex.url()), assetsInfo, assetIndex.sha1(), getProject().getLogger(), false);
|
||||
}
|
||||
|
||||
try (FileReader fileReader = new FileReader(assetsInfo)) {
|
||||
return LoomGradlePlugin.OBJECT_MAPPER.readValue(fileReader, AssetIndex.class);
|
||||
}
|
||||
}
|
||||
|
||||
private File getAssetsFile(AssetIndex.Object object, AssetIndex index) {
|
||||
if (index.mapToResources() || index.virtual()) {
|
||||
return new File(getLegacyResourcesDirectory().get().getAsFile(), object.path());
|
||||
}
|
||||
|
||||
final String filename = "objects" + File.separator + object.hash().substring(0, 2) + File.separator + object.hash();
|
||||
return new File(getAssetsDirectory().get().getAsFile(), filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ import net.fabricmc.loom.api.decompilers.LoomDecompiler;
|
||||
import net.fabricmc.loom.api.mappings.layered.MappingsNamespace;
|
||||
import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor;
|
||||
import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor;
|
||||
import net.fabricmc.loom.configuration.mods.ModJavadocProcessor;
|
||||
import net.fabricmc.loom.decompilers.LineNumberRemapper;
|
||||
import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
@@ -342,6 +343,12 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
|
||||
mappingsProcessors.add(new InterfaceInjectionProcessor(getProject()));
|
||||
}
|
||||
|
||||
final ModJavadocProcessor javadocProcessor = ModJavadocProcessor.create(getProject());
|
||||
|
||||
if (javadocProcessor != null) {
|
||||
mappingsProcessors.add(javadocProcessor);
|
||||
}
|
||||
|
||||
if (mappingsProcessors.isEmpty()) {
|
||||
return inputMappings;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2021 FabricMC
|
||||
* Copyright (c) 2016-2022 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
|
||||
@@ -34,6 +34,7 @@ import org.gradle.api.tasks.TaskProvider;
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.task.launch.GenerateDLIConfigTask;
|
||||
import net.fabricmc.loom.task.launch.GenerateLog4jConfigTask;
|
||||
import net.fabricmc.loom.task.launch.GenerateRemapClasspathTask;
|
||||
@@ -142,11 +143,30 @@ public final class LoomTasks {
|
||||
extension.getRunConfigs().create("client", RunConfigSettings::client);
|
||||
extension.getRunConfigs().create("server", RunConfigSettings::server);
|
||||
|
||||
// Remove the client run config when server only. Done by name to not remove any possible custom run configs
|
||||
// Remove the client or server run config when not required. Done by name to not remove any possible custom run configs
|
||||
project.afterEvaluate(p -> {
|
||||
if (extension.getMinecraftJarConfiguration().get() == MinecraftJarConfiguration.SERVER_ONLY) {
|
||||
extension.getRunConfigs().removeIf(settings -> settings.getName().equals("client"));
|
||||
String taskName = switch (extension.getMinecraftJarConfiguration().get()) {
|
||||
case SERVER_ONLY -> "client";
|
||||
case CLIENT_ONLY -> "server";
|
||||
default -> null;
|
||||
};
|
||||
|
||||
if (taskName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
extension.getRunConfigs().removeIf(settings -> settings.getName().equals(taskName));
|
||||
});
|
||||
|
||||
// Configure the run config source sets.
|
||||
project.afterEvaluate(p -> {
|
||||
if (!extension.areEnvironmentSourceSetsSplit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
extension.getRunConfigs().configureEach(settings ->
|
||||
settings.source(MinecraftSourceSets.get(project).getSourceSetForEnv(settings.getEnvironment()))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -39,17 +39,20 @@ import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -69,6 +72,7 @@ import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.SetProperty;
|
||||
import org.gradle.api.tasks.Input;
|
||||
@@ -89,6 +93,7 @@ import net.fabricmc.loom.build.MixinRefmapHelper;
|
||||
import net.fabricmc.loom.build.nesting.IncludedJarFactory;
|
||||
import net.fabricmc.loom.build.nesting.JarNester;
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets;
|
||||
import net.fabricmc.loom.extension.MixinExtension;
|
||||
import net.fabricmc.loom.task.service.JarManifestService;
|
||||
import net.fabricmc.loom.task.service.MappingsService;
|
||||
@@ -97,13 +102,16 @@ import net.fabricmc.loom.util.Constants;
|
||||
import net.fabricmc.loom.util.FileSystemUtil;
|
||||
import net.fabricmc.loom.util.LfWriter;
|
||||
import net.fabricmc.loom.util.ModPlatform;
|
||||
import net.fabricmc.loom.util.Pair;
|
||||
import net.fabricmc.loom.util.SidedClassVisitor;
|
||||
import net.fabricmc.loom.util.ZipUtils;
|
||||
import net.fabricmc.loom.util.aw2at.Aw2At;
|
||||
import net.fabricmc.loom.util.service.UnsafeWorkQueueHelper;
|
||||
import net.fabricmc.lorenztiny.TinyMappingsReader;
|
||||
|
||||
public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
public static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
|
||||
public static final String MANIFEST_NAMESPACE_KEY = "Fabric-Mapping-Namespace";
|
||||
|
||||
@InputFiles
|
||||
public abstract ConfigurableFileCollection getNestedJars();
|
||||
@@ -212,6 +220,16 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
if (!getAtAccessWideners().get().isEmpty()) {
|
||||
params.getMappingBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get())));
|
||||
}
|
||||
|
||||
if (extension.areEnvironmentSourceSetsSplit()) {
|
||||
final List<String> clientOnlyJarEntries = getClientOnlyJarEntries();
|
||||
params.getManifestAttributes().set(Map.of(
|
||||
"Fabric-Loom-Split-Environment", "true",
|
||||
"Fabric-Loom-Client-Only-Entries", String.join(";", clientOnlyJarEntries)
|
||||
));
|
||||
|
||||
params.getClientOnlyClasses().set(clientOnlyJarEntries.stream().filter(s -> s.endsWith(".class")).toList());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -272,34 +290,14 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
MixinExtension.getMixinInformationContainer(sourceSet)
|
||||
);
|
||||
|
||||
String[] rootPaths = sourceSet.getResources().getSrcDirs().stream()
|
||||
.map(root -> {
|
||||
String rootPath = root.getAbsolutePath().replace("\\", "/");
|
||||
|
||||
if (rootPath.charAt(rootPath.length() - 1) != '/') {
|
||||
rootPath += '/';
|
||||
}
|
||||
|
||||
return rootPath;
|
||||
})
|
||||
.toArray(String[]::new);
|
||||
final List<String> rootPaths = getRootPaths(sourceSet.getResources().getSrcDirs());
|
||||
|
||||
final String refmapName = container.refmapNameProvider().get();
|
||||
final List<String> mixinConfigs = container.sourceSet().getResources()
|
||||
.matching(container.mixinConfigPattern())
|
||||
.getFiles()
|
||||
.stream()
|
||||
.map(file -> {
|
||||
String s = file.getAbsolutePath().replace("\\", "/");
|
||||
|
||||
for (String rootPath : rootPaths) {
|
||||
if (s.startsWith(rootPath)) {
|
||||
s = s.substring(rootPath.length());
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
})
|
||||
.map(relativePath(rootPaths))
|
||||
.filter(allMixinConfigs::contains)
|
||||
.toList();
|
||||
|
||||
@@ -346,6 +344,9 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
Property<JarManifestService> getJarManifestService();
|
||||
Property<String> getTinyRemapperBuildServiceUuid();
|
||||
Property<String> getMappingBuildServiceUuid();
|
||||
|
||||
MapProperty<String, String> getManifestAttributes();
|
||||
ListProperty<String> getClientOnlyClasses();
|
||||
}
|
||||
|
||||
public abstract static class RemapAction extends AbstractRemapAction<RemapParams> {
|
||||
@@ -367,6 +368,10 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
|
||||
remap();
|
||||
|
||||
if (getParameters().getClientOnlyClasses().isPresent()) {
|
||||
markClientOnlyClasses();
|
||||
}
|
||||
|
||||
if (!injectAccessWidener()) {
|
||||
remapAccessWidener();
|
||||
}
|
||||
@@ -400,6 +405,15 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
}
|
||||
|
||||
private void markClientOnlyClasses() throws IOException {
|
||||
final Stream<Pair<String, ZipUtils.UnsafeUnaryOperator<byte[]>>> tranformers = getParameters().getClientOnlyClasses().get().stream()
|
||||
.map(s -> new Pair<>(s,
|
||||
(ZipUtils.AsmClassOperator) classVisitor -> SidedClassVisitor.CLIENT.insertApplyVisitor(null, classVisitor)
|
||||
));
|
||||
|
||||
ZipUtils.transform(outputFile, tranformers);
|
||||
}
|
||||
|
||||
private boolean injectAccessWidener() throws IOException {
|
||||
if (!getParameters().getInjectAccessWidener().isPresent()) return false;
|
||||
|
||||
@@ -518,8 +532,8 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
int count = ZipUtils.transform(outputFile, Map.of(MANIFEST_PATH, bytes -> {
|
||||
var manifest = new Manifest(new ByteArrayInputStream(bytes));
|
||||
|
||||
getParameters().getJarManifestService().get().apply(manifest);
|
||||
manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", getParameters().getTargetNamespace().get());
|
||||
getParameters().getJarManifestService().get().apply(manifest, getParameters().getManifestAttributes().get());
|
||||
manifest.getMainAttributes().putValue(MANIFEST_NAMESPACE_KEY, getParameters().getTargetNamespace().get());
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
manifest.write(out);
|
||||
@@ -546,6 +560,50 @@ public abstract class RemapJarTask extends AbstractRemapJarTask {
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getClientOnlyJarEntries() {
|
||||
final SourceSet clientSourceSet = MinecraftSourceSets.Split.getClientSourceSet(getProject());
|
||||
|
||||
final ConfigurableFileCollection output = getProject().getObjects().fileCollection();
|
||||
output.from(clientSourceSet.getOutput().getClassesDirs());
|
||||
output.from(clientSourceSet.getOutput().getResourcesDir());
|
||||
|
||||
final List<String> rootPaths = new ArrayList<>();
|
||||
|
||||
rootPaths.addAll(getRootPaths(clientSourceSet.getOutput().getClassesDirs().getFiles()));
|
||||
rootPaths.addAll(getRootPaths(Set.of(Objects.requireNonNull(clientSourceSet.getOutput().getResourcesDir()))));
|
||||
|
||||
return output.getAsFileTree().getFiles().stream()
|
||||
.map(relativePath(rootPaths))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static List<String> getRootPaths(Set<File> files) {
|
||||
return files.stream()
|
||||
.map(root -> {
|
||||
String rootPath = root.getAbsolutePath().replace("\\", "/");
|
||||
|
||||
if (rootPath.charAt(rootPath.length() - 1) != '/') {
|
||||
rootPath += '/';
|
||||
}
|
||||
|
||||
return rootPath;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static Function<File, String> relativePath(List<String> rootPaths) {
|
||||
return file -> {
|
||||
String s = file.getAbsolutePath().replace("\\", "/");
|
||||
|
||||
for (String rootPath : rootPaths) {
|
||||
if (s.startsWith(rootPath)) {
|
||||
s = s.substring(rootPath.length());
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
};
|
||||
}
|
||||
|
||||
@Internal
|
||||
public TinyRemapperService getTinyRemapperService() {
|
||||
return tinyRemapperService.get();
|
||||
|
||||
@@ -41,14 +41,24 @@ import org.gradle.api.logging.configuration.ConsoleOutput;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta;
|
||||
import net.fabricmc.loom.configuration.providers.minecraft.mapped.MappedMinecraftProvider;
|
||||
import net.fabricmc.loom.task.AbstractLoomTask;
|
||||
import net.fabricmc.loom.util.PropertyUtil;
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper;
|
||||
|
||||
public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
@TaskAction
|
||||
public void run() throws IOException {
|
||||
final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath();
|
||||
|
||||
final MinecraftVersionMeta versionInfo = getExtension().getMinecraftProvider().getVersionInfo();
|
||||
File assetsDirectory = new File(getExtension().getFiles().getUserCache(), "assets");
|
||||
|
||||
if (versionInfo.assets().equals("legacy")) {
|
||||
assetsDirectory = new File(assetsDirectory, "/legacy/" + versionInfo.id());
|
||||
}
|
||||
|
||||
final LaunchConfig launchConfig = new LaunchConfig()
|
||||
.property(!getExtension().isQuilt() ? "fabric.development" : "loader.development", "true")
|
||||
.property(!getExtension().isQuilt() ? "fabric.remapClasspathFile" : "loader.remapClasspathFile", getExtension().getFiles().getRemapClasspathFile().getAbsolutePath())
|
||||
@@ -58,12 +68,21 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
.property("client", "java.library.path", nativesPath)
|
||||
.property("client", "org.lwjgl.librarypath", nativesPath);
|
||||
|
||||
if (!getExtension().isForge()) {
|
||||
if (!getExtension().isForge())
|
||||
launchConfig
|
||||
.argument("client", "--assetIndex")
|
||||
.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion()))
|
||||
.argument("client", "--assetsDir")
|
||||
.argument("client", new File(getExtension().getFiles().getUserCache(), "assets").getAbsolutePath());
|
||||
.argument("client", assetsDirectory.getAbsolutePath());
|
||||
|
||||
if (getExtension().areEnvironmentSourceSetsSplit()) {
|
||||
launchConfig.property("client", "fabric.gameJarPath.client", getGameJarPath("client"));
|
||||
launchConfig.property("fabric.gameJarPath", getGameJarPath("common"));
|
||||
}
|
||||
|
||||
if (!getExtension().getMods().isEmpty()) {
|
||||
launchConfig.property("fabric.classPathGroups", getClassPathGroups());
|
||||
}
|
||||
}
|
||||
|
||||
if (getExtension().isQuilt()) {
|
||||
@@ -132,6 +151,29 @@ public abstract class GenerateDLIConfigTask extends AbstractLoomTask {
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
private String getGameJarPath(String env) {
|
||||
MappedMinecraftProvider.Split split = (MappedMinecraftProvider.Split) getExtension().getNamedMinecraftProvider();
|
||||
|
||||
return switch (env) {
|
||||
case "client" -> split.getClientOnlyJar().toAbsolutePath().toString();
|
||||
case "common" -> split.getCommonJar().toAbsolutePath().toString();
|
||||
default -> throw new UnsupportedOperationException();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See: https://github.com/FabricMC/fabric-loader/pull/585.
|
||||
*/
|
||||
private String getClassPathGroups() {
|
||||
return getExtension().getMods().stream()
|
||||
.map(modSettings ->
|
||||
SourceSetHelper.getClasspath(modSettings, getProject()).stream()
|
||||
.map(File::getAbsolutePath)
|
||||
.collect(Collectors.joining(File.pathSeparator))
|
||||
)
|
||||
.collect(Collectors.joining(File.pathSeparator+File.pathSeparator));
|
||||
}
|
||||
|
||||
public static class LaunchConfig {
|
||||
private final Map<String, List<String>> values = new HashMap<>();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -25,6 +25,7 @@
|
||||
package net.fabricmc.loom.task.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
@@ -70,7 +71,7 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
||||
});
|
||||
}
|
||||
|
||||
public void apply(Manifest manifest) {
|
||||
public void apply(Manifest manifest, Map<String, String> extraValues) {
|
||||
// Don't set when running the reproducible build tests as it will break them when anything updates
|
||||
if (Boolean.getBoolean("loom.test.reproducible")) {
|
||||
return;
|
||||
@@ -91,6 +92,10 @@ public abstract class JarManifestService implements BuildService<JarManifestServ
|
||||
attributes.putValue("Fabric-Mixin-Version", p.getMixinVersion().get().version());
|
||||
attributes.putValue("Fabric-Mixin-Group", p.getMixinVersion().get().group());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : extraValues.entrySet()) {
|
||||
attributes.putValue(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> getLoaderVersion(Project project) {
|
||||
|
||||
@@ -39,10 +39,13 @@ import dev.architectury.tinyremapper.IMappingProvider;
|
||||
import dev.architectury.tinyremapper.InputTag;
|
||||
import dev.architectury.tinyremapper.TinyRemapper;
|
||||
import org.gradle.api.Project;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension;
|
||||
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension;
|
||||
import net.fabricmc.loom.task.AbstractRemapJarTask;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspath;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinClasspathService;
|
||||
import net.fabricmc.loom.util.kotlin.KotlinRemapperClassloader;
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
@@ -54,15 +57,15 @@ public class TinyRemapperService implements SharedService {
|
||||
final LoomGradleExtension extension = LoomGradleExtension.get(project);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get();
|
||||
final boolean useKotlinExtension = project.getPluginManager().hasPlugin("org.jetbrains.kotlin.jvm");
|
||||
final @Nullable KotlinClasspathService kotlinClasspathService = KotlinClasspathService.getOrCreateIfRequired(project);
|
||||
|
||||
// Generates an id that is used to share the remapper across projects. This tasks in the remap jar task name to handle custom remap jar tasks separately.
|
||||
final var joiner = new StringJoiner(":");
|
||||
joiner.add(extension.getMappingsProvider().getBuildServiceName("remapJarService", from, to));
|
||||
joiner.add(remapJarTask.getName());
|
||||
|
||||
if (useKotlinExtension) {
|
||||
joiner.add("kotlin");
|
||||
if (kotlinClasspathService != null) {
|
||||
joiner.add("kotlin-" + kotlinClasspathService.version());
|
||||
}
|
||||
|
||||
if (remapJarTask.getRemapperIsolation().get()) {
|
||||
@@ -76,10 +79,10 @@ public class TinyRemapperService implements SharedService {
|
||||
mappings.add(MappingsService.createDefault(project, from, to).getMappingsProvider());
|
||||
|
||||
if (legacyMixin) {
|
||||
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project), extension.getMappingsProvider()).getMappingProvider("named", "intermediary"));
|
||||
mappings.add(MixinMappingsService.getService(SharedServiceManager.get(project), extension.getMappingsProvider()).getMappingProvider(from, to));
|
||||
}
|
||||
|
||||
return new TinyRemapperService(mappings, !legacyMixin, useKotlinExtension);
|
||||
return new TinyRemapperService(mappings, !legacyMixin, kotlinClasspathService);
|
||||
});
|
||||
|
||||
service.readClasspath(remapJarTask.getClasspath().getFiles().stream().map(File::toPath).toList());
|
||||
@@ -88,12 +91,14 @@ public class TinyRemapperService implements SharedService {
|
||||
}
|
||||
|
||||
private TinyRemapper tinyRemapper;
|
||||
@Nullable
|
||||
private KotlinRemapperClassloader kotlinRemapperClassloader;
|
||||
private final Map<String, InputTag> inputTagMap = new HashMap<>();
|
||||
private final HashSet<Path> classpath = new HashSet<>();
|
||||
// Set to true once remapping has started, once set no inputs can be read.
|
||||
private boolean isRemapping = false;
|
||||
|
||||
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, boolean useKotlinExtension) {
|
||||
public TinyRemapperService(List<IMappingProvider> mappings, boolean useMixinExtension, @Nullable KotlinClasspath kotlinClasspath) {
|
||||
TinyRemapper.Builder builder = TinyRemapper.newRemapper();
|
||||
|
||||
for (IMappingProvider provider : mappings) {
|
||||
@@ -104,8 +109,9 @@ public class TinyRemapperService implements SharedService {
|
||||
builder.extension(new dev.architectury.tinyremapper.extension.mixin.MixinExtension());
|
||||
}
|
||||
|
||||
if (useKotlinExtension) {
|
||||
builder.extension(KotlinMetadataTinyRemapperExtension.INSTANCE);
|
||||
if (kotlinClasspath != null) {
|
||||
kotlinRemapperClassloader = KotlinRemapperClassloader.create(kotlinClasspath);
|
||||
builder.extension(kotlinRemapperClassloader.getTinyRemapperExtension());
|
||||
}
|
||||
|
||||
tinyRemapper = builder.build();
|
||||
@@ -156,5 +162,9 @@ public class TinyRemapperService implements SharedService {
|
||||
tinyRemapper.finish();
|
||||
tinyRemapper = null;
|
||||
}
|
||||
|
||||
if (kotlinRemapperClassloader != null) {
|
||||
kotlinRemapperClassloader.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ public class Constants {
|
||||
public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries";
|
||||
public static final String MINECRAFT_RUNTIME_DEPENDENCIES = "minecraftRuntimeOnlyLibraries";
|
||||
public static final String MINECRAFT_NATIVES = "minecraftNatives";
|
||||
public static final String MINECRAFT_NAMED = "minecraftNamed";
|
||||
public static final String MAPPINGS = "mappings";
|
||||
public static final String MAPPINGS_FINAL = "mappingsFinal";
|
||||
public static final String LOADER_DEPENDENCIES = "loaderLibraries";
|
||||
@@ -178,6 +177,11 @@ public class Constants {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CustomModJsonKeys {
|
||||
public static final String INJECTED_INTERFACE = "loom:injected_interfaces";
|
||||
public static final String PROVIDED_JAVADOC = "loom:provided_javadoc";
|
||||
}
|
||||
|
||||
public static final class Forge {
|
||||
public static final String LAUNCH_TESTING = "net.minecraftforge.userdev.LaunchTesting";
|
||||
public static final String ACCESS_TRANSFORMER_PATH = "META-INF/accesstransformer.cfg";
|
||||
|
||||
@@ -35,7 +35,6 @@ import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.Files;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.logging.Logger;
|
||||
@@ -120,13 +119,6 @@ public class HashedDownloadUtil {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (!Checksum.equals(to, expectedHash)) {
|
||||
String actualHash = Files.asByteSource(to).hash(Hashing.sha1()).toString();
|
||||
delete(to);
|
||||
|
||||
throw new IOException(String.format("Downloaded file from %s to %s and got unexpected hash of %s expected %s", from, to, actualHash, expectedHash));
|
||||
}
|
||||
|
||||
saveSha1(to, expectedHash, logger);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.analysis.Analyzer;
|
||||
import org.objectweb.asm.util.ASMifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* It's quite common for other plugins to shade these libraries, thus the wrong version is used.
|
||||
* This file logs out the version + location of each library as a debugging aid.
|
||||
*
|
||||
* <p>gradlew buildEnvironment is a useful command to run alongside this.
|
||||
*/
|
||||
public final class LibraryLocationLogger {
|
||||
private static final List<Class<?>> libraryClasses = List.of(
|
||||
KotlinClassMetadata.class,
|
||||
ClassVisitor.class,
|
||||
Analyzer.class,
|
||||
ClassRemapper.class,
|
||||
ClassNode.class,
|
||||
ASMifier.class,
|
||||
ObjectMapper.class,
|
||||
Gson.class,
|
||||
Preconditions.class,
|
||||
FileUtils.class
|
||||
);
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LibraryLocationLogger.class);
|
||||
|
||||
public static void logLibraryVersions() {
|
||||
for (Class<?> clazz : libraryClasses) {
|
||||
LOGGER.info("({}) with version ({}) was loaded from ({})",
|
||||
clazz.getName(),
|
||||
clazz.getPackage().getImplementationVersion(),
|
||||
clazz.getProtectionDomain().getCodeSource().getLocation().getPath()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private LibraryLocationLogger() {
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2021 FabricMC
|
||||
* Copyright (c) 2016-2022 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
|
||||
@@ -25,21 +25,50 @@
|
||||
package net.fabricmc.loom.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
|
||||
public final class ModUtils {
|
||||
private ModUtils() {
|
||||
}
|
||||
|
||||
public static boolean isMod(File input, ModPlatform platform) {
|
||||
public static boolean isMod(File file, ModPlatform platform) {
|
||||
return isMod(file.toPath());
|
||||
}
|
||||
|
||||
public static boolean isMod(Path input, ModPlatform platform) {
|
||||
if (platform == ModPlatform.FORGE) {
|
||||
return ZipUtils.contains(input.toPath(), "META-INF/mods.toml");
|
||||
} else if (platform == ModPlatform.QUILT) {
|
||||
return ZipUtils.contains(input.toPath(), "quilt.mod.json");
|
||||
}
|
||||
|
||||
return ZipUtils.contains(input.toPath(), "fabric.mod.json");
|
||||
return ZipUtils.contains(input, "fabric.mod.json");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JsonObject getFabricModJson(Path path) {
|
||||
final byte[] modJsonBytes;
|
||||
|
||||
try {
|
||||
modJsonBytes = ZipUtils.unpackNullable(path, "fabric.mod.json");
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to extract fabric.mod.json from " + path, e);
|
||||
}
|
||||
|
||||
if (modJsonBytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return LoomGradlePlugin.GSON.fromJson(new String(modJsonBytes, StandardCharsets.UTF_8), JsonObject.class);
|
||||
}
|
||||
|
||||
public static boolean shouldRemapMod(Logger logger, File input, Object id, ModPlatform platform, String config) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -41,6 +41,7 @@ public final class SidedClassVisitor extends ClassVisitor {
|
||||
private static final String SIDE_DESCRIPTOR = "Lnet/fabricmc/api/EnvType;";
|
||||
|
||||
private final String side;
|
||||
private boolean hasExisting = false;
|
||||
|
||||
private SidedClassVisitor(String side, ClassVisitor next) {
|
||||
super(Constants.ASM_VERSION, next);
|
||||
@@ -48,11 +49,22 @@ public final class SidedClassVisitor extends ClassVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
|
||||
if (ENVIRONMENT_DESCRIPTOR.equals(descriptor)) {
|
||||
hasExisting = true;
|
||||
}
|
||||
|
||||
final AnnotationVisitor annotationVisitor = visitAnnotation(ENVIRONMENT_DESCRIPTOR, true);
|
||||
annotationVisitor.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT));
|
||||
annotationVisitor.visitEnd();
|
||||
return super.visitAnnotation(descriptor, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!hasExisting) {
|
||||
final AnnotationVisitor annotationVisitor = visitAnnotation(ENVIRONMENT_DESCRIPTOR, true);
|
||||
annotationVisitor.visitEnum("value", SIDE_DESCRIPTOR, side.toUpperCase(Locale.ROOT));
|
||||
annotationVisitor.visitEnd();
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2021 FabricMC
|
||||
* Copyright (c) 2021-2022 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
|
||||
@@ -44,6 +44,9 @@ import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
|
||||
@@ -231,6 +234,20 @@ public class ZipUtils {
|
||||
T apply(T arg) throws IOException;
|
||||
}
|
||||
|
||||
public interface AsmClassOperator extends UnsafeUnaryOperator<byte[]> {
|
||||
ClassVisitor visit(ClassVisitor classVisitor);
|
||||
|
||||
@Override
|
||||
default byte[] apply(byte[] arg) throws IOException {
|
||||
final ClassReader reader = new ClassReader(arg);
|
||||
final ClassWriter writer = new ClassWriter(0);
|
||||
|
||||
reader.accept(visit(writer), 0);
|
||||
|
||||
return writer.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> Map<String, UnsafeUnaryOperator<T>> collectTransformersStream(Stream<Pair<String, UnsafeUnaryOperator<T>>> transforms) {
|
||||
Map<String, UnsafeUnaryOperator<T>> map = new HashMap<>();
|
||||
Iterator<Pair<String, UnsafeUnaryOperator<T>>> iterator = transforms.iterator();
|
||||
|
||||
172
src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java
Normal file
172
src/main/java/net/fabricmc/loom/util/gradle/SourceSetHelper.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetOutput;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import net.fabricmc.loom.api.ModSettings;
|
||||
import net.fabricmc.loom.configuration.ide.idea.IdeaUtils;
|
||||
|
||||
public final class SourceSetHelper {
|
||||
@VisibleForTesting
|
||||
@Language("xpath")
|
||||
public static final String IDEA_OUTPUT_XPATH = "/project/component[@name='ProjectRootManager']/output/@url";
|
||||
|
||||
private SourceSetHelper() {
|
||||
}
|
||||
|
||||
public static List<File> getClasspath(ModSettings modSettings, Project project) {
|
||||
final List<File> files = new ArrayList<>();
|
||||
|
||||
files.addAll(modSettings.getModSourceSets().get().stream()
|
||||
.flatMap(sourceSet -> getClasspath(sourceSet, project).stream())
|
||||
.toList());
|
||||
files.addAll(modSettings.getModFiles().getFiles());
|
||||
|
||||
return Collections.unmodifiableList(files);
|
||||
}
|
||||
|
||||
public static List<File> getClasspath(SourceSet sourceSet, Project project) {
|
||||
final List<File> classpath = getGradleClasspath(sourceSet);
|
||||
|
||||
classpath.addAll(getIdeaClasspath(sourceSet, project));
|
||||
classpath.addAll(getEclipseClasspath(sourceSet, project));
|
||||
classpath.addAll(getVscodeClasspath(sourceSet, project));
|
||||
|
||||
return classpath;
|
||||
}
|
||||
|
||||
private static List<File> getGradleClasspath(SourceSet sourceSet) {
|
||||
final SourceSetOutput output = sourceSet.getOutput();
|
||||
final File resources = output.getResourcesDir();
|
||||
|
||||
final List<File> classpath = new ArrayList<>();
|
||||
|
||||
classpath.addAll(output.getClassesDirs().getFiles());
|
||||
|
||||
if (resources != null) {
|
||||
classpath.add(resources);
|
||||
}
|
||||
|
||||
return classpath;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static List<File> getIdeaClasspath(SourceSet sourceSet, Project project) {
|
||||
final File projectDir = project.getRootDir();
|
||||
final File dotIdea = new File(projectDir, ".idea");
|
||||
|
||||
if (!dotIdea.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final File miscXml = new File(dotIdea, "misc.xml");
|
||||
|
||||
if (!miscXml.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String outputDirUrl = evaluateXpath(miscXml, IDEA_OUTPUT_XPATH);
|
||||
|
||||
if (outputDirUrl == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
outputDirUrl = outputDirUrl.replace("$PROJECT_DIR$", projectDir.getAbsolutePath());
|
||||
outputDirUrl = outputDirUrl.replaceAll("^file:", "");
|
||||
|
||||
final File productionDir = new File(outputDirUrl, "production");
|
||||
final File outputDir = new File(productionDir, IdeaUtils.getIdeaModuleName(project, sourceSet));
|
||||
|
||||
return Collections.singletonList(outputDir);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String evaluateXpath(File file, @Language("xpath") String expression) {
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
return xpath.evaluate(expression, new InputSource(fis));
|
||||
} catch (XPathExpressionException e) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static List<File> getEclipseClasspath(SourceSet sourceSet, Project project) {
|
||||
// Somewhat of a guess, I'm unsure if this is correct for multi-project builds
|
||||
final File projectDir = project.getProjectDir();
|
||||
final File classpath = new File(projectDir, ".classpath");
|
||||
|
||||
if (!classpath.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return getBinDirClasspath(projectDir, sourceSet);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static List<File> getVscodeClasspath(SourceSet sourceSet, Project project) {
|
||||
// Somewhat of a guess, I'm unsure if this is correct for multi-project builds
|
||||
final File projectDir = project.getProjectDir();
|
||||
final File dotVscode = new File(projectDir, ".vscode");
|
||||
|
||||
if (!dotVscode.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return getBinDirClasspath(projectDir, sourceSet);
|
||||
}
|
||||
|
||||
private static List<File> getBinDirClasspath(File projectDir, SourceSet sourceSet) {
|
||||
final File binDir = new File(projectDir, "bin");
|
||||
|
||||
if (!binDir.exists()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.singletonList(new File(binDir, sourceSet.getName()));
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2016-2021 FabricMC
|
||||
* Copyright (c) 2022 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
|
||||
@@ -22,8 +22,13 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.configuration.providers.minecraft.assets;
|
||||
package net.fabricmc.loom.util.kotlin;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public record AssetObject(String hash, long size) {
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
|
||||
public interface KotlinClasspath {
|
||||
String version();
|
||||
|
||||
Set<URL> classpath();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util.kotlin;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.fabricmc.loom.util.service.SharedService;
|
||||
import net.fabricmc.loom.util.service.SharedServiceManager;
|
||||
|
||||
public record KotlinClasspathService(Set<URL> classpath, String version) implements KotlinClasspath, SharedService {
|
||||
@Nullable
|
||||
public static KotlinClasspathService getOrCreateIfRequired(Project project) {
|
||||
if (!KotlinPluginUtils.hasKotlinPlugin(project)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getOrCreate(project, KotlinPluginUtils.getKotlinPluginVersion(project), KotlinPluginUtils.getKotlinMetadataVersion());
|
||||
}
|
||||
|
||||
public static synchronized KotlinClasspathService getOrCreate(Project project, String kotlinVersion, String kotlinMetadataVersion) {
|
||||
final String id = "kotlinclasspath:%s:%s".formatted(kotlinVersion, kotlinMetadataVersion);
|
||||
final SharedServiceManager sharedServiceManager = SharedServiceManager.get(project);
|
||||
return sharedServiceManager.getOrCreateService(id, () -> create(project, kotlinVersion, kotlinMetadataVersion));
|
||||
}
|
||||
|
||||
private static KotlinClasspathService create(Project project, String kotlinVersion, String kotlinMetadataVersion) {
|
||||
// Create a detached config to resolve the kotlin std lib for the provided version.
|
||||
Configuration detachedConfiguration = project.getConfigurations().detachedConfiguration(
|
||||
project.getDependencies().create("org.jetbrains.kotlin:kotlin-stdlib:" + kotlinVersion),
|
||||
// Load kotlinx-metadata-jvm like this to work around: https://github.com/gradle/gradle/issues/14727
|
||||
project.getDependencies().create("org.jetbrains.kotlinx:kotlinx-metadata-jvm:" + kotlinMetadataVersion)
|
||||
);
|
||||
|
||||
Set<URL> classpath = detachedConfiguration.getFiles().stream()
|
||||
.map(file -> {
|
||||
try {
|
||||
return file.toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}).collect(Collectors.toSet());;
|
||||
|
||||
return new KotlinClasspathService(classpath, kotlinVersion);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util.kotlin;
|
||||
|
||||
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||
|
||||
public interface KotlinMetadataTinyRemapperExtension extends TinyRemapper.ApplyVisitorProvider, TinyRemapper.Extension {
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util.kotlin;
|
||||
|
||||
import kotlinx.metadata.jvm.KotlinClassMetadata;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
public class KotlinPluginUtils {
|
||||
private static final String KOTLIN_PLUGIN_ID = "org.jetbrains.kotlin.jvm";
|
||||
|
||||
public static boolean hasKotlinPlugin(Project project) {
|
||||
return project.getPluginManager().hasPlugin(KOTLIN_PLUGIN_ID);
|
||||
}
|
||||
|
||||
public static String getKotlinPluginVersion(Project project) {
|
||||
Class<?> koltinPluginClass = project.getPlugins().getPlugin(KOTLIN_PLUGIN_ID).getClass();
|
||||
return koltinPluginClass.getPackage().getImplementationVersion().split("-")[0];
|
||||
}
|
||||
|
||||
public static String getKotlinMetadataVersion() {
|
||||
return KotlinClassMetadata.class.getPackage().getImplementationVersion();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2022 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 net.fabricmc.loom.util.kotlin;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.fabricmc.loom.LoomGradlePlugin;
|
||||
import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtensionImpl;
|
||||
|
||||
/**
|
||||
* Used to run the Kotlin remapper with a specific version of Koltin that may not match the kotlin version included with gradle.
|
||||
*/
|
||||
public class KotlinRemapperClassloader extends URLClassLoader {
|
||||
// Packages that should be loaded from the gradle plugin classloader.
|
||||
private static final List<String> PARENT_PACKAGES = List.of(
|
||||
"net.fabricmc.tinyremapper",
|
||||
"net.fabricmc.loom.util.kotlin",
|
||||
"org.objectweb.asm",
|
||||
"org.slf4j"
|
||||
);
|
||||
|
||||
private KotlinRemapperClassloader(URL[] urls) {
|
||||
super(urls, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (PARENT_PACKAGES.stream().anyMatch(name::startsWith)) {
|
||||
return LoomGradlePlugin.class.getClassLoader().loadClass(name);
|
||||
}
|
||||
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
|
||||
public static KotlinRemapperClassloader create(KotlinClasspath classpathProvider) {
|
||||
// Include the libraries that are not on the kotlin classpath.
|
||||
final Stream<URL> loomUrls = getClassUrls(
|
||||
KotlinMetadataTinyRemapperExtensionImpl.class // Loom
|
||||
);
|
||||
|
||||
final URL[] urls = Stream.concat(
|
||||
loomUrls,
|
||||
classpathProvider.classpath().stream()
|
||||
).toArray(URL[]::new);
|
||||
|
||||
return new KotlinRemapperClassloader(urls);
|
||||
}
|
||||
|
||||
private static Stream<URL> getClassUrls(Class<?>... classes) {
|
||||
return Arrays.stream(classes).map(klass -> klass.getProtectionDomain().getCodeSource().getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the {@link KotlinMetadataTinyRemapperExtensionImpl} class on the new classloader.
|
||||
*/
|
||||
public KotlinMetadataTinyRemapperExtension getTinyRemapperExtension() {
|
||||
try {
|
||||
Class<?> klass = this.loadClass(KotlinMetadataTinyRemapperExtensionImpl.class.getCanonicalName());
|
||||
return (KotlinMetadataTinyRemapperExtension) klass.getField("INSTANCE").get(null);
|
||||
} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException("Failed to create instance", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user