Rewrite minecraft game data handling.
Much faster asset and native validation logic. Simplfied game metadata model.
This commit is contained in:
		
							parent
							
								
									24c166fc79
								
							
						
					
					
						commit
						0d1f40aee4
					
				
					 10 changed files with 442 additions and 343 deletions
				
			
		|  | @ -59,7 +59,7 @@ public class SetupIntelijRunConfigs { | ||||||
| 		if (extension.ideSync()) { | 		if (extension.ideSync()) { | ||||||
| 			//Ensures the assets are downloaded when idea is syncing a project | 			//Ensures the assets are downloaded when idea is syncing a project | ||||||
| 			MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | 			MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | ||||||
| 			MinecraftNativesProvider.provide(extension.getMinecraftProvider(), project); | 			MinecraftNativesProvider.provide(project); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		String projectPath = project == rootProject ? "" : project.getPath().replace(':', '_'); | 		String projectPath = project == rootProject ? "" : project.getPath().replace(':', '_'); | ||||||
|  |  | ||||||
|  | @ -64,7 +64,7 @@ public class LaunchProvider extends DependencyProvider { | ||||||
| 				.property("client", "org.lwjgl.librarypath", getExtension().getNativesDirectory().getAbsolutePath()) | 				.property("client", "org.lwjgl.librarypath", getExtension().getNativesDirectory().getAbsolutePath()) | ||||||
| 
 | 
 | ||||||
| 				.argument("client", "--assetIndex") | 				.argument("client", "--assetIndex") | ||||||
| 				.argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex.getFabricId(getExtension().getMinecraftProvider().getMinecraftVersion())) | 				.argument("client", getExtension().getMinecraftProvider().getVersionInfo().getAssetIndex().getFabricId(getExtension().getMinecraftProvider().getMinecraftVersion())) | ||||||
| 				.argument("client", "--assetsDir") | 				.argument("client", "--assetsDir") | ||||||
| 				.argument("client", new File(getExtension().getUserCache(), "assets").getAbsolutePath()); | 				.argument("client", new File(getExtension().getUserCache(), "assets").getAbsolutePath()); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,7 +43,7 @@ import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.configuration.DependencyProvider; | import net.fabricmc.loom.configuration.DependencyProvider; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion; | 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.MinecraftVersionInfo; | 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.DownloadUtil; | import net.fabricmc.loom.util.DownloadUtil; | ||||||
| import net.fabricmc.loom.util.HashedDownloadUtil; | import net.fabricmc.loom.util.HashedDownloadUtil; | ||||||
|  | @ -52,7 +52,7 @@ import net.fabricmc.stitch.merge.JarMerger; | ||||||
| public class MinecraftProvider extends DependencyProvider { | public class MinecraftProvider extends DependencyProvider { | ||||||
| 	private String minecraftVersion; | 	private String minecraftVersion; | ||||||
| 
 | 
 | ||||||
| 	private MinecraftVersionInfo versionInfo; | 	private MinecraftVersionMeta versionInfo; | ||||||
| 	private MinecraftLibraryProvider libraryProvider; | 	private MinecraftLibraryProvider libraryProvider; | ||||||
| 
 | 
 | ||||||
| 	private File minecraftJson; | 	private File minecraftJson; | ||||||
|  | @ -76,7 +76,7 @@ public class MinecraftProvider extends DependencyProvider { | ||||||
| 		downloadMcJson(offline); | 		downloadMcJson(offline); | ||||||
| 
 | 
 | ||||||
| 		try (FileReader reader = new FileReader(minecraftJson)) { | 		try (FileReader reader = new FileReader(minecraftJson)) { | ||||||
| 			versionInfo = LoomGradlePlugin.GSON.fromJson(reader, MinecraftVersionInfo.class); | 			versionInfo = LoomGradlePlugin.GSON.fromJson(reader, MinecraftVersionMeta.class); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Add Loom as an annotation processor | 		// Add Loom as an annotation processor | ||||||
|  | @ -209,11 +209,11 @@ public class MinecraftProvider extends DependencyProvider { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		MinecraftVersionInfo.Downloads client = versionInfo.downloads.get("client"); | 		MinecraftVersionMeta.Download client = versionInfo.getDownload("client"); | ||||||
| 		MinecraftVersionInfo.Downloads server = versionInfo.downloads.get("server"); | 		MinecraftVersionMeta.Download server = versionInfo.getDownload("server"); | ||||||
| 
 | 
 | ||||||
| 		HashedDownloadUtil.downloadIfInvalid(new URL(client.url), minecraftClientJar, client.sha1, logger, false); | 		HashedDownloadUtil.downloadIfInvalid(new URL(client.getUrl()), minecraftClientJar, client.getSha1(), logger, false); | ||||||
| 		HashedDownloadUtil.downloadIfInvalid(new URL(server.url), minecraftServerJar, server.sha1, logger, false); | 		HashedDownloadUtil.downloadIfInvalid(new URL(server.getUrl()), minecraftServerJar, server.getSha1(), logger, false); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void mergeJars(Logger logger) throws IOException { | 	private void mergeJars(Logger logger) throws IOException { | ||||||
|  | @ -233,7 +233,7 @@ public class MinecraftProvider extends DependencyProvider { | ||||||
| 		return minecraftVersion; | 		return minecraftVersion; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public MinecraftVersionInfo getVersionInfo() { | 	public MinecraftVersionMeta getVersionInfo() { | ||||||
| 		return versionInfo; | 		return versionInfo; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ import org.zeroturnaround.zip.ZipUtil; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionInfo; | import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; | ||||||
| import net.fabricmc.loom.util.DownloadUtil; | import net.fabricmc.loom.util.DownloadUtil; | ||||||
| import net.fabricmc.lorenztiny.TinyMappingsReader; | import net.fabricmc.lorenztiny.TinyMappingsReader; | ||||||
| import net.fabricmc.mapping.tree.TinyMappingFactory; | import net.fabricmc.mapping.tree.TinyMappingFactory; | ||||||
|  | @ -121,14 +121,14 @@ public class MojangMappingsDependency implements SelfResolvingDependency { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private MappingSet getMappingsSet(Path clientMappings, Path serverMappings) throws IOException { | 	private MappingSet getMappingsSet(Path clientMappings, Path serverMappings) throws IOException { | ||||||
| 		MinecraftVersionInfo versionInfo = extension.getMinecraftProvider().getVersionInfo(); | 		MinecraftVersionMeta versionInfo = extension.getMinecraftProvider().getVersionInfo(); | ||||||
| 
 | 
 | ||||||
| 		if (versionInfo.downloads.get(MANIFEST_CLIENT_MAPPINGS) == null) { | 		if (versionInfo.getDownload(MANIFEST_CLIENT_MAPPINGS) == null) { | ||||||
| 			throw new RuntimeException("Failed to find official mojang mappings for " + getVersion()); | 			throw new RuntimeException("Failed to find official mojang mappings for " + getVersion()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		String clientMappingsUrl = versionInfo.downloads.get(MANIFEST_CLIENT_MAPPINGS).url; | 		String clientMappingsUrl = versionInfo.getDownload(MANIFEST_CLIENT_MAPPINGS).getUrl(); | ||||||
| 		String serverMappingsUrl = versionInfo.downloads.get(MANIFEST_SERVER_MAPPINGS).url; | 		String serverMappingsUrl = versionInfo.getDownload(MANIFEST_CLIENT_MAPPINGS).getUrl(); | ||||||
| 
 | 
 | ||||||
| 		DownloadUtil.downloadIfChanged(new URL(clientMappingsUrl), clientMappings.toFile(), project.getLogger()); | 		DownloadUtil.downloadIfChanged(new URL(clientMappingsUrl), clientMappings.toFile(), project.getLogger()); | ||||||
| 		DownloadUtil.downloadIfChanged(new URL(serverMappingsUrl), serverMappings.toFile(), project.getLogger()); | 		DownloadUtil.downloadIfChanged(new URL(serverMappingsUrl), serverMappings.toFile(), project.getLogger()); | ||||||
|  |  | ||||||
|  | @ -36,22 +36,13 @@ public class MinecraftLibraryProvider { | ||||||
| 	public File MINECRAFT_LIBS; | 	public File MINECRAFT_LIBS; | ||||||
| 
 | 
 | ||||||
| 	public void provide(MinecraftProvider minecraftProvider, Project project) { | 	public void provide(MinecraftProvider minecraftProvider, Project project) { | ||||||
| 		MinecraftVersionInfo versionInfo = minecraftProvider.getVersionInfo(); | 		MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); | ||||||
| 
 | 
 | ||||||
| 		initFiles(project, minecraftProvider); | 		initFiles(project, minecraftProvider); | ||||||
| 
 | 
 | ||||||
| 		for (MinecraftVersionInfo.Library library : versionInfo.libraries) { | 		for (MinecraftVersionMeta.Library library : versionInfo.getLibraries()) { | ||||||
| 			if (library.allowed() && !library.isNative() && library.getFile(MINECRAFT_LIBS) != null) { | 			if (library.isValidForOS() && !library.hasNatives() && library.getArtifact() != null) { | ||||||
| 				// TODO: Add custom library locations | 				project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.getName())); | ||||||
| 
 |  | ||||||
| 				// By default, they are all available on all sides |  | ||||||
| 				/* boolean isClientOnly = false; |  | ||||||
| 
 |  | ||||||
| 				if (library.name.contains("java3d") || library.name.contains("paulscode") || library.name.contains("lwjgl") || library.name.contains("twitch") || library.name.contains("jinput") || library.name.contains("text2speech") || library.name.contains("objc")) { |  | ||||||
| 					isClientOnly = true; |  | ||||||
| 				} */ |  | ||||||
| 
 |  | ||||||
| 				project.getDependencies().add(Constants.Configurations.MINECRAFT_DEPENDENCIES, project.getDependencies().module(library.getArtifactName())); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -27,24 +27,39 @@ package net.fabricmc.loom.configuration.providers.minecraft; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.net.URL; | 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.GradleException; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| import org.zeroturnaround.zip.ZipUtil; | import org.zeroturnaround.zip.ZipUtil; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.configuration.providers.MinecraftProvider; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.util.DownloadUtil; | import net.fabricmc.loom.util.HashedDownloadUtil; | ||||||
| 
 | 
 | ||||||
| public class MinecraftNativesProvider { | public class MinecraftNativesProvider { | ||||||
| 	public static void provide(MinecraftProvider minecraftProvider, Project project) throws IOException { | 	private final Project project; | ||||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | 	private final LoomGradleExtension extension; | ||||||
| 		MinecraftVersionInfo versionInfo = minecraftProvider.getVersionInfo(); | 	private final File nativesDir; | ||||||
| 		boolean offline = project.getGradle().getStartParameter().isOffline(); | 	private final File jarStore; | ||||||
| 
 | 
 | ||||||
| 		File nativesDir = extension.getNativesDirectory(); | 	public MinecraftNativesProvider(Project project) { | ||||||
| 		File jarStore = extension.getNativesJarStore(); | 		this.project = project; | ||||||
|  | 		extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||||
| 
 | 
 | ||||||
|  | 		nativesDir = extension.getNativesDirectory(); | ||||||
|  | 		jarStore = extension.getNativesJarStore(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public static void provide(Project project) throws IOException { | ||||||
|  | 		new MinecraftNativesProvider(project).provide(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private void provide() throws IOException { | ||||||
| 		if (extension.hasCustomNatives()) { | 		if (extension.hasCustomNatives()) { | ||||||
| 			if (!nativesDir.exists()) { | 			if (!nativesDir.exists()) { | ||||||
| 				throw new RuntimeException("Could no find custom natives directory at " + nativesDir.getAbsolutePath()); | 				throw new RuntimeException("Could no find custom natives directory at " + nativesDir.getAbsolutePath()); | ||||||
|  | @ -53,21 +68,82 @@ public class MinecraftNativesProvider { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (MinecraftVersionInfo.Library library : versionInfo.libraries) { | 		if (!LoomGradlePlugin.refreshDeps && !requiresExtract()) { | ||||||
| 			File libJarFile = library.getFile(jarStore); | 			project.getLogger().info("Natives do no need extracting, skipping"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 			if (library.allowed() && library.isNative() && libJarFile != null) { | 		extractNatives(); | ||||||
| 				if (!offline) { | 	} | ||||||
| 					DownloadUtil.downloadIfChanged(new URL(library.getURL()), libJarFile, project.getLogger()); |  | ||||||
| 				} |  | ||||||
| 
 | 
 | ||||||
| 				if (!libJarFile.exists()) { | 	private void extractNatives() throws IOException { | ||||||
| 					throw new GradleException("Native jar not found at " + libJarFile.getAbsolutePath()); | 		boolean offline = project.getGradle().getStartParameter().isOffline(); | ||||||
| 				} |  | ||||||
| 
 | 
 | ||||||
| 				// TODO possibly find a way to prevent needing to re-extract after each run, doesnt seem too slow | 		if (nativesDir.exists()) { | ||||||
| 				ZipUtil.unpack(libJarFile, nativesDir); | 			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.Classifier library : getNatives()) { | ||||||
|  | 			File libJarFile = library.getRelativeFile(jarStore); | ||||||
|  | 
 | ||||||
|  | 			if (!offline) { | ||||||
|  | 				HashedDownloadUtil.downloadIfInvalid(new URL(library.getUrl()), libJarFile, library.getSha1(), project.getLogger(), false); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (!libJarFile.exists()) { | ||||||
|  | 				throw new GradleException("Native jar not found at " + libJarFile.getAbsolutePath()); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			ZipUtil.unpack(libJarFile, nativesDir); | ||||||
|  | 
 | ||||||
|  | 			// 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.getSha1(), StandardCharsets.UTF_8); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private boolean requiresExtract() { | ||||||
|  | 		List<MinecraftVersionMeta.Classifier> natives = getNatives(); | ||||||
|  | 
 | ||||||
|  | 		if (natives.isEmpty()) { | ||||||
|  | 			throw new IllegalStateException("No natives found for the current system"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for (MinecraftVersionMeta.Classifier library : natives) { | ||||||
|  | 			File libJarFile = library.getRelativeFile(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.getSha1())) { | ||||||
|  | 					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.Classifier> getNatives() { | ||||||
|  | 		return extension.getMinecraftProvider().getVersionInfo().getLibraries().stream() | ||||||
|  | 				.filter((MinecraftVersionMeta.Library::hasNativesForOS)) | ||||||
|  | 				.map(MinecraftVersionMeta.Library::getClassifierForOS) | ||||||
|  | 				.filter(Objects::nonNull) | ||||||
|  | 				.collect(Collectors.toList()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,198 +0,0 @@ | ||||||
| /* |  | ||||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). |  | ||||||
|  * |  | ||||||
|  * Copyright (c) 2016, 2017, 2018 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.util.List; |  | ||||||
| import java.util.Map; |  | ||||||
| 
 |  | ||||||
| import com.google.gson.JsonElement; |  | ||||||
| import com.google.gson.JsonObject; |  | ||||||
| 
 |  | ||||||
| import net.fabricmc.loom.util.Constants; |  | ||||||
| import net.fabricmc.loom.util.OperatingSystem; |  | ||||||
| 
 |  | ||||||
| public class MinecraftVersionInfo { |  | ||||||
| 	public List<Library> libraries; |  | ||||||
| 	public Map<String, Downloads> downloads; |  | ||||||
| 	public AssetIndex assetIndex; |  | ||||||
| 
 |  | ||||||
| 	public class Downloads { |  | ||||||
| 		public String url; |  | ||||||
| 		public String sha1; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public class AssetIndex { |  | ||||||
| 		private String id; |  | ||||||
| 		public String sha1; |  | ||||||
| 		public String url; |  | ||||||
| 
 |  | ||||||
| 		public String getId() { |  | ||||||
| 			return id; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public String getFabricId(String version) { |  | ||||||
| 			return id.equals(version) ? version : version + "-" + id; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public class Library { |  | ||||||
| 		public String name; |  | ||||||
| 		public JsonObject natives; |  | ||||||
| 		public JsonObject downloads; |  | ||||||
| 		private Artifact artifact; |  | ||||||
| 		public Rule[] rules; |  | ||||||
| 
 |  | ||||||
| 		public String getURL() { |  | ||||||
| 			String path; |  | ||||||
| 			String[] parts = this.name.split(":", 3); |  | ||||||
| 			path = parts[0].replace(".", "/") + "/" + parts[1] + "/" + parts[2] + "/" + parts[1] + "-" + parts[2] + getClassifier() + ".jar"; |  | ||||||
| 			return Constants.LIBRARIES_BASE + path; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public File getFile(File baseDir) { |  | ||||||
| 			String[] parts = this.name.split(":", 3); |  | ||||||
| 			return new File(baseDir, parts[0].replace(".", File.separator) + File.separator + parts[1] + File.separator + parts[2] + File.separator + parts[1] + "-" + parts[2] + getClassifier() + ".jar"); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public String getSha1() { |  | ||||||
| 			if (this.downloads == null) { |  | ||||||
| 				return ""; |  | ||||||
| 			} else if (this.downloads.getAsJsonObject("artifact") == null) { |  | ||||||
| 				return ""; |  | ||||||
| 			} else if (this.downloads.getAsJsonObject("artifact").get("sha1") == null) { |  | ||||||
| 				return ""; |  | ||||||
| 			} else { |  | ||||||
| 				return this.downloads.getAsJsonObject("artifact").get("sha1").getAsString(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public String getClassifier() { |  | ||||||
| 			if (natives == null) { |  | ||||||
| 				return ""; |  | ||||||
| 			} else { |  | ||||||
| 				JsonElement element = natives.get(OperatingSystem.getOS().replace("${arch}", OperatingSystem.getArch())); |  | ||||||
| 
 |  | ||||||
| 				if (element == null) { |  | ||||||
| 					return ""; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				return "-" + element.getAsString().replace("\"", "").replace("${arch}", OperatingSystem.getArch()); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public boolean isNative() { |  | ||||||
| 			return getClassifier().contains("natives"); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public boolean allowed() { |  | ||||||
| 			if (this.rules == null || this.rules.length <= 0) { |  | ||||||
| 				return true; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			boolean success = false; |  | ||||||
| 
 |  | ||||||
| 			for (Rule rule : this.rules) { |  | ||||||
| 				if (rule.os != null && rule.os.name != null) { |  | ||||||
| 					if (rule.os.name.equalsIgnoreCase(OperatingSystem.getOS())) { |  | ||||||
| 						return rule.action.equalsIgnoreCase("allow"); |  | ||||||
| 					} |  | ||||||
| 				} else { |  | ||||||
| 					success = rule.action.equalsIgnoreCase("allow"); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return success; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public String getArtifactName() { |  | ||||||
| 			if (artifact == null) { |  | ||||||
| 				artifact = new Artifact(name); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (natives != null) { |  | ||||||
| 				JsonElement jsonElement = natives.get(OperatingSystem.getOS()); |  | ||||||
| 
 |  | ||||||
| 				if (jsonElement != null) { |  | ||||||
| 					return artifact.getArtifact(jsonElement.getAsString()); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return artifact.getArtifact(artifact.classifier); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		private class Artifact { |  | ||||||
| 			private final String domain, name, version, classifier, ext; |  | ||||||
| 
 |  | ||||||
| 			Artifact(String name) { |  | ||||||
| 				String[] splitedArtifact = name.split(":"); |  | ||||||
| 				int idx = splitedArtifact[splitedArtifact.length - 1].indexOf('@'); |  | ||||||
| 
 |  | ||||||
| 				if (idx != -1) { |  | ||||||
| 					ext = splitedArtifact[splitedArtifact.length - 1].substring(idx + 1); |  | ||||||
| 					splitedArtifact[splitedArtifact.length - 1] = splitedArtifact[splitedArtifact.length - 1].substring(0, idx); |  | ||||||
| 				} else { |  | ||||||
| 					ext = "jar"; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				this.domain = splitedArtifact[0]; |  | ||||||
| 				this.name = splitedArtifact[1]; |  | ||||||
| 				this.version = splitedArtifact[2]; |  | ||||||
| 				this.classifier = splitedArtifact.length > 3 ? splitedArtifact[3] : null; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			public String getArtifact(String classifier) { |  | ||||||
| 				String ret = domain + ":" + name + ":" + version; |  | ||||||
| 
 |  | ||||||
| 				if (classifier != null && classifier.indexOf('$') > -1) { |  | ||||||
| 					classifier = classifier.replace("${arch}", Constants.SYSTEM_ARCH); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (classifier != null) { |  | ||||||
| 					ret += ":" + classifier; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (!"jar".equals(ext)) { |  | ||||||
| 					ret += "@" + ext; |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				return ret; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			public String getClassifier() { |  | ||||||
| 				return classifier; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private class Rule { |  | ||||||
| 		public String action; |  | ||||||
| 		public OS os; |  | ||||||
| 
 |  | ||||||
| 		private class OS { |  | ||||||
| 			String name; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,277 @@ | ||||||
|  | /* | ||||||
|  |  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2016, 2017, 2018 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.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Objects; | ||||||
|  | 
 | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  | 
 | ||||||
|  | import net.fabricmc.loom.util.OperatingSystem; | ||||||
|  | 
 | ||||||
|  | @SuppressWarnings("unused") | ||||||
|  | public final class MinecraftVersionMeta { | ||||||
|  | 	private JsonObject arguments; | ||||||
|  | 	private AssetIndex assetIndex; | ||||||
|  | 	private String assets; | ||||||
|  | 	private int complianceLevel; | ||||||
|  | 	private Map<String, Download> downloads; | ||||||
|  | 	private String id; | ||||||
|  | 	private List<Library> libraries; | ||||||
|  | 	private JsonObject logging; | ||||||
|  | 	private String mainClass; | ||||||
|  | 	private int minimumLauncherVersion; | ||||||
|  | 	private String releaseTime; | ||||||
|  | 	private String time; | ||||||
|  | 	private String type; | ||||||
|  | 
 | ||||||
|  | 	public Download getDownload(String key) { | ||||||
|  | 		return getDownloads().get(key); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public JsonObject getArguments() { | ||||||
|  | 		return arguments; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public AssetIndex getAssetIndex() { | ||||||
|  | 		return assetIndex; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getAssets() { | ||||||
|  | 		return assets; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public int getComplianceLevel() { | ||||||
|  | 		return complianceLevel; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public Map<String, Download> getDownloads() { | ||||||
|  | 		return downloads; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getId() { | ||||||
|  | 		return id; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public List<Library> getLibraries() { | ||||||
|  | 		return libraries; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public JsonObject getLogging() { | ||||||
|  | 		return logging; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getMainClass() { | ||||||
|  | 		return mainClass; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public int getMinimumLauncherVersion() { | ||||||
|  | 		return minimumLauncherVersion; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getReleaseTime() { | ||||||
|  | 		return releaseTime; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getTime() { | ||||||
|  | 		return time; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public String getType() { | ||||||
|  | 		return type; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class AssetIndex extends Downloadable { | ||||||
|  | 		private String id; | ||||||
|  | 		private long totalSize; | ||||||
|  | 
 | ||||||
|  | 		public String getFabricId(String version) { | ||||||
|  | 			return id.equals(version) ? version : version + "-" + id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getId() { | ||||||
|  | 			return id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public long getTotalSize() { | ||||||
|  | 			return totalSize; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Download extends Downloadable { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Library { | ||||||
|  | 		private Downloads downloads; | ||||||
|  | 		private String name; | ||||||
|  | 		private Map<String, String> natives; | ||||||
|  | 		private List<Rule> rules; | ||||||
|  | 
 | ||||||
|  | 		public boolean isValidForOS() { | ||||||
|  | 			if (rules == null || rules.isEmpty()) { | ||||||
|  | 				return true; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			for (Rule rule : rules) { | ||||||
|  | 				if (rule.appliesToOS() && !rule.isAllowed()) { | ||||||
|  | 					return false; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public boolean hasNatives() { | ||||||
|  | 			return this.natives != null; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public boolean hasNativesForOS() { | ||||||
|  | 			if (!hasNatives()) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (natives.get(OperatingSystem.getOS()) == null) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return isValidForOS(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Classifier getClassifierForOS() { | ||||||
|  | 			return getDownloads().getClassifier(natives.get(OperatingSystem.getOS())); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Downloads getDownloads() { | ||||||
|  | 			return downloads; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Artifact getArtifact() { | ||||||
|  | 			if (getDownloads() == null) { | ||||||
|  | 				return null; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return getDownloads().getArtifact(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getName() { | ||||||
|  | 			return name; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Map<String, String> getNatives() { | ||||||
|  | 			return natives; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public List<Rule> getRules() { | ||||||
|  | 			return rules; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Downloads { | ||||||
|  | 		private Artifact artifact; | ||||||
|  | 		private Map<String, Classifier> classifiers; | ||||||
|  | 
 | ||||||
|  | 		public Classifier getClassifier(String os) { | ||||||
|  | 			return classifiers.get(os); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Artifact getArtifact() { | ||||||
|  | 			return artifact; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public Map<String, Classifier> getClassifiers() { | ||||||
|  | 			return classifiers; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Artifact extends Downloadable { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Classifier extends Downloadable { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class Rule { | ||||||
|  | 		private String action; | ||||||
|  | 		private OS os; | ||||||
|  | 
 | ||||||
|  | 		public boolean appliesToOS() { | ||||||
|  | 			return getOS() == null || getOS().isValidForOS(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public boolean isAllowed() { | ||||||
|  | 			return getAction().equals("allow"); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getAction() { | ||||||
|  | 			return action; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public OS getOS() { | ||||||
|  | 			return os; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	public final class OS { | ||||||
|  | 		private String name; | ||||||
|  | 
 | ||||||
|  | 		public boolean isValidForOS() { | ||||||
|  | 			return getName() == null || getName().equalsIgnoreCase(OperatingSystem.getOS()); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getName() { | ||||||
|  | 			return name; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// A base class for everything that can be downloaded | ||||||
|  | 	public abstract class Downloadable { | ||||||
|  | 		private String path; | ||||||
|  | 		private String sha1; | ||||||
|  | 		private long size; | ||||||
|  | 		private String url; | ||||||
|  | 
 | ||||||
|  | 		public File getRelativeFile(File baseDirectory) { | ||||||
|  | 			Objects.requireNonNull(getPath(), "Cannot get relative file from a null path"); | ||||||
|  | 			return new File(baseDirectory, getPath()); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getPath() { | ||||||
|  | 			return path; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getSha1() { | ||||||
|  | 			return sha1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public long getSize() { | ||||||
|  | 			return size; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public String getUrl() { | ||||||
|  | 			return url; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -26,32 +26,25 @@ package net.fabricmc.loom.configuration.providers.minecraft.assets; | ||||||
| 
 | 
 | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FileReader; | import java.io.FileReader; | ||||||
| import java.io.FileWriter; |  | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
| import java.util.Deque; | import java.util.Deque; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.concurrent.ConcurrentHashMap; |  | ||||||
| import java.util.concurrent.ConcurrentLinkedDeque; | import java.util.concurrent.ConcurrentLinkedDeque; | ||||||
| import java.util.concurrent.ExecutorService; | import java.util.concurrent.ExecutorService; | ||||||
| import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| 
 | 
 | ||||||
| import com.google.common.base.Stopwatch; | import com.google.common.base.Stopwatch; | ||||||
| import com.google.common.hash.Hashing; |  | ||||||
| import com.google.common.io.Files; |  | ||||||
| import com.google.gson.Gson; |  | ||||||
| import com.google.gson.reflect.TypeToken; |  | ||||||
| import org.gradle.api.GradleException; | import org.gradle.api.GradleException; | ||||||
| import org.gradle.api.Project; | import org.gradle.api.Project; | ||||||
| 
 | 
 | ||||||
| import net.fabricmc.loom.LoomGradleExtension; | import net.fabricmc.loom.LoomGradleExtension; | ||||||
| import net.fabricmc.loom.LoomGradlePlugin; | import net.fabricmc.loom.LoomGradlePlugin; | ||||||
| import net.fabricmc.loom.configuration.providers.MinecraftProvider; | import net.fabricmc.loom.configuration.providers.MinecraftProvider; | ||||||
| import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionInfo; | import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; | ||||||
| import net.fabricmc.loom.util.Checksum; |  | ||||||
| import net.fabricmc.loom.util.Constants; | import net.fabricmc.loom.util.Constants; | ||||||
| import net.fabricmc.loom.util.DownloadUtil; | import net.fabricmc.loom.util.HashedDownloadUtil; | ||||||
| import net.fabricmc.loom.util.gradle.ProgressLogger; | import net.fabricmc.loom.util.gradle.ProgressLogger; | ||||||
| 
 | 
 | ||||||
| public class MinecraftAssetsProvider { | public class MinecraftAssetsProvider { | ||||||
|  | @ -59,8 +52,8 @@ public class MinecraftAssetsProvider { | ||||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||||
| 		boolean offline = project.getGradle().getStartParameter().isOffline(); | 		boolean offline = project.getGradle().getStartParameter().isOffline(); | ||||||
| 
 | 
 | ||||||
| 		MinecraftVersionInfo versionInfo = minecraftProvider.getVersionInfo(); | 		MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); | ||||||
| 		MinecraftVersionInfo.AssetIndex assetIndex = versionInfo.assetIndex; | 		MinecraftVersionMeta.AssetIndex assetIndex = versionInfo.getAssetIndex(); | ||||||
| 
 | 
 | ||||||
| 		// get existing cache files | 		// get existing cache files | ||||||
| 		File assets = new File(extension.getUserCache(), "assets"); | 		File assets = new File(extension.getUserCache(), "assets"); | ||||||
|  | @ -70,42 +63,28 @@ public class MinecraftAssetsProvider { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		File assetsInfo = new File(assets, "indexes" + File.separator + assetIndex.getFabricId(minecraftProvider.getMinecraftVersion()) + ".json"); | 		File assetsInfo = new File(assets, "indexes" + File.separator + assetIndex.getFabricId(minecraftProvider.getMinecraftVersion()) + ".json"); | ||||||
| 		File checksumInfo = new File(assets, "checksum" + File.separator + minecraftProvider.getMinecraftVersion() + ".json"); |  | ||||||
| 
 | 
 | ||||||
| 		if (!assetsInfo.exists() || !Checksum.equals(assetsInfo, assetIndex.sha1)) { | 		project.getLogger().info(":downloading asset index"); | ||||||
| 			project.getLogger().info(":downloading asset index"); |  | ||||||
| 
 | 
 | ||||||
| 			if (offline) { | 		if (offline) { | ||||||
| 				if (assetsInfo.exists()) { | 			if (assetsInfo.exists()) { | ||||||
| 					//We know it's outdated but can't do anything about it, oh well | 				//We know it's outdated but can't do anything about it, oh well | ||||||
| 					project.getLogger().warn("Asset index outdated"); | 				project.getLogger().warn("Asset index outdated"); | ||||||
| 				} else { |  | ||||||
| 					//We don't know what assets we need, just that we don't have any |  | ||||||
| 					throw new GradleException("Asset index not found at " + assetsInfo.getAbsolutePath()); |  | ||||||
| 				} |  | ||||||
| 			} else { | 			} else { | ||||||
| 				DownloadUtil.downloadIfChanged(new URL(assetIndex.url), assetsInfo, project.getLogger()); | 				//We don't know what assets we need, just that we don't have any | ||||||
| 			} | 				throw new GradleException("Asset index not found at " + assetsInfo.getAbsolutePath()); | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		Gson gson = new Gson(); |  | ||||||
| 		Map<String, String> checksumInfos = new ConcurrentHashMap<>(); |  | ||||||
| 
 |  | ||||||
| 		if (checksumInfo.exists()) { |  | ||||||
| 			try (FileReader reader = new FileReader(checksumInfo)) { |  | ||||||
| 				checksumInfos.putAll(gson.fromJson(reader, new TypeToken<Map<String, String>>() { |  | ||||||
| 				}.getType())); |  | ||||||
| 			} | 			} | ||||||
|  | 		} else { | ||||||
|  | 			HashedDownloadUtil.downloadIfInvalid(new URL(assetIndex.getUrl()), assetsInfo, assetIndex.getSha1(), project.getLogger(), false); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		Deque<ProgressLogger> loggers = new ConcurrentLinkedDeque<>(); | 		Deque<ProgressLogger> loggers = new ConcurrentLinkedDeque<>(); | ||||||
| 		ExecutorService executor = Executors.newFixedThreadPool(Math.min(10, Math.max(Runtime.getRuntime().availableProcessors() / 2, 1))); | 		ExecutorService executor = Executors.newFixedThreadPool(Math.min(10, Math.max(Runtime.getRuntime().availableProcessors() / 2, 1))); | ||||||
| 		int toDownload = 0; |  | ||||||
| 
 | 
 | ||||||
| 		AssetIndex index; | 		AssetIndex index; | ||||||
| 
 | 
 | ||||||
| 		try (FileReader fileReader = new FileReader(assetsInfo)) { | 		try (FileReader fileReader = new FileReader(assetsInfo)) { | ||||||
| 			index = gson.fromJson(fileReader, AssetIndex.class); | 			index = LoomGradlePlugin.GSON.fromJson(fileReader, AssetIndex.class); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		Stopwatch stopwatch = Stopwatch.createStarted(); | 		Stopwatch stopwatch = Stopwatch.createStarted(); | ||||||
|  | @ -118,75 +97,49 @@ public class MinecraftAssetsProvider { | ||||||
| 			String filename = "objects" + File.separator + sha1.substring(0, 2) + File.separator + sha1; | 			String filename = "objects" + File.separator + sha1.substring(0, 2) + File.separator + sha1; | ||||||
| 			File file = new File(assets, filename); | 			File file = new File(assets, filename); | ||||||
| 
 | 
 | ||||||
| 			String localFileChecksum = !file.exists() ? null : checksumInfos.computeIfAbsent(entry.getKey(), path -> { | 			if (offline) { | ||||||
| 				try { | 				if (file.exists()) { | ||||||
| 					return Files.asByteSource(file).hash(Hashing.sha1()).toString(); | 					project.getLogger().warn("Outdated asset " + entry.getKey()); | ||||||
| 				} catch (IOException e) { |  | ||||||
| 					e.printStackTrace(); |  | ||||||
| 					return null; |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 
 |  | ||||||
| 			if (LoomGradlePlugin.refreshDeps || localFileChecksum == null || !localFileChecksum.equals(sha1)) { |  | ||||||
| 				if (offline) { |  | ||||||
| 					if (file.exists()) { |  | ||||||
| 						project.getLogger().warn("Outdated asset " + entry.getKey()); |  | ||||||
| 					} else { |  | ||||||
| 						throw new GradleException("Asset " + entry.getKey() + " not found at " + file.getAbsolutePath()); |  | ||||||
| 					} |  | ||||||
| 				} else { | 				} else { | ||||||
| 					toDownload++; | 					throw new GradleException("Asset " + entry.getKey() + " not found at " + file.getAbsolutePath()); | ||||||
| 					executor.execute(() -> { |  | ||||||
| 						ProgressLogger progressLogger; |  | ||||||
| 
 |  | ||||||
| 						if (loggers.isEmpty()) { |  | ||||||
| 							//Create a new logger if we need one |  | ||||||
| 							progressLogger = ProgressLogger.getProgressFactory(project, MinecraftAssetsProvider.class.getName()); |  | ||||||
| 							progressLogger.start("Downloading assets...", "assets"); |  | ||||||
| 						} else { |  | ||||||
| 							// use a free logger if we can |  | ||||||
| 							progressLogger = loggers.pop(); |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 						String assetName = entry.getKey(); |  | ||||||
| 						int end = assetName.lastIndexOf("/") + 1; |  | ||||||
| 
 |  | ||||||
| 						if (end > 0) { |  | ||||||
| 							assetName = assetName.substring(end); |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 						project.getLogger().debug(":downloading asset " + assetName); |  | ||||||
| 						progressLogger.progress(String.format("%-30.30s", assetName) + " - " + sha1); |  | ||||||
| 
 |  | ||||||
| 						try { |  | ||||||
| 							DownloadUtil.downloadIfChanged(new URL(Constants.RESOURCES_BASE + sha1.substring(0, 2) + "/" + sha1), file, project.getLogger(), true); |  | ||||||
| 						} catch (IOException e) { |  | ||||||
| 							throw new RuntimeException("Failed to download: " + assetName, e); |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 						if (localFileChecksum == null) { |  | ||||||
| 							checksumInfos.put(entry.getKey(), sha1); |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 						//Give this logger back |  | ||||||
| 						loggers.add(progressLogger); |  | ||||||
| 					}); |  | ||||||
| 				} | 				} | ||||||
|  | 			} else { | ||||||
|  | 				executor.execute(() -> { | ||||||
|  | 					ProgressLogger progressLogger; | ||||||
|  | 
 | ||||||
|  | 					if (loggers.isEmpty()) { | ||||||
|  | 						//Create a new logger if we need one | ||||||
|  | 						progressLogger = ProgressLogger.getProgressFactory(project, MinecraftAssetsProvider.class.getName()); | ||||||
|  | 						progressLogger.start("Downloading assets...", "assets"); | ||||||
|  | 					} else { | ||||||
|  | 						// use a free logger if we can | ||||||
|  | 						progressLogger = loggers.pop(); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					String assetName = entry.getKey(); | ||||||
|  | 					int end = assetName.lastIndexOf("/") + 1; | ||||||
|  | 
 | ||||||
|  | 					if (end > 0) { | ||||||
|  | 						assetName = assetName.substring(end); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					project.getLogger().debug(":downloading asset " + assetName); | ||||||
|  | 					progressLogger.progress(String.format("%-30.30s", assetName) + " - " + sha1); | ||||||
|  | 
 | ||||||
|  | 					try { | ||||||
|  | 						HashedDownloadUtil.downloadIfInvalid(new URL(Constants.RESOURCES_BASE + sha1.substring(0, 2) + "/" + sha1), file, sha1, project.getLogger(), true); | ||||||
|  | 					} catch (IOException e) { | ||||||
|  | 						throw new RuntimeException("Failed to download: " + assetName, e); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					//Give this logger back | ||||||
|  | 					loggers.add(progressLogger); | ||||||
|  | 				}); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		project.getLogger().info("Took " + stopwatch.stop() + " to iterate " + parent.size() + " asset index."); | 		project.getLogger().info("Took " + stopwatch.stop() + " to iterate " + parent.size() + " asset index."); | ||||||
| 
 | 
 | ||||||
| 		if (toDownload > 0) { |  | ||||||
| 			project.getLogger().lifecycle(":downloading " + toDownload + " asset" + (toDownload == 1 ? "" : "s") + "..."); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		checksumInfo.getParentFile().mkdirs(); |  | ||||||
| 
 |  | ||||||
| 		try (FileWriter writer = new FileWriter(checksumInfo)) { |  | ||||||
| 			gson.toJson(checksumInfos, writer); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		//Wait for the assets to all download | 		//Wait for the assets to all download | ||||||
| 		executor.shutdown(); | 		executor.shutdown(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -40,6 +40,6 @@ public class DownloadAssetsTask extends AbstractLoomTask { | ||||||
| 		LoomGradleExtension extension = getExtension(); | 		LoomGradleExtension extension = getExtension(); | ||||||
| 
 | 
 | ||||||
| 		MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | 		MinecraftAssetsProvider.provide(extension.getMinecraftProvider(), project); | ||||||
| 		MinecraftNativesProvider.provide(extension.getMinecraftProvider(), project); | 		MinecraftNativesProvider.provide(project); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue