diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index b1ccf73..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,40 +0,0 @@ -version: 2 -registries: - maven-central: - type: maven-repository - url: https://repo.maven.apache.org/maven2/ - fabricmc: - type: maven-repository - url: https://maven.fabricmc.net/ - quiltmc: - type: maven-repository - url: https://maven.quiltmc.org/repository/release/ - parchment: - type: maven-repository - url: https://maven.parchmentmc.org/ - neoforged: - type: maven-repository - url: https://maven.neoforged.net/ - lukebemish: - type: maven-repository - url: https://maven.lukebemish.dev/ - architectury: - type: maven-repository - url: https://maven.architectury.dev/ -updates: - - package-ecosystem: "gradle" - directory: "/" - registries: - - maven-central - - fabricmc - - quiltmc - - parchment - - neoforged - - lukebemish - - architectury - schedule: - interval: "weekly" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/workflows/build_pr.yml b/.github/workflows/build_pr.yml index ed01916..837cc52 100644 --- a/.github/workflows/build_pr.yml +++ b/.github/workflows/build_pr.yml @@ -22,7 +22,7 @@ "restore-keys": "${{ runner.os }}-gradle-" }, "name": "Cache", - "uses": "actions/cache/restore@v3" + "uses": "actions/cache/restore@v4" }, { "with": { @@ -30,11 +30,11 @@ "gradle-home-cache-cleanup": true }, "name": "Setup Gradle", - "uses": "gradle/gradle-build-action@v2" + "uses": "gradle/gradle-build-action@v3" }, { "name": "Build", - "run": "./gradlew checkLicenses build", + "run": "./gradlew build", "id": "build", "env": { "PR_NUMBER": "${{ github.event.pull_request.number }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 521e31d..b850061 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,9 @@ { "jobs": { "build": { + "outputs": { + "version": "${{ steps.record_version_capture_version.outputs.version }}" + }, "runs-on": "ubuntu-22.04", "permissions": { "contents": "write" @@ -24,14 +27,14 @@ "restore-keys": "${{ runner.os }}-gradle-" }, "name": "Cache", - "uses": "actions/cache@v3" + "uses": "actions/cache@v4" }, { "with": { "gradle-home-cache-cleanup": true }, "name": "Setup Gradle", - "uses": "gradle/gradle-build-action@v2" + "uses": "gradle/gradle-build-action@v3" }, { "uses": "fregante/setup-git-user@v2" @@ -43,43 +46,85 @@ "env": { "BUILD_CACHE_PASSWORD": "${{ secrets.BUILD_CACHE_PASSWORD }}", "BUILD_CACHE_USER": "${{ secrets.BUILD_CACHE_USER }}", - "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}", - "RELEASE_MAVEN_PASSWORD": "${{ secrets.RELEASE_MAVEN_PASSWORD }}", - "RELEASE_MAVEN_USER": "github", - "RELEASE_MAVEN_URL": "https://maven.lukebemish.dev/releases/", - "CURSEFORGE_KEY": "${{ secrets.CURSEFORGE_KEY }}", - "MODRINTH_KEY": "${{ secrets.MODRINTH_KEY }}" + "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}" } }, { "name": "Build", - "run": "./gradlew checkLicenses build", + "run": "./gradlew build", "id": "build", "env": { "BUILD_CACHE_PASSWORD": "${{ secrets.BUILD_CACHE_PASSWORD }}", "BUILD_CACHE_USER": "${{ secrets.BUILD_CACHE_USER }}", - "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}", - "RELEASE_MAVEN_PASSWORD": "${{ secrets.RELEASE_MAVEN_PASSWORD }}", - "RELEASE_MAVEN_USER": "github", - "RELEASE_MAVEN_URL": "https://maven.lukebemish.dev/releases/", - "CURSEFORGE_KEY": "${{ secrets.CURSEFORGE_KEY }}", - "MODRINTH_KEY": "${{ secrets.MODRINTH_KEY }}" + "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}" } }, { "run": "git push && git push --tags" }, + { + "name": "Record Version", + "run": "./gradlew recordVersion", + "id": "record_version", + "env": { + "BUILD_CACHE_PASSWORD": "${{ secrets.BUILD_CACHE_PASSWORD }}", + "BUILD_CACHE_USER": "${{ secrets.BUILD_CACHE_USER }}", + "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}" + } + }, + { + "name": "Capture Recorded Version", + "run": "echo version=$(cat build/recordVersion.txt) >> \"$GITHUB_OUTPUT\"", + "id": "record_version_capture_version" + } + ] + }, + "publish": { + "needs": [ + "build" + ], + "runs-on": "ubuntu-22.04", + "steps": [ + { + "name": "Setup Java", + "run": "echo \"JAVA_HOME=$JAVA_HOME_17_X64\" >> \"$GITHUB_ENV\"" + }, + { + "with": { + "fetch-depth": "0", + "ref": "refs/tags/${{needs.build.outputs.version}}", + "persist-credentials": "false" + }, + "name": "Checkout", + "uses": "actions/checkout@v4" + }, + { + "with": { + "path": "**/.gradle/loom-cache", + "key": "${{ runner.os }}-gradle-${{ hashFiles('**/libs.versions.*', '**/*.gradle*', '**/gradle-wrapper.properties') }}", + "restore-keys": "${{ runner.os }}-gradle-" + }, + "name": "Cache", + "uses": "actions/cache/restore@v4" + }, + { + "with": { + "cache-read-only": true, + "gradle-home-cache-cleanup": true + }, + "name": "Setup Gradle", + "uses": "gradle/gradle-build-action@v3" + }, { "name": "Publish", - "run": "./gradlew publish", + "run": "./gradlew publish closeAndReleaseSonatypeStagingRepository", "id": "publish", "env": { "BUILD_CACHE_PASSWORD": "${{ secrets.BUILD_CACHE_PASSWORD }}", "BUILD_CACHE_USER": "${{ secrets.BUILD_CACHE_USER }}", "BUILD_CACHE_URL": "${{ secrets.BUILD_CACHE_URL }}", - "RELEASE_MAVEN_PASSWORD": "${{ secrets.RELEASE_MAVEN_PASSWORD }}", - "RELEASE_MAVEN_USER": "github", - "RELEASE_MAVEN_URL": "https://maven.lukebemish.dev/releases/", + "SONATYPE_PASSWORD": "${{ secrets.SONATYPE_PASSWORD }}", + "SONATYPE_USER": "${{ secrets.SONATYPE_USER }}", "CURSEFORGE_KEY": "${{ secrets.CURSEFORGE_KEY }}", "MODRINTH_KEY": "${{ secrets.MODRINTH_KEY }}" } diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index f86329a..4f5e907 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -22,7 +22,7 @@ "restore-keys": "${{ runner.os }}-gradle-" }, "name": "Cache", - "uses": "actions/cache/restore@v3" + "uses": "actions/cache/restore@v4" }, { "with": { @@ -30,11 +30,11 @@ "gradle-home-cache-cleanup": true }, "name": "Setup Gradle", - "uses": "gradle/gradle-build-action@v2" + "uses": "gradle/gradle-build-action@v3" }, { "name": "Build", - "run": "./gradlew checkLicenses build", + "run": "./gradlew build", "id": "build", "env": { "BUILD_CACHE_PASSWORD": "${{ secrets.BUILD_CACHE_PASSWORD }}", diff --git a/build.gradle b/build.gradle index 7db2680..3545c07 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,11 @@ plugins { - alias libs.plugins.quilt.licenser apply false - alias libs.plugins.mdg.plugin - alias libs.plugins.managedversioning + alias libs.plugins.mdg apply false + alias cLibs.plugins.managedversioning alias libs.plugins.architectury.loom apply false } managedVersioning { - versionFile.set rootProject.file('version.properties') + versionFile.set project.file('version.properties') metadataVersion.set libs.versions.minecraft versionPRs() versionSnapshots() @@ -19,7 +18,7 @@ managedVersioning { gradleJob { buildCache() name.set 'build' - gradlew 'Build', 'checkLicenses', 'build' + gradlew 'Build', 'build' gradlew 'Publish', 'publish' mavenSnapshot('github') } @@ -35,12 +34,19 @@ managedVersioning { } readOnly.set false gradlew 'Tag Release', 'tagRelease' - gradlew 'Build', 'checkLicenses', 'build' + gradlew 'Build', 'build' step { run.set 'git push && git push --tags' } - gradlew 'Publish', 'publish' - mavenRelease('github') + recordVersion 'Record Version', 'version' + } + gradleJob { + buildCache() + name.set 'publish' + needs.add('build') + tag.set('${{needs.build.outputs.version}}') + gradlew 'Publish', 'publish', 'closeAndReleaseSonatypeStagingRepository' + mavenCentral() modPublishing() } } @@ -49,7 +55,7 @@ managedVersioning { pullRequest.set(true) gradleJob { name.set 'build' - gradlew 'Build', 'checkLicenses', 'build' + gradlew 'Build', 'build' gradlew 'Publish', 'publish' pullRequestArtifact() } @@ -80,41 +86,4 @@ artifacts { add 'license', file("LICENSE") } -modsDotGroovy { - dslVersion = libs.versions.mdg.dsl.get() - platform 'multiloader' - multiloader { - forge = [project(":neoforge")] - fabric = [project(":fabriquilt")] - quilt = [] - } -} - -subprojects { p -> - apply plugin: 'maven-publish' - apply plugin: 'java-library' - apply plugin: libs.plugins.quilt.licenser.get().pluginId - - java.toolchain.languageVersion = JavaLanguageVersion.of(17) - java.withSourcesJar() - java.withJavadocJar() - - license { - rule rootProject.file('header.txt') - exclude '**/*.mcmeta' - exclude '**/package-info.java' - } - - jar { - manifest { - attributes([ - 'Implementation-Commit-Time': managedVersioning.timestamp.get(), - 'Implementation-Commit': managedVersioning.hash.get() - ]) - } - } - - managedVersioning.publishing.mavenPullRequest(publishing) - managedVersioning.publishing.mavenSnapshot(publishing) - managedVersioning.publishing.mavenRelease(publishing) -} +managedVersioning.publishing.mavenCentral() diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 6784052..a671508 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -1,3 +1,7 @@ plugins { - id 'groovy-gradle-plugin' + alias cLibs.plugins.conventions.buildsrc +} + +dependencies { + implementation cLibs.conventions.java } diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 0000000..d4b425b --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,13 @@ +pluginManagement { + repositories { + maven { + name = "Luke's Maven" + url = 'https://maven.lukebemish.dev/releases' + } + gradlePluginPortal() + } +} + +plugins { + id 'dev.lukebemish.conventions' +} diff --git a/buildSrc/src/main/groovy/convention.consumer.gradle b/buildSrc/src/main/groovy/convention.consumer.gradle index dc873b8..d09f171 100644 --- a/buildSrc/src/main/groovy/convention.consumer.gradle +++ b/buildSrc/src/main/groovy/convention.consumer.gradle @@ -38,3 +38,9 @@ tasks.named("sourcesJar", Jar) { dependsOn(configurations.commonResources) from(configurations.commonResources) } + +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { + configurations."$it".outgoing { + capability("$group:$artifact_id-common:$version") + } +} diff --git a/buildSrc/src/main/groovy/convention.shared.gradle b/buildSrc/src/main/groovy/convention.shared.gradle index 1b3389d..9d1b2d8 100644 --- a/buildSrc/src/main/groovy/convention.shared.gradle +++ b/buildSrc/src/main/groovy/convention.shared.gradle @@ -1,10 +1,21 @@ plugins { id 'java-library' id 'maven-publish' - id 'idea' - id 'dev.lukebemish.conventions.project' + id 'signing' + id 'dev.lukebemish.conventions.java' + id 'dev.lukebemish.managedversioning' } +managedVersioning { + versionFile.set project.rootDir.toPath().resolve('version.properties').toFile() + gitWorkingDir.set project.rootDir + metadataVersion.set libs.versions.minecraft + versionPRs() + versionSnapshots() +} + +managedVersioning.apply() + version = rootProject.version group = rootProject.group @@ -43,12 +54,21 @@ dependencies { publishing { publications { register('mavenJava', MavenPublication) { - artifactId base.archivesName.get() + artifactId "$artifact_id-${project.name}" from components.java + managedVersioning.publishing.sign(signing, it) + managedVersioning.publishing.pom(it, github_repo, license) + pom { + name = "$mod_id - ${project.name}" + description = mod_description + } } } } +managedVersioning.publishing.mavenPullRequest(publishing) +managedVersioning.publishing.mavenSnapshot(publishing) + sourcesJar { dependsOn(configurations.rootProjectLicense) from(configurations.rootProjectLicense) { @@ -56,6 +76,13 @@ sourcesJar { } } +['apiElements', 'runtimeElements', 'sourcesElements', 'javadocElements'].each { + configurations."$it".outgoing { + capability("$group:$artifact_id:$version") + capability("$group:$artifact_id-${project.name}:$version") + } +} + jar { dependsOn(configurations.rootProjectLicense) from(configurations.rootProjectLicense) { @@ -64,13 +91,15 @@ jar { manifest { attributes([ - 'Specification-Title' : mod_name, - 'Specification-Vendor' : mod_author, - 'Specification-Version' : rootProject.version, - 'Implementation-Title' : "$mod_name - ${project.name}", - 'Implementation-Version' : rootProject.version, - 'Implementation-Vendor' : mod_author, - 'Built-On-Minecraft' : libs.versions.minecraft.get() + 'Specification-Title' : mod_name, + 'Specification-Vendor' : mod_author, + 'Specification-Version' : rootProject.version, + 'Implementation-Title' : "$mod_name - ${project.name}", + 'Implementation-Version' : rootProject.version, + 'Implementation-Vendor' : mod_author, + 'Implementation-Commit-Time': managedVersioning.timestamp.get(), + 'Implementation-Commit' : managedVersioning.hash.get(), + 'Built-On-Minecraft' : libs.versions.minecraft.get() ]) } } diff --git a/common/build.gradle b/common/build.gradle index ce5151a..cda84c9 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,40 +1,43 @@ plugins { - id 'convention.shared' - alias libs.plugins.architectury.loom + id 'convention.shared' + alias libs.plugins.architectury.loom + alias libs.plugins.mdg } +modsDotGroovy.multiplatform.expose() + configurations { - commonJava { - canBeResolved = false - canBeConsumed = true - } - commonResources { - canBeResolved = false - canBeConsumed = true - } + commonJava { + canBeResolved = false + canBeConsumed = true + } + commonResources { + canBeResolved = false + canBeConsumed = true + } } loom { - runConfigs.configureEach { - ideConfigGenerated = false - } + runConfigs.configureEach { + ideConfigGenerated = false + } } import net.fabricmc.loom.task.AbstractRemapJarTask tasks.withType(AbstractRemapJarTask).each { - it.targetNamespace = "named" + it.targetNamespace = "named" } dependencies { - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") - } - minecraft libs.minecraft - modImplementation libs.fabric.loader + mappings loom.layered() { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") + } + minecraft libs.minecraft + modCompileOnly libs.fabric.loader } artifacts { - commonJava sourceSets.main.java.sourceDirectories.singleFile - commonResources sourceSets.main.resources.sourceDirectories.singleFile + commonJava sourceSets.main.java.sourceDirectories.singleFile + commonResources sourceSets.main.resources.sourceDirectories.singleFile } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/api/GlobalResourceManager.java b/common/src/main/java/dev/lukebemish/defaultresources/api/GlobalResourceManager.java index 34f1190..d8fd0ce 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/api/GlobalResourceManager.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/api/GlobalResourceManager.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.api; import dev.lukebemish.defaultresources.impl.ManagerHolder; @@ -18,41 +13,38 @@ */ public interface GlobalResourceManager extends ResourceManager { - /** - * Provides a resource manager for global assets. Global assets are data that is not specific to a world, and is - * required only on the client. The acquired resource manager should be made more specific with {@link #prefix(String)}. - * @return a resource manager which loads resources in {@code globalassets} - * @throws IllegalStateException if called on a dedicated server - */ - @NonNull - @Contract(pure = true) - static GlobalResourceManager getGlobalAssets() { - if (!Services.PLATFORM.isClient()) { - throw new IllegalStateException("Cannot create client resource manager on dedicated server"); - } - return ManagerHolder.STATIC_ASSETS; - } + /** + * Provides a resource manager for global assets. Global assets are data that is not specific to a world, and is + * required only on the client. The acquired resource manager should be made more specific with {@link #prefix(String)}. + * @return a resource manager which loads resources in {@code globalassets} + * @throws IllegalStateException if called on a dedicated server + */ + @NonNull @Contract(pure = true) + static GlobalResourceManager getGlobalAssets() { + if (!Services.PLATFORM.isClient()) { + throw new IllegalStateException("Cannot create client resource manager on dedicated server"); + } + return ManagerHolder.STATIC_ASSETS; + } - /** - * Provides a resource manager for global data. Global data is data that is not specific to a world, and is required - * on the server. The acquired resource manager should be made more specific with {@link #prefix(String)}. - * @return a resource manager which loads resources in {@code globaldata} - */ - @NonNull - @Contract(pure = true) - static GlobalResourceManager getGlobalData() { - return ManagerHolder.STATIC_DATA; - } + /** + * Provides a resource manager for global data. Global data is data that is not specific to a world, and is required + * on the server. The acquired resource manager should be made more specific with {@link #prefix(String)}. + * @return a resource manager which loads resources in {@code globaldata} + */ + @NonNull @Contract(pure = true) + static GlobalResourceManager getGlobalData() { + return ManagerHolder.STATIC_DATA; + } - /** - * Creates a new global resource manager that looks are resources in the given prefix, relative to the current path. - * @param prefix the prefix to use for the resource manager - * @return a new resource manager, which loads resources in {@code global[data/assets]/[namespace]/[original path]/[prefix]}. - */ - @NonNull - @Contract(value = "_ -> new", pure = true) - @ApiStatus.NonExtendable - default GlobalResourceManager prefix(String prefix) { - return new WrappingResourceManager(this, prefix); - } + /** + * Creates a new global resource manager that looks are resources in the given prefix, relative to the current path. + * @param prefix the prefix to use for the resource manager + * @return a new resource manager, which loads resources in {@code global[data/assets]/[namespace]/[original path]/[prefix]}. + */ + @NonNull @Contract(value = "_ -> new", pure = true) + @ApiStatus.NonExtendable + default GlobalResourceManager prefix(String prefix) { + return new WrappingResourceManager(this, prefix); + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/api/OutdatedResourcesListener.java b/common/src/main/java/dev/lukebemish/defaultresources/api/OutdatedResourcesListener.java index 44cf319..75463ba 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/api/OutdatedResourcesListener.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/api/OutdatedResourcesListener.java @@ -1,14 +1,8 @@ -/* - * Copyright (C) 2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.api; import dev.lukebemish.defaultresources.impl.DefaultResources; -import org.jspecify.annotations.Nullable; - import java.util.Optional; +import org.jspecify.annotations.Nullable; /** * Allows mods to provide custom logic for when the extracted default resources are outdated, but cannot be updated due @@ -16,27 +10,27 @@ */ public interface OutdatedResourcesListener { - /** - * Called when the listener is fired. - * @param oldDataVersion the data version of the outdated resources on disk, or {@code null} if none is present - * @param newDataVersion the data version of the new resources the mod provides, or {@code null} if none is present - */ - void resourcesOutdated(@Nullable String oldDataVersion, @Nullable String newDataVersion); + /** + * Called when the listener is fired. + * @param oldDataVersion the data version of the outdated resources on disk, or {@code null} if none is present + * @param newDataVersion the data version of the new resources the mod provides, or {@code null} if none is present + */ + void resourcesOutdated(@Nullable String oldDataVersion, @Nullable String newDataVersion); - /** - * Registers a listener to be notified when the extracted default resources are outdated, but cannot be updated due - * to having been changed on disk. - * @param modId the mod ID to listen for - * @param listener the listener to call if the resources cannot be updated - */ - @SuppressWarnings("unused") - static void register(String modId, OutdatedResourcesListener listener) { - DefaultResources.delegate(() -> { - Optional oldVersion = DefaultResources.OUTDATED_TARGETS.get(modId); - Optional newVersion = DefaultResources.MOD_TARGETS.get(modId); - if (oldVersion != null && newVersion != null) { - listener.resourcesOutdated(oldVersion.orElse(null), newVersion.orElse(null)); - } - }, () -> DefaultResources.addListener(modId, listener)); - } + /** + * Registers a listener to be notified when the extracted default resources are outdated, but cannot be updated due + * to having been changed on disk. + * @param modId the mod ID to listen for + * @param listener the listener to call if the resources cannot be updated + */ + @SuppressWarnings("unused") + static void register(String modId, OutdatedResourcesListener listener) { + DefaultResources.delegate(() -> { + Optional oldVersion = DefaultResources.OUTDATED_TARGETS.get(modId); + Optional newVersion = DefaultResources.MOD_TARGETS.get(modId); + if (oldVersion != null && newVersion != null) { + listener.resourcesOutdated(oldVersion.orElse(null), newVersion.orElse(null)); + } + }, () -> DefaultResources.addListener(modId, listener)); + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataFilePackResources.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataFilePackResources.java index d8eec06..cedd06d 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataFilePackResources.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataFilePackResources.java @@ -1,18 +1,6 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.google.common.collect.Sets; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.resources.IoSupplier; -import org.apache.commons.io.IOUtils; -import org.jspecify.annotations.Nullable; - import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; @@ -20,125 +8,128 @@ import java.util.Locale; import java.util.Set; import java.util.zip.ZipFile; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.IoSupplier; +import org.apache.commons.io.IOUtils; +import org.jspecify.annotations.Nullable; public class AutoMetadataFilePackResources extends AutoMetadataPathPackResources { - private final ZipFileHolder zipFileHolder; - public AutoMetadataFilePackResources(String s, String prefix, Path path, PackType packType) { - super(s, prefix, path, packType); - this.zipFileHolder = new ZipFileHolder(); - } - - private String getPathFromLocation(PackType packType, ResourceLocation location) { - return String.format(Locale.ROOT, "%s/%s/%s", this.getPackFolderName(), location.getNamespace(), location.getPath()); - } - - public IoSupplier getResource(PackType packType, ResourceLocation location) { - return this.getResource(getPathFromLocation(packType, location)); - } - - @Nullable - private IoSupplier getResource(String resourcePath) { - var zipFile = this.zipFileHolder.getOrCreateZipFile(); - if (zipFile == null) { - return null; - } else { - var entry = zipFile.getEntry(resourcePath); - return entry == null ? null : IoSupplier.create(zipFile, entry); - } - } - - public Set getNamespaces(PackType type) { - var zipFile = this.zipFileHolder.getOrCreateZipFile(); - if (zipFile == null) { - return Set.of(); - } else { - Set set = Sets.newHashSet(); - var prefix = getPackFolderName() + "/"; - - for (var entry : ofEnumeration(zipFile.entries())) { - var entryPath = entry.getName(); - var namespace = ""; - if (entryPath.startsWith(prefix)) { - var parts = entryPath.substring(prefix.length()).split("/"); - if (parts.length != 0) { - namespace = parts[0]; - } - } - if (!namespace.isEmpty()) { - if (ResourceLocation.isValidNamespace(namespace)) { - set.add(namespace); - } else { - DefaultResources.LOGGER.warn(AutoMetadataFilePackResources.class.getSimpleName()+": Non [a-z0-9_.-] character in namespace {} in pack {}, ignoring", namespace, this.path); - } - } - } - - return set; - } - } - - private static Iterable ofEnumeration(Enumeration enumeration) { - return enumeration::asIterator; - } - - public void listResources(PackType packType, String namespace, String path, PackResources.ResourceOutput resourceOutput) { - var zipFile = this.zipFileHolder.getOrCreateZipFile(); - if (zipFile != null) { - var namespacePrefix = getPackFolderName() + "/" + namespace + "/"; - var pathPrefix = namespacePrefix + path + "/"; - for (var entry : ofEnumeration(zipFile.entries())) { - if (!entry.isDirectory()) { - var entryPath = entry.getName(); - if (entryPath.startsWith(pathPrefix)) { - var location = ResourceLocation.tryBuild(namespace, entryPath.substring(namespacePrefix.length())); - if (location != null) { - resourceOutput.accept(location, IoSupplier.create(zipFile, entry)); - } else { - DefaultResources.LOGGER.warn(AutoMetadataFilePackResources.class.getSimpleName()+": Invalid path in datapack: {}:{}, ignoring", namespace, entryPath); - } - } - } - } - } - } - - private class ZipFileHolder implements AutoCloseable { - @Nullable - private ZipFile zipFile; - private boolean loaded; - - @Nullable - ZipFile getOrCreateZipFile() { - if (zipFile == null && this.loaded) { - return null; - } else { - if (this.zipFile == null) { - this.loaded = true; - try { - this.zipFile = new ZipFile(AutoMetadataFilePackResources.this.path.toFile()); - } catch (IOException var2) { - DefaultResources.LOGGER.error(AutoMetadataFilePackResources.class.getSimpleName()+": Failed to open pack {}", AutoMetadataFilePackResources.this.path, var2); - return null; - } - } - - return this.zipFile; - } - } - - public void close() { - if (this.zipFile != null) { - IOUtils.closeQuietly(this.zipFile); - this.zipFile = null; - } - } - } - - @Override - public void close() { - super.close(); - if (this.zipFileHolder != null) { - this.zipFileHolder.close(); - } - } + private final ZipFileHolder zipFileHolder; + public AutoMetadataFilePackResources(String s, String prefix, Path path, PackType packType) { + super(s, prefix, path, packType); + this.zipFileHolder = new ZipFileHolder(); + } + + private String getPathFromLocation(PackType packType, ResourceLocation location) { + return String.format(Locale.ROOT, "%s/%s/%s", this.getPackFolderName(), location.getNamespace(), location.getPath()); + } + + public IoSupplier getResource(PackType packType, ResourceLocation location) { + return this.getResource(getPathFromLocation(packType, location)); + } + + @Nullable private IoSupplier getResource(String resourcePath) { + var zipFile = this.zipFileHolder.getOrCreateZipFile(); + if (zipFile == null) { + return null; + } else { + var entry = zipFile.getEntry(resourcePath); + return entry == null ? null : IoSupplier.create(zipFile, entry); + } + } + + public Set getNamespaces(PackType type) { + var zipFile = this.zipFileHolder.getOrCreateZipFile(); + if (zipFile == null) { + return Set.of(); + } else { + Set set = Sets.newHashSet(); + var prefix = getPackFolderName() + "/"; + + for (var entry : ofEnumeration(zipFile.entries())) { + var entryPath = entry.getName(); + var namespace = ""; + if (entryPath.startsWith(prefix)) { + var parts = entryPath.substring(prefix.length()).split("/"); + if (parts.length != 0) { + namespace = parts[0]; + } + } + if (!namespace.isEmpty()) { + if (ResourceLocation.isValidNamespace(namespace)) { + set.add(namespace); + } else { + DefaultResources.LOGGER.warn(AutoMetadataFilePackResources.class.getSimpleName()+": Non [a-z0-9_.-] character in namespace {} in pack {}, ignoring", namespace, this.path); + } + } + } + + return set; + } + } + + private static Iterable ofEnumeration(Enumeration enumeration) { + return enumeration::asIterator; + } + + public void listResources(PackType packType, String namespace, String path, PackResources.ResourceOutput resourceOutput) { + var zipFile = this.zipFileHolder.getOrCreateZipFile(); + if (zipFile != null) { + var namespacePrefix = getPackFolderName() + "/" + namespace + "/"; + var pathPrefix = namespacePrefix + path + "/"; + for (var entry : ofEnumeration(zipFile.entries())) { + if (!entry.isDirectory()) { + var entryPath = entry.getName(); + if (entryPath.startsWith(pathPrefix)) { + var location = ResourceLocation.tryBuild(namespace, entryPath.substring(namespacePrefix.length())); + if (location != null) { + resourceOutput.accept(location, IoSupplier.create(zipFile, entry)); + } else { + DefaultResources.LOGGER.warn(AutoMetadataFilePackResources.class.getSimpleName()+": Invalid path in datapack: {}:{}, ignoring", namespace, entryPath); + } + } + } + } + } + } + + private class ZipFileHolder implements AutoCloseable { + @Nullable private ZipFile zipFile; + private boolean loaded; + + @Nullable ZipFile getOrCreateZipFile() { + if (zipFile == null && this.loaded) { + return null; + } else { + if (this.zipFile == null) { + this.loaded = true; + try { + this.zipFile = new ZipFile(AutoMetadataFilePackResources.this.path.toFile()); + } catch (IOException var2) { + DefaultResources.LOGGER.error(AutoMetadataFilePackResources.class.getSimpleName()+": Failed to open pack {}", AutoMetadataFilePackResources.this.path, var2); + return null; + } + } + + return this.zipFile; + } + } + + public void close() { + if (this.zipFile != null) { + IOUtils.closeQuietly(this.zipFile); + this.zipFile = null; + } + } + } + + @Override + public void close() { + super.close(); + if (this.zipFileHolder != null) { + this.zipFileHolder.close(); + } + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataPathPackResources.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataPathPackResources.java index a311d85..7259f0e 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataPathPackResources.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/AutoMetadataPathPackResources.java @@ -1,12 +1,15 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.google.gson.JsonObject; import com.mojang.logging.LogUtils; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; import net.minecraft.FileUtil; import net.minecraft.SharedConstants; import net.minecraft.resources.ResourceLocation; @@ -19,98 +22,86 @@ import org.jspecify.annotations.Nullable; import org.slf4j.Logger; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; - public class AutoMetadataPathPackResources extends AbstractPackResources { - private static final Logger LOGGER = LogUtils.getLogger(); - - private final String name; - protected final Path path; - private final PackType packType; - - public AutoMetadataPathPackResources(String s, String prefix, Path path, PackType packType) { - super(s, false); - this.name = prefix+packType.getDirectory(); - this.path = path; - this.packType = packType; - } - - protected String getPackFolderName() { - return name; - } - - @Nullable - @Override - public IoSupplier getRootResource(String... elements) { - return null; - } - - @Nullable - @Override - public IoSupplier getResource(PackType packType, ResourceLocation location) { - Path path = this.path.resolve(getPackFolderName()).resolve(location.getNamespace()); - if (!Files.isDirectory(path)) { - return null; - } - return PathPackResources.getResource(location, path); - } - - @Override - public void listResources(PackType packType, String namespace, String path, ResourceOutput resourceOutput) { - FileUtil.decomposePath(path).get().ifLeft((list) -> { - Path namespacePath = this.path.resolve(getPackFolderName()).resolve(namespace); - if (!Files.isDirectory(namespacePath)) { - return; - } - PathPackResources.listPath(namespace, namespacePath, list, resourceOutput); - }).ifRight((partialResult) -> LOGGER.error("Invalid path {}: {}", path, partialResult.message())); - } - - @Override - public @NonNull Set getNamespaces(PackType type) { - Set set = new HashSet<>(); - Path path = this.path.resolve(getPackFolderName()); - - if (!Files.isDirectory(path)) { - return Set.of(); - } - - try (DirectoryStream paths = Files.newDirectoryStream(path)) { - for (Path namespacePath : paths) { - if (Files.isDirectory(namespacePath)) { - String namespace = namespacePath.getFileName().toString(); - if (namespace.equals(namespace.toLowerCase(Locale.ROOT))) { - set.add(namespace); - } - } - } - } catch (IOException e) { - LOGGER.error("Failed to list path {}", path, e); - } - return set; - } - - @Nullable - @Override - public T getMetadataSection(MetadataSectionSerializer serializer) { - if (serializer.getMetadataSectionName().equals("pack")) { - JsonObject object = new JsonObject(); - object.addProperty("pack_format", SharedConstants.getCurrentVersion().getPackVersion(this.packType)); - object.addProperty("description", "Global resources"); - return serializer.fromJson(object); - } - return null; - } - - @Override - public void close() { - - } + private static final Logger LOGGER = LogUtils.getLogger(); + + private final String name; + protected final Path path; + private final PackType packType; + + public AutoMetadataPathPackResources(String s, String prefix, Path path, PackType packType) { + super(s, false); + this.name = prefix+packType.getDirectory(); + this.path = path; + this.packType = packType; + } + + protected String getPackFolderName() { + return name; + } + + @Nullable @Override + public IoSupplier getRootResource(String... elements) { + return null; + } + + @Nullable @Override + public IoSupplier getResource(PackType packType, ResourceLocation location) { + Path path = this.path.resolve(getPackFolderName()).resolve(location.getNamespace()); + if (!Files.isDirectory(path)) { + return null; + } + return PathPackResources.getResource(location, path); + } + + @Override + public void listResources(PackType packType, String namespace, String path, ResourceOutput resourceOutput) { + FileUtil.decomposePath(path).get().ifLeft((list) -> { + Path namespacePath = this.path.resolve(getPackFolderName()).resolve(namespace); + if (!Files.isDirectory(namespacePath)) { + return; + } + PathPackResources.listPath(namespace, namespacePath, list, resourceOutput); + }).ifRight((partialResult) -> LOGGER.error("Invalid path {}: {}", path, partialResult.message())); + } + + @Override + public @NonNull Set getNamespaces(PackType type) { + Set set = new HashSet<>(); + Path path = this.path.resolve(getPackFolderName()); + + if (!Files.isDirectory(path)) { + return Set.of(); + } + + try (DirectoryStream paths = Files.newDirectoryStream(path)) { + for (Path namespacePath : paths) { + if (Files.isDirectory(namespacePath)) { + String namespace = namespacePath.getFileName().toString(); + if (namespace.equals(namespace.toLowerCase(Locale.ROOT))) { + set.add(namespace); + } + } + } + } catch (IOException e) { + LOGGER.error("Failed to list path {}", path, e); + } + return set; + } + + @Nullable @Override + public T getMetadataSection(MetadataSectionSerializer serializer) { + if (serializer.getMetadataSectionName().equals("pack")) { + JsonObject object = new JsonObject(); + object.addProperty("pack_format", SharedConstants.getCurrentVersion().getPackVersion(this.packType)); + object.addProperty("description", "Global resources"); + return serializer.fromJson(object); + } + return null; + } + + @Override + public void close() { + + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/CombinedResourceManager.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/CombinedResourceManager.java index 7105006..193c955 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/CombinedResourceManager.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/CombinedResourceManager.java @@ -1,21 +1,7 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.mojang.datafixers.util.Pair; import dev.lukebemish.defaultresources.api.GlobalResourceManager; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.Pack; -import net.minecraft.server.packs.resources.IoSupplier; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceMetadata; -import org.jspecify.annotations.NonNull; - import java.io.IOException; import java.io.InputStream; import java.util.*; @@ -24,125 +10,132 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.Pack; +import net.minecraft.server.packs.resources.IoSupplier; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceMetadata; +import org.jspecify.annotations.NonNull; public class CombinedResourceManager implements GlobalResourceManager { - private final List resources; - private final Map> namespaceMap; - private final PackType type; + private final List resources; + private final Map> namespaceMap; + private final PackType type; - public CombinedResourceManager(PackType type, List> resources) { - this.type = type; - this.resources = resources.stream().sorted(Comparator.comparing(Pair::getFirst)).map(p -> p.getSecond().openPrimary(p.getFirst())).toList(); - Map> namespaceBuilder = new HashMap<>(); - for (var resource : this.resources) { - for (var namespace : resource.getNamespaces(type)) { - namespaceBuilder.computeIfAbsent(namespace, k -> new ArrayList<>()).add(resource); - } - } - this.namespaceMap = namespaceBuilder.entrySet().stream().collect(Collectors.toMap( - Map.Entry::getKey, - e -> List.copyOf(e.getValue()) - )); - } + public CombinedResourceManager(PackType type, List> resources) { + this.type = type; + this.resources = resources.stream().sorted(Comparator.comparing(Pair::getFirst)).map(p -> p.getSecond().openPrimary(p.getFirst())).toList(); + Map> namespaceBuilder = new HashMap<>(); + for (var resource : this.resources) { + for (var namespace : resource.getNamespaces(type)) { + namespaceBuilder.computeIfAbsent(namespace, k -> new ArrayList<>()).add(resource); + } + } + this.namespaceMap = namespaceBuilder.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, + e -> List.copyOf(e.getValue()) + )); + } - @Override - public @NonNull Set getNamespaces() { - return namespaceMap.keySet(); - } + @Override + public @NonNull Set getNamespaces() { + return namespaceMap.keySet(); + } - @Override - public @NonNull List getResourceStack(ResourceLocation location) { - List builder = new ArrayList<>(); - getResourceStream(location) - .forEach(builder::add); - Collections.reverse(builder); - return Collections.unmodifiableList(builder); - } + @Override + public @NonNull List getResourceStack(ResourceLocation location) { + List builder = new ArrayList<>(); + getResourceStream(location) + .forEach(builder::add); + Collections.reverse(builder); + return Collections.unmodifiableList(builder); + } - @NonNull - private Stream getResourceStream(ResourceLocation location) { - return namespaceMap.getOrDefault(location.getNamespace(), List.of()).stream() - .map(p -> { - IoSupplier ioSupplier = p.getResource(this.type, location); - if (ioSupplier != null) { - ResourceLocation metadataLocation = getMetadataLocation(location); - IoSupplier metadataSupplier = () -> { - IoSupplier metadataIoSupplier = p.getResource(this.type, metadataLocation); - if (metadataIoSupplier == null) return ResourceMetadata.EMPTY; - try (InputStream metadata = ioSupplier.get()) { - return ResourceMetadata.fromJsonStream(metadata); - } catch (Throwable t) { - throw new IOException(t); - } - }; - return new Resource(p, ioSupplier, metadataSupplier); - } - return null; - }) - .filter(Objects::nonNull); - } + @NonNull private Stream getResourceStream(ResourceLocation location) { + return namespaceMap.getOrDefault(location.getNamespace(), List.of()).stream() + .map(p -> { + IoSupplier ioSupplier = p.getResource(this.type, location); + if (ioSupplier != null) { + ResourceLocation metadataLocation = getMetadataLocation(location); + IoSupplier metadataSupplier = () -> { + IoSupplier metadataIoSupplier = p.getResource(this.type, metadataLocation); + if (metadataIoSupplier == null) return ResourceMetadata.EMPTY; + try (InputStream metadata = ioSupplier.get()) { + return ResourceMetadata.fromJsonStream(metadata); + } catch (Throwable t) { + throw new IOException(t); + } + }; + return new Resource(p, ioSupplier, metadataSupplier); + } + return null; + }) + .filter(Objects::nonNull); + } - private static ResourceLocation getMetadataLocation(ResourceLocation location) { - return location.withPath(location.getPath() + ".mcmeta"); - } + private static ResourceLocation getMetadataLocation(ResourceLocation location) { + return location.withPath(location.getPath() + ".mcmeta"); + } - @Override - public @NonNull Map listResources(String path, Predicate filter) { - Map builder = new HashMap<>(); - BiConsumer consumer = builder::put; - findResources(path, filter, consumer); - return Collections.unmodifiableMap(builder); - } + @Override + public @NonNull Map listResources(String path, Predicate filter) { + Map builder = new HashMap<>(); + BiConsumer consumer = builder::put; + findResources(path, filter, consumer); + return Collections.unmodifiableMap(builder); + } - @Override - public @NonNull Map> listResourceStacks(String path, Predicate filter) { - Map> builder = new HashMap<>(); - BiConsumer consumer = (rl, r) -> builder.computeIfAbsent(rl, k -> new ArrayList<>()).add(r); - findResources(path, filter, consumer); - return builder.entrySet().stream().collect(Collectors.toMap( - Map.Entry::getKey, - e -> { - var list = e.getValue(); - Collections.reverse(list); - return Collections.unmodifiableList(list); - } - )); - } + @Override + public @NonNull Map> listResourceStacks(String path, Predicate filter) { + Map> builder = new HashMap<>(); + BiConsumer consumer = (rl, r) -> builder.computeIfAbsent(rl, k -> new ArrayList<>()).add(r); + findResources(path, filter, consumer); + return builder.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, + e -> { + var list = e.getValue(); + Collections.reverse(list); + return Collections.unmodifiableList(list); + } + )); + } - private void findResources(String path, Predicate filter, BiConsumer consumer) { - for (Map.Entry> entry : namespaceMap.entrySet()) { - var namespace = entry.getKey(); - for (PackResources packResources : entry.getValue()) { - packResources.listResources(this.type, namespace, path, (rl, ioSupplier) -> { - if (rl.getPath().endsWith(".mcmeta")) return; - if (filter.test(rl)) { - ResourceLocation metadataLocation = getMetadataLocation(rl); - IoSupplier metadataSupplier = () -> { - IoSupplier metadataIoSupplier = packResources.getResource(this.type, metadataLocation); - if (metadataIoSupplier == null) return ResourceMetadata.EMPTY; - try (InputStream metadata = ioSupplier.get()){ - return ResourceMetadata.fromJsonStream(metadata); - } catch (Throwable t) { - throw new IOException(t); - } - }; - consumer.accept(rl, new Resource(packResources, ioSupplier, metadataSupplier)); - } - }); - } - } - } + private void findResources(String path, Predicate filter, BiConsumer consumer) { + for (Map.Entry> entry : namespaceMap.entrySet()) { + var namespace = entry.getKey(); + for (PackResources packResources : entry.getValue()) { + packResources.listResources(this.type, namespace, path, (rl, ioSupplier) -> { + if (rl.getPath().endsWith(".mcmeta")) return; + if (filter.test(rl)) { + ResourceLocation metadataLocation = getMetadataLocation(rl); + IoSupplier metadataSupplier = () -> { + IoSupplier metadataIoSupplier = packResources.getResource(this.type, metadataLocation); + if (metadataIoSupplier == null) return ResourceMetadata.EMPTY; + try (InputStream metadata = ioSupplier.get()){ + return ResourceMetadata.fromJsonStream(metadata); + } catch (Throwable t) { + throw new IOException(t); + } + }; + consumer.accept(rl, new Resource(packResources, ioSupplier, metadataSupplier)); + } + }); + } + } + } - @Override - public @NonNull Stream listPacks() { - return resources.stream(); - } + @Override + public @NonNull Stream listPacks() { + return resources.stream(); + } - @Override - public @NonNull Optional getResource(ResourceLocation location) { - AtomicReference resource = new AtomicReference<>(); - getResourceStream(location) - .forEach(resource::set); - return Optional.ofNullable(resource.get()); - } + @Override + public @NonNull Optional getResource(ResourceLocation location) { + AtomicReference resource = new AtomicReference<>(); + getResourceStream(location) + .forEach(resource::set); + return Optional.ofNullable(resource.get()); + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/Config.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/Config.java index 1037f04..15d1874 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/Config.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/Config.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.google.common.base.Suppliers; @@ -12,9 +7,6 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.util.StringRepresentable; -import org.jspecify.annotations.NonNull; - import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; @@ -25,152 +17,154 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.zip.ZipFile; +import net.minecraft.util.StringRepresentable; +import org.jspecify.annotations.NonNull; public record Config(ConcurrentHashMap extract, HashMap fromResourcePacks) { - public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - Codec.unboundedMap(Codec.STRING, StringRepresentable.fromEnum(ExtractionState::values)).xmap(ConcurrentHashMap::new, Function.identity()).fieldOf("extract").forGetter(Config::extract), - Codec.unboundedMap(Codec.STRING, Codec.BOOL).fieldOf("from_resource_packs").xmap(HashMap::new, Function.identity()).forGetter(Config::fromResourcePacks) - ).apply(i, Config::new)); - - public static final Supplier INSTANCE = Suppliers.memoize(Config::readFromConfig); - - private static Config getDefault() { - return new Config(new ConcurrentHashMap<>(), new HashMap<>()); - } - - private static Config readFromConfig() { - Path configPath = Services.PLATFORM.getConfigDir().resolve(DefaultResources.MOD_ID + ".json"); - Config config = getDefault(); - if (Files.exists(configPath)) { - try { - JsonElement json = DefaultResources.GSON.fromJson(Files.newBufferedReader(configPath), JsonElement.class); - config = CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(false, e -> - DefaultResources.LOGGER.error("Error parsing {}.json config; using (and replacing) with default: {}", DefaultResources.MOD_ID, e)); - } catch (IOException e) { - DefaultResources.LOGGER.error("Could not read {}.json config; using (and replacing) with default.", DefaultResources.MOD_ID, e); - } catch (JsonSyntaxException e) { - DefaultResources.LOGGER.error("Error parsing {}.json config; using (and replacing) with default.", DefaultResources.MOD_ID, e); - } catch (RuntimeException ignored) { - // Already caught and logged. - } - } - var map = new ConcurrentHashMap<>(config.extract()); - Services.PLATFORM.getExistingModdedPaths(DefaultResources.META_FILE_PATH).forEach((modId, metaPath) -> { - try (var is = Files.newInputStream(metaPath)) { - JsonElement object = DefaultResources.GSON.fromJson(new InputStreamReader(is), JsonElement.class); - ModMetaFile metaFile = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, object).getOrThrow(false, e -> { - }); - if (!map.containsKey(modId)) { - map.put(modId, metaFile.extract() ? ExtractionState.EXTRACT : ExtractionState.UNEXTRACTED); - } - } catch (IOException | RuntimeException e) { - DefaultResources.LOGGER.warn("We thought there was a readable {} for mod {}, but we got an error when reading it!", - DefaultResources.META_FILE_PATH, modId, e); - } - }); - - var resourcePacks = new HashMap(); - var originalResourcePacks = config.fromResourcePacks(); - Path resourcePacksPath = Services.PLATFORM.getResourcePackDir(); - try (var paths = Files.list(resourcePacksPath)) { - paths.forEach(path -> { - String fileName = path.getFileName().toString(); - boolean detect; - if (fileName.endsWith(".zip") || fileName.endsWith(".jar")) { - detect = checkZipForMeta(path); - } else if (Files.isDirectory(path)) { - detect = checkPathForMeta(path); - } else { - return; - } - if (detect) { - resourcePacks.put(fileName, originalResourcePacks.getOrDefault(fileName, true)); - } - }); - } catch (IOException e) { - if (Files.exists(resourcePacksPath)) { - DefaultResources.LOGGER.warn("Could not read resource packs from {}!", resourcePacksPath, e); - } - } - - config = new Config(map, resourcePacks); - - try { - writeConfig(configPath, config); - } catch (IOException e) { - DefaultResources.LOGGER.error("Could not write {}.json config. There may be odd behavior. ", DefaultResources.MOD_ID, e); - } - - return config; - } - - private static boolean checkZipForMeta(Path path) { - try (var zipFile = new ZipFile(path.toFile()); - var reader = zipFile.getInputStream(zipFile.getEntry("pack.mcmeta"))) { - if (reader != null) { - JsonObject object = DefaultResources.GSON.fromJson(new InputStreamReader(reader), JsonObject.class); - JsonElement meta = object.get(DefaultResources.MOD_ID); - var result = DefaultResourcesMetadataSection.CODEC.parse(JsonOps.INSTANCE, meta); - if (result.error().isPresent()) { - DefaultResources.LOGGER.error("Could not read metadata of {} for resource pack detection; ignoring: {}", path.getFileName(), result.error().get()); - } - return result.result().isPresent() && result.result().get().detect(); - } - } catch (Exception e) { - DefaultResources.LOGGER.error("Could not read {}, which looks like a zip file, for resource pack detection; ignoring.", path.getFileName(), e); - } - return false; - } - - private static boolean checkPathForMeta(Path path) { - var metaFile = path.resolve("pack.mcmeta"); - if (Files.exists(metaFile)) { - try (var reader = Files.newBufferedReader(metaFile)) { - JsonObject object = DefaultResources.GSON.fromJson(reader, JsonObject.class); - JsonElement meta = object.get(DefaultResources.MOD_ID); - var result = DefaultResourcesMetadataSection.CODEC.parse(JsonOps.INSTANCE, meta); - if (result.error().isPresent()) { - DefaultResources.LOGGER.error("Could not read metadata of {} for resource pack detection; ignoring: {}", path.getFileName(), result.error().get()); - } - return result.result().isPresent() && result.result().get().detect(); - } catch (Exception e) { - DefaultResources.LOGGER.error("Could not read {} for resource pack detection; ignoring.", path.getFileName(), e); - } - } - return false; - } - - private static void writeConfig(Path path, Config config) throws IOException { - if (!Files.exists(path.getParent())) - Files.createDirectories(path.getParent()); - Files.deleteIfExists(path); - try (var writer = Files.newBufferedWriter(path)) { - writer.write("// Set extraction to \"extract\" to extract currently unextracted resources.\n"); - DefaultResources.GSON.toJson(CODEC.encodeStart(JsonOps.INSTANCE, config) - .getOrThrow(false, e -> { - }), - writer); - } - } - - public void save() { - Path configPath = Services.PLATFORM.getConfigDir().resolve(DefaultResources.MOD_ID + ".json"); - try { - writeConfig(configPath, this); - } catch (IOException e) { - DefaultResources.LOGGER.error("Could not save {} config!", DefaultResources.MOD_ID, e); - } - } - - enum ExtractionState implements StringRepresentable { - UNEXTRACTED, - EXTRACT, - EXTRACTED, - OUTDATED; - - @Override - public @NonNull String getSerializedName() { - return name().toLowerCase(Locale.ROOT); - } - } + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.unboundedMap(Codec.STRING, StringRepresentable.fromEnum(ExtractionState::values)).xmap(ConcurrentHashMap::new, Function.identity()).fieldOf("extract").forGetter(Config::extract), + Codec.unboundedMap(Codec.STRING, Codec.BOOL).fieldOf("from_resource_packs").xmap(HashMap::new, Function.identity()).forGetter(Config::fromResourcePacks) + ).apply(i, Config::new)); + + public static final Supplier INSTANCE = Suppliers.memoize(Config::readFromConfig); + + private static Config getDefault() { + return new Config(new ConcurrentHashMap<>(), new HashMap<>()); + } + + private static Config readFromConfig() { + Path configPath = Services.PLATFORM.getConfigDir().resolve(DefaultResources.MOD_ID + ".json"); + Config config = getDefault(); + if (Files.exists(configPath)) { + try { + JsonElement json = DefaultResources.GSON.fromJson(Files.newBufferedReader(configPath), JsonElement.class); + config = CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(false, e -> + DefaultResources.LOGGER.error("Error parsing {}.json config; using (and replacing) with default: {}", DefaultResources.MOD_ID, e)); + } catch (IOException e) { + DefaultResources.LOGGER.error("Could not read {}.json config; using (and replacing) with default.", DefaultResources.MOD_ID, e); + } catch (JsonSyntaxException e) { + DefaultResources.LOGGER.error("Error parsing {}.json config; using (and replacing) with default.", DefaultResources.MOD_ID, e); + } catch (RuntimeException ignored) { + // Already caught and logged. + } + } + var map = new ConcurrentHashMap<>(config.extract()); + Services.PLATFORM.getExistingModdedPaths(DefaultResources.META_FILE_PATH).forEach((modId, metaPath) -> { + try (var is = Files.newInputStream(metaPath)) { + JsonElement object = DefaultResources.GSON.fromJson(new InputStreamReader(is), JsonElement.class); + ModMetaFile metaFile = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, object).getOrThrow(false, e -> { + }); + if (!map.containsKey(modId)) { + map.put(modId, metaFile.extract() ? ExtractionState.EXTRACT : ExtractionState.UNEXTRACTED); + } + } catch (IOException | RuntimeException e) { + DefaultResources.LOGGER.warn("We thought there was a readable {} for mod {}, but we got an error when reading it!", + DefaultResources.META_FILE_PATH, modId, e); + } + }); + + var resourcePacks = new HashMap(); + var originalResourcePacks = config.fromResourcePacks(); + Path resourcePacksPath = Services.PLATFORM.getResourcePackDir(); + try (var paths = Files.list(resourcePacksPath)) { + paths.forEach(path -> { + String fileName = path.getFileName().toString(); + boolean detect; + if (fileName.endsWith(".zip") || fileName.endsWith(".jar")) { + detect = checkZipForMeta(path); + } else if (Files.isDirectory(path)) { + detect = checkPathForMeta(path); + } else { + return; + } + if (detect) { + resourcePacks.put(fileName, originalResourcePacks.getOrDefault(fileName, true)); + } + }); + } catch (IOException e) { + if (Files.exists(resourcePacksPath)) { + DefaultResources.LOGGER.warn("Could not read resource packs from {}!", resourcePacksPath, e); + } + } + + config = new Config(map, resourcePacks); + + try { + writeConfig(configPath, config); + } catch (IOException e) { + DefaultResources.LOGGER.error("Could not write {}.json config. There may be odd behavior. ", DefaultResources.MOD_ID, e); + } + + return config; + } + + private static boolean checkZipForMeta(Path path) { + try (var zipFile = new ZipFile(path.toFile()); + var reader = zipFile.getInputStream(zipFile.getEntry("pack.mcmeta"))) { + if (reader != null) { + JsonObject object = DefaultResources.GSON.fromJson(new InputStreamReader(reader), JsonObject.class); + JsonElement meta = object.get(DefaultResources.MOD_ID); + var result = DefaultResourcesMetadataSection.CODEC.parse(JsonOps.INSTANCE, meta); + if (result.error().isPresent()) { + DefaultResources.LOGGER.error("Could not read metadata of {} for resource pack detection; ignoring: {}", path.getFileName(), result.error().get()); + } + return result.result().isPresent() && result.result().get().detect(); + } + } catch (Exception e) { + DefaultResources.LOGGER.error("Could not read {}, which looks like a zip file, for resource pack detection; ignoring.", path.getFileName(), e); + } + return false; + } + + private static boolean checkPathForMeta(Path path) { + var metaFile = path.resolve("pack.mcmeta"); + if (Files.exists(metaFile)) { + try (var reader = Files.newBufferedReader(metaFile)) { + JsonObject object = DefaultResources.GSON.fromJson(reader, JsonObject.class); + JsonElement meta = object.get(DefaultResources.MOD_ID); + var result = DefaultResourcesMetadataSection.CODEC.parse(JsonOps.INSTANCE, meta); + if (result.error().isPresent()) { + DefaultResources.LOGGER.error("Could not read metadata of {} for resource pack detection; ignoring: {}", path.getFileName(), result.error().get()); + } + return result.result().isPresent() && result.result().get().detect(); + } catch (Exception e) { + DefaultResources.LOGGER.error("Could not read {} for resource pack detection; ignoring.", path.getFileName(), e); + } + } + return false; + } + + private static void writeConfig(Path path, Config config) throws IOException { + if (!Files.exists(path.getParent())) + Files.createDirectories(path.getParent()); + Files.deleteIfExists(path); + try (var writer = Files.newBufferedWriter(path)) { + writer.write("// Set extraction to \"extract\" to extract currently unextracted resources.\n"); + DefaultResources.GSON.toJson(CODEC.encodeStart(JsonOps.INSTANCE, config) + .getOrThrow(false, e -> { + }), + writer); + } + } + + public void save() { + Path configPath = Services.PLATFORM.getConfigDir().resolve(DefaultResources.MOD_ID + ".json"); + try { + writeConfig(configPath, this); + } catch (IOException e) { + DefaultResources.LOGGER.error("Could not save {} config!", DefaultResources.MOD_ID, e); + } + } + + enum ExtractionState implements StringRepresentable { + UNEXTRACTED, + EXTRACT, + EXTRACTED, + OUTDATED; + + @Override + public @NonNull String getSerializedName() { + return name().toLowerCase(Locale.ROOT); + } + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResources.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResources.java index af988f2..6f1d5bc 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResources.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResources.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.google.gson.Gson; @@ -12,14 +7,6 @@ import com.mojang.serialization.JsonOps; import dev.lukebemish.defaultresources.api.GlobalResourceManager; import dev.lukebemish.defaultresources.api.OutdatedResourcesListener; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.Pack; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jspecify.annotations.NonNull; -import org.jspecify.annotations.Nullable; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -35,336 +22,341 @@ import java.util.function.Supplier; import java.util.zip.Adler32; import java.util.zip.Checksum; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.Pack; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; public class DefaultResources { - public static final String MOD_ID = "defaultresources"; - public static final Logger LOGGER = LogManager.getLogger(MOD_ID); - private static final int BUFFER_SIZE = 1024; - public static final Map> OUTDATED_TARGETS = new ConcurrentHashMap<>(); - public static final Map> MOD_TARGETS = new ConcurrentHashMap<>(); - private volatile static boolean GLOBAL_SETUP = false; - private static final Map> OUTDATED_RESOURCES_LISTENERS = new ConcurrentHashMap<>(); - public static final String META_FILE_PATH = DefaultResources.MOD_ID + ".meta.json"; - public static final String CHECK_FILE_PATH = "." + DefaultResources.MOD_ID; + public static final String MOD_ID = "defaultresources"; + public static final Logger LOGGER = LogManager.getLogger(MOD_ID); + private static final int BUFFER_SIZE = 1024; + public static final Map> OUTDATED_TARGETS = new ConcurrentHashMap<>(); + public static final Map> MOD_TARGETS = new ConcurrentHashMap<>(); + private volatile static boolean GLOBAL_SETUP = false; + private static final Map> OUTDATED_RESOURCES_LISTENERS = new ConcurrentHashMap<>(); + public static final String META_FILE_PATH = DefaultResources.MOD_ID + ".meta.json"; + public static final String CHECK_FILE_PATH = "." + DefaultResources.MOD_ID; - public static final Gson GSON = new GsonBuilder().setLenient().setPrettyPrinting().create(); + public static final Gson GSON = new GsonBuilder().setLenient().setPrettyPrinting().create(); - private static final Map>> QUEUED_RESOURCES = new ConcurrentHashMap<>(); - private static final Map>> QUEUED_STATIC_RESOURCES = new ConcurrentHashMap<>(); - public static final String GLOBAL_PREFIX = "global"; + private static final Map>> QUEUED_RESOURCES = new ConcurrentHashMap<>(); + private static final Map>> QUEUED_STATIC_RESOURCES = new ConcurrentHashMap<>(); + public static final String GLOBAL_PREFIX = "global"; - public static void addListener(String modId, OutdatedResourcesListener listener) { - OUTDATED_RESOURCES_LISTENERS.computeIfAbsent(modId, s -> new ArrayList<>()).add(listener); - } + public static void addListener(String modId, OutdatedResourcesListener listener) { + OUTDATED_RESOURCES_LISTENERS.computeIfAbsent(modId, s -> new ArrayList<>()).add(listener); + } - public static void forMod(Function inJarPathGetter, String modId) { - Path defaultResourcesMeta = inJarPathGetter.apply(META_FILE_PATH); - ModMetaFile meta; - if (Files.exists(defaultResourcesMeta)) { - try (InputStream is = Files.newInputStream(defaultResourcesMeta)) { - JsonObject obj = GSON.fromJson(new BufferedReader(new InputStreamReader(is)), JsonObject.class); - meta = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, obj).getOrThrow(false, e -> {}); - } catch (IOException | RuntimeException e) { - DefaultResources.LOGGER.error("Could not read meta file for mod {}", modId, e); - return; - } - } else { - try { - meta = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, new JsonObject()).getOrThrow(false, e -> {}); - } catch (RuntimeException e) { - DefaultResources.LOGGER.error("Could not parse default meta file", e); - return; - } - } - Path defaultResources = inJarPathGetter.apply(meta.resourcesPath()); + public static void forMod(Function inJarPathGetter, String modId) { + Path defaultResourcesMeta = inJarPathGetter.apply(META_FILE_PATH); + ModMetaFile meta; + if (Files.exists(defaultResourcesMeta)) { + try (InputStream is = Files.newInputStream(defaultResourcesMeta)) { + JsonObject obj = GSON.fromJson(new BufferedReader(new InputStreamReader(is)), JsonObject.class); + meta = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, obj).getOrThrow(false, e -> {}); + } catch (IOException | RuntimeException e) { + DefaultResources.LOGGER.error("Could not read meta file for mod {}", modId, e); + return; + } + } else { + try { + meta = ModMetaFile.CODEC.parse(JsonOps.INSTANCE, new JsonObject()).getOrThrow(false, e -> {}); + } catch (RuntimeException e) { + DefaultResources.LOGGER.error("Could not parse default meta file", e); + return; + } + } + Path defaultResources = inJarPathGetter.apply(meta.resourcesPath()); - try { - if (Files.exists(defaultResources)) { - MOD_TARGETS.put(modId, meta.dataVersion()); - var defaultExtraction = meta.extract() ? Config.ExtractionState.EXTRACT : Config.ExtractionState.UNEXTRACTED; - Config.ExtractionState extractionState = Config.INSTANCE.get().extract().getOrDefault(modId, defaultExtraction); - if (extractionState == Config.ExtractionState.OUTDATED) { - extractionState = defaultExtraction; - } - if (!Config.INSTANCE.get().extract().containsKey(modId)) { - Config.INSTANCE.get().extract().put(modId, defaultExtraction); - } - if (extractionState == Config.ExtractionState.UNEXTRACTED) { - QUEUED_RESOURCES.put("__unextracted_" + modId, (s, type) -> { - if (!Files.exists(defaultResources.resolve(type.getDirectory()))) return null; - return () -> new AutoMetadataPathPackResources(s, "", defaultResources, type); - }); - QUEUED_STATIC_RESOURCES.put("__unextracted_" + modId, (s, type) -> { - if (!Files.exists(defaultResources.resolve(GLOBAL_PREFIX + type.getDirectory()))) return null; - return () -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, defaultResources, type); - }); - } else if (extractionState == Config.ExtractionState.EXTRACT) { - Config.INSTANCE.get().extract().put(modId, meta.extract() ? Config.ExtractionState.EXTRACT : Config.ExtractionState.EXTRACTED); - if (!meta.zip()) { - Path outPath = Services.PLATFORM.getGlobalFolder().resolve(modId); - String checksum = shouldCopy(defaultResources, outPath, Files.exists(outPath), modId, meta); - if (checksum != null) { - copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); - } - } else { - Path zipPath = Services.PLATFORM.getGlobalFolder().resolve(modId + ".zip"); - boolean zipExists = Files.exists(zipPath); - String checksum; - try (FileSystem zipFs = FileSystems.newFileSystem( - zipPath, - Collections.singletonMap("create", "true"))) { - Path outPath = zipFs.getPath("/"); - checksum = shouldCopy(defaultResources, outPath, zipExists, modId, meta); - if (checksum != null && !zipExists) { - copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); - } - } - if (checksum != null && zipExists) { - Files.delete(zipPath); - try (FileSystem zipFs = FileSystems.newFileSystem( - zipPath, - Collections.singletonMap("create", "true"))) { - Path outPath = zipFs.getPath("/"); - copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); - } - } - } - } - } - } catch (IOException | RuntimeException e) { - DefaultResources.LOGGER.error("Could not handle default resources for mod {}", modId, e); - } - } + try { + if (Files.exists(defaultResources)) { + MOD_TARGETS.put(modId, meta.dataVersion()); + var defaultExtraction = meta.extract() ? Config.ExtractionState.EXTRACT : Config.ExtractionState.UNEXTRACTED; + Config.ExtractionState extractionState = Config.INSTANCE.get().extract().getOrDefault(modId, defaultExtraction); + if (extractionState == Config.ExtractionState.OUTDATED) { + extractionState = defaultExtraction; + } + if (!Config.INSTANCE.get().extract().containsKey(modId)) { + Config.INSTANCE.get().extract().put(modId, defaultExtraction); + } + if (extractionState == Config.ExtractionState.UNEXTRACTED) { + QUEUED_RESOURCES.put("__unextracted_" + modId, (s, type) -> { + if (!Files.exists(defaultResources.resolve(type.getDirectory()))) return null; + return () -> new AutoMetadataPathPackResources(s, "", defaultResources, type); + }); + QUEUED_STATIC_RESOURCES.put("__unextracted_" + modId, (s, type) -> { + if (!Files.exists(defaultResources.resolve(GLOBAL_PREFIX + type.getDirectory()))) return null; + return () -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, defaultResources, type); + }); + } else if (extractionState == Config.ExtractionState.EXTRACT) { + Config.INSTANCE.get().extract().put(modId, meta.extract() ? Config.ExtractionState.EXTRACT : Config.ExtractionState.EXTRACTED); + if (!meta.zip()) { + Path outPath = Services.PLATFORM.getGlobalFolder().resolve(modId); + String checksum = shouldCopy(defaultResources, outPath, Files.exists(outPath), modId, meta); + if (checksum != null) { + copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); + } + } else { + Path zipPath = Services.PLATFORM.getGlobalFolder().resolve(modId + ".zip"); + boolean zipExists = Files.exists(zipPath); + String checksum; + try (FileSystem zipFs = FileSystems.newFileSystem( + zipPath, + Collections.singletonMap("create", "true"))) { + Path outPath = zipFs.getPath("/"); + checksum = shouldCopy(defaultResources, outPath, zipExists, modId, meta); + if (checksum != null && !zipExists) { + copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); + } + } + if (checksum != null && zipExists) { + Files.delete(zipPath); + try (FileSystem zipFs = FileSystems.newFileSystem( + zipPath, + Collections.singletonMap("create", "true"))) { + Path outPath = zipFs.getPath("/"); + copyResources(defaultResources, outPath, checksum, meta.dataVersion().orElse(null)); + } + } + } + } + } + } catch (IOException | RuntimeException e) { + DefaultResources.LOGGER.error("Could not handle default resources for mod {}", modId, e); + } + } - private static void couldNotUpdate(String modId, Path outPath, ModMetaFile meta) { - String oldDataVersion; - try { - oldDataVersion = dataVersion(outPath); - } catch (IOException e) { - DefaultResources.LOGGER.error("Could not read old data version for mod {}", modId, e); - oldDataVersion = null; - } - DefaultResources.LOGGER.error("Could not extract default resources for mod {} (data version {} to version {}) because they are already extracted and have been changed on disk", modId, oldDataVersion, meta.dataVersion().orElse(null)); - OUTDATED_TARGETS.put(modId, Optional.ofNullable(oldDataVersion)); - Config.INSTANCE.get().extract().put(modId, Config.ExtractionState.OUTDATED); - } + private static void couldNotUpdate(String modId, Path outPath, ModMetaFile meta) { + String oldDataVersion; + try { + oldDataVersion = dataVersion(outPath); + } catch (IOException e) { + DefaultResources.LOGGER.error("Could not read old data version for mod {}", modId, e); + oldDataVersion = null; + } + DefaultResources.LOGGER.error("Could not extract default resources for mod {} (data version {} to version {}) because they are already extracted and have been changed on disk", modId, oldDataVersion, meta.dataVersion().orElse(null)); + OUTDATED_TARGETS.put(modId, Optional.ofNullable(oldDataVersion)); + Config.INSTANCE.get().extract().put(modId, Config.ExtractionState.OUTDATED); + } - private static @Nullable String shouldCopy(Path defaultResources, Path outPath, boolean alreadyExists, String modId, ModMetaFile meta) { - try { - if (alreadyExists) { - Path checksumPath = outPath.resolve(CHECK_FILE_PATH); - String oldChecksum; - String oldVersion; - if (Files.exists(checksumPath)) { - var parts = Files.readString(checksumPath).split(":", 2); - oldChecksum = parts[0]; - if (parts.length == 2) { - oldVersion = parts[1]; - } else { - oldVersion = null; - } - } else { - couldNotUpdate(modId, outPath, meta); - return null; - } - String newChecksum = checkPath(defaultResources); - String newVersion = meta.dataVersion().orElse(null); - if (newChecksum.equals(oldChecksum) && Objects.equals(newVersion, oldVersion)) { - // The resources to extract have not changed, but the extracted resources have been modified - return null; - } else { - // The resources to extract differ from the saved checksum - String newExtractedChecksum = checkPath(outPath); - if (newExtractedChecksum.equals(oldChecksum)) { - // The calculated extracted checksum does not differ from the saved checksum - return newChecksum; - } - } - } else { - return checkPath(defaultResources); - } - } catch (IOException e) { - DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}", defaultResources, outPath, e); - } - couldNotUpdate(modId, outPath, meta); - return null; - } + private static @Nullable String shouldCopy(Path defaultResources, Path outPath, boolean alreadyExists, String modId, ModMetaFile meta) { + try { + if (alreadyExists) { + Path checksumPath = outPath.resolve(CHECK_FILE_PATH); + String oldChecksum; + String oldVersion; + if (Files.exists(checksumPath)) { + var parts = Files.readString(checksumPath).split(":", 2); + oldChecksum = parts[0]; + if (parts.length == 2) { + oldVersion = parts[1]; + } else { + oldVersion = null; + } + } else { + couldNotUpdate(modId, outPath, meta); + return null; + } + String newChecksum = checkPath(defaultResources); + String newVersion = meta.dataVersion().orElse(null); + if (newChecksum.equals(oldChecksum) && Objects.equals(newVersion, oldVersion)) { + // The resources to extract have not changed, but the extracted resources have been modified + return null; + } else { + // The resources to extract differ from the saved checksum + String newExtractedChecksum = checkPath(outPath); + if (newExtractedChecksum.equals(oldChecksum)) { + // The calculated extracted checksum does not differ from the saved checksum + return newChecksum; + } + } + } else { + return checkPath(defaultResources); + } + } catch (IOException e) { + DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}", defaultResources, outPath, e); + } + couldNotUpdate(modId, outPath, meta); + return null; + } - private static @Nullable String dataVersion(Path path) throws IOException { - Path checksumPath = path.resolve(CHECK_FILE_PATH); - if (Files.exists(checksumPath)) { - var parts = Files.readString(checksumPath).split(":", 2); - if (parts.length == 2) { - return parts[1]; - } - } - return null; - } + private static @Nullable String dataVersion(Path path) throws IOException { + Path checksumPath = path.resolve(CHECK_FILE_PATH); + if (Files.exists(checksumPath)) { + var parts = Files.readString(checksumPath).split(":", 2); + if (parts.length == 2) { + return parts[1]; + } + } + return null; + } - private static String checkPath(Path path) throws IOException { - StringBuilder newChecksum = new StringBuilder(); - try (var walk = Files.walk(path)) { - walk.sorted(Comparator.comparing(p -> path.relativize(p).toString())).forEach(p -> { - try { - if (!Files.isDirectory(p) && !(path.relativize(p).getNameCount() == 1 && p.endsWith(CHECK_FILE_PATH))) { - Checksum check = new Adler32(); - try (var is = Files.newInputStream(p)) { - byte[] buffer = new byte[BUFFER_SIZE]; - int length; - while ((length = is.read(buffer)) > 0) { - check.update(buffer, 0, length); - } - } - newChecksum.append(encode((int) check.getValue())); - } - } catch (IOException e) { - DefaultResources.LOGGER.error("Error calculating checksum at {}", p, e); - } - }); - } - return newChecksum.toString(); - } + private static String checkPath(Path path) throws IOException { + StringBuilder newChecksum = new StringBuilder(); + try (var walk = Files.walk(path)) { + walk.sorted(Comparator.comparing(p -> path.relativize(p).toString())).forEach(p -> { + try { + if (!Files.isDirectory(p) && !(path.relativize(p).getNameCount() == 1 && p.endsWith(CHECK_FILE_PATH))) { + Checksum check = new Adler32(); + try (var is = Files.newInputStream(p)) { + byte[] buffer = new byte[BUFFER_SIZE]; + int length; + while ((length = is.read(buffer)) > 0) { + check.update(buffer, 0, length); + } + } + newChecksum.append(encode((int) check.getValue())); + } + } catch (IOException e) { + DefaultResources.LOGGER.error("Error calculating checksum at {}", p, e); + } + }); + } + return newChecksum.toString(); + } - private static CharSequence encode(int i) { - StringBuilder sb = new StringBuilder(); - for (int j = 0; j < 4; j++) { - sb.append((char) (((i >> (j * 4)) & 0xF) + 97)); - } - return sb; - } + private static CharSequence encode(int i) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < 4; j++) { + sb.append((char) (((i >> (j * 4)) & 0xF) + 97)); + } + return sb; + } - private static void copyResources(Path defaultResources, Path outPath, String checksum, @Nullable String dataVersion) { - try (var walk = Files.walk(defaultResources)) { - walk.sorted(Comparator.comparing(p -> p.relativize(defaultResources).toString())).forEach(p -> { - try { - if (!Files.isDirectory(p)) { - String rel = defaultResources.relativize(p).toString(); - Path newPath = outPath.resolve(rel); - if (!Files.exists(newPath.getParent())) Files.createDirectories(newPath.getParent()); - Files.copy(p, newPath); - } - } catch (IOException e) { - DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}, for path {}", defaultResources, outPath, p, e); - } - }); - Path checksumPath = outPath.resolve(CHECK_FILE_PATH); - Files.writeString(checksumPath, checksum + (dataVersion == null ? "" : ":" + dataVersion)); - } catch (IOException e) { - DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}", defaultResources, outPath, e); - } - } + private static void copyResources(Path defaultResources, Path outPath, String checksum, @Nullable String dataVersion) { + try (var walk = Files.walk(defaultResources)) { + walk.sorted(Comparator.comparing(p -> p.relativize(defaultResources).toString())).forEach(p -> { + try { + if (!Files.isDirectory(p)) { + String rel = defaultResources.relativize(p).toString(); + Path newPath = outPath.resolve(rel); + if (!Files.exists(newPath.getParent())) Files.createDirectories(newPath.getParent()); + Files.copy(p, newPath); + } + } catch (IOException e) { + DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}, for path {}", defaultResources, outPath, p, e); + } + }); + Path checksumPath = outPath.resolve(CHECK_FILE_PATH); + Files.writeString(checksumPath, checksum + (dataVersion == null ? "" : ":" + dataVersion)); + } catch (IOException e) { + DefaultResources.LOGGER.error("Error checking compatibility of resources from {} targeted at {}", defaultResources, outPath, e); + } + } - public static void cleanupExtraction() { - Config.INSTANCE.get().save(); - } + public static void cleanupExtraction() { + Config.INSTANCE.get().save(); + } - public static Pack.ResourcesSupplier wrap(Function function) { - return new Pack.ResourcesSupplier() { - @Override - public @NonNull PackResources openPrimary(String string) { - return function.apply(string); - } + public static Pack.ResourcesSupplier wrap(Function function) { + return new Pack.ResourcesSupplier() { + @Override + public @NonNull PackResources openPrimary(String string) { + return function.apply(string); + } - @Override - public @NonNull PackResources openFull(String string, Pack.Info info) { - return function.apply(string); - } - }; - } + @Override + public @NonNull PackResources openFull(String string, Pack.Info info) { + return function.apply(string); + } + }; + } - @NonNull - public static List> getPackResources(PackType type) { - List> packs = new ArrayList<>(); - try (var files = Files.list(Services.PLATFORM.getGlobalFolder())) { - for (var file : files.toList()) { - if (Files.isDirectory(file)) { - Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, "", file, type)); - packs.add(new Pair<>(file.getFileName().toString(), packResources)); - } else if (file.getFileName().toString().endsWith(".zip")) { - Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, "", file, type)); - packs.add(new Pair<>(file.getFileName().toString(), packResources)); - } - } - } catch (IOException ignored) { + @NonNull public static List> getPackResources(PackType type) { + List> packs = new ArrayList<>(); + try (var files = Files.list(Services.PLATFORM.getGlobalFolder())) { + for (var file : files.toList()) { + if (Files.isDirectory(file)) { + Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, "", file, type)); + packs.add(new Pair<>(file.getFileName().toString(), packResources)); + } else if (file.getFileName().toString().endsWith(".zip")) { + Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, "", file, type)); + packs.add(new Pair<>(file.getFileName().toString(), packResources)); + } + } + } catch (IOException ignored) { - } - QUEUED_RESOURCES.forEach((s, biFunction) -> { - Supplier resources = biFunction.apply(s, type); - if (resources == null) return; - packs.add(new Pair<>(s, wrap(str -> resources.get()))); - }); - return packs; - } + } + QUEUED_RESOURCES.forEach((s, biFunction) -> { + Supplier resources = biFunction.apply(s, type); + if (resources == null) return; + packs.add(new Pair<>(s, wrap(str -> resources.get()))); + }); + return packs; + } - @NonNull - private static List> getStaticPackResources(PackType type) { - List> packs = new ArrayList<>(); - try (var files = Files.list(Services.PLATFORM.getGlobalFolder())) { - for (var file : files.toList()) { - if (Files.isDirectory(file)) { - Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, file, type)); - packs.add(new Pair<>(file.getFileName().toString(), packResources)); - } else if (file.getFileName().toString().endsWith(".zip")) { - Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, file, type)); - packs.add(new Pair<>(file.getFileName().toString(), packResources)); - } - } - } catch (IOException ignored) { + @NonNull private static List> getStaticPackResources(PackType type) { + List> packs = new ArrayList<>(); + try (var files = Files.list(Services.PLATFORM.getGlobalFolder())) { + for (var file : files.toList()) { + if (Files.isDirectory(file)) { + Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, file, type)); + packs.add(new Pair<>(file.getFileName().toString(), packResources)); + } else if (file.getFileName().toString().endsWith(".zip")) { + Pack.ResourcesSupplier packResources = wrap(s -> new AutoMetadataPathPackResources(s, GLOBAL_PREFIX, file, type)); + packs.add(new Pair<>(file.getFileName().toString(), packResources)); + } + } + } catch (IOException ignored) { - } - packs.addAll(getDetectedPacks(type)); - QUEUED_STATIC_RESOURCES.forEach((s, biFunction) -> { - Supplier resources = biFunction.apply(s, type); - if (resources == null) return; - packs.add(new Pair<>(s, wrap(str -> resources.get()))); - }); - return packs; - } + } + packs.addAll(getDetectedPacks(type)); + QUEUED_STATIC_RESOURCES.forEach((s, biFunction) -> { + Supplier resources = biFunction.apply(s, type); + if (resources == null) return; + packs.add(new Pair<>(s, wrap(str -> resources.get()))); + }); + return packs; + } - private static List> getDetectedPacks(PackType type) { - List> packs = new ArrayList<>(); - Config.INSTANCE.get().fromResourcePacks().forEach((name, enabled) -> { - if (enabled) { - Path path = Services.PLATFORM.getResourcePackDir().resolve(name); - if (Files.isDirectory(path)) { - packs.add(Pair.of(name, wrap(n -> new AutoMetadataPathPackResources(n, GLOBAL_PREFIX, path, type)))); - } else if (Files.isRegularFile(path)) { - packs.add(Pair.of(name, wrap(n -> new AutoMetadataFilePackResources(n, GLOBAL_PREFIX, path, type)))); - } else { - return; - } - DefaultResources.LOGGER.info("Added resource pack \"{}\" to global {} resource providers", name, type.getDirectory()); - } - }); - return packs; - } + private static List> getDetectedPacks(PackType type) { + List> packs = new ArrayList<>(); + Config.INSTANCE.get().fromResourcePacks().forEach((name, enabled) -> { + if (enabled) { + Path path = Services.PLATFORM.getResourcePackDir().resolve(name); + if (Files.isDirectory(path)) { + packs.add(Pair.of(name, wrap(n -> new AutoMetadataPathPackResources(n, GLOBAL_PREFIX, path, type)))); + } else if (Files.isRegularFile(path)) { + packs.add(Pair.of(name, wrap(n -> new AutoMetadataFilePackResources(n, GLOBAL_PREFIX, path, type)))); + } else { + return; + } + DefaultResources.LOGGER.info("Added resource pack \"{}\" to global {} resource providers", name, type.getDirectory()); + } + }); + return packs; + } - public synchronized static void delegate(Runnable ifInitialized, Runnable ifUninitialized) { - if (GLOBAL_SETUP) { - ifInitialized.run(); - } else { - ifUninitialized.run(); - } - } + public synchronized static void delegate(Runnable ifInitialized, Runnable ifUninitialized) { + if (GLOBAL_SETUP) { + ifInitialized.run(); + } else { + ifUninitialized.run(); + } + } - public synchronized static void initialize() { - if (!GLOBAL_SETUP) { - Services.PLATFORM.extractResources(); - DefaultResources.cleanupExtraction(); - for (var entry : OUTDATED_TARGETS.entrySet()) { - String oldVersion = MOD_TARGETS.getOrDefault(entry.getKey(), Optional.empty()).orElse(null); - String newVersion = entry.getValue().orElse(null); - String modId = entry.getKey(); - OUTDATED_RESOURCES_LISTENERS.getOrDefault(modId, List.of()).forEach(listener -> listener.resourcesOutdated(oldVersion, newVersion)); - } - GLOBAL_SETUP = true; - } - } + public synchronized static void initialize() { + if (!GLOBAL_SETUP) { + Services.PLATFORM.extractResources(); + DefaultResources.cleanupExtraction(); + for (var entry : OUTDATED_TARGETS.entrySet()) { + String oldVersion = MOD_TARGETS.getOrDefault(entry.getKey(), Optional.empty()).orElse(null); + String newVersion = entry.getValue().orElse(null); + String modId = entry.getKey(); + OUTDATED_RESOURCES_LISTENERS.getOrDefault(modId, List.of()).forEach(listener -> listener.resourcesOutdated(oldVersion, newVersion)); + } + GLOBAL_SETUP = true; + } + } - public synchronized static GlobalResourceManager createStaticResourceManager(PackType type) { - initialize(); - List> sources = new ArrayList<>(getStaticPackResources(type)); - sources.addAll(Services.PLATFORM.getJarProviders(type)); - return new CombinedResourceManager(type, sources); - } + public synchronized static GlobalResourceManager createStaticResourceManager(PackType type) { + initialize(); + List> sources = new ArrayList<>(getStaticPackResources(type)); + sources.addAll(Services.PLATFORM.getJarProviders(type)); + return new CombinedResourceManager(type, sources); + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResourcesMetadataSection.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResourcesMetadataSection.java index 20ec9c1..e1085f5 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResourcesMetadataSection.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/DefaultResourcesMetadataSection.java @@ -1,15 +1,10 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; public record DefaultResourcesMetadataSection(boolean detect) { - public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( - Codec.BOOL.optionalFieldOf("detect", false).forGetter(DefaultResourcesMetadataSection::detect) - ).apply(i, DefaultResourcesMetadataSection::new)); + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.BOOL.optionalFieldOf("detect", false).forGetter(DefaultResourcesMetadataSection::detect) + ).apply(i, DefaultResourcesMetadataSection::new)); } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/ManagerHolder.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/ManagerHolder.java index 60f49d4..3db1c68 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/ManagerHolder.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/ManagerHolder.java @@ -1,16 +1,11 @@ -/* - * Copyright (C) 2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import dev.lukebemish.defaultresources.api.GlobalResourceManager; import net.minecraft.server.packs.PackType; public final class ManagerHolder { - private ManagerHolder() {} + private ManagerHolder() {} - public static final GlobalResourceManager STATIC_ASSETS = DefaultResources.createStaticResourceManager(PackType.CLIENT_RESOURCES); - public static final GlobalResourceManager STATIC_DATA = DefaultResources.createStaticResourceManager(PackType.SERVER_DATA); + public static final GlobalResourceManager STATIC_ASSETS = DefaultResources.createStaticResourceManager(PackType.CLIENT_RESOURCES); + public static final GlobalResourceManager STATIC_DATA = DefaultResources.createStaticResourceManager(PackType.SERVER_DATA); } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/ModMetaFile.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/ModMetaFile.java index fbbcb96..700f0e8 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/ModMetaFile.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/ModMetaFile.java @@ -1,20 +1,14 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; - import java.util.Optional; public record ModMetaFile(String resourcesPath, boolean zip, boolean extract, Optional dataVersion) { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.STRING.optionalFieldOf("resources_path", "defaultresources").forGetter(ModMetaFile::resourcesPath), - Codec.BOOL.optionalFieldOf("zip", true).forGetter(ModMetaFile::zip), - Codec.BOOL.optionalFieldOf("extract", true).forGetter(ModMetaFile::extract), - Codec.STRING.optionalFieldOf("data_version").forGetter(ModMetaFile::dataVersion) - ).apply(instance, ModMetaFile::new)); + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.optionalFieldOf("resources_path", "defaultresources").forGetter(ModMetaFile::resourcesPath), + Codec.BOOL.optionalFieldOf("zip", true).forGetter(ModMetaFile::zip), + Codec.BOOL.optionalFieldOf("extract", true).forGetter(ModMetaFile::extract), + Codec.STRING.optionalFieldOf("data_version").forGetter(ModMetaFile::dataVersion) + ).apply(instance, ModMetaFile::new)); } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/ParallelExecutor.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/ParallelExecutor.java index fa397f2..4315057 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/ParallelExecutor.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/ParallelExecutor.java @@ -1,12 +1,5 @@ -/* - * Copyright (C) 2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; -import net.minecraft.util.Unit; - import java.util.Objects; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; @@ -14,47 +7,48 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Stream; +import net.minecraft.util.Unit; public final class ParallelExecutor { - private ParallelExecutor() {} - - private static final AtomicInteger POOL_THREAD_COUNTER = new AtomicInteger(0); - private static final ForkJoinPool POOL; - - static { - final ClassLoader classLoader = ParallelExecutor.class.getClassLoader(); - POOL = new ForkJoinPool( - Math.max(4, Runtime.getRuntime().availableProcessors() - 4), - forkJoinPool -> { - final ForkJoinWorkerThread thread = new ForkJoinWorkerThread(forkJoinPool) {}; - thread.setContextClassLoader(classLoader); - thread.setName(String.format("DefaultResources parallel executor: %s", POOL_THREAD_COUNTER.incrementAndGet())); - return thread; - }, null, true - ); - } - - public static void execute(Stream stream, Consumer task) { - POOL.invoke(new RunnableExecuteAction(() -> stream.parallel().forEach(task))); - } - - private static final class RunnableExecuteAction extends ForkJoinTask { - final Runnable runnable; - - private RunnableExecuteAction(Runnable runnable) { - this.runnable = Objects.requireNonNull(runnable); - } - - public Unit getRawResult() { - return Unit.INSTANCE; - } - - public void setRawResult(Unit v) { - } - - public boolean exec() { - this.runnable.run(); - return true; - } - } + private ParallelExecutor() {} + + private static final AtomicInteger POOL_THREAD_COUNTER = new AtomicInteger(0); + private static final ForkJoinPool POOL; + + static { + final ClassLoader classLoader = ParallelExecutor.class.getClassLoader(); + POOL = new ForkJoinPool( + Math.max(4, Runtime.getRuntime().availableProcessors() - 4), + forkJoinPool -> { + final ForkJoinWorkerThread thread = new ForkJoinWorkerThread(forkJoinPool) {}; + thread.setContextClassLoader(classLoader); + thread.setName(String.format("DefaultResources parallel executor: %s", POOL_THREAD_COUNTER.incrementAndGet())); + return thread; + }, null, true + ); + } + + public static void execute(Stream stream, Consumer task) { + POOL.invoke(new RunnableExecuteAction(() -> stream.parallel().forEach(task))); + } + + private static final class RunnableExecuteAction extends ForkJoinTask { + final Runnable runnable; + + private RunnableExecuteAction(Runnable runnable) { + this.runnable = Objects.requireNonNull(runnable); + } + + public Unit getRawResult() { + return Unit.INSTANCE; + } + + public void setRawResult(Unit v) { + } + + public boolean exec() { + this.runnable.run(); + return true; + } + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/Services.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/Services.java index 5f723f8..97f5804 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/Services.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/Services.java @@ -1,23 +1,17 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import dev.lukebemish.defaultresources.impl.services.Platform; - import java.util.ServiceLoader; public class Services { - public static final Platform PLATFORM = load(Platform.class); + public static final Platform PLATFORM = load(Platform.class); - public static T load(Class clazz) { + public static T load(Class clazz) { - final T loadedService = ServiceLoader.load(clazz) - .findFirst() - .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); - DefaultResources.LOGGER.debug("Loaded {} for service {}", loadedService, clazz); - return loadedService; - } + final T loadedService = ServiceLoader.load(clazz) + .findFirst() + .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName())); + DefaultResources.LOGGER.debug("Loaded {} for service {}", loadedService, clazz); + return loadedService; + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/WrappingResourceManager.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/WrappingResourceManager.java index 01c6ddc..52bb80a 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/WrappingResourceManager.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/WrappingResourceManager.java @@ -1,12 +1,12 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl; import dev.lukebemish.defaultresources.api.GlobalResourceManager; import dev.lukebemish.defaultresources.impl.mixin.ResourceAccessor; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Stream; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; @@ -17,137 +17,128 @@ import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Stream; - public class WrappingResourceManager implements GlobalResourceManager { - private final GlobalResourceManager wrapped; - private final String prefix; - - private static void checkValidPrefix(String prefix) { - if (prefix.isEmpty()) { - throw new IllegalArgumentException("Invalid prefix; prefixes must not be empty."); - } - for (char c : prefix.toCharArray()) { - if (c == '_' || c == '-' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9') { - continue; - } - throw new IllegalArgumentException("Invalid prefix: \"" + prefix+"\". Prefixes must contain only lowercase letters, numbers, underscores, and dashes."); - } - } - - public WrappingResourceManager(GlobalResourceManager wrapped, String prefix) { - checkValidPrefix(prefix); - this.wrapped = wrapped; - this.prefix = prefix+"/"; - } - - @Override - public @NonNull Set getNamespaces() { - return wrapped.getNamespaces(); - } - - @Override - public @NonNull List getResourceStack(ResourceLocation location) { - List out = new ArrayList<>(); - for (var resource : wrapped.getResourceStack(location.withPrefix(prefix))) { - out.add(wrapResource(resource)); - } - return out; - } - - @Override - public @NonNull Map listResources(String path, Predicate filter) { - Map out = new HashMap<>(); - for (var entry : wrapped.listResources(prefix + path, filter).entrySet()) { - out.put(wrapLocation(entry.getKey()), wrapResource(entry.getValue())); - } - return out; - } - - @Override - public @NonNull Map> listResourceStacks(String path, Predicate filter) { - Map> out = new HashMap<>(); - for (var entry : wrapped.listResourceStacks(prefix + path, filter).entrySet()) { - List resources = new ArrayList<>(); - for (var resource : entry.getValue()) { - resources.add(wrapResource(resource)); - } - out.put(wrapLocation(entry.getKey()), resources); - } - return out; - } - - @Override - public @NonNull Stream listPacks() { - return wrapped.listPacks().map(this::wrapResources); - } - - private Resource wrapResource(Resource resource) { - if (((ResourceAccessor) resource).defaultresources_getMetadataSupplier() == ResourceMetadata.EMPTY_SUPPLIER) { - return new Resource(wrapResources(resource.source()), ((ResourceAccessor) resource).defaultresources_getStreamSupplier()); - } - return new Resource(wrapResources(resource.source()), ((ResourceAccessor) resource).defaultresources_getStreamSupplier(), ((ResourceAccessor) resource).defaultresources_getMetadataSupplier()); - } - - private ResourceLocation wrapLocation(ResourceLocation location) { - return location.withPath(s -> s.substring(prefix.length())); - } - - private PackResources wrapResources(PackResources pack) { - return new PackResources() { - @Nullable - @Override - public IoSupplier getRootResource(String... elements) { - return pack.getRootResource(elements); - } - - @Nullable - @Override - public IoSupplier getResource(PackType packType, ResourceLocation location) { - return pack.getResource(packType, location.withPrefix(prefix)); - } - - @Override - public void listResources(PackType packType, String namespace, String path, ResourceOutput resourceOutput) { - pack.listResources(packType, namespace, prefix+path, (rl, ioSupplier) -> - resourceOutput.accept(wrapLocation(rl), ioSupplier)); - } - - @Override - public @NonNull Set getNamespaces(PackType type) { - return pack.getNamespaces(type); - } - - @Nullable - @Override - public T getMetadataSection(MetadataSectionSerializer deserializer) throws IOException { - return pack.getMetadataSection(deserializer); - } - - @Override - public @NonNull String packId() { - return pack.packId(); - } - - @Override - public boolean isBuiltin() { - return pack.isBuiltin(); - } - - @Override - public void close() { - pack.close(); - } - }; - } - - @Override - public @NonNull Optional getResource(ResourceLocation location) { - return wrapped.getResource(location.withPrefix(prefix)).map(this::wrapResource); - } + private final GlobalResourceManager wrapped; + private final String prefix; + + private static void checkValidPrefix(String prefix) { + if (prefix.isEmpty()) { + throw new IllegalArgumentException("Invalid prefix; prefixes must not be empty."); + } + for (char c : prefix.toCharArray()) { + if (c == '_' || c == '-' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9') { + continue; + } + throw new IllegalArgumentException("Invalid prefix: \"" + prefix+"\". Prefixes must contain only lowercase letters, numbers, underscores, and dashes."); + } + } + + public WrappingResourceManager(GlobalResourceManager wrapped, String prefix) { + checkValidPrefix(prefix); + this.wrapped = wrapped; + this.prefix = prefix+"/"; + } + + @Override + public @NonNull Set getNamespaces() { + return wrapped.getNamespaces(); + } + + @Override + public @NonNull List getResourceStack(ResourceLocation location) { + List out = new ArrayList<>(); + for (var resource : wrapped.getResourceStack(location.withPrefix(prefix))) { + out.add(wrapResource(resource)); + } + return out; + } + + @Override + public @NonNull Map listResources(String path, Predicate filter) { + Map out = new HashMap<>(); + for (var entry : wrapped.listResources(prefix + path, filter).entrySet()) { + out.put(wrapLocation(entry.getKey()), wrapResource(entry.getValue())); + } + return out; + } + + @Override + public @NonNull Map> listResourceStacks(String path, Predicate filter) { + Map> out = new HashMap<>(); + for (var entry : wrapped.listResourceStacks(prefix + path, filter).entrySet()) { + List resources = new ArrayList<>(); + for (var resource : entry.getValue()) { + resources.add(wrapResource(resource)); + } + out.put(wrapLocation(entry.getKey()), resources); + } + return out; + } + + @Override + public @NonNull Stream listPacks() { + return wrapped.listPacks().map(this::wrapResources); + } + + private Resource wrapResource(Resource resource) { + if (((ResourceAccessor) resource).defaultresources_getMetadataSupplier() == ResourceMetadata.EMPTY_SUPPLIER) { + return new Resource(wrapResources(resource.source()), ((ResourceAccessor) resource).defaultresources_getStreamSupplier()); + } + return new Resource(wrapResources(resource.source()), ((ResourceAccessor) resource).defaultresources_getStreamSupplier(), ((ResourceAccessor) resource).defaultresources_getMetadataSupplier()); + } + + private ResourceLocation wrapLocation(ResourceLocation location) { + return location.withPath(s -> s.substring(prefix.length())); + } + + private PackResources wrapResources(PackResources pack) { + return new PackResources() { + @Nullable @Override + public IoSupplier getRootResource(String... elements) { + return pack.getRootResource(elements); + } + + @Nullable @Override + public IoSupplier getResource(PackType packType, ResourceLocation location) { + return pack.getResource(packType, location.withPrefix(prefix)); + } + + @Override + public void listResources(PackType packType, String namespace, String path, ResourceOutput resourceOutput) { + pack.listResources(packType, namespace, prefix+path, (rl, ioSupplier) -> + resourceOutput.accept(wrapLocation(rl), ioSupplier)); + } + + @Override + public @NonNull Set getNamespaces(PackType type) { + return pack.getNamespaces(type); + } + + @Nullable @Override + public T getMetadataSection(MetadataSectionSerializer deserializer) throws IOException { + return pack.getMetadataSection(deserializer); + } + + @Override + public @NonNull String packId() { + return pack.packId(); + } + + @Override + public boolean isBuiltin() { + return pack.isBuiltin(); + } + + @Override + public void close() { + pack.close(); + } + }; + } + + @Override + public @NonNull Optional getResource(ResourceLocation location) { + return wrapped.getResource(location.withPrefix(prefix)).map(this::wrapResource); + } } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/mixin/ResourceAccessor.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/mixin/ResourceAccessor.java index 9ff640c..511cc8d 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/mixin/ResourceAccessor.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/mixin/ResourceAccessor.java @@ -1,22 +1,16 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.mixin; +import java.io.InputStream; import net.minecraft.server.packs.resources.IoSupplier; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceMetadata; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -import java.io.InputStream; - @Mixin(Resource.class) public interface ResourceAccessor { - @Accessor(value = "streamSupplier") - IoSupplier defaultresources_getStreamSupplier(); - @Accessor(value = "metadataSupplier") - IoSupplier defaultresources_getMetadataSupplier(); + @Accessor(value = "streamSupplier") + IoSupplier defaultresources_getStreamSupplier(); + @Accessor(value = "metadataSupplier") + IoSupplier defaultresources_getMetadataSupplier(); } diff --git a/common/src/main/java/dev/lukebemish/defaultresources/impl/services/Platform.java b/common/src/main/java/dev/lukebemish/defaultresources/impl/services/Platform.java index afa8e4d..384b2d2 100644 --- a/common/src/main/java/dev/lukebemish/defaultresources/impl/services/Platform.java +++ b/common/src/main/java/dev/lukebemish/defaultresources/impl/services/Platform.java @@ -1,29 +1,23 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.services; import com.mojang.datafixers.util.Pair; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.Pack; - import java.nio.file.Path; import java.util.Collection; import java.util.Map; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.Pack; public interface Platform { - Path getGlobalFolder(); + Path getGlobalFolder(); - void extractResources(); + void extractResources(); - Collection> getJarProviders(PackType type); + Collection> getJarProviders(PackType type); - Path getConfigDir(); - Path getResourcePackDir(); + Path getConfigDir(); + Path getResourcePackDir(); - Map getExistingModdedPaths(String relative); + Map getExistingModdedPaths(String relative); - boolean isClient(); + boolean isClient(); } diff --git a/common/src/main/resources/mods.groovy b/common/src/main/resources/mods.groovy index 1290f3d..222f3f0 100644 --- a/common/src/main/resources/mods.groovy +++ b/common/src/main/resources/mods.groovy @@ -1,29 +1,19 @@ -/* - * Copyright (C) 2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - -import modsdotgroovy.Dependency - -/* - * Copyright (C) 2023 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - -ModsDotGroovy.make { +MultiplatformModsDotGroovy.make { modLoader = 'javafml' loaderVersion = '[1,)' issueTrackerUrl = 'https://github.com/lukebemishprojects/DefaultResources/issues' license = 'LGPL-3.0-or-later' mod { - modId = this.buildProperties.mod_id - displayName = this.buildProperties.mod_name - version = this.version + modId = buildProperties.mod_id + displayName = buildProperties.mod_name + version = environmentInfo.version displayUrl = 'https://github.com/lukebemishprojects/DefaultResources' - contact.sources = 'https://github.com/lukebemishprojects/DefaultResources' - author 'Luke Bemish' - description = "A tool for loading and extracting resources provided by mods or by users." + contact { + sources = 'https://github.com/lukebemishprojects/DefaultResources' + } + author = 'Luke Bemish' + description = buildProperties.description entrypoints { main = 'dev.lukebemish.defaultresources.impl.fabriquilt.DefaultResourcesFabriQuilt' @@ -32,43 +22,30 @@ ModsDotGroovy.make { dependencies { mod 'minecraft', { - def minor = this.libs.versions.minecraft.split(/\./)[1] as int - versionRange = "[${this.libs.versions.minecraft},1.${minor+1}.0)" + def minor = libs.versions.minecraft.split(/\./)[1] as int + versionRange = "[${libs.versions.minecraft},1.${minor+1}.0)" } - onForge { - neoforge = ">=${this.libs.versions.neoforge}" + onNeoForge { + neoforge = ">=${libs.versions.neoforge}" } onFabric { mod 'fabricloader', { - versionRange = ">=${this.libs.versions.fabric.loader}" + versionRange = ">=${libs.versions.fabric_loader}" } mod 'fabric-api', { - versionRange = ">=${this.libs.versions.fabric.api.split(/\+/)[0]}" - } - } - } - - onForge { - dependencies = dependencies.collect { dep -> - new Dependency() { - @Override - Map asForgeMap() { - def map = dep.asForgeMap() - map.remove('mandatory') - map.put('type', this.mandatory ? 'required' : 'optional') - return map - } + versionRange = ">=${libs.versions.fabric_api.split(/\+/)[0]}" } } } } + onFabric { mixin = [ 'mixin.defaultresources.fabriquilt.json', 'mixin.defaultresources.json' ] } - onForge { + onNeoForge { mixins = [ ['config':'mixin.defaultresources.json'] ] diff --git a/fabriquilt/build.gradle b/fabriquilt/build.gradle index f20f813..e225bbd 100644 --- a/fabriquilt/build.gradle +++ b/fabriquilt/build.gradle @@ -1,34 +1,52 @@ +import org.groovymc.modsdotgroovy.core.Platform +import org.groovymc.modsdotgroovy.gradle.tasks.AbstractGatherPlatformDetailsTask + plugins { - id 'convention.consumer' - alias libs.plugins.architectury.loom + id 'convention.consumer' + alias libs.plugins.architectury.loom + alias libs.plugins.mdg +} + +modsDotGroovy { + platform = Platform.FABRIC + inferGather.set false + multiplatform { + from ':common' + } + apply() +} + +tasks.named('gatherFabricPlatformDetails', AbstractGatherPlatformDetailsTask).configure { + minecraftVersion = libs.versions.minecraft.get() + platformVersion = libs.versions.fabric.loader.get() } dependencies { - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") - } - minecraft libs.minecraft - modImplementation libs.fabric.loader - modImplementation libs.fabric.api + mappings loom.layered() { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") + } + minecraft libs.minecraft + modImplementation libs.fabric.loader + modImplementation libs.fabric.api } loom { - mixin { - defaultRefmapName = "defaultresources.refmap.json" - } - runs { - client { - client() - setConfigName("Fabric Client") - ideConfigGenerated(true) - runDir("run") - } - server { - server() - setConfigName("Fabric Server") - ideConfigGenerated(true) - runDir("runserver") - } - } + mixin { + defaultRefmapName = "defaultresources.refmap.json" + } + runs { + client { + client() + setConfigName("Fabric Client") + ideConfigGenerated(true) + runDir("run") + } + server { + server() + setConfigName("Fabric Server") + ideConfigGenerated(true) + runDir("runserver") + } + } } diff --git a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuilt.java b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuilt.java index b36d315..76c3fb3 100644 --- a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuilt.java +++ b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuilt.java @@ -1,14 +1,15 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.fabriquilt; import com.mojang.datafixers.util.Pair; import dev.lukebemish.defaultresources.impl.DefaultResources; import dev.lukebemish.defaultresources.impl.ParallelExecutor; import dev.lukebemish.defaultresources.impl.Services; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.network.chat.Component; @@ -18,49 +19,42 @@ import net.minecraft.server.packs.repository.PackCompatibility; import net.minecraft.world.flag.FeatureFlagSet; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.function.BiConsumer; - @SuppressWarnings("deprecation") public class DefaultResourcesFabriQuilt implements ModInitializer { - @Override - public void onInitialize() { - DefaultResources.initialize(); - addPackResources(PackType.SERVER_DATA); - } + @Override + public void onInitialize() { + DefaultResources.initialize(); + addPackResources(PackType.SERVER_DATA); + } - public static void forAllMods(BiConsumer consumer) { - FabricLoader.getInstance().getAllMods().forEach(mod -> consumer.accept(mod.getMetadata().getId(), mod.getRootPath())); - } + public static void forAllMods(BiConsumer consumer) { + FabricLoader.getInstance().getAllMods().forEach(mod -> consumer.accept(mod.getMetadata().getId(), mod.getRootPath())); + } - public static void forAllModsParallel(BiConsumer consumer) { - ParallelExecutor.execute(FabricLoader.getInstance().getAllMods().stream(), mod -> consumer.accept(mod.getMetadata().getId(), mod.getRootPath())); - } + public static void forAllModsParallel(BiConsumer consumer) { + ParallelExecutor.execute(FabricLoader.getInstance().getAllMods().stream(), mod -> consumer.accept(mod.getMetadata().getId(), mod.getRootPath())); + } - public static void addPackResources(PackType type) { - try { - if (!Files.exists(Services.PLATFORM.getGlobalFolder())) - Files.createDirectories(Services.PLATFORM.getGlobalFolder()); - } catch (IOException e) { - throw new RuntimeException(e); - } - ResourceLoader.get(type).addPacks(() -> { - List out = new ArrayList<>(); - List> packs = DefaultResources.getPackResources(type); - for (var pair : packs) { - Pack.Info info = new Pack.Info( - Component.literal("Global Resources - "+pair.getFirst()), - PackCompatibility.COMPATIBLE, - FeatureFlagSet.of(), - List.of() - ); - out.add(pair.getSecond().openFull(pair.getFirst(), info)); - } - return out; - }); - } + public static void addPackResources(PackType type) { + try { + if (!Files.exists(Services.PLATFORM.getGlobalFolder())) + Files.createDirectories(Services.PLATFORM.getGlobalFolder()); + } catch (IOException e) { + throw new RuntimeException(e); + } + ResourceLoader.get(type).addPacks(() -> { + List out = new ArrayList<>(); + List> packs = DefaultResources.getPackResources(type); + for (var pair : packs) { + Pack.Info info = new Pack.Info( + Component.literal("Global Resources - "+pair.getFirst()), + PackCompatibility.COMPATIBLE, + FeatureFlagSet.of(), + List.of() + ); + out.add(pair.getSecond().openFull(pair.getFirst(), info)); + } + return out; + }); + } } diff --git a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuiltClient.java b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuiltClient.java index 90460ea..9fca546 100644 --- a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuiltClient.java +++ b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/DefaultResourcesFabriQuiltClient.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.fabriquilt; import net.fabricmc.api.ClientModInitializer; @@ -10,8 +5,8 @@ @SuppressWarnings("deprecation") public class DefaultResourcesFabriQuiltClient implements ClientModInitializer { - @Override - public void onInitializeClient() { - DefaultResourcesFabriQuilt.addPackResources(PackType.CLIENT_RESOURCES); - } + @Override + public void onInitializeClient() { + DefaultResourcesFabriQuilt.addPackResources(PackType.CLIENT_RESOURCES); + } } diff --git a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/PlatformImpl.java b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/PlatformImpl.java index db1c165..a5c7317 100644 --- a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/PlatformImpl.java +++ b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/PlatformImpl.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.fabriquilt; import com.google.auto.service.AutoService; @@ -11,6 +6,10 @@ import dev.lukebemish.defaultresources.impl.DefaultResources; import dev.lukebemish.defaultresources.impl.Services; import dev.lukebemish.defaultresources.impl.services.Platform; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; import net.fabricmc.api.EnvType; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.packs.PackResources; @@ -18,80 +17,75 @@ import net.minecraft.server.packs.repository.Pack; import org.jspecify.annotations.NonNull; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; - @AutoService(Platform.class) public class PlatformImpl implements Platform { - @Override - public Path getGlobalFolder() { - return FabricLoader.getInstance().getGameDir().resolve("globalresources"); - } + @Override + public Path getGlobalFolder() { + return FabricLoader.getInstance().getGameDir().resolve("globalresources"); + } - @Override - public void extractResources() { - try { - if (!Files.exists(Services.PLATFORM.getGlobalFolder())) - Files.createDirectories(Services.PLATFORM.getGlobalFolder()); - } catch (IOException e) { - DefaultResources.LOGGER.error(e); - } - DefaultResourcesFabriQuilt.forAllModsParallel((modID, path) -> { - if (!modID.equals("minecraft")) { - DefaultResources.forMod(path::resolve, modID); - } - }); - } + @Override + public void extractResources() { + try { + if (!Files.exists(Services.PLATFORM.getGlobalFolder())) + Files.createDirectories(Services.PLATFORM.getGlobalFolder()); + } catch (IOException e) { + DefaultResources.LOGGER.error(e); + } + DefaultResourcesFabriQuilt.forAllModsParallel((modID, path) -> { + if (!modID.equals("minecraft")) { + DefaultResources.forMod(path::resolve, modID); + } + }); + } - @Override - public Collection> getJarProviders(PackType type) { - List> providers = new ArrayList<>(); - DefaultResourcesFabriQuilt.forAllMods((modID, path) -> { - if (!modID.equals("minecraft")) { - providers.add(new Pair<>(modID, new Pack.ResourcesSupplier() { - @Override - public @NonNull PackResources openPrimary(@NonNull String s) { - return new AutoMetadataPathPackResources(s, "global", path, type); - } + @Override + public Collection> getJarProviders(PackType type) { + List> providers = new ArrayList<>(); + DefaultResourcesFabriQuilt.forAllMods((modID, path) -> { + if (!modID.equals("minecraft")) { + providers.add(new Pair<>(modID, new Pack.ResourcesSupplier() { + @Override + public @NonNull PackResources openPrimary(@NonNull String s) { + return new AutoMetadataPathPackResources(s, "global", path, type); + } - @Override - public @NonNull PackResources openFull(@NonNull String s, Pack.@NonNull Info info) { - return new AutoMetadataPathPackResources(s, "global", path, type); - } - })); - } - }); - return providers; - } + @Override + public @NonNull PackResources openFull(@NonNull String s, Pack.@NonNull Info info) { + return new AutoMetadataPathPackResources(s, "global", path, type); + } + })); + } + }); + return providers; + } - @Override - public Path getConfigDir() { - return FabricLoader.getInstance().getConfigDir(); - } + @Override + public Path getConfigDir() { + return FabricLoader.getInstance().getConfigDir(); + } - @Override - public Path getResourcePackDir() { - return FabricLoader.getInstance().getGameDir().resolve("resourcepacks"); - } + @Override + public Path getResourcePackDir() { + return FabricLoader.getInstance().getGameDir().resolve("resourcepacks"); + } - @Override - public Map getExistingModdedPaths(String relative) { - Map out = new HashMap<>(); - DefaultResourcesFabriQuilt.forAllMods((modID, path) -> { - if (!modID.equals("minecraft")) { - Path p = path.resolve(relative); - if (Files.exists(p)) { - out.put(modID, p); - } - } - }); - return out; - } + @Override + public Map getExistingModdedPaths(String relative) { + Map out = new HashMap<>(); + DefaultResourcesFabriQuilt.forAllMods((modID, path) -> { + if (!modID.equals("minecraft")) { + Path p = path.resolve(relative); + if (Files.exists(p)) { + out.put(modID, p); + } + } + }); + return out; + } - @Override - public boolean isClient() { - return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT; - } + @Override + public boolean isClient() { + return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT; + } } diff --git a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/ResourceLoader.java b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/ResourceLoader.java index 76af51c..c6184d7 100644 --- a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/ResourceLoader.java +++ b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/ResourceLoader.java @@ -1,42 +1,36 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.fabriquilt; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; - import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; public class ResourceLoader { - private ResourceLoader() {} - - public static final ResourceLoader CLIENT = new ResourceLoader(); - public static final ResourceLoader SERVER = new ResourceLoader(); - - private final List>> packs = new ArrayList<>(); - - public void addPacks(Supplier> resources) { - this.packs.add(resources); - } - - public void appendTopPacks(Consumer packConsumer) { - for (var packSupplier : this.packs) { - for (var pack : packSupplier.get()) { - packConsumer.accept(pack); - } - } - } - - public static ResourceLoader get(PackType type) { - return switch (type) { - case CLIENT_RESOURCES -> CLIENT; - case SERVER_DATA -> SERVER; - }; - } + private ResourceLoader() {} + + public static final ResourceLoader CLIENT = new ResourceLoader(); + public static final ResourceLoader SERVER = new ResourceLoader(); + + private final List>> packs = new ArrayList<>(); + + public void addPacks(Supplier> resources) { + this.packs.add(resources); + } + + public void appendTopPacks(Consumer packConsumer) { + for (var packSupplier : this.packs) { + for (var pack : packSupplier.get()) { + packConsumer.accept(pack); + } + } + } + + public static ResourceLoader get(PackType type) { + return switch (type) { + case CLIENT_RESOURCES -> CLIENT; + case SERVER_DATA -> SERVER; + }; + } } diff --git a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/mixin/MultiPackResourceManagerMixin.java b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/mixin/MultiPackResourceManagerMixin.java index fc93bbc..8b1d2e8 100644 --- a/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/mixin/MultiPackResourceManagerMixin.java +++ b/fabriquilt/src/main/java/dev/lukebemish/defaultresources/impl/fabriquilt/mixin/MultiPackResourceManagerMixin.java @@ -1,11 +1,8 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.fabriquilt.mixin; import dev.lukebemish.defaultresources.impl.fabriquilt.ResourceLoader; +import java.util.ArrayList; +import java.util.List; import net.minecraft.server.packs.PackResources; import net.minecraft.server.packs.PackType; import net.minecraft.server.packs.resources.MultiPackResourceManager; @@ -14,32 +11,28 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.List; - @Mixin(MultiPackResourceManager.class) public class MultiPackResourceManagerMixin { - @Mutable - @Shadow - @Final - private List packs; + @Mutable + @Shadow + @Final + private List packs; - @Unique - private PackType defaultresources$type; + @Unique private PackType defaultresources$type; - @Inject( - method = "", - at = @At("RETURN") - ) - private void defaultresources$captureType(PackType type, List packs, CallbackInfo ci) { - this.defaultresources$type = type; - this.defaultresources$addPacksToTop(); - } + @Inject( + method = "", + at = @At("RETURN") + ) + private void defaultresources$captureType(PackType type, List packs, CallbackInfo ci) { + this.defaultresources$type = type; + this.defaultresources$addPacksToTop(); + } - private void defaultresources$addPacksToTop() { - if (!(this.packs instanceof ArrayList)) { - this.packs = new ArrayList<>(this.packs); - } - ResourceLoader.get(defaultresources$type).appendTopPacks(this.packs::add); - } + private void defaultresources$addPacksToTop() { + if (!(this.packs instanceof ArrayList)) { + this.packs = new ArrayList<>(this.packs); + } + ResourceLoader.get(defaultresources$type).appendTopPacks(this.packs::add); + } } diff --git a/gradle.properties b/gradle.properties index 7250e9e..5a1baab 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,6 +5,9 @@ mod_name=Default Resources mod_author=Luke Bemish mod_id=defaultresources artifact_id=defaultresources +github_repo=DefaultResources +mod_description=A tool for providing default "resources" (assets, world-specific data, or other data) for a mod +license=LGPL-3.0-or-later # Gradle org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 68c083e..f755d8f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,11 +8,9 @@ neoforge = "20.4.80-beta" fabric_loader = "0.15.3" fabric_api = "0.92.1+1.20.4" -mdg_plugin = "1.4.3" -mdg_dsl = "1.5.1" +mdg = "2.0.0-beta.17" architectury_loom = "1.4.373" -quilt_licenser = "2.0.1" [libraries] minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } @@ -24,6 +22,5 @@ neoforge = { module = "net.neoforged:neoforge", version.ref = "neoforge" } [plugins] -mdg_plugin = { id = "org.groovymc.modsdotgroovy", version.ref = "mdg_plugin" } -quilt_licenser = { id = "org.quiltmc.gradle.licenser", version.ref = "quilt_licenser" } +mdg = { id = "org.groovymc.modsdotgroovy", version.ref = "mdg" } architectury_loom = { id = "dev.architectury.loom", version.ref = "architectury_loom" } diff --git a/header.txt b/header.txt deleted file mode 100644 index 6dd7519..0000000 --- a/header.txt +++ /dev/null @@ -1,5 +0,0 @@ -Copyright (C) ${YEAR} Luke Bemish, and contributors -SPDX-License-Identifier: LGPL-3.0-or-later - -;;year_display: lenient_range -;;year_selection: file diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 808c31f..a864994 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -1,51 +1,69 @@ +import org.groovymc.modsdotgroovy.core.Platform +import org.groovymc.modsdotgroovy.gradle.tasks.AbstractGatherPlatformDetailsTask + plugins { - id 'convention.consumer' - alias libs.plugins.architectury.loom + id 'convention.consumer' + alias libs.plugins.architectury.loom + alias libs.plugins.mdg +} + +modsDotGroovy { + platform = Platform.NEOFORGE + inferGather.set false + multiplatform { + from ':common' + } + apply() +} + +tasks.named('gatherNeoForgePlatformDetails', AbstractGatherPlatformDetailsTask).configure { + minecraftVersion = libs.versions.minecraft.get() + platformVersion = libs.versions.neoforge.get() } repositories { - maven { - name = 'NeoForged' - url = 'https://maven.neoforged.net/' - } + maven { + name = 'NeoForged' + url = 'https://maven.neoforged.net/' + } } dependencies { - minecraft libs.minecraft - neoForge libs.neoforge - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") - } + minecraft libs.minecraft + neoForge libs.neoforge + mappings loom.layered() { + officialMojangMappings() + parchment("org.parchmentmc.data:parchment-${libs.versions.parchment.minecraft.get()}:${libs.versions.parchment.mappings.get()}@zip") + } } loom { - runs { - client { - client() - setConfigName("NeoForge Client") - ideConfigGenerated(true) - runDir("run") - } - server { - server() - setConfigName("NeoForge Server") - ideConfigGenerated(true) - runDir("runserver") - } - } + runs { + client { + client() + setConfigName("NeoForge Client") + ideConfigGenerated(true) + runDir("run") + } + server { + server() + setConfigName("NeoForge Server") + ideConfigGenerated(true) + runDir("runserver") + } + } } import groovy.json.JsonOutput import groovy.json.JsonSlurper processResources { - doLast { - fileTree(dir: outputs.files.asPath, include: "mixin.*.json").each { File file -> - def obj = new JsonSlurper().parse(file) - if (obj.refmap) { - obj.remove('refmap') - } - file.text = JsonOutput.toJson(obj) - } - } + doLast { + fileTree(dir: outputs.files.asPath, include: "mixin.*.json").each { File file -> + def obj = new JsonSlurper().parse(file) + if (obj.refmap) { + obj.remove('refmap') + } + file.text = JsonOutput.toJson(obj) + } + } } diff --git a/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/DefaultResourcesNeoForge.java b/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/DefaultResourcesNeoForge.java index 218c698..46a3695 100644 --- a/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/DefaultResourcesNeoForge.java +++ b/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/DefaultResourcesNeoForge.java @@ -1,13 +1,12 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.neoforge; import com.mojang.datafixers.util.Pair; import dev.lukebemish.defaultresources.impl.DefaultResources; import dev.lukebemish.defaultresources.impl.Services; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.stream.Stream; import net.minecraft.SharedConstants; import net.minecraft.network.chat.Component; import net.minecraft.server.packs.metadata.pack.PackMetadataSection; @@ -21,76 +20,71 @@ import net.neoforged.neoforge.event.AddPackFindersEvent; import net.neoforged.neoforge.resource.EmptyPackResources; -import java.io.IOException; -import java.nio.file.Files; -import java.util.List; -import java.util.stream.Stream; - @Mod(DefaultResources.MOD_ID) public class DefaultResourcesNeoForge { - public DefaultResourcesNeoForge(IEventBus modbus) { - DefaultResources.initialize(); - modbus.register(this); - } + public DefaultResourcesNeoForge(IEventBus modbus) { + DefaultResources.initialize(); + modbus.register(this); + } - @SubscribeEvent - public void addPacks(AddPackFindersEvent event) { - event.addRepositorySource((packConsumer) -> { - try { - if (!Files.exists(Services.PLATFORM.getGlobalFolder())) - Files.createDirectories(Services.PLATFORM.getGlobalFolder()); - List> packs = DefaultResources.getPackResources(event.getPackType()); - var desc = Component.literal("Global Resources"); - Pack root = Pack.create( - DefaultResources.MOD_ID, - desc, - true, - new EmptyPackResources.EmptyResourcesSupplier( - new PackMetadataSection( - desc, - SharedConstants.getCurrentVersion().getPackVersion(event.getPackType()) - ), - false - ), - new Pack.Info( - desc, - PackCompatibility.COMPATIBLE, - FeatureFlagSet.of(), - List.of(), - true - ), - Pack.Position.TOP, - true, - PackSource.DEFAULT - ).withChildren(createPackStream(packs).toList()); - packConsumer.accept(root); - } catch (IOException e) { - DefaultResources.LOGGER.error("Couldn't inject resources!"); - } - }); - } + @SubscribeEvent + public void addPacks(AddPackFindersEvent event) { + event.addRepositorySource((packConsumer) -> { + try { + if (!Files.exists(Services.PLATFORM.getGlobalFolder())) + Files.createDirectories(Services.PLATFORM.getGlobalFolder()); + List> packs = DefaultResources.getPackResources(event.getPackType()); + var desc = Component.literal("Global Resources"); + Pack root = Pack.create( + DefaultResources.MOD_ID, + desc, + true, + new EmptyPackResources.EmptyResourcesSupplier( + new PackMetadataSection( + desc, + SharedConstants.getCurrentVersion().getPackVersion(event.getPackType()) + ), + false + ), + new Pack.Info( + desc, + PackCompatibility.COMPATIBLE, + FeatureFlagSet.of(), + List.of(), + true + ), + Pack.Position.TOP, + true, + PackSource.DEFAULT + ).withChildren(createPackStream(packs).toList()); + packConsumer.accept(root); + } catch (IOException e) { + DefaultResources.LOGGER.error("Couldn't inject resources!"); + } + }); + } - private static Stream createPackStream(List> packs) { - return packs.stream().map(pair -> { - var desc = Component.literal("Global Resources - "+pair.getFirst()); - Pack.Info info = new Pack.Info( - desc, - PackCompatibility.COMPATIBLE, - FeatureFlagSet.of(), - List.of(), - true - ); - return Pack.create( - DefaultResources.MOD_ID + ":" + pair.getFirst(), - desc, - true, - pair.getSecond(), - info, - Pack.Position.TOP, - true, - PackSource.DEFAULT - ); - }); - } + private static Stream createPackStream(List> packs) { + return packs.stream().map(pair -> { + var desc = Component.literal("Global Resources - "+pair.getFirst()); + Pack.Info info = new Pack.Info( + desc, + PackCompatibility.COMPATIBLE, + FeatureFlagSet.of(), + List.of(), + true + ); + return Pack.create( + DefaultResources.MOD_ID + ":" + pair.getFirst(), + desc, + true, + pair.getSecond(), + info, + Pack.Position.TOP, + true, + PackSource.DEFAULT + ); + }); + } } diff --git a/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/PlatformImpl.java b/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/PlatformImpl.java index 837eedd..d7b8e66 100644 --- a/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/PlatformImpl.java +++ b/neoforge/src/main/java/dev/lukebemish/defaultresources/impl/neoforge/PlatformImpl.java @@ -1,8 +1,3 @@ -/* - * Copyright (C) 2023-2024 Luke Bemish, and contributors - * SPDX-License-Identifier: LGPL-3.0-or-later - */ - package dev.lukebemish.defaultresources.impl.neoforge; import com.google.auto.service.AutoService; @@ -12,15 +7,6 @@ import dev.lukebemish.defaultresources.impl.ParallelExecutor; import dev.lukebemish.defaultresources.impl.Services; import dev.lukebemish.defaultresources.impl.services.Platform; -import net.minecraft.server.packs.PackResources; -import net.minecraft.server.packs.PackType; -import net.minecraft.server.packs.repository.Pack; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.fml.loading.FMLLoader; -import net.neoforged.fml.loading.FMLPaths; -import net.neoforged.neoforgespi.language.IModInfo; -import org.jspecify.annotations.NonNull; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -29,75 +15,83 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.repository.Pack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforgespi.language.IModInfo; +import org.jspecify.annotations.NonNull; @AutoService(Platform.class) public class PlatformImpl implements Platform { - public Path getGlobalFolder() { - return FMLPaths.GAMEDIR.get().resolve("globalresources"); - } + public Path getGlobalFolder() { + return FMLPaths.GAMEDIR.get().resolve("globalresources"); + } - @Override - public void extractResources() { - try { - if (!Files.exists(Services.PLATFORM.getGlobalFolder())) - Files.createDirectories(Services.PLATFORM.getGlobalFolder()); - } catch (IOException e) { - DefaultResources.LOGGER.error(e); - } - ParallelExecutor.execute(FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) - .filter(PlatformImpl::isExtractable), - mod -> DefaultResources.forMod(mod.getOwningFile().getFile()::findResource, mod.getModId())); - } + @Override + public void extractResources() { + try { + if (!Files.exists(Services.PLATFORM.getGlobalFolder())) + Files.createDirectories(Services.PLATFORM.getGlobalFolder()); + } catch (IOException e) { + DefaultResources.LOGGER.error(e); + } + ParallelExecutor.execute(FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) + .filter(PlatformImpl::isExtractable), + mod -> DefaultResources.forMod(mod.getOwningFile().getFile()::findResource, mod.getModId())); + } - @Override - public Collection> getJarProviders(PackType type) { - List> providers = new ArrayList<>(); - FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) - .filter(PlatformImpl::isExtractable) - .forEach(mod -> { - Path packPath = mod.getOwningFile().getFile().getSecureJar().getPath(String.join("/")); - providers.add(new Pair<>(mod.getModId(), new Pack.ResourcesSupplier() { - @Override - public @NonNull PackResources openPrimary(@NonNull String s) { - return new AutoMetadataPathPackResources(s, "global", packPath, type); - } + @Override + public Collection> getJarProviders(PackType type) { + List> providers = new ArrayList<>(); + FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) + .filter(PlatformImpl::isExtractable) + .forEach(mod -> { + Path packPath = mod.getOwningFile().getFile().getSecureJar().getPath(String.join("/")); + providers.add(new Pair<>(mod.getModId(), new Pack.ResourcesSupplier() { + @Override + public @NonNull PackResources openPrimary(@NonNull String s) { + return new AutoMetadataPathPackResources(s, "global", packPath, type); + } - @Override - public @NonNull PackResources openFull(@NonNull String s, Pack.@NonNull Info info) { - return new AutoMetadataPathPackResources(s, "global", packPath, type); - } - })); - }); - return providers; - } + @Override + public @NonNull PackResources openFull(@NonNull String s, Pack.@NonNull Info info) { + return new AutoMetadataPathPackResources(s, "global", packPath, type); + } + })); + }); + return providers; + } - @Override - public Path getConfigDir() { - return FMLPaths.CONFIGDIR.get(); - } + @Override + public Path getConfigDir() { + return FMLPaths.CONFIGDIR.get(); + } - @Override - public Path getResourcePackDir() { - return FMLPaths.GAMEDIR.get().resolve("resourcepacks"); - } + @Override + public Path getResourcePackDir() { + return FMLPaths.GAMEDIR.get().resolve("resourcepacks"); + } - @Override - public Map getExistingModdedPaths(String relative) { - return FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) - .filter(PlatformImpl::isExtractable) - .map(mod -> - new Pair<>(mod.getModId(), mod.getOwningFile().getFile().findResource(relative))) - .filter(it -> it.getSecond() != null && Files.exists(it.getSecond())) - .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (a, b) -> a)); - } + @Override + public Map getExistingModdedPaths(String relative) { + return FMLLoader.getLoadingModList().getModFiles().stream().flatMap(f -> f.getMods().stream()) + .filter(PlatformImpl::isExtractable) + .map(mod -> + new Pair<>(mod.getModId(), mod.getOwningFile().getFile().findResource(relative))) + .filter(it -> it.getSecond() != null && Files.exists(it.getSecond())) + .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (a, b) -> a)); + } - private static boolean isExtractable(IModInfo mod) { - return !mod.getModId().equals("forge") && !mod.getModId().equals("neoforge") && !mod.getModId().equals("minecraft"); - } + private static boolean isExtractable(IModInfo mod) { + return !mod.getModId().equals("forge") && !mod.getModId().equals("neoforge") && !mod.getModId().equals("minecraft"); + } - @Override - public boolean isClient() { - return FMLLoader.getDist() == Dist.CLIENT; - } + @Override + public boolean isClient() { + return FMLLoader.getDist() == Dist.CLIENT; + } } diff --git a/settings.gradle b/settings.gradle index 78148b3..002d6d2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -24,13 +24,12 @@ pluginManagement { url "https://maven.architectury.dev/" } - mavenCentral() gradlePluginPortal() } } plugins { - id 'dev.lukebemish.conventions.settings' version '0.1.3' + id 'dev.lukebemish.conventions' version '0.1.8' } rootProject.name = 'defaultresources'