library-resource-pack is a Kotlin/JVM library for composing a validated Minecraft resource pack from independently owned contributions. It publishes three modules:
resource-pack-apicontains the contribution contract and policy types. A feature module such aslibrary-guishould depend only on this module.resource-pack-buildervalidates contributions, composes a pack, and writes directory or ZIP artifacts. A product/application owns this dependency and the final pack definition.resource-pack-testkitprovides assertions for contribution validity, vanilla claims, and deterministic ZIP output in consumer tests.
The supported baseline is Java 25 and Kotlin 2.2.20.
Artifacts are published to GitHub Packages under gg.grounds:
repositories {
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/groundsgg/library-resource-pack")
credentials {
username = providers.gradleProperty("github.user").orNull ?: System.getenv("GITHUB_ACTOR")
password = providers.gradleProperty("github.token").orNull ?: System.getenv("GITHUB_TOKEN")
}
}
}
dependencies {
implementation("gg.grounds:resource-pack-api:0.1.0")
implementation("gg.grounds:resource-pack-builder:0.1.0") // product composer only
testImplementation("gg.grounds:resource-pack-testkit:0.1.0")
}Contributing modules return PackContribution; they do not own PackDefinition, ResourcePackComposer, or writer types. This is the intended boundary for library-gui and similar libraries: the imports below are API imports only.
import gg.grounds.resourcepack.api.ContributionId
import gg.grounds.resourcepack.api.PackContribution
import gg.grounds.resourcepack.api.PackEntry
import gg.grounds.resourcepack.api.PackFormatRange
import java.nio.file.Path
fun guiContribution(assets: Path): PackContribution = PackContribution(
id = ContributionId.of("grounds:gui"),
supportedFormats = PackFormatRange(65, 65),
entries = listOf(
PackEntry.file(
"assets/grounds/textures/gui/menu.png",
assets.resolve("textures/gui/menu.png"),
),
),
)The product composes all contributions and owns the pack-level definition, validation, and output paths. compose validates and throws PackBuildException when the result is invalid; call validate first if the product needs to inspect the full PackValidationResult.
import gg.grounds.resourcepack.api.PackDefinition
import gg.grounds.resourcepack.api.PackFormat
import gg.grounds.resourcepack.builder.DirectoryPackWriter
import gg.grounds.resourcepack.builder.ResourcePackComposer
import gg.grounds.resourcepack.builder.ZipPackWriter
import java.nio.file.Path
fun buildPlatformPack(gui: gg.grounds.resourcepack.api.PackContribution, output: Path) {
val composer = ResourcePackComposer()
val definition = PackDefinition(
description = "Grounds platform",
format = PackFormat(65),
)
val contributions = listOf(gui)
val validation = composer.validate(definition, contributions)
validation.throwIfInvalid()
val pack = composer.compose(definition, contributions)
DirectoryPackWriter().write(pack, output.resolve("inspection"))
val artifact = ZipPackWriter().write(pack, output.resolve("platform.zip"))
println("ZIP: ${artifact.path}")
println("SHA-1: ${artifact.sha1}")
println("SHA-256: ${artifact.sha256}")
}DirectoryPackWriter writes a readable inspection directory. ZipPackWriter writes a deterministic ZIP: entry order and ZIP timestamps are stable for identical input. Its PackArtifact reports the resulting path, byte size, SHA-1, and SHA-256. SHA-1 is supplied for legacy ecosystem compatibility; use SHA-256 when you need a modern integrity identifier.
There is no JSON merging and no last-writer-wins behavior. Each resource path may have exactly one contribution entry. Paths under assets/minecraft/ are vanilla paths: with VanillaPathPolicy.ALLOW_CLAIMED, every such entry needs an exclusive exact VanillaPathClaim, and every claim must correspond to exactly that contribution's entry. The default policy, FORBID, rejects vanilla paths entirely. Validation also reports duplicate contribution IDs and paths, unsupported pack formats, missing or multiply provided rendering capabilities, reserved root paths, and configured size limits.
Use resource-pack-testkit from consumer tests to prove a contribution is valid, that its vanilla claims match its entries, or that a complete pack produces identical ZIP bytes and hashes regardless of contribution ordering:
import gg.grounds.resourcepack.testkit.assertValidContribution
import gg.grounds.resourcepack.testkit.assertVanillaClaimsMatch
assertValidContribution(gui)
assertVanillaClaimsMatch(gui)This library does not discover assets, load JSON, merge JSON, resolve resource inheritance, choose product-level pack metadata, or publish packs. It also does not permit path conflicts to be resolved by contribution ordering. The product supplies files and policy, then decides where and how to distribute the finished artifact.