Modded pack metadata

- Modded jars ship pack.mcmeta for client resources and mod data
- Modded jars bundle jlibdeflate and its native libraries
- Artifact check requires pack.mcmeta and the jlibdeflate entries
- Artifact check rejects client language resources without pack.mcmeta
- Test loads the pack metadata against the current Minecraft formats
This commit is contained in:
Brian Neumann-Fopiano
2026-09-29 00:29:26 -04:00
parent c20296d106
commit 34684da611
8 changed files with 90 additions and 0 deletions
+1
View File
@@ -201,6 +201,7 @@ dependencies {
libs.asm, libs.asm,
libs.lru, libs.lru,
libs.caffeine, libs.caffeine,
'com.fulcrumgenomics:jlibdeflate:0.2.0',
libs.dom4j, libs.dom4j,
libs.jaxen libs.jaxen
] ]
+1
View File
@@ -200,6 +200,7 @@ dependencies {
libs.asm, libs.asm,
libs.lru, libs.lru,
libs.caffeine, libs.caffeine,
'com.fulcrumgenomics:jlibdeflate:0.2.0',
libs.dom4j, libs.dom4j,
libs.jaxen libs.jaxen
] ]
@@ -0,0 +1,7 @@
{
"pack": {
"description": "Iris client resources and mod data",
"min_format": [88, 0],
"max_format": [107, 1]
}
}
@@ -0,0 +1,45 @@
package art.arcane.iris.modded;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import net.minecraft.SharedConstants;
import net.minecraft.server.Bootstrap;
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.metadata.pack.PackMetadataSection;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class ModdedPackMetadataTest {
@BeforeClass
public static void bootstrapMinecraftRegistries() {
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
}
@Test
public void metadataLoadsClientResourcesAndServerDataForCurrentMinecraft() throws IOException {
try (InputStream resource = ModdedPackMetadataTest.class.getResourceAsStream("/pack.mcmeta")) {
assertNotNull(resource);
try (InputStreamReader reader = new InputStreamReader(resource, StandardCharsets.UTF_8)) {
JsonObject metadata = JsonParser.parseReader(reader).getAsJsonObject();
for (PackType type : PackType.values()) {
PackMetadataSection section = PackMetadataSection.forPackType(type).codec()
.parse(JsonOps.INSTANCE, metadata.get("pack")).getOrThrow();
assertEquals("Iris client resources and mod data", section.description().getString());
assertTrue(type.toString(), section.supportedFormats().isValueInRange(
SharedConstants.getCurrentVersion().packVersion(type)));
}
}
}
}
}
+1
View File
@@ -173,6 +173,7 @@ dependencies {
libs.asm, libs.asm,
libs.lru, libs.lru,
libs.caffeine, libs.caffeine,
'com.fulcrumgenomics:jlibdeflate:0.2.0',
libs.dom4j, libs.dom4j,
libs.jaxen libs.jaxen
] ]
+8
View File
@@ -576,6 +576,14 @@ tasks.named('check').configure {
} }
List<String> commonModdedArtifactEntries = [ List<String> commonModdedArtifactEntries = [
'pack.mcmeta',
'com/fulcrumgenomics/jlibdeflate/LibdeflateDecompressor.class',
'com/fulcrumgenomics/jlibdeflate/LibdeflateException.class',
'native/linux-aarch64/libjlibdeflate.so',
'native/linux-x86_64/libjlibdeflate.so',
'native/osx-aarch64/libjlibdeflate.dylib',
'native/osx-x86_64/libjlibdeflate.dylib',
'native/windows-x86_64/jlibdeflate.dll',
'META-INF/iris/generation-kernels/catalog.tsv', 'META-INF/iris/generation-kernels/catalog.tsv',
'META-INF/iris/generation-kernels/abi-1.revision', 'META-INF/iris/generation-kernels/abi-1.revision',
'META-INF/services/art.arcane.iris.localization.IrisMessageContributor', 'META-INF/services/art.arcane.iris.localization.IrisMessageContributor',
@@ -85,6 +85,11 @@ public final class ModdedArtifactVerifier {
throw new GradleException(artifact.getName() + " is missing " + requiredEntry); throw new GradleException(artifact.getName() + " is missing " + requiredEntry);
} }
} }
if (jar.getJarEntry("assets/irisworldgen/lang/en_us.json") != null
&& jar.getJarEntry("pack.mcmeta") == null) {
throw new GradleException(artifact.getName()
+ " ships Iris client language resources without pack.mcmeta");
}
Set<String> bundledRuntimeEntries = new LinkedHashSet<>(); Set<String> bundledRuntimeEntries = new LinkedHashSet<>();
Set<String> privateReferenceClasses = new LinkedHashSet<>(); Set<String> privateReferenceClasses = new LinkedHashSet<>();
@@ -44,6 +44,28 @@ public class ModdedArtifactVerifierTest {
ModdedArtifactVerifier.verify(artifact, REQUIRED_ENTRIES); ModdedArtifactVerifier.verify(artifact, REQUIRED_ENTRIES);
} }
@Test
public void rejectsClientLanguagesWithoutPackMetadata() throws Exception {
Map<String, byte[]> entries = validEntries();
entries.put("assets/irisworldgen/lang/en_us.json", "{}".getBytes(StandardCharsets.UTF_8));
File artifact = createArtifact(entries);
GradleException failure = assertThrows(GradleException.class,
() -> ModdedArtifactVerifier.verify(artifact, REQUIRED_ENTRIES));
assertTrue(failure.getMessage().contains("client language resources without pack.mcmeta"));
}
@Test
public void acceptsClientLanguagesWithPackMetadata() throws Exception {
Map<String, byte[]> entries = validEntries();
entries.put("assets/irisworldgen/lang/en_us.json", "{}".getBytes(StandardCharsets.UTF_8));
entries.put("pack.mcmeta", ("{\"pack\":{\"description\":\"Iris\","
+ "\"min_format\":[88,0],\"max_format\":[107,1]}}")
.getBytes(StandardCharsets.UTF_8));
ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES);
}
@Test @Test
public void rejectsRelocatedRuntimeReference() throws Exception { public void rejectsRelocatedRuntimeReference() throws Exception {
Map<String, byte[]> entries = validEntries(); Map<String, byte[]> entries = validEntries();