Support ARM natives, rewrite native handling and misc cleanup. (#554)
* Rewrite natives handling, upgrade LWJGL on ARM machines. * Remove old natives override hack, should now always be done via gradle. * Use "idea" everywhere * Add server specific libraries onto their own classpath. Includes misc code cleanup. * Start on writing the excluded server libs. * Gradle deprecation fixes, and misc cleanup * Add support mod. * Make native support mod none transitive. * Update gradle.
This commit is contained in:
		
							parent
							
								
									4ace257c37
								
							
						
					
					
						commit
						5a16440c1e
					
				
					 53 changed files with 905 additions and 470 deletions
				
			
		
							
								
								
									
										10
									
								
								.github/workflows/test-push.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/test-push.yml
									
									
									
									
										vendored
									
									
								
							|  | @ -13,7 +13,7 @@ jobs: | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v2 | ||||||
|       - uses: gradle/wrapper-validation-action@v1 |       - uses: gradle/wrapper-validation-action@v1 | ||||||
|       - run: gradle build check -x test --stacktrace |       - run: gradle build check -x test --stacktrace --warning-mode fail | ||||||
| 
 | 
 | ||||||
|   # This job is used to feed the test matrix of next job to allow the tests to run in parallel |   # This job is used to feed the test matrix of next job to allow the tests to run in parallel | ||||||
|   prepare_test_matrix: |   prepare_test_matrix: | ||||||
|  | @ -27,7 +27,7 @@ jobs: | ||||||
| 
 | 
 | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v2 | ||||||
|       - run: gradle writeActionsTestMatrix --stacktrace |       - run: gradle writeActionsTestMatrix --stacktrace --warning-mode fail | ||||||
|       - |       - | ||||||
|         id: set-matrix |         id: set-matrix | ||||||
|         run: echo "::set-output name=matrix::$(cat build/test_matrix.json)" |         run: echo "::set-output name=matrix::$(cat build/test_matrix.json)" | ||||||
|  | @ -51,7 +51,7 @@ jobs: | ||||||
| 
 | 
 | ||||||
|     steps: |     steps: | ||||||
|       - uses: actions/checkout@v2 |       - uses: actions/checkout@v2 | ||||||
|       - run: gradle test --tests ${{ matrix.test }} --stacktrace |       - run: gradle test --tests ${{ matrix.test }} --stacktrace --warning-mode fail | ||||||
|         env: |         env: | ||||||
|           TEST_WARNING_MODE: fail |           TEST_WARNING_MODE: fail | ||||||
| 
 | 
 | ||||||
|  | @ -78,7 +78,7 @@ jobs: | ||||||
|         uses: actions/setup-java@v1 |         uses: actions/setup-java@v1 | ||||||
|         with: |         with: | ||||||
|           java-version: ${{ matrix.java }} |           java-version: ${{ matrix.java }} | ||||||
|       - run: ./gradlew test --tests ${{ matrix.test }} --stacktrace |       - run: ./gradlew test --tests ${{ matrix.test }} --stacktrace --warning-mode fail | ||||||
|         env: |         env: | ||||||
|           TEST_WARNING_MODE: fail |           TEST_WARNING_MODE: fail | ||||||
| 
 | 
 | ||||||
|  | @ -105,7 +105,7 @@ jobs: | ||||||
|         with: |         with: | ||||||
|           java-version: ${{ matrix.java }} |           java-version: ${{ matrix.java }} | ||||||
| 
 | 
 | ||||||
|       - run: ./gradlew test --tests *ReproducibleBuildTest --stacktrace |       - run: ./gradlew test --tests *ReproducibleBuildTest --stacktrace --warning-mode fail | ||||||
| 
 | 
 | ||||||
|       - uses: actions/upload-artifact@v2 |       - uses: actions/upload-artifact@v2 | ||||||
|         if: ${{ failure() }} |         if: ${{ failure() }} | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							|  | @ -37,6 +37,9 @@ repositories { | ||||||
| 		url = 'https://maven.fabricmc.net/' | 		url = 'https://maven.fabricmc.net/' | ||||||
| 	} | 	} | ||||||
| 	mavenCentral() | 	mavenCentral() | ||||||
|  | 	maven { | ||||||
|  | 		url = 'https://plugins.gradle.org/m2/' | ||||||
|  | 	} | ||||||
| 	mavenLocal() | 	mavenLocal() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -92,6 +95,9 @@ dependencies { | ||||||
| 	// source code remapping | 	// source code remapping | ||||||
| 	implementation ('net.fabricmc:mercury:0.2.4') | 	implementation ('net.fabricmc:mercury:0.2.4') | ||||||
| 
 | 
 | ||||||
|  | 	// IDEA support | ||||||
|  | 	implementation ('gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:1.1.1') | ||||||
|  | 
 | ||||||
| 	// Kapt integration | 	// Kapt integration | ||||||
| 	compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0') | 	compileOnly('org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0') | ||||||
| 
 | 
 | ||||||
|  | @ -162,8 +168,8 @@ jacoco { | ||||||
| jacocoTestReport { | jacocoTestReport { | ||||||
| 	dependsOn test | 	dependsOn test | ||||||
| 	reports { | 	reports { | ||||||
| 		xml.enabled false | 		xml.required = false | ||||||
| 		csv.enabled false | 		csv.required = false | ||||||
| 		html.destination file("${buildDir}/jacocoHtml") | 		html.destination file("${buildDir}/jacocoHtml") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							|  | @ -1,5 +1,5 @@ | ||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.2-all.zip | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ import java.util.function.Supplier; | ||||||
| 
 | 
 | ||||||
| import org.cadixdev.lorenz.MappingSet; | import org.cadixdev.lorenz.MappingSet; | ||||||
| import org.cadixdev.mercury.Mercury; | import org.cadixdev.mercury.Mercury; | ||||||
|  | import org.gradle.api.Action; | ||||||
| import org.gradle.api.NamedDomainObjectProvider; | import org.gradle.api.NamedDomainObjectProvider; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.artifacts.Configuration; | import org.gradle.api.artifacts.Configuration; | ||||||
|  | @ -54,7 +55,12 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { | ||||||
| 
 | 
 | ||||||
| 	LoomFiles getFiles(); | 	LoomFiles getFiles(); | ||||||
| 
 | 
 | ||||||
| 	NamedDomainObjectProvider<Configuration> createLazyConfiguration(String name); | 	default NamedDomainObjectProvider<Configuration> createLazyConfiguration(String name) { | ||||||
|  | 		return createLazyConfiguration(name, config -> { | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	NamedDomainObjectProvider<Configuration> createLazyConfiguration(String name, Action<? super Configuration> configurationAction); | ||||||
| 
 | 
 | ||||||
| 	NamedDomainObjectProvider<Configuration> getLazyConfigurationProvider(String name); | 	NamedDomainObjectProvider<Configuration> getLazyConfigurationProvider(String name); | ||||||
| 
 | 
 | ||||||
|  | @ -94,10 +100,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { | ||||||
| 
 | 
 | ||||||
| 	boolean isRootProject(); | 	boolean isRootProject(); | ||||||
| 
 | 
 | ||||||
| 	default boolean ideSync() { |  | ||||||
| 		return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false")); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	default String getIntermediaryUrl(String minecraftVersion) { | 	default String getIntermediaryUrl(String minecraftVersion) { | ||||||
| 		return String.format(this.getIntermediaryUrl().get(), minecraftVersion); | 		return String.format(this.getIntermediaryUrl().get(), minecraftVersion); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -40,6 +40,7 @@ import net.fabricmc.loom.configuration.CompileConfiguration; | ||||||
| import net.fabricmc.loom.configuration.FabricApiExtension; | import net.fabricmc.loom.configuration.FabricApiExtension; | ||||||
| import net.fabricmc.loom.configuration.MavenPublication; | import net.fabricmc.loom.configuration.MavenPublication; | ||||||
| import net.fabricmc.loom.configuration.ide.IdeConfiguration; | import net.fabricmc.loom.configuration.ide.IdeConfiguration; | ||||||
|  | import net.fabricmc.loom.configuration.ide.idea.IdeaConfiguration; | ||||||
| import net.fabricmc.loom.decompilers.DecompilerConfiguration; | import net.fabricmc.loom.decompilers.DecompilerConfiguration; | ||||||
| import net.fabricmc.loom.extension.LoomFiles; | import net.fabricmc.loom.extension.LoomFiles; | ||||||
| import net.fabricmc.loom.extension.LoomGradleExtensionImpl; | import net.fabricmc.loom.extension.LoomGradleExtensionImpl; | ||||||
|  | @ -84,5 +85,6 @@ public class LoomGradlePlugin implements BootstrappedPlugin { | ||||||
| 		MavenPublication.configure(project); | 		MavenPublication.configure(project); | ||||||
| 		LoomTasks.registerTasks(project); | 		LoomTasks.registerTasks(project); | ||||||
| 		DecompilerConfiguration.setup(project); | 		DecompilerConfiguration.setup(project); | ||||||
|  | 		IdeaConfiguration.setup(project); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -27,9 +27,10 @@ package net.fabricmc.loom.api.mappings.layered.spec; | ||||||
| import groovy.lang.Closure; | import groovy.lang.Closure; | ||||||
| import groovy.lang.DelegatesTo; | import groovy.lang.DelegatesTo; | ||||||
| import org.gradle.api.Action; | import org.gradle.api.Action; | ||||||
| import org.gradle.util.ConfigureUtil; |  | ||||||
| import org.jetbrains.annotations.ApiStatus; | import org.jetbrains.annotations.ApiStatus; | ||||||
| 
 | 
 | ||||||
|  | import net.fabricmc.loom.util.ClosureAction; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * Used to configure a layered mapping spec. |  * Used to configure a layered mapping spec. | ||||||
|  */ |  */ | ||||||
|  | @ -52,7 +53,7 @@ public interface LayeredMappingSpecBuilder { | ||||||
| 	 */ | 	 */ | ||||||
| 	@SuppressWarnings("rawtypes") | 	@SuppressWarnings("rawtypes") | ||||||
| 	default LayeredMappingSpecBuilder officialMojangMappings(@DelegatesTo(value = MojangMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { | 	default LayeredMappingSpecBuilder officialMojangMappings(@DelegatesTo(value = MojangMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { | ||||||
| 		return officialMojangMappings(mojangMappingsSpecBuilder -> ConfigureUtil.configure(closure, mojangMappingsSpecBuilder)); | 		return officialMojangMappings(new ClosureAction<>(closure)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -66,7 +67,7 @@ public interface LayeredMappingSpecBuilder { | ||||||
| 
 | 
 | ||||||
| 	@SuppressWarnings("rawtypes") | 	@SuppressWarnings("rawtypes") | ||||||
| 	default LayeredMappingSpecBuilder parchment(Object object, @DelegatesTo(value = ParchmentMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { | 	default LayeredMappingSpecBuilder parchment(Object object, @DelegatesTo(value = ParchmentMappingsSpecBuilder.class, strategy = Closure.DELEGATE_FIRST) Closure closure) { | ||||||
| 		return parchment(object, parchmentMappingsSpecBuilder -> ConfigureUtil.configure(closure, parchmentMappingsSpecBuilder)); | 		return parchment(object, new ClosureAction<>(closure)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	LayeredMappingSpecBuilder parchment(Object object, Action<ParchmentMappingsSpecBuilder> action); | 	LayeredMappingSpecBuilder parchment(Object object, Action<ParchmentMappingsSpecBuilder> action); | ||||||
|  |  | ||||||
|  | @ -99,7 +99,7 @@ public class JarRemapper { | ||||||
| 
 | 
 | ||||||
| 				outputConsumer.addNonClassFiles(data.input); | 				outputConsumer.addNonClassFiles(data.input); | ||||||
| 
 | 
 | ||||||
| 				data.processAccessWidener(remapper.getRemapper()); | 				data.processAccessWidener(remapper.getEnvironment().getRemapper()); | ||||||
| 				remapper.apply(outputConsumer, data.tag); | 				remapper.apply(outputConsumer, data.tag); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,7 +29,6 @@ import java.io.IOException; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.function.Supplier; | import java.util.function.Supplier; | ||||||
| import java.util.zip.ZipFile; |  | ||||||
| 
 | 
 | ||||||
| import com.google.common.io.Files; | import com.google.common.io.Files; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
|  | @ -58,6 +57,7 @@ import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo; | ||||||
| import net.fabricmc.loom.configuration.processors.dependency.RemapData; | import net.fabricmc.loom.configuration.processors.dependency.RemapData; | ||||||
| import net.fabricmc.loom.util.Checksum; | import net.fabricmc.loom.util.Checksum; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
|  | import net.fabricmc.loom.util.ModUtils; | ||||||
| import net.fabricmc.loom.util.OperatingSystem; | import net.fabricmc.loom.util.OperatingSystem; | ||||||
| import net.fabricmc.loom.util.SourceRemapper; | import net.fabricmc.loom.util.SourceRemapper; | ||||||
| 
 | 
 | ||||||
|  | @ -91,7 +91,7 @@ public class ModCompileRemapper { | ||||||
| 					String name = artifact.getModuleVersion().getId().getName(); | 					String name = artifact.getModuleVersion().getId().getName(); | ||||||
| 					String version = replaceIfNullOrEmpty(artifact.getModuleVersion().getId().getVersion(), () -> Checksum.truncatedSha256(artifact.getFile())); | 					String version = replaceIfNullOrEmpty(artifact.getModuleVersion().getId().getVersion(), () -> Checksum.truncatedSha256(artifact.getFile())); | ||||||
| 
 | 
 | ||||||
| 					if (!isFabricMod(logger, artifact.getFile(), artifact.getId())) { | 					if (!ModUtils.isMod(artifact.getFile())) { | ||||||
| 						addToRegularCompile(project, regularConfig, artifact); | 						addToRegularCompile(project, regularConfig, artifact); | ||||||
| 						continue; | 						continue; | ||||||
| 					} | 					} | ||||||
|  | @ -118,7 +118,7 @@ public class ModCompileRemapper { | ||||||
| 
 | 
 | ||||||
| 					// Create a mod dependency for each file in the file collection | 					// Create a mod dependency for each file in the file collection | ||||||
| 					for (File artifact : files) { | 					for (File artifact : files) { | ||||||
| 						if (!isFabricMod(logger, artifact, artifact.getName())) { | 						if (!ModUtils.isMod(artifact)) { | ||||||
| 							dependencies.add(regularConfig.getName(), project.files(artifact)); | 							dependencies.add(regularConfig.getName(), project.files(artifact)); | ||||||
| 							continue; | 							continue; | ||||||
| 						} | 						} | ||||||
|  | @ -161,22 +161,6 @@ public class ModCompileRemapper { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * Checks if an artifact is a fabric mod, according to the presence of a fabric.mod.json. |  | ||||||
| 	 */ |  | ||||||
| 	private static boolean isFabricMod(Logger logger, File artifact, Object id) { |  | ||||||
| 		try (ZipFile zipFile = new ZipFile(artifact)) { |  | ||||||
| 			if (zipFile.getEntry("fabric.mod.json") != null) { |  | ||||||
| 				logger.info("Found Fabric mod in modCompile: {}", id); |  | ||||||
| 				return true; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return false; |  | ||||||
| 		} catch (IOException e) { |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private static void addToRegularCompile(Project project, Configuration regularCompile, ResolvedArtifact artifact) { | 	private static void addToRegularCompile(Project project, Configuration regularCompile, ResolvedArtifact artifact) { | ||||||
| 		project.getLogger().info(":providing " + artifact); | 		project.getLogger().info(":providing " + artifact); | ||||||
| 		DependencyHandler dependencies = project.getDependencies(); | 		DependencyHandler dependencies = project.getDependencies(); | ||||||
|  |  | ||||||
|  | @ -39,8 +39,9 @@ import org.gradle.api.artifacts.Configuration; | ||||||
| import org.gradle.api.artifacts.ConfigurationContainer; | import org.gradle.api.artifacts.ConfigurationContainer; | ||||||
| import org.gradle.api.tasks.SourceSet; | import org.gradle.api.tasks.SourceSet; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.extension.MixinExtension; |  | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
|  | import net.fabricmc.loom.configuration.ide.idea.IdeaUtils; | ||||||
|  | import net.fabricmc.loom.extension.MixinExtension; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -97,9 +98,8 @@ public abstract class AnnotationProcessorInvoker<T extends Task> { | ||||||
| 
 | 
 | ||||||
| 	public void configureMixin() { | 	public void configureMixin() { | ||||||
| 		ConfigurationContainer configs = project.getConfigurations(); | 		ConfigurationContainer configs = project.getConfigurations(); | ||||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(project); |  | ||||||
| 
 | 
 | ||||||
| 		if (!extension.ideSync()) { | 		if (!IdeaUtils.isIdeaSync()) { | ||||||
| 			for (Configuration processorConfig : apConfigurations) { | 			for (Configuration processorConfig : apConfigurations) { | ||||||
| 				project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName()); | 				project.getLogger().info("Adding mixin to classpath of AP config: " + processorConfig.getName()); | ||||||
| 				// Pass named MC classpath to mixin AP classpath | 				// Pass named MC classpath to mixin AP classpath | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ public class JavaApInvoker extends AnnotationProcessorInvoker<JavaCompile> { | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected File getRefmapDestinationDir(JavaCompile task) { | 	protected File getRefmapDestinationDir(JavaCompile task) { | ||||||
| 		return task.getDestinationDir(); | 		return task.getDestinationDirectory().getAsFile().get(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static String getAptConfigurationName(String sourceSet) { | 	private static String getAptConfigurationName(String sourceSet) { | ||||||
|  |  | ||||||
|  | @ -84,7 +84,7 @@ public class KaptApInvoker extends AnnotationProcessorInvoker<JavaCompile> { | ||||||
| 				try { | 				try { | ||||||
| 					String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get(); | 					String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get(); | ||||||
| 					Path src = Paths.get(getRefmapDestination(task, refmapName)); | 					Path src = Paths.get(getRefmapDestination(task, refmapName)); | ||||||
| 					Path dest = Paths.get(task.getDestinationDir().toString(), refmapName); | 					Path dest = Paths.get(task.getDestinationDirectory().get().getAsFile().toString(), refmapName); | ||||||
| 
 | 
 | ||||||
| 					// Possible that no mixin annotations exist | 					// Possible that no mixin annotations exist | ||||||
| 					if (Files.exists(src)) { | 					if (Files.exists(src)) { | ||||||
|  |  | ||||||
|  | @ -59,6 +59,6 @@ public class ScalaApInvoker extends AnnotationProcessorInvoker<ScalaCompile> { | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected File getRefmapDestinationDir(ScalaCompile task) { | 	protected File getRefmapDestinationDir(ScalaCompile task) { | ||||||
| 		return task.getDestinationDir(); | 		return task.getDestinationDirectory().get().getAsFile(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -53,6 +53,7 @@ import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.task.RemapJarTask; | import net.fabricmc.loom.task.RemapJarTask; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
|  | import net.fabricmc.loom.util.ModUtils; | ||||||
| import net.fabricmc.loom.util.ZipUtils; | import net.fabricmc.loom.util.ZipUtils; | ||||||
| 
 | 
 | ||||||
| public final class NestedDependencyProvider implements NestedJarProvider { | public final class NestedDependencyProvider implements NestedJarProvider { | ||||||
|  | @ -158,7 +159,7 @@ public final class NestedDependencyProvider implements NestedJarProvider { | ||||||
| 			File file = metaFile.file; | 			File file = metaFile.file; | ||||||
| 
 | 
 | ||||||
| 			//A lib that doesnt have a mod.json, we turn it into a fake mod | 			//A lib that doesnt have a mod.json, we turn it into a fake mod | ||||||
| 			if (!ZipUtils.contains(file.toPath(), "fabric.mod.json")) { | 			if (!ModUtils.isMod(file)) { | ||||||
| 				LoomGradleExtension extension = LoomGradleExtension.get(project); | 				LoomGradleExtension extension = LoomGradleExtension.get(project); | ||||||
| 				File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing"); | 				File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,9 +26,11 @@ package net.fabricmc.loom.configuration; | ||||||
| 
 | 
 | ||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
| 
 | 
 | ||||||
|  | import org.gradle.api.NamedDomainObjectProvider; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
|  | import org.gradle.api.artifacts.Configuration; | ||||||
| import org.gradle.api.plugins.JavaPlugin; | import org.gradle.api.plugins.JavaPlugin; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| import org.gradle.api.tasks.AbstractCopyTask; | import org.gradle.api.tasks.AbstractCopyTask; | ||||||
| import org.gradle.api.tasks.SourceSet; | import org.gradle.api.tasks.SourceSet; | ||||||
| import org.gradle.api.tasks.compile.JavaCompile; | import org.gradle.api.tasks.compile.JavaCompile; | ||||||
|  | @ -39,7 +41,6 @@ import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.build.mixin.JavaApInvoker; | import net.fabricmc.loom.build.mixin.JavaApInvoker; | ||||||
| import net.fabricmc.loom.build.mixin.KaptApInvoker; | import net.fabricmc.loom.build.mixin.KaptApInvoker; | ||||||
| import net.fabricmc.loom.build.mixin.ScalaApInvoker; | import net.fabricmc.loom.build.mixin.ScalaApInvoker; | ||||||
| import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs; |  | ||||||
| import net.fabricmc.loom.configuration.providers.LaunchProvider; | import net.fabricmc.loom.configuration.providers.LaunchProvider; | ||||||
| import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; | import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; | ||||||
| import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; | import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; | ||||||
|  | @ -53,15 +54,20 @@ public final class CompileConfiguration { | ||||||
| 	public static void setupConfigurations(Project project) { | 	public static void setupConfigurations(Project project) { | ||||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(project); | 		LoomGradleExtension extension = LoomGradleExtension.get(project); | ||||||
| 
 | 
 | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH).configure(configuration -> configuration.setTransitive(true)); | 		extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH, configuration -> configuration.setTransitive(true)); | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED).configure(configuration -> configuration.setTransitive(false)); | 		extension.createLazyConfiguration(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED, configuration -> configuration.setTransitive(false)); | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NAMED).configure(configuration -> configuration.setTransitive(false)); // The launchers do not recurse dependencies | 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NAMED, configuration -> configuration.setTransitive(false)); // The launchers do not recurse dependencies | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_DEPENDENCIES).configure(configuration -> configuration.setTransitive(false)); | 		NamedDomainObjectProvider<Configuration> serverDeps = extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, configuration -> configuration.setTransitive(false)); | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.LOADER_DEPENDENCIES).configure(configuration -> configuration.setTransitive(false)); | 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_DEPENDENCIES, configuration -> { | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT).configure(configuration -> configuration.setTransitive(false)); | 			configuration.extendsFrom(serverDeps.get()); | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.INCLUDE).configure(configuration -> configuration.setTransitive(false)); // Dont get transitive deps | 			configuration.setTransitive(false); | ||||||
|  | 		}); | ||||||
|  | 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT_NATIVES, configuration -> configuration.setTransitive(false)); | ||||||
|  | 		extension.createLazyConfiguration(Constants.Configurations.LOADER_DEPENDENCIES, configuration -> configuration.setTransitive(false)); | ||||||
|  | 		extension.createLazyConfiguration(Constants.Configurations.MINECRAFT, configuration -> configuration.setTransitive(false)); | ||||||
|  | 		extension.createLazyConfiguration(Constants.Configurations.INCLUDE, configuration -> configuration.setTransitive(false)); // Dont get transitive deps | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.MAPPING_CONSTANTS); | 		extension.createLazyConfiguration(Constants.Configurations.MAPPING_CONSTANTS); | ||||||
| 		extension.createLazyConfiguration(Constants.Configurations.NAMED_ELEMENTS).configure(configuration -> { | 		extension.createLazyConfiguration(Constants.Configurations.NAMED_ELEMENTS, configuration -> { | ||||||
| 			configuration.setCanBeConsumed(true); | 			configuration.setCanBeConsumed(true); | ||||||
| 			configuration.setCanBeResolved(false); | 			configuration.setCanBeResolved(false); | ||||||
| 			configuration.extendsFrom(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); | 			configuration.extendsFrom(project.getConfigurations().getByName(JavaPlugin.API_CONFIGURATION_NAME)); | ||||||
|  | @ -117,9 +123,9 @@ public final class CompileConfiguration { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public static void configureCompile(Project p) { | 	public static void configureCompile(Project p) { | ||||||
| 		JavaPluginConvention javaModule = (JavaPluginConvention) p.getConvention().getPlugins().get("java"); | 		final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class); | ||||||
| 
 | 
 | ||||||
| 		SourceSet main = javaModule.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); | 		SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); | ||||||
| 
 | 
 | ||||||
| 		Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); | 		Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME); | ||||||
| 		javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); | 		javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); | ||||||
|  | @ -140,7 +146,6 @@ public final class CompileConfiguration { | ||||||
| 			project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns")); | 			project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns")); | ||||||
| 			project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns")); | 			project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns")); | ||||||
| 
 | 
 | ||||||
| 			SetupIntelijRunConfigs.setup(project); |  | ||||||
| 			extension.getRemapArchives().finalizeValue(); | 			extension.getRemapArchives().finalizeValue(); | ||||||
| 
 | 
 | ||||||
| 			// Enables the default mod remapper | 			// Enables the default mod remapper | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.LoomRepositoryPlugin; | import net.fabricmc.loom.LoomRepositoryPlugin; | ||||||
| import net.fabricmc.loom.build.ModCompileRemapper; | import net.fabricmc.loom.build.ModCompileRemapper; | ||||||
| import net.fabricmc.loom.configuration.DependencyProvider.DependencyInfo; | import net.fabricmc.loom.configuration.DependencyProvider.DependencyInfo; | ||||||
|  | import net.fabricmc.loom.configuration.ide.idea.IdeaUtils; | ||||||
| import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; | import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
| import net.fabricmc.loom.util.SourceRemapper; | import net.fabricmc.loom.util.SourceRemapper; | ||||||
|  | @ -209,7 +210,7 @@ public class LoomDependencyManager { | ||||||
| 			loaderDepsConfig.getDependencies().add(modDep); | 			loaderDepsConfig.getDependencies().add(modDep); | ||||||
| 
 | 
 | ||||||
| 			// TODO: work around until https://github.com/FabricMC/Mixin/pull/60 and https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/14 is fixed. | 			// TODO: work around until https://github.com/FabricMC/Mixin/pull/60 and https://github.com/FabricMC/fabric-mixin-compile-extensions/issues/14 is fixed. | ||||||
| 			if (!extension.ideSync() && extension.getMixin().getUseLegacyMixinAp().get()) { | 			if (!IdeaUtils.isIdeaSync() && extension.getMixin().getUseLegacyMixinAp().get()) { | ||||||
| 				apDepsConfig.getDependencies().add(modDep); | 				apDepsConfig.getDependencies().add(modDep); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ public class TransitiveAccessWidenerJarProcessor implements JarProcessor { | ||||||
| 		try { | 		try { | ||||||
| 			AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper( | 			AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper( | ||||||
| 					accessWidener, | 					accessWidener, | ||||||
| 					tinyRemapper.getRemapper(), | 					tinyRemapper.getEnvironment().getRemapper(), | ||||||
| 					MappingsNamespace.INTERMEDIARY.toString(), | 					MappingsNamespace.INTERMEDIARY.toString(), | ||||||
| 					MappingsNamespace.NAMED.toString() | 					MappingsNamespace.NAMED.toString() | ||||||
| 			); | 			); | ||||||
|  |  | ||||||
|  | @ -45,6 +45,7 @@ import org.w3c.dom.Node; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.configuration.InstallerData; | import net.fabricmc.loom.configuration.InstallerData; | ||||||
|  | import net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask; | ||||||
| 
 | 
 | ||||||
| public class RunConfig { | public class RunConfig { | ||||||
| 	public String configName; | 	public String configName; | ||||||
|  | @ -174,7 +175,7 @@ public class RunConfig { | ||||||
| 	public String fromDummy(String dummy, boolean relativeDir, Project project) throws IOException { | 	public String fromDummy(String dummy, boolean relativeDir, Project project) throws IOException { | ||||||
| 		String dummyConfig; | 		String dummyConfig; | ||||||
| 
 | 
 | ||||||
| 		try (InputStream input = SetupIntelijRunConfigs.class.getClassLoader().getResourceAsStream(dummy)) { | 		try (InputStream input = IdeaSyncTask.class.getClassLoader().getResourceAsStream(dummy)) { | ||||||
| 			dummyConfig = new String(input.readAllBytes(), StandardCharsets.UTF_8); | 			dummyConfig = new String(input.readAllBytes(), StandardCharsets.UTF_8); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,7 +34,7 @@ import java.util.function.Function; | ||||||
| 
 | 
 | ||||||
| import org.gradle.api.Named; | import org.gradle.api.Named; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| import org.gradle.api.tasks.SourceSet; | import org.gradle.api.tasks.SourceSet; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
|  | @ -229,10 +229,7 @@ public final class RunConfigSettings implements Named { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void source(String source) { | 	public void source(String source) { | ||||||
| 		setSource(proj -> { | 		setSource(proj -> project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().getByName(source)); | ||||||
| 			JavaPluginConvention conv = proj.getConvention().getPlugin(JavaPluginConvention.class); |  | ||||||
| 			return conv.getSourceSets().getByName(source); |  | ||||||
| 		}); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public void ideConfigGenerated(boolean ideConfigGenerated) { | 	public void ideConfigGenerated(boolean ideConfigGenerated) { | ||||||
|  | @ -243,7 +240,7 @@ public final class RunConfigSettings implements Named { | ||||||
| 	 * Add the {@code -XstartOnFirstThread} JVM argument when on OSX. | 	 * Add the {@code -XstartOnFirstThread} JVM argument when on OSX. | ||||||
| 	 */ | 	 */ | ||||||
| 	public void startFirstThread() { | 	public void startFirstThread() { | ||||||
| 		if (OperatingSystem.getOS().equalsIgnoreCase("osx")) { | 		if (OperatingSystem.CURRENT_OS.equals(OperatingSystem.MAC_OS)) { | ||||||
| 			vmArg("-XstartOnFirstThread"); | 			vmArg("-XstartOnFirstThread"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1,90 +0,0 @@ | ||||||
| /* |  | ||||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2016-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.ide; |  | ||||||
| 
 |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.nio.charset.StandardCharsets; |  | ||||||
| 
 |  | ||||||
| import org.apache.commons.io.FileUtils; |  | ||||||
| import org.gradle.api.Project; |  | ||||||
| 
 |  | ||||||
| import net.fabricmc.loom.LoomGradleExtension; |  | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftNativesProvider; |  | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider; |  | ||||||
| 
 |  | ||||||
| public class SetupIntelijRunConfigs { |  | ||||||
| 	public static void setup(Project project) { |  | ||||||
| 		File projectDir = project.getRootProject().file(".idea"); |  | ||||||
| 
 |  | ||||||
| 		if (!projectDir.exists()) { |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		try { |  | ||||||
| 			generate(project); |  | ||||||
| 		} catch (IOException e) { |  | ||||||
| 			throw new RuntimeException("Failed to generate run configs", e); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private static void generate(Project project) throws IOException { |  | ||||||
| 		Project rootProject = project.getRootProject(); |  | ||||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(project); |  | ||||||
| 
 |  | ||||||
| 		if (extension.ideSync()) { |  | ||||||
| 			//Ensures the assets are downloaded when idea is syncing a project |  | ||||||
| 			MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); |  | ||||||
| 			MinecraftNativesProvider.provide(project); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		String projectPath = project == rootProject ? "" : project.getPath().replace(':', '_'); |  | ||||||
| 
 |  | ||||||
| 		File projectDir = rootProject.file(".idea"); |  | ||||||
| 		File runConfigsDir = new File(projectDir, "runConfigurations"); |  | ||||||
| 
 |  | ||||||
| 		if (!runConfigsDir.exists()) { |  | ||||||
| 			runConfigsDir.mkdirs(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (RunConfigSettings settings : extension.getRunConfigs()) { |  | ||||||
| 			if (!settings.isIdeConfigGenerated()) { |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			RunConfig config = RunConfig.runConfig(project, settings); |  | ||||||
| 			String name = config.configName.replaceAll("[^a-zA-Z0-9$_]", "_"); |  | ||||||
| 
 |  | ||||||
| 			File runConfigs = new File(runConfigsDir, name + projectPath + ".xml"); |  | ||||||
| 			String runConfigXml = config.fromDummy("idea_run_config_template.xml", true, project); |  | ||||||
| 
 |  | ||||||
| 			if (!runConfigs.exists()) { |  | ||||||
| 				FileUtils.writeStringToFile(runConfigs, runConfigXml, StandardCharsets.UTF_8); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			settings.makeRunDir(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,83 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.configuration.ide.idea; | ||||||
|  | 
 | ||||||
|  | import java.util.Objects; | ||||||
|  | 
 | ||||||
|  | import org.gradle.api.NamedDomainObjectContainer; | ||||||
|  | import org.gradle.api.Project; | ||||||
|  | import org.gradle.api.plugins.ExtensionAware; | ||||||
|  | import org.gradle.api.tasks.TaskProvider; | ||||||
|  | import org.gradle.plugins.ide.idea.model.IdeaModel; | ||||||
|  | import org.gradle.plugins.ide.idea.model.IdeaProject; | ||||||
|  | import org.jetbrains.gradle.ext.ActionDelegationConfig; | ||||||
|  | import org.jetbrains.gradle.ext.IdeaExtPlugin; | ||||||
|  | import org.jetbrains.gradle.ext.ProjectSettings; | ||||||
|  | import org.jetbrains.gradle.ext.RunConfiguration; | ||||||
|  | import org.jetbrains.gradle.ext.TaskTriggersConfig; | ||||||
|  | 
 | ||||||
|  | public class IdeaConfiguration { | ||||||
|  | 	public static void setup(Project project) { | ||||||
|  | 		TaskProvider<IdeaSyncTask> ideaSyncTask = project.getTasks().register("ideaSyncTask", IdeaSyncTask.class, ideaSyncTask1 -> { | ||||||
|  | 			ideaSyncTask1.dependsOn(project.getTasks().named("downloadAssets")); | ||||||
|  | 		}); | ||||||
|  | 
 | ||||||
|  | 		if (!IdeaUtils.isIdeaSync()) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		project.getPlugins().apply(IdeaExtPlugin.class); | ||||||
|  | 		project.getPlugins().withType(IdeaExtPlugin.class, ideaExtPlugin -> { | ||||||
|  | 			if (project != project.getRootProject()) { | ||||||
|  | 				// Also ensure it's applied to the root project. | ||||||
|  | 				project.getRootProject().getPlugins().apply(IdeaExtPlugin.class); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			final IdeaModel ideaModel = project.getRootProject().getExtensions().findByType(IdeaModel.class); | ||||||
|  | 
 | ||||||
|  | 			if (ideaModel == null) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			final IdeaProject ideaProject = ideaModel.getProject(); | ||||||
|  | 
 | ||||||
|  | 			if (ideaProject == null) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			final ProjectSettings settings = getExtension(ideaProject, ProjectSettings.class); | ||||||
|  | 			final ActionDelegationConfig delegateActions = getExtension(settings, ActionDelegationConfig.class); | ||||||
|  | 			final TaskTriggersConfig taskTriggers = getExtension(settings, TaskTriggersConfig.class); | ||||||
|  | 			final NamedDomainObjectContainer<RunConfiguration> runConfigurations = (NamedDomainObjectContainer<RunConfiguration>) ((ExtensionAware) settings).getExtensions().getByName("runConfigurations"); | ||||||
|  | 
 | ||||||
|  | 			// Run the sync task on import | ||||||
|  | 			taskTriggers.afterSync(ideaSyncTask); | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static <T> T getExtension(Object extensionAware, Class<T> type) { | ||||||
|  | 		return Objects.requireNonNull(((ExtensionAware) extensionAware).getExtensions().getByType(type)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,130 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.configuration.ide.idea; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.LinkedList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | import javax.inject.Inject; | ||||||
|  | 
 | ||||||
|  | import org.apache.commons.io.FileUtils; | ||||||
|  | import org.gradle.api.Project; | ||||||
|  | import org.gradle.api.tasks.TaskAction; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.LoomGradleExtension; | ||||||
|  | import net.fabricmc.loom.configuration.ide.RunConfig; | ||||||
|  | import net.fabricmc.loom.configuration.ide.RunConfigSettings; | ||||||
|  | import net.fabricmc.loom.configuration.providers.BundleMetadata; | ||||||
|  | import net.fabricmc.loom.task.AbstractLoomTask; | ||||||
|  | import net.fabricmc.loom.util.Constants; | ||||||
|  | 
 | ||||||
|  | public abstract class IdeaSyncTask extends AbstractLoomTask { | ||||||
|  | 	@Inject | ||||||
|  | 	public IdeaSyncTask() { | ||||||
|  | 		// Always re-run this task. | ||||||
|  | 		getOutputs().upToDateWhen(element -> false); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@TaskAction | ||||||
|  | 	public void runTask() throws IOException { | ||||||
|  | 		File projectDir = getProject().getRootProject().file(".idea"); | ||||||
|  | 
 | ||||||
|  | 		if (!projectDir.exists()) { | ||||||
|  | 			throw new RuntimeException("No .idea directory found"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		generateRunConfigs(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// See: https://github.com/FabricMC/fabric-loom/pull/206#issuecomment-986054254 for the reason why XML's are still used to provide the run configs | ||||||
|  | 	private void generateRunConfigs() throws IOException { | ||||||
|  | 		Project rootProject = getProject().getRootProject(); | ||||||
|  | 		LoomGradleExtension extension = LoomGradleExtension.get(getProject()); | ||||||
|  | 		String projectPath = getProject() == rootProject ? "" : getProject().getPath().replace(':', '_'); | ||||||
|  | 		File runConfigsDir = new File(rootProject.file(".idea"), "runConfigurations"); | ||||||
|  | 
 | ||||||
|  | 		if (!runConfigsDir.exists()) { | ||||||
|  | 			runConfigsDir.mkdirs(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		final List<String> excludedServerLibraries = getExcludedServerLibraries(); | ||||||
|  | 
 | ||||||
|  | 		for (RunConfigSettings settings : extension.getRunConfigs()) { | ||||||
|  | 			if (!settings.isIdeConfigGenerated()) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			RunConfig config = RunConfig.runConfig(getProject(), settings); | ||||||
|  | 			String name = config.configName.replaceAll("[^a-zA-Z0-9$_]", "_"); | ||||||
|  | 
 | ||||||
|  | 			File runConfigs = new File(runConfigsDir, name + projectPath + ".xml"); | ||||||
|  | 			String runConfigXml = config.fromDummy("idea_run_config_template.xml", true, getProject()); | ||||||
|  | 
 | ||||||
|  | 			if (!runConfigs.exists()) { | ||||||
|  | 				FileUtils.writeStringToFile(runConfigs, runConfigXml, StandardCharsets.UTF_8); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			settings.makeRunDir(); | ||||||
|  | 
 | ||||||
|  | 			if (settings.getEnvironment().equals("server") && !excludedServerLibraries.isEmpty()) { | ||||||
|  | 				try { | ||||||
|  | 					setClasspathModifications(runConfigs, excludedServerLibraries); | ||||||
|  | 				} catch (Exception e) { | ||||||
|  | 					getProject().getLogger().error("Failed to modify run configuration xml", e); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private List<String> getExcludedServerLibraries() { | ||||||
|  | 		final BundleMetadata bundleMetadata = getExtension().getMinecraftProvider().getServerBundleMetadata(); | ||||||
|  | 
 | ||||||
|  | 		if (bundleMetadata == null) { | ||||||
|  | 			// Legacy version | ||||||
|  | 			return Collections.emptyList(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		final Set<File> allLibraries = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES).getFiles(); | ||||||
|  | 		final Set<File> serverLibraries = getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES).getFiles(); | ||||||
|  | 		final List<String> clientOnlyLibraries = new LinkedList<>(); | ||||||
|  | 
 | ||||||
|  | 		for (File commonLibrary : allLibraries) { | ||||||
|  | 			if (!serverLibraries.contains(commonLibrary)) { | ||||||
|  | 				clientOnlyLibraries.add(commonLibrary.getAbsolutePath()); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return clientOnlyLibraries; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private void setClasspathModifications(File runConfig, List<String> exclusions) throws Exception { | ||||||
|  | 		// TODO modify the xml | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,45 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.configuration.ide.idea; | ||||||
|  | 
 | ||||||
|  | import java.util.Objects; | ||||||
|  | 
 | ||||||
|  | public class IdeaUtils { | ||||||
|  | 	public static boolean isIdeaSync() { | ||||||
|  | 		return Boolean.parseBoolean(System.getProperty("idea.sync.active", "false")); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public static String getIdeaVersion() { | ||||||
|  | 		return Objects.requireNonNull(System.getProperty("idea.version"), "Could not get idea version"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// 2021.3 or newer | ||||||
|  | 	public static boolean supportsCustomizableClasspath() { | ||||||
|  | 		final String[] split = getIdeaVersion().split("\\."); | ||||||
|  | 		final int major = Integer.parseInt(split[0]); | ||||||
|  | 		final int minor = Integer.parseInt(split[1]); | ||||||
|  | 		return major > 2021 || (major == 2021 && minor >= 3); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -30,7 +30,7 @@ import java.io.IOException; | ||||||
| 
 | 
 | ||||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| 
 | 
 | ||||||
|  | @ -67,7 +67,7 @@ public class ModVersionParser { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private File locateModJsonFile() { | 	private File locateModJsonFile() { | ||||||
| 		return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets() | 		return project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets() | ||||||
| 				.getByName("main") | 				.getByName("main") | ||||||
| 				.getResources() | 				.getResources() | ||||||
| 				.matching(patternFilterable -> patternFilterable.include("fabric.mod.json")) | 				.matching(patternFilterable -> patternFilterable.include("fabric.mod.json")) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,93 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.configuration.providers; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.InputStream; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.Path; | ||||||
|  | import java.nio.file.StandardCopyOption; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.util.FileSystemUtil; | ||||||
|  | 
 | ||||||
|  | public record BundleMetadata(List<Entry> libraries, List<Entry> versions, String mainClass) { | ||||||
|  | 	private static final String LIBRARIES_LIST_PATH = "META-INF/libraries.list"; | ||||||
|  | 	private static final String VERSIONS_LIST_PATH = "META-INF/versions.list"; | ||||||
|  | 	private static final String MAINCLASS_PATH = "META-INF/main-class"; | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	public static BundleMetadata fromJar(Path jar) throws IOException { | ||||||
|  | 		final List<Entry> libraries; | ||||||
|  | 		final List<Entry> versions; | ||||||
|  | 		final String mainClass; | ||||||
|  | 
 | ||||||
|  | 		try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(jar)) { | ||||||
|  | 			if (!Files.exists(fs.get().getPath(VERSIONS_LIST_PATH))) { | ||||||
|  | 				// Legacy jar | ||||||
|  | 				return null; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			libraries = readEntries(fs.readString(LIBRARIES_LIST_PATH), "META-INF/libraries/"); | ||||||
|  | 			versions = readEntries(fs.readString(VERSIONS_LIST_PATH), "META-INF/versions/"); | ||||||
|  | 			mainClass = fs.readString(MAINCLASS_PATH).trim(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return new BundleMetadata(libraries, versions, mainClass); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static List<Entry> readEntries(String content, String pathPrefix) { | ||||||
|  | 		List<Entry> entries = new ArrayList<>(); | ||||||
|  | 
 | ||||||
|  | 		for (String entry : content.split("\n")) { | ||||||
|  | 			if (entry.isBlank()) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			String[] split = entry.split("\t"); | ||||||
|  | 
 | ||||||
|  | 			if (split.length != 3) { | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			entries.add(new Entry(split[0], split[1], pathPrefix + split[2])); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return Collections.unmodifiableList(entries); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public record Entry(String sha1, String name, String path) { | ||||||
|  | 		public void unpackEntry(Path jar, Path dest) throws IOException { | ||||||
|  | 			try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(jar); | ||||||
|  | 					InputStream is = Files.newInputStream(fs.get().getPath(path()))) { | ||||||
|  | 				Files.copy(is, dest, StandardCopyOption.REPLACE_EXISTING); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -54,13 +54,15 @@ public class LaunchProvider extends DependencyProvider { | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws IOException { | 	public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws IOException { | ||||||
|  | 		final String nativesPath = getExtension().getFiles().getNativesDirectory(getProject()).getAbsolutePath(); | ||||||
|  | 
 | ||||||
| 		final LaunchConfig launchConfig = new LaunchConfig() | 		final LaunchConfig launchConfig = new LaunchConfig() | ||||||
| 				.property("fabric.development", "true") | 				.property("fabric.development", "true") | ||||||
| 				.property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath()) | 				.property("fabric.remapClasspathFile", getRemapClasspathFile().getAbsolutePath()) | ||||||
| 				.property("log4j.configurationFile", getAllLog4JConfigFiles()) | 				.property("log4j.configurationFile", getAllLog4JConfigFiles()) | ||||||
| 
 | 
 | ||||||
| 				.property("client", "java.library.path", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) | 				.property("client", "java.library.path", nativesPath) | ||||||
| 				.property("client", "org.lwjgl.librarypath", getExtension().getMinecraftProvider().nativesDir().getAbsolutePath()) | 				.property("client", "org.lwjgl.librarypath", nativesPath) | ||||||
| 
 | 
 | ||||||
| 				.argument("client", "--assetIndex") | 				.argument("client", "--assetIndex") | ||||||
| 				.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) | 				.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) | ||||||
|  |  | ||||||
|  | @ -31,10 +31,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; | ||||||
| public interface MinecraftProvider { | public interface MinecraftProvider { | ||||||
| 	File workingDir(); | 	File workingDir(); | ||||||
| 
 | 
 | ||||||
| 	boolean hasCustomNatives(); |  | ||||||
| 
 |  | ||||||
| 	File nativesDir(); |  | ||||||
| 
 |  | ||||||
| 	File dir(String path); | 	File dir(String path); | ||||||
| 
 | 
 | ||||||
| 	File file(String path); | 	File file(String path); | ||||||
|  |  | ||||||
|  | @ -27,20 +27,16 @@ package net.fabricmc.loom.configuration.providers; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FileReader; | import java.io.FileReader; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.InputStream; |  | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
| import java.nio.file.StandardCopyOption; |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| import java.util.zip.ZipEntry; |  | ||||||
| import java.util.zip.ZipFile; |  | ||||||
| 
 | 
 | ||||||
| import com.google.common.io.Files; | import com.google.common.io.Files; | ||||||
| import org.gradle.api.GradleException; | import org.gradle.api.GradleException; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.logging.Logger; | import org.gradle.api.logging.Logger; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.configuration.DependencyProvider; | import net.fabricmc.loom.configuration.DependencyProvider; | ||||||
|  | @ -48,9 +44,9 @@ import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider; | import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; | import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
| import net.fabricmc.loom.util.MirrorUtil; |  | ||||||
| import net.fabricmc.loom.util.DownloadUtil; | import net.fabricmc.loom.util.DownloadUtil; | ||||||
| import net.fabricmc.loom.util.HashedDownloadUtil; | import net.fabricmc.loom.util.HashedDownloadUtil; | ||||||
|  | import net.fabricmc.loom.util.MirrorUtil; | ||||||
| import net.fabricmc.stitch.merge.JarMerger; | import net.fabricmc.stitch.merge.JarMerger; | ||||||
| 
 | 
 | ||||||
| public class MinecraftProviderImpl extends DependencyProvider implements MinecraftProvider { | public class MinecraftProviderImpl extends DependencyProvider implements MinecraftProvider { | ||||||
|  | @ -66,6 +62,8 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra | ||||||
| 	private File minecraftServerJar; | 	private File minecraftServerJar; | ||||||
| 	// The extracted server jar from the boostrap, only exists in >=21w39a | 	// The extracted server jar from the boostrap, only exists in >=21w39a | ||||||
| 	private File minecraftExtractedServerJar; | 	private File minecraftExtractedServerJar; | ||||||
|  | 	@Nullable | ||||||
|  | 	private BundleMetadata serverBundleMetadata; | ||||||
| 	private File minecraftMergedJar; | 	private File minecraftMergedJar; | ||||||
| 	private File versionManifestJson; | 	private File versionManifestJson; | ||||||
| 	private File experimentalVersionsJson; | 	private File experimentalVersionsJson; | ||||||
|  | @ -101,6 +99,8 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra | ||||||
| 			downloadJars(getProject().getLogger()); | 			downloadJars(getProject().getLogger()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath()); | ||||||
|  | 
 | ||||||
| 		libraryProvider = new MinecraftLibraryProvider(); | 		libraryProvider = new MinecraftLibraryProvider(); | ||||||
| 		libraryProvider.provide(this, getProject()); | 		libraryProvider.provide(this, getProject()); | ||||||
| 
 | 
 | ||||||
|  | @ -257,61 +257,22 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra | ||||||
| 	private void mergeJars(Logger logger) throws IOException { | 	private void mergeJars(Logger logger) throws IOException { | ||||||
| 		logger.info(":merging jars"); | 		logger.info(":merging jars"); | ||||||
| 
 | 
 | ||||||
| 		try (JarMerger jarMerger = new JarMerger(minecraftClientJar, getServerJarToMerge(logger), minecraftMergedJar)) { | 		File jarToMerge = minecraftServerJar; | ||||||
| 			jarMerger.enableSyntheticParamsOffset(); |  | ||||||
| 			jarMerger.merge(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private File getServerJarToMerge(Logger logger) throws IOException { |  | ||||||
| 		try (ZipFile zipFile = new ZipFile(minecraftServerJar)) { |  | ||||||
| 			ZipEntry versionsListEntry = zipFile.getEntry("META-INF/versions.list"); |  | ||||||
| 
 |  | ||||||
| 			if (versionsListEntry == null) { |  | ||||||
| 				// Legacy pre 21w38a jar |  | ||||||
| 				return minecraftServerJar; |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
|  | 		if (serverBundleMetadata != null) { | ||||||
| 			logger.info(":Extracting server jar from bootstrap"); | 			logger.info(":Extracting server jar from bootstrap"); | ||||||
| 
 | 
 | ||||||
| 			String versionsList; | 			if (serverBundleMetadata.versions().size() != 1) { | ||||||
| 
 | 				throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(serverBundleMetadata.versions().size())); | ||||||
| 			try (InputStream is = zipFile.getInputStream(versionsListEntry)) { |  | ||||||
| 				versionsList = new String(is.readAllBytes(), StandardCharsets.UTF_8); |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			String jarPath = null; | 			serverBundleMetadata.versions().get(0).unpackEntry(minecraftServerJar.toPath(), minecraftExtractedServerJar.toPath()); | ||||||
| 			String[] versions = versionsList.split("\n"); | 			jarToMerge = minecraftExtractedServerJar; | ||||||
| 
 |  | ||||||
| 			if (versions.length != 1) { |  | ||||||
| 				throw new UnsupportedOperationException("Expected only 1 version in META-INF/versions.list, but got %d".formatted(versions.length)); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 			for (String version : versions) { | 		try (JarMerger jarMerger = new JarMerger(minecraftClientJar, jarToMerge, minecraftMergedJar)) { | ||||||
| 				if (version.isBlank()) continue; | 			jarMerger.enableSyntheticParamsOffset(); | ||||||
| 
 | 			jarMerger.merge(); | ||||||
| 				String[] split = version.split("\t"); |  | ||||||
| 
 |  | ||||||
| 				if (split.length != 3) continue; |  | ||||||
| 
 |  | ||||||
| 				final String hash = split[0]; |  | ||||||
| 				final String id = split[1]; |  | ||||||
| 				final String path = split[2]; |  | ||||||
| 
 |  | ||||||
| 				// Take the first (only) version we find. |  | ||||||
| 				jarPath = path; |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			Objects.requireNonNull(jarPath, "Could not find minecraft server jar for " + minecraftVersion()); |  | ||||||
| 			ZipEntry serverJarEntry = zipFile.getEntry("META-INF/versions/" + jarPath); |  | ||||||
| 			Objects.requireNonNull(serverJarEntry, "Could not find server jar in boostrap@ " + jarPath); |  | ||||||
| 
 |  | ||||||
| 			try (InputStream is = zipFile.getInputStream(serverJarEntry)) { |  | ||||||
| 				java.nio.file.Files.copy(is, minecraftExtractedServerJar.toPath(), StandardCopyOption.REPLACE_EXISTING); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return minecraftExtractedServerJar; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -324,20 +285,6 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra | ||||||
| 		return workingDir; | 		return workingDir; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override |  | ||||||
| 	public boolean hasCustomNatives() { |  | ||||||
| 		return getProject().getProperties().get("fabric.loom.natives.dir") != null; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	public File nativesDir() { |  | ||||||
| 		if (hasCustomNatives()) { |  | ||||||
| 			return new File((String) getProject().property("fabric.loom.natives.dir")); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return dir("natives"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public File dir(String path) { | 	public File dir(String path) { | ||||||
| 		File dir = file(path); | 		File dir = file(path); | ||||||
|  | @ -368,4 +315,9 @@ public class MinecraftProviderImpl extends DependencyProvider implements Minecra | ||||||
| 	public String getTargetConfig() { | 	public String getTargetConfig() { | ||||||
| 		return Constants.Configurations.MINECRAFT; | 		return Constants.Configurations.MINECRAFT; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	public BundleMetadata getServerBundleMetadata() { | ||||||
|  | 		return serverBundleMetadata; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.configuration.providers.minecraft; | ||||||
|  | 
 | ||||||
|  | import static net.fabricmc.loom.util.OperatingSystem.LINUX; | ||||||
|  | import static net.fabricmc.loom.util.OperatingSystem.MAC_OS; | ||||||
|  | import static net.fabricmc.loom.util.OperatingSystem.WINDOWS; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import org.gradle.api.Project; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.util.Architecture; | ||||||
|  | import net.fabricmc.loom.util.OperatingSystem; | ||||||
|  | 
 | ||||||
|  | public class LWJGLVersionOverride { | ||||||
|  | 	public static final String LWJGL_VERSION = "3.3.0"; | ||||||
|  | 	@Nullable | ||||||
|  | 	public static final String NATIVE_CLASSIFIER = getNativesClassifier(); | ||||||
|  | 
 | ||||||
|  | 	public static final List<String> DEPENDENCIES = List.of( | ||||||
|  | 			"org.lwjgl:lwjgl:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-glfw:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-jemalloc:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-openal:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-opengl:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-stb:" + LWJGL_VERSION, | ||||||
|  | 			"org.lwjgl:lwjgl-tinyfd:" + LWJGL_VERSION | ||||||
|  | 	); | ||||||
|  | 	public static final List<String> NATIVES = DEPENDENCIES.stream().map(s -> s + ":" + NATIVE_CLASSIFIER).toList(); | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Update lwjgl by default when running on arm and a supported configuration. | ||||||
|  | 	 */ | ||||||
|  | 	public static boolean overrideByDefault() { | ||||||
|  | 		return NATIVE_CLASSIFIER != null && Architecture.CURRENT.isArm(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public static boolean forceOverride(Project project) { | ||||||
|  | 		return project.getProperties().get("fabric.loom.override-lwjgl") != null; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private static String getNativesClassifier() { | ||||||
|  | 		return switch (OperatingSystem.CURRENT_OS) { | ||||||
|  | 		case WINDOWS -> getWindowsClassifier(); | ||||||
|  | 		case MAC_OS -> getMacOSClassifier(); | ||||||
|  | 		case LINUX -> getLinuxClassifier(); | ||||||
|  | 		default -> null; | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static String getWindowsClassifier() { | ||||||
|  | 		if (Architecture.CURRENT.is64Bit()) { | ||||||
|  | 			if (Architecture.CURRENT.isArm()) { | ||||||
|  | 				// Arm 64 bit | ||||||
|  | 				return "natives-windows-arm64"; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// None arm 64bit | ||||||
|  | 			return "natives-windows"; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// All 32bit, including arm | ||||||
|  | 		return "natives-windows-x86"; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static String getMacOSClassifier() { | ||||||
|  | 		if (Architecture.CURRENT.isArm()) { | ||||||
|  | 			// Apple silicone arm | ||||||
|  | 			return "natives-macos-arm64"; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Intel 64bit. | ||||||
|  | 		return "natives-macos"; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static String getLinuxClassifier() { | ||||||
|  | 		if (Architecture.CURRENT.isArm()) { | ||||||
|  | 			return Architecture.CURRENT.is64Bit() ? "natives-linux-arm64" : "natives-linux-arm32"; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return "natives-linux"; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -24,31 +24,77 @@ | ||||||
| 
 | 
 | ||||||
| package net.fabricmc.loom.configuration.providers.minecraft; | package net.fabricmc.loom.configuration.providers.minecraft; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.util.regex.Matcher; | ||||||
|  | import java.util.regex.Pattern; | ||||||
| 
 | 
 | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
|  | import org.gradle.api.artifacts.ExternalModuleDependency; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.configuration.providers.BundleMetadata; | ||||||
| import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; | import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
| 
 | 
 | ||||||
| public class MinecraftLibraryProvider { | public class MinecraftLibraryProvider { | ||||||
| 	public File MINECRAFT_LIBS; | 	private static final Pattern NATIVES_PATTERN = Pattern.compile("^(?<group>.*)/(.*?)/(?<version>.*)/((?<name>.*?)-([0-9].*?)-)(?<classifier>.*).jar$"); | ||||||
| 
 | 
 | ||||||
| 	public void provide(MinecraftProviderImpl minecraftProvider, Project project) { | 	public void provide(MinecraftProviderImpl minecraftProvider, Project project) { | ||||||
| 		MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); | 		MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); | ||||||
|  | 		BundleMetadata serverBundleMetadata = minecraftProvider.getServerBundleMetadata(); | ||||||
| 
 | 
 | ||||||
| 		initFiles(project, minecraftProvider); | 		final boolean overrideLWJGL = LWJGLVersionOverride.overrideByDefault() || LWJGLVersionOverride.forceOverride(project) || Boolean.getBoolean("loom.test.lwjgloverride"); | ||||||
|  | 
 | ||||||
|  | 		if (overrideLWJGL) { | ||||||
|  | 			project.getLogger().warn("Loom is upgrading Minecraft's LWJGL version to {}", LWJGLVersionOverride.LWJGL_VERSION); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		for (MinecraftVersionMeta.Library library : versionInfo.libraries()) { | 		for (MinecraftVersionMeta.Library library : versionInfo.libraries()) { | ||||||
| 			if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) { | 			if (overrideLWJGL && library.name().startsWith("org.lwjgl")) { | ||||||
| 				project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.name())); | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			if (library.isValidForOS() && !library.hasNatives() && library.artifact() != null) { | ||||||
|  | 				if (serverBundleMetadata != null && isLibraryInBundle(serverBundleMetadata, library)) { | ||||||
|  | 					project.getDependencies().add(Constants.Configurations.MINECRAFT_SERVER_DEPENDENCIES, library.name()); | ||||||
|  | 				} else { | ||||||
|  | 					// Client only library, or legacy version | ||||||
|  | 					project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, library.name()); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 	private void initFiles(Project project, MinecraftProviderImpl minecraftProvider) { | 			if (library.hasNativesForOS()) { | ||||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(project); | 				MinecraftVersionMeta.Download nativeDownload = library.classifierForOS(); | ||||||
| 		MINECRAFT_LIBS = new File(extension.getFiles().getUserCache(), "libraries"); | 
 | ||||||
|  | 				Matcher matcher = NATIVES_PATTERN.matcher(nativeDownload.path()); | ||||||
|  | 
 | ||||||
|  | 				if (!matcher.find()) { | ||||||
|  | 					project.getLogger().warn("Failed to match regex for natives path : " + nativeDownload.path()); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				final String group = matcher.group("group").replace("/", "."); | ||||||
|  | 				final String name = matcher.group("name"); | ||||||
|  | 				final String version = matcher.group("version"); | ||||||
|  | 				final String classifier = matcher.group("classifier"); | ||||||
|  | 
 | ||||||
|  | 				final String dependencyNotation = "%s:%s:%s:%s".formatted(group, name, version, classifier); | ||||||
|  | 
 | ||||||
|  | 				project.getLogger().debug("Add native dependency '{}'", dependencyNotation); | ||||||
|  | 				project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, dependencyNotation); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (overrideLWJGL) { | ||||||
|  | 			LWJGLVersionOverride.DEPENDENCIES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, s)); | ||||||
|  | 			LWJGLVersionOverride.NATIVES.forEach(s -> project.getDependencies().add(Constants.Configurations.MINECRAFT_NATIVES, s)); | ||||||
|  | 
 | ||||||
|  | 			// Add the native support mod that fixes a handful of issues related to the LWJGL update at runtime. | ||||||
|  | 			ExternalModuleDependency dependency = (ExternalModuleDependency) project.getDependencies().create(Constants.Dependencies.NATIVE_SUPPORT + Constants.Dependencies.Versions.NATIVE_SUPPORT_VERSION); | ||||||
|  | 			dependency.setTransitive(false); | ||||||
|  | 			project.getDependencies().add("modLocalRuntime", dependency); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static boolean isLibraryInBundle(BundleMetadata bundleMetadata, MinecraftVersionMeta.Library library) { | ||||||
|  | 		return bundleMetadata.libraries().stream().anyMatch(entry -> entry.name().equals(library.name())); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -155,7 +155,7 @@ public class MinecraftMappedProvider extends DependencyProvider { | ||||||
| 					// Remap the sig fixes from intermediary to the target namespace | 					// Remap the sig fixes from intermediary to the target namespace | ||||||
| 					final Map<String, String> remapped = new HashMap<>(); | 					final Map<String, String> remapped = new HashMap<>(); | ||||||
| 					final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(getProject(), MappingsNamespace.INTERMEDIARY.toString(), toM); | 					final TinyRemapper sigTinyRemapper = TinyRemapperHelper.getTinyRemapper(getProject(), MappingsNamespace.INTERMEDIARY.toString(), toM); | ||||||
| 					final Remapper sigAsmRemapper = sigTinyRemapper.getRemapper(); | 					final Remapper sigAsmRemapper = sigTinyRemapper.getEnvironment().getRemapper(); | ||||||
| 
 | 
 | ||||||
| 					// Remap the class names and the signatures using a new tiny remapper instance. | 					// Remap the class names and the signatures using a new tiny remapper instance. | ||||||
| 					for (Map.Entry<String, String> entry : mappingsProvider.getSignatureFixes().entrySet()) { | 					for (Map.Entry<String, String> entry : mappingsProvider.getSignatureFixes().entrySet()) { | ||||||
|  |  | ||||||
|  | @ -1,150 +0,0 @@ | ||||||
| /* |  | ||||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2016-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; |  | ||||||
| 
 |  | ||||||
| import java.io.File; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.URL; |  | ||||||
| import java.nio.charset.StandardCharsets; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Objects; |  | ||||||
| import java.util.stream.Collectors; |  | ||||||
| 
 |  | ||||||
| import org.apache.commons.io.FileUtils; |  | ||||||
| import org.gradle.api.GradleException; |  | ||||||
| import org.gradle.api.Project; |  | ||||||
| 
 |  | ||||||
| import net.fabricmc.loom.LoomGradleExtension; |  | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; |  | ||||||
| import net.fabricmc.loom.util.HashedDownloadUtil; |  | ||||||
| import net.fabricmc.loom.util.MirrorUtil; |  | ||||||
| import net.fabricmc.loom.util.ZipUtils; |  | ||||||
| 
 |  | ||||||
| public class MinecraftNativesProvider { |  | ||||||
| 	private final Project project; |  | ||||||
| 	private final LoomGradleExtension extension; |  | ||||||
| 	private final File nativesDir; |  | ||||||
| 	private final File jarStore; |  | ||||||
| 
 |  | ||||||
| 	public MinecraftNativesProvider(Project project) { |  | ||||||
| 		this.project = project; |  | ||||||
| 		extension = LoomGradleExtension.get(project); |  | ||||||
| 
 |  | ||||||
| 		nativesDir = extension.getMinecraftProvider().nativesDir(); |  | ||||||
| 		jarStore = extension.getFiles().getNativesJarStore(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public static void provide(Project project) throws IOException { |  | ||||||
| 		new MinecraftNativesProvider(project).provide(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private void provide() throws IOException { |  | ||||||
| 		if (extension.getMinecraftProvider().hasCustomNatives()) { |  | ||||||
| 			if (!nativesDir.exists()) { |  | ||||||
| 				throw new RuntimeException("Could no find custom natives directory at " + nativesDir.getAbsolutePath()); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (!LoomGradlePlugin.refreshDeps && !requiresExtract()) { |  | ||||||
| 			project.getLogger().info("Natives do no need extracting, skipping"); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		extractNatives(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private void extractNatives() throws IOException { |  | ||||||
| 		boolean offline = project.getGradle().getStartParameter().isOffline(); |  | ||||||
| 
 |  | ||||||
| 		if (nativesDir.exists()) { |  | ||||||
| 			try { |  | ||||||
| 				FileUtils.deleteDirectory(nativesDir); |  | ||||||
| 			} catch (IOException e) { |  | ||||||
| 				throw new IOException("Failed to delete the natives directory, is the game running?", e); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		nativesDir.mkdirs(); |  | ||||||
| 
 |  | ||||||
| 		for (MinecraftVersionMeta.Download library : getNatives()) { |  | ||||||
| 			File libJarFile = library.relativeFile(jarStore); |  | ||||||
| 
 |  | ||||||
| 			if (!offline) { |  | ||||||
| 				HashedDownloadUtil.downloadIfInvalid(new URL(MirrorUtil.getLibrariesBase(project) + library.path()), libJarFile, library.sha1(), project.getLogger(), false); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (!libJarFile.exists()) { |  | ||||||
| 				throw new GradleException("Native jar not found at " + libJarFile.getAbsolutePath()); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			ZipUtils.unpackAll(libJarFile.toPath(), nativesDir.toPath()); |  | ||||||
| 
 |  | ||||||
| 			// Store a file containing the hash of the extracted natives, used on subsequent runs to skip extracting all the natives if they haven't changed |  | ||||||
| 			File libSha1File = new File(nativesDir, libJarFile.getName() + ".sha1"); |  | ||||||
| 			FileUtils.writeStringToFile(libSha1File, library.sha1(), StandardCharsets.UTF_8); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private boolean requiresExtract() { |  | ||||||
| 		List<MinecraftVersionMeta.Download> natives = getNatives(); |  | ||||||
| 
 |  | ||||||
| 		if (natives.isEmpty()) { |  | ||||||
| 			throw new IllegalStateException("No natives found for the current system"); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (MinecraftVersionMeta.Download library : natives) { |  | ||||||
| 			File libJarFile = library.relativeFile(jarStore); |  | ||||||
| 			File libSha1File = new File(nativesDir, libJarFile.getName() + ".sha1"); |  | ||||||
| 
 |  | ||||||
| 			if (!libSha1File.exists()) { |  | ||||||
| 				return true; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			try { |  | ||||||
| 				String sha1 = FileUtils.readFileToString(libSha1File, StandardCharsets.UTF_8); |  | ||||||
| 
 |  | ||||||
| 				if (!sha1.equalsIgnoreCase(library.sha1())) { |  | ||||||
| 					return true; |  | ||||||
| 				} |  | ||||||
| 			} catch (IOException e) { |  | ||||||
| 				project.getLogger().error("Failed to read " + libSha1File.getAbsolutePath(), e); |  | ||||||
| 				return true; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// All looks good, no need to re-extract |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private List<MinecraftVersionMeta.Download> getNatives() { |  | ||||||
| 		return extension.getMinecraftProvider().getVersionInfo().libraries().stream() |  | ||||||
| 				.filter((MinecraftVersionMeta.Library::hasNativesForOS)) |  | ||||||
| 				.map(MinecraftVersionMeta.Library::classifierForOS) |  | ||||||
| 				.filter(Objects::nonNull) |  | ||||||
| 				.collect(Collectors.toList()); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -81,7 +81,7 @@ public record MinecraftVersionMeta( | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (natives.get(OperatingSystem.getOS()) == null) { | 			if (natives.get(OperatingSystem.CURRENT_OS) == null) { | ||||||
| 				return false; | 				return false; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -89,7 +89,7 @@ public record MinecraftVersionMeta( | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		public Download classifierForOS() { | 		public Download classifierForOS() { | ||||||
| 			return downloads().classifier(natives.get(OperatingSystem.getOS())); | 			return downloads().classifier(natives.get(OperatingSystem.CURRENT_OS)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		public Download artifact() { | 		public Download artifact() { | ||||||
|  | @ -119,7 +119,7 @@ public record MinecraftVersionMeta( | ||||||
| 
 | 
 | ||||||
| 	public record OS(String name) { | 	public record OS(String name) { | ||||||
| 		public boolean isValidForOS() { | 		public boolean isValidForOS() { | ||||||
| 			return name() == null || name().equalsIgnoreCase(OperatingSystem.getOS()); | 			return name() == null || name().equalsIgnoreCase(OperatingSystem.CURRENT_OS); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ public interface LoomFiles { | ||||||
| 	File getProjectPersistentCache(); | 	File getProjectPersistentCache(); | ||||||
| 	File getProjectBuildCache(); | 	File getProjectBuildCache(); | ||||||
| 	File getRemappedModCache(); | 	File getRemappedModCache(); | ||||||
| 	File getNativesJarStore(); | 	File getNativesDirectory(Project project); | ||||||
| 	File getDefaultLog4jConfigFile(); | 	File getDefaultLog4jConfigFile(); | ||||||
| 	File getDevLauncherConfig(); | 	File getDevLauncherConfig(); | ||||||
| 	File getUnpickLoggingConfigFile(); | 	File getUnpickLoggingConfigFile(); | ||||||
|  |  | ||||||
|  | @ -26,6 +26,10 @@ package net.fabricmc.loom.extension; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
| 
 | 
 | ||||||
|  | import org.gradle.api.Project; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.LoomGradleExtension; | ||||||
|  | 
 | ||||||
| public abstract class LoomFilesBaseImpl implements LoomFiles { | public abstract class LoomFilesBaseImpl implements LoomFiles { | ||||||
| 	protected abstract File getGradleUserHomeDir(); | 	protected abstract File getGradleUserHomeDir(); | ||||||
| 	protected abstract File getRootDir(); | 	protected abstract File getRootDir(); | ||||||
|  | @ -70,8 +74,8 @@ public abstract class LoomFilesBaseImpl implements LoomFiles { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public File getNativesJarStore() { | 	public File getNativesDirectory(Project project) { | ||||||
| 		return createFile(getUserCache(), "natives/jars"); | 		return createFile(getRootProjectPersistentCache(), "natives/" + LoomGradleExtension.get(project).getMinecraftProvider().minecraftVersion()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
|  |  | ||||||
|  | @ -37,6 +37,7 @@ import java.util.function.Supplier; | ||||||
| 
 | 
 | ||||||
| import org.cadixdev.lorenz.MappingSet; | import org.cadixdev.lorenz.MappingSet; | ||||||
| import org.cadixdev.mercury.Mercury; | import org.cadixdev.mercury.Mercury; | ||||||
|  | import org.gradle.api.Action; | ||||||
| import org.gradle.api.NamedDomainObjectProvider; | import org.gradle.api.NamedDomainObjectProvider; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.artifacts.Configuration; | import org.gradle.api.artifacts.Configuration; | ||||||
|  | @ -145,8 +146,8 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public NamedDomainObjectProvider<Configuration> createLazyConfiguration(String name) { | 	public NamedDomainObjectProvider<Configuration> createLazyConfiguration(String name, Action<? super Configuration> configurationAction) { | ||||||
| 		NamedDomainObjectProvider<Configuration> provider = project.getConfigurations().register(name); | 		NamedDomainObjectProvider<Configuration> provider = project.getConfigurations().register(name, configurationAction); | ||||||
| 
 | 
 | ||||||
| 		if (lazyConfigurations.containsKey(name)) { | 		if (lazyConfigurations.containsKey(name)) { | ||||||
| 			throw new IllegalStateException("Duplicate configuration name" + name); | 			throw new IllegalStateException("Duplicate configuration name" + name); | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ import java.util.Objects; | ||||||
| import org.gradle.api.Action; | import org.gradle.api.Action; | ||||||
| import org.gradle.api.InvalidUserDataException; | import org.gradle.api.InvalidUserDataException; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| import org.gradle.api.provider.Property; | import org.gradle.api.provider.Property; | ||||||
| import org.gradle.api.provider.Provider; | import org.gradle.api.provider.Provider; | ||||||
| import org.gradle.api.tasks.SourceSet; | import org.gradle.api.tasks.SourceSet; | ||||||
|  | @ -110,8 +110,7 @@ public abstract class MixinExtensionApiImpl implements MixinExtensionAPI { | ||||||
| 
 | 
 | ||||||
| 	private SourceSet resolveSourceSet(String sourceSetName) { | 	private SourceSet resolveSourceSet(String sourceSetName) { | ||||||
| 		// try to find sourceSet with name sourceSetName in this project | 		// try to find sourceSet with name sourceSetName in this project | ||||||
| 		SourceSet sourceSet = project.getConvention().getPlugin(JavaPluginConvention.class) | 		SourceSet sourceSet = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().findByName(sourceSetName); | ||||||
| 				.getSourceSets().findByName(sourceSetName); |  | ||||||
| 
 | 
 | ||||||
| 		if (sourceSet == null) { | 		if (sourceSet == null) { | ||||||
| 			throw new InvalidUserDataException("No sourceSet " + sourceSetName + " was found"); | 			throw new InvalidUserDataException("No sourceSet " + sourceSetName + " was found"); | ||||||
|  |  | ||||||
|  | @ -38,8 +38,8 @@ import org.gradle.api.Project; | ||||||
| import org.gradle.api.Task; | import org.gradle.api.Task; | ||||||
| import org.gradle.api.UnknownTaskException; | import org.gradle.api.UnknownTaskException; | ||||||
| import org.gradle.api.artifacts.Configuration; | import org.gradle.api.artifacts.Configuration; | ||||||
| import org.gradle.api.plugins.BasePluginConvention; | import org.gradle.api.plugins.BasePluginExtension; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| import org.gradle.api.provider.Property; | import org.gradle.api.provider.Property; | ||||||
| import org.gradle.api.provider.Provider; | import org.gradle.api.provider.Provider; | ||||||
| import org.gradle.api.tasks.Input; | import org.gradle.api.tasks.Input; | ||||||
|  | @ -67,7 +67,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private String getDefaultMixinRefmapName() { | 	private String getDefaultMixinRefmapName() { | ||||||
| 		String defaultRefmapName = project.getConvention().getPlugin(BasePluginConvention.class).getArchivesBaseName() + "-refmap.json"; | 		String defaultRefmapName = project.getExtensions().getByType(BasePluginExtension.class).getArchivesName().get() + "-refmap.json"; | ||||||
| 		project.getLogger().info("Could not find refmap definition, will be using default name: " + defaultRefmapName); | 		project.getLogger().info("Could not find refmap definition, will be using default name: " + defaultRefmapName); | ||||||
| 		return defaultRefmapName; | 		return defaultRefmapName; | ||||||
| 	} | 	} | ||||||
|  | @ -87,7 +87,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx | ||||||
| 	@Override | 	@Override | ||||||
| 	@NotNull | 	@NotNull | ||||||
| 	public Stream<SourceSet> getMixinSourceSetsStream() { | 	public Stream<SourceSet> getMixinSourceSetsStream() { | ||||||
| 		return project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().stream() | 		return project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().stream() | ||||||
| 				.filter(sourceSet -> MixinExtension.getMixinInformationContainer(sourceSet) != null); | 				.filter(sourceSet -> MixinExtension.getMixinInformationContainer(sourceSet) != null); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -122,7 +122,7 @@ public class MixinExtensionImpl extends MixinExtensionApiImpl implements MixinEx | ||||||
| 	@Override | 	@Override | ||||||
| 	public void init() { | 	public void init() { | ||||||
| 		if (isDefault) { | 		if (isDefault) { | ||||||
| 			project.getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().forEach(this::add); | 			project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets().forEach(this::add); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		isDefault = false; | 		isDefault = false; | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ public abstract class AbstractRunTask extends JavaExec { | ||||||
| 
 | 
 | ||||||
| 		setClasspath(config.sourceSet.getRuntimeClasspath()); | 		setClasspath(config.sourceSet.getRuntimeClasspath()); | ||||||
| 		args(config.programArgs); | 		args(config.programArgs); | ||||||
|  | 		getMainClass().set(config.mainClass); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
|  | @ -64,11 +65,6 @@ public abstract class AbstractRunTask extends JavaExec { | ||||||
| 		super.setWorkingDir(dir); | 		super.setWorkingDir(dir); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override |  | ||||||
| 	public String getMain() { |  | ||||||
| 		return config.mainClass; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public List<String> getJvmArgs() { | 	public List<String> getJvmArgs() { | ||||||
| 		List<String> superArgs = super.getJvmArgs(); | 		List<String> superArgs = super.getJvmArgs(); | ||||||
|  |  | ||||||
|  | @ -30,7 +30,6 @@ import org.gradle.api.Project; | ||||||
| import org.gradle.api.tasks.TaskAction; | import org.gradle.api.tasks.TaskAction; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftNativesProvider; |  | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider; | import net.fabricmc.loom.configuration.providers.minecraft.assets.MinecraftAssetsProvider; | ||||||
| 
 | 
 | ||||||
| public class DownloadAssetsTask extends AbstractLoomTask { | public class DownloadAssetsTask extends AbstractLoomTask { | ||||||
|  | @ -40,6 +39,5 @@ public class DownloadAssetsTask extends AbstractLoomTask { | ||||||
| 		LoomGradleExtension extension = getExtension(); | 		LoomGradleExtension extension = getExtension(); | ||||||
| 
 | 
 | ||||||
| 		MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | 		MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | ||||||
| 		MinecraftNativesProvider.provide(project); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										50
									
								
								src/main/java/net/fabricmc/loom/task/ExtractNativesTask.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/main/java/net/fabricmc/loom/task/ExtractNativesTask.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.task; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | 
 | ||||||
|  | import javax.inject.Inject; | ||||||
|  | 
 | ||||||
|  | import org.gradle.api.tasks.Sync; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.LoomGradleExtension; | ||||||
|  | import net.fabricmc.loom.util.Constants; | ||||||
|  | 
 | ||||||
|  | public abstract class ExtractNativesTask extends Sync { | ||||||
|  | 	@Inject | ||||||
|  | 	public ExtractNativesTask() { | ||||||
|  | 		// Is there a lazy way to do this for many files? - Doesnt seem there is... | ||||||
|  | 		for (File nativeFile : getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_NATIVES).getFiles()) { | ||||||
|  | 			from(getProject().zipTree(nativeFile), copySpec -> { | ||||||
|  | 				copySpec.exclude("META-INF/**"); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		into(LoomGradleExtension.get(getProject()).getFiles().getNativesDirectory(getProject())); | ||||||
|  | 
 | ||||||
|  | 		setDescription("Downloads and extracts the minecraft natives"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -43,6 +43,7 @@ public final class LoomTasks { | ||||||
| 
 | 
 | ||||||
| 	public static void registerTasks(Project project) { | 	public static void registerTasks(Project project) { | ||||||
| 		TaskContainer tasks = project.getTasks(); | 		TaskContainer tasks = project.getTasks(); | ||||||
|  | 		LoomGradleExtension extension = LoomGradleExtension.get(project); | ||||||
| 
 | 
 | ||||||
| 		tasks.register("migrateMappings", MigrateMappingsTask.class, t -> { | 		tasks.register("migrateMappings", MigrateMappingsTask.class, t -> { | ||||||
| 			t.setDescription("Migrates mappings to a new version."); | 			t.setDescription("Migrates mappings to a new version."); | ||||||
|  | @ -54,7 +55,11 @@ public final class LoomTasks { | ||||||
| 			t.setGroup(Constants.TaskGroup.FABRIC); | 			t.setGroup(Constants.TaskGroup.FABRIC); | ||||||
| 		}); | 		}); | ||||||
| 
 | 
 | ||||||
| 		tasks.register("downloadAssets", DownloadAssetsTask.class, t -> t.setDescription("Downloads required assets for Fabric.")); | 		TaskProvider<ExtractNativesTask> extractNatives = tasks.register("extractNatives", ExtractNativesTask.class); | ||||||
|  | 		tasks.register("downloadAssets", DownloadAssetsTask.class, t -> { | ||||||
|  | 			t.dependsOn(extractNatives); | ||||||
|  | 			t.setDescription("Downloads required assets for Fabric."); | ||||||
|  | 		}); | ||||||
| 		tasks.register("remapSourcesJar", RemapSourcesJarTask.class, t -> t.setDescription("Remaps the project sources jar to intermediary names.")); | 		tasks.register("remapSourcesJar", RemapSourcesJarTask.class, t -> t.setDescription("Remaps the project sources jar to intermediary names.")); | ||||||
| 
 | 
 | ||||||
| 		TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> { | 		TaskProvider<ValidateAccessWidenerTask> validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> { | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ import org.gradle.api.IllegalDependencyNotation; | ||||||
| import org.gradle.api.JavaVersion; | import org.gradle.api.JavaVersion; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.gradle.api.artifacts.Dependency; | import org.gradle.api.artifacts.Dependency; | ||||||
| import org.gradle.api.plugins.JavaPluginConvention; | import org.gradle.api.plugins.JavaPluginExtension; | ||||||
| import org.gradle.api.tasks.TaskAction; | import org.gradle.api.tasks.TaskAction; | ||||||
| import org.gradle.api.tasks.options.Option; | import org.gradle.api.tasks.options.Option; | ||||||
| 
 | 
 | ||||||
|  | @ -171,12 +171,7 @@ public class MigrateMappingsTask extends AbstractLoomTask { | ||||||
| 		project.getLogger().lifecycle(":remapping"); | 		project.getLogger().lifecycle(":remapping"); | ||||||
| 		Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false); | 		Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false); | ||||||
| 
 | 
 | ||||||
| 		final JavaPluginConvention convention = project.getConvention().findPlugin(JavaPluginConvention.class); | 		final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility(); | ||||||
| 		final JavaVersion javaVersion = convention != null |  | ||||||
| 				? |  | ||||||
| 				convention.getSourceCompatibility() |  | ||||||
| 				: |  | ||||||
| 				JavaVersion.current(); |  | ||||||
| 		mercury.setSourceCompatibility(javaVersion.toString()); | 		mercury.setSourceCompatibility(javaVersion.toString()); | ||||||
| 
 | 
 | ||||||
| 		mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath()); | 		mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath()); | ||||||
|  |  | ||||||
|  | @ -124,7 +124,7 @@ public class RemapJarTask extends Jar { | ||||||
| 		Project project = getProject(); | 		Project project = getProject(); | ||||||
| 		LoomGradleExtension extension = LoomGradleExtension.get(getProject()); | 		LoomGradleExtension extension = LoomGradleExtension.get(getProject()); | ||||||
| 		Path input = this.getInput().getAsFile().get().toPath(); | 		Path input = this.getInput().getAsFile().get().toPath(); | ||||||
| 		Path output = this.getArchivePath().toPath(); | 		Path output = this.getArchiveFile().get().getAsFile().toPath(); | ||||||
| 
 | 
 | ||||||
| 		if (!Files.exists(input)) { | 		if (!Files.exists(input)) { | ||||||
| 			throw new FileNotFoundException(input.toString()); | 			throw new FileNotFoundException(input.toString()); | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								src/main/java/net/fabricmc/loom/util/Architecture.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/main/java/net/fabricmc/loom/util/Architecture.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.util; | ||||||
|  | 
 | ||||||
|  | public class Architecture { | ||||||
|  | 	public static final Architecture CURRENT = new Architecture(System.getProperty("os.arch")); | ||||||
|  | 
 | ||||||
|  | 	private final String name; | ||||||
|  | 
 | ||||||
|  | 	public Architecture(String name) { | ||||||
|  | 		this.name = name; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public boolean is64Bit() { | ||||||
|  | 		return name.contains("64") || name.startsWith("armv8"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public boolean isArm() { | ||||||
|  | 		return name.startsWith("arm") || name.startsWith("aarch64"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getName() { | ||||||
|  | 		return name; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								src/main/java/net/fabricmc/loom/util/ClosureAction.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/main/java/net/fabricmc/loom/util/ClosureAction.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.util; | ||||||
|  | 
 | ||||||
|  | import groovy.lang.Closure; | ||||||
|  | import org.gradle.api.Action; | ||||||
|  | 
 | ||||||
|  | public record ClosureAction<T>(Closure closure) implements Action<T> { | ||||||
|  | 	@Override | ||||||
|  | 	public void execute(T t) { | ||||||
|  | 		closure.setDelegate(t); | ||||||
|  | 		closure.call(t); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -40,8 +40,6 @@ public class Constants { | ||||||
| 	public static final String EXPERIMENTAL_VERSIONS = "https://maven.fabricmc.net/net/minecraft/experimental_versions.json"; | 	public static final String EXPERIMENTAL_VERSIONS = "https://maven.fabricmc.net/net/minecraft/experimental_versions.json"; | ||||||
| 	public static final String FABRIC_REPOSITORY = "https://maven.fabricmc.net/"; | 	public static final String FABRIC_REPOSITORY = "https://maven.fabricmc.net/"; | ||||||
| 
 | 
 | ||||||
| 	public static final String SYSTEM_ARCH = System.getProperty("os.arch").equals("64") ? "64" : "32"; |  | ||||||
| 
 |  | ||||||
| 	public static final int ASM_VERSION = Opcodes.ASM9; | 	public static final int ASM_VERSION = Opcodes.ASM9; | ||||||
| 
 | 
 | ||||||
| 	public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of( | 	public static final List<RemappedConfigurationEntry> MOD_COMPILE_ENTRIES = ImmutableList.of( | ||||||
|  | @ -64,8 +62,13 @@ public class Constants { | ||||||
| 		public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped"; | 		public static final String MOD_COMPILE_CLASSPATH_MAPPED = "modCompileClasspathMapped"; | ||||||
| 		public static final String INCLUDE = "include"; | 		public static final String INCLUDE = "include"; | ||||||
| 		public static final String MINECRAFT = "minecraft"; | 		public static final String MINECRAFT = "minecraft"; | ||||||
|  | 		/** | ||||||
|  | 		 * The server specific configuration will be empty when using a legacy (pre 21w38a server jar) | ||||||
|  | 		 * find the client only dependencies on the "minecraftLibraries" config. | ||||||
|  | 		 */ | ||||||
|  | 		public static final String MINECRAFT_SERVER_DEPENDENCIES = "minecraftServerLibraries"; | ||||||
| 		public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; | 		public static final String MINECRAFT_DEPENDENCIES = "minecraftLibraries"; | ||||||
| 		public static final String MINECRAFT_REMAP_CLASSPATH = "minecraftRemapClasspath"; | 		public static final String MINECRAFT_NATIVES = "minecraftNatives"; | ||||||
| 		public static final String MINECRAFT_NAMED = "minecraftNamed"; | 		public static final String MINECRAFT_NAMED = "minecraftNamed"; | ||||||
| 		public static final String MAPPINGS = "mappings"; | 		public static final String MAPPINGS = "mappings"; | ||||||
| 		public static final String MAPPINGS_FINAL = "mappingsFinal"; | 		public static final String MAPPINGS_FINAL = "mappingsFinal"; | ||||||
|  | @ -93,6 +96,7 @@ public class Constants { | ||||||
| 		public static final String DEV_LAUNCH_INJECTOR = "net.fabricmc:dev-launch-injector:"; | 		public static final String DEV_LAUNCH_INJECTOR = "net.fabricmc:dev-launch-injector:"; | ||||||
| 		public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:"; | 		public static final String TERMINAL_CONSOLE_APPENDER = "net.minecrell:terminalconsoleappender:"; | ||||||
| 		public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:"; | 		public static final String JETBRAINS_ANNOTATIONS = "org.jetbrains:annotations:"; | ||||||
|  | 		public static final String NATIVE_SUPPORT = "net.fabricmc:fabric-loom-native-support:"; | ||||||
| 
 | 
 | ||||||
| 		private Dependencies() { | 		private Dependencies() { | ||||||
| 		} | 		} | ||||||
|  | @ -105,6 +109,7 @@ public class Constants { | ||||||
| 			public static final String DEV_LAUNCH_INJECTOR = "0.2.1+build.8"; | 			public static final String DEV_LAUNCH_INJECTOR = "0.2.1+build.8"; | ||||||
| 			public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0"; | 			public static final String TERMINAL_CONSOLE_APPENDER = "1.2.0"; | ||||||
| 			public static final String JETBRAINS_ANNOTATIONS = "23.0.0"; | 			public static final String JETBRAINS_ANNOTATIONS = "23.0.0"; | ||||||
|  | 			public static final String NATIVE_SUPPORT_VERSION = "1.0.1"; | ||||||
| 
 | 
 | ||||||
| 			private Versions() { | 			private Versions() { | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -28,9 +28,12 @@ import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.net.URI; | import java.net.URI; | ||||||
| import java.net.URISyntaxException; | import java.net.URISyntaxException; | ||||||
|  | import java.nio.charset.StandardCharsets; | ||||||
| import java.nio.file.FileSystem; | import java.nio.file.FileSystem; | ||||||
| import java.nio.file.FileSystemAlreadyExistsException; | import java.nio.file.FileSystemAlreadyExistsException; | ||||||
| import java.nio.file.FileSystems; | import java.nio.file.FileSystems; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.NoSuchFileException; | ||||||
| import java.nio.file.Path; | import java.nio.file.Path; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  | @ -38,6 +41,20 @@ import java.util.function.Supplier; | ||||||
| 
 | 
 | ||||||
| public final class FileSystemUtil { | public final class FileSystemUtil { | ||||||
| 	public record Delegate(FileSystem fs, boolean owner) implements AutoCloseable, Supplier<FileSystem> { | 	public record Delegate(FileSystem fs, boolean owner) implements AutoCloseable, Supplier<FileSystem> { | ||||||
|  | 		public byte[] readAllBytes(String path) throws IOException { | ||||||
|  | 			Path fsPath = get().getPath(path); | ||||||
|  | 
 | ||||||
|  | 			if (Files.exists(fsPath)) { | ||||||
|  | 				return Files.readAllBytes(fsPath); | ||||||
|  | 			} else { | ||||||
|  | 				throw new NoSuchFileException(fsPath.toString()); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String readString(String path) throws IOException { | ||||||
|  | 			return new String(readAllBytes(path), StandardCharsets.UTF_8); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		@Override | 		@Override | ||||||
| 		public void close() throws IOException { | 		public void close() throws IOException { | ||||||
| 			if (owner) { | 			if (owner) { | ||||||
|  | @ -65,6 +82,10 @@ public final class FileSystemUtil { | ||||||
| 		return getJarFileSystem(path.toUri(), create); | 		return getJarFileSystem(path.toUri(), create); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	public static Delegate getJarFileSystem(Path path) throws IOException { | ||||||
|  | 		return getJarFileSystem(path, false); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	public static Delegate getJarFileSystem(URI uri, boolean create) throws IOException { | 	public static Delegate getJarFileSystem(URI uri, boolean create) throws IOException { | ||||||
| 		URI jarUri; | 		URI jarUri; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,18 +25,12 @@ | ||||||
| package net.fabricmc.loom.util; | package net.fabricmc.loom.util; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; |  | ||||||
| import java.util.zip.ZipFile; |  | ||||||
| 
 | 
 | ||||||
| public final class ModUtils { | public final class ModUtils { | ||||||
| 	private ModUtils() { | 	private ModUtils() { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public static boolean isMod(File input) { | 	public static boolean isMod(File input) { | ||||||
| 		try (ZipFile zipFile = new ZipFile(input)) { | 		return ZipUtils.contains(input.toPath(), "fabric.mod.json"); | ||||||
| 			return zipFile.getEntry("fabric.mod.json") != null; |  | ||||||
| 		} catch (IOException e) { |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,23 +30,21 @@ import java.net.StandardProtocolFamily; | ||||||
| import java.nio.channels.ServerSocketChannel; | import java.nio.channels.ServerSocketChannel; | ||||||
| 
 | 
 | ||||||
| public class OperatingSystem { | public class OperatingSystem { | ||||||
| 	public static String getOS() { | 	public static final String WINDOWS = "windows"; | ||||||
|  | 	public static final String MAC_OS = "osx"; | ||||||
|  | 	public static final String LINUX = "linux"; | ||||||
|  | 
 | ||||||
|  | 	public static final String CURRENT_OS = getOS(); | ||||||
|  | 
 | ||||||
|  | 	private static String getOS() { | ||||||
| 		String osName = System.getProperty("os.name").toLowerCase(); | 		String osName = System.getProperty("os.name").toLowerCase(); | ||||||
| 
 | 
 | ||||||
| 		if (osName.contains("win")) { | 		if (osName.contains("win")) { | ||||||
| 			return "windows"; | 			return WINDOWS; | ||||||
| 		} else if (osName.contains("mac")) { | 		} else if (osName.contains("mac")) { | ||||||
| 			return "osx"; | 			return MAC_OS; | ||||||
| 		} else { | 		} else { | ||||||
| 			return "linux"; | 			return LINUX; | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public static String getArch() { |  | ||||||
| 		if (is64Bit()) { |  | ||||||
| 			return "64"; |  | ||||||
| 		} else { |  | ||||||
| 			return "32"; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -54,10 +52,6 @@ public class OperatingSystem { | ||||||
| 		return System.getProperty("sun.arch.data.model").contains("64"); | 		return System.getProperty("sun.arch.data.model").contains("64"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public static boolean isWindows() { |  | ||||||
| 		return getOS().equals("windows"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public static boolean isCIBuild() { | 	public static boolean isCIBuild() { | ||||||
| 		String loomProperty = System.getProperty("fabric.loom.ci"); | 		String loomProperty = System.getProperty("fabric.loom.ci"); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -83,13 +83,7 @@ public class ZipUtils { | ||||||
| 
 | 
 | ||||||
| 	public static byte[] unpack(Path zip, String path) throws IOException { | 	public static byte[] unpack(Path zip, String path) throws IOException { | ||||||
| 		try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) { | 		try (FileSystemUtil.Delegate fs = FileSystemUtil.getJarFileSystem(zip, false)) { | ||||||
| 			Path fsPath = fs.get().getPath(path); | 			return fs.readAllBytes(path); | ||||||
| 
 |  | ||||||
| 			if (Files.exists(fsPath)) { |  | ||||||
| 				return Files.readAllBytes(fsPath); |  | ||||||
| 			} else { |  | ||||||
| 				throw new NoSuchFileException(fsPath.toString()); |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ import org.gradle.util.GradleVersion | ||||||
| 
 | 
 | ||||||
| class LoomTestConstants { | class LoomTestConstants { | ||||||
|     public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion() |     public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion() | ||||||
|     public final static String PRE_RELEASE_GRADLE = "7.4-20211203231050+0000" |     public final static String PRE_RELEASE_GRADLE = "7.4-20211216231505+0000" | ||||||
| 
 | 
 | ||||||
|     public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE] |     public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE] | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,86 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2021 FabricMC | ||||||
|  |  * | ||||||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |  * of this software and associated documentation files (the "Software"), to deal | ||||||
|  |  * in the Software without restriction, including without limitation the rights | ||||||
|  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |  * copies of the Software, and to permit persons to whom the Software is | ||||||
|  |  * furnished to do so, subject to the following conditions: | ||||||
|  |  * | ||||||
|  |  * The above copyright notice and this permission notice shall be included in all | ||||||
|  |  * copies or substantial portions of the Software. | ||||||
|  |  * | ||||||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |  * SOFTWARE. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | package net.fabricmc.loom.test.integration | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.test.util.GradleProjectTestTrait | ||||||
|  | import spock.lang.Specification | ||||||
|  | import spock.lang.Unroll | ||||||
|  | import spock.util.environment.RestoreSystemProperties | ||||||
|  | 
 | ||||||
|  | import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS | ||||||
|  | import static org.gradle.testkit.runner.TaskOutcome.SUCCESS | ||||||
|  | import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE | ||||||
|  | 
 | ||||||
|  | class NativesTest extends Specification implements GradleProjectTestTrait  { | ||||||
|  |     @Unroll | ||||||
|  |     def "Default natives for 1.18 (gradle #version)"() { | ||||||
|  |         setup: | ||||||
|  |             def gradle = gradleProject(project: "minimalBase", version: version) | ||||||
|  | 
 | ||||||
|  |             gradle.buildGradle << ''' | ||||||
|  |                     dependencies { | ||||||
|  |                         minecraft "com.mojang:minecraft:1.18" | ||||||
|  |                         mappings loom.officialMojangMappings() | ||||||
|  |                     } | ||||||
|  |                 ''' | ||||||
|  | 
 | ||||||
|  |         when: | ||||||
|  |             // Run the task twice to ensure its up to date | ||||||
|  |             def result = gradle.run(task: "extractNatives") | ||||||
|  |             def result2 = gradle.run(task: "extractNatives") | ||||||
|  | 
 | ||||||
|  |         then: | ||||||
|  |             result.task(":extractNatives").outcome == SUCCESS | ||||||
|  |             result2.task(":extractNatives").outcome == UP_TO_DATE | ||||||
|  | 
 | ||||||
|  |         where: | ||||||
|  |             version << STANDARD_TEST_VERSIONS | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @RestoreSystemProperties | ||||||
|  |     @Unroll | ||||||
|  |     def "Overridden natives for 1.18 (gradle #version)"() { | ||||||
|  |         setup: | ||||||
|  |             System.setProperty('loom.test.lwjgloverride', "true") | ||||||
|  |             def gradle = gradleProject(project: "minimalBase", version: version) | ||||||
|  | 
 | ||||||
|  |             gradle.buildGradle << ''' | ||||||
|  |                     dependencies { | ||||||
|  |                         minecraft "com.mojang:minecraft:1.18" | ||||||
|  |                         mappings loom.officialMojangMappings() | ||||||
|  |                     } | ||||||
|  |                 ''' | ||||||
|  | 
 | ||||||
|  |         when: | ||||||
|  |             // Run the task twice to ensure its up to date | ||||||
|  |             def result = gradle.run(task: "extractNatives") | ||||||
|  | 
 | ||||||
|  |         then: | ||||||
|  |             result.task(":extractNatives").outcome == SUCCESS | ||||||
|  | 
 | ||||||
|  |         where: | ||||||
|  |             version << STANDARD_TEST_VERSIONS | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -30,29 +30,29 @@ import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuil | ||||||
| import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec | import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec | ||||||
| import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec | import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec | ||||||
| import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec | import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec | ||||||
| import org.gradle.api.Action | import net.fabricmc.loom.util.ClosureAction | ||||||
| import org.gradle.util.ConfigureUtil |  | ||||||
| import spock.lang.Specification | import spock.lang.Specification | ||||||
| 
 | 
 | ||||||
| class LayeredMappingSpecBuilderTest extends Specification { | class LayeredMappingSpecBuilderTest extends Specification { | ||||||
|     def "simple mojmap" () { |     def "simple mojmap" () { | ||||||
|         when: |         when: | ||||||
|             def spec = layered() { |             def spec = layered { | ||||||
|                 officialMojangMappings() |                 officialMojangMappings() | ||||||
|             } |             } | ||||||
|             def layers = spec.layers() |             def layers = spec.layers() | ||||||
|         then: |         then: | ||||||
|             spec.version == "layered+hash.2198" |  | ||||||
|             layers.size() == 2 |             layers.size() == 2 | ||||||
|  |             spec.version == "layered+hash.2198" | ||||||
|             layers[0].class == IntermediaryMappingsSpec |             layers[0].class == IntermediaryMappingsSpec | ||||||
|             layers[1].class == MojangMappingsSpec |             layers[1].class == MojangMappingsSpec | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     def "simple mojmap with parchment" () { |     def "simple mojmap with parchment" () { | ||||||
|         when: |         when: | ||||||
|  |             def dep = "I like cake" | ||||||
|             def spec = layered() { |             def spec = layered() { | ||||||
|                 officialMojangMappings() |                 officialMojangMappings() | ||||||
|                 parchment("I like cake") |                 parchment(dep) | ||||||
|             } |             } | ||||||
|             def layers = spec.layers() |             def layers = spec.layers() | ||||||
|             def parchment = layers[2] as ParchmentMappingsSpec |             def parchment = layers[2] as ParchmentMappingsSpec | ||||||
|  | @ -88,7 +88,7 @@ class LayeredMappingSpecBuilderTest extends Specification { | ||||||
| 
 | 
 | ||||||
|     def "simple mojmap with parchment keep prefix alternate hash" () { |     def "simple mojmap with parchment keep prefix alternate hash" () { | ||||||
|         when: |         when: | ||||||
|             def spec = layered() { |             def spec = layered { | ||||||
|                 officialMojangMappings() |                 officialMojangMappings() | ||||||
|                 parchment("I really like cake") { |                 parchment("I really like cake") { | ||||||
|                     it.removePrefix = false |                     it.removePrefix = false | ||||||
|  | @ -106,14 +106,9 @@ class LayeredMappingSpecBuilderTest extends Specification { | ||||||
|             parchment.removePrefix() == false |             parchment.removePrefix() == false | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Gradle does this big of magic behind the scenes |  | ||||||
|     LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) { |     LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilderImpl) Closure cl) { | ||||||
|         return layeredAction(ConfigureUtil.configureUsing(cl)) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     LayeredMappingSpec layeredAction(Action<LayeredMappingSpecBuilderImpl> action) { |  | ||||||
|         LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl() |         LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl() | ||||||
|         action.execute(builder) |         new ClosureAction(cl).execute(builder) | ||||||
|         return builder.build() |         return builder.build() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue