Added 1.21.1 mod targets

- Build Fabric, Forge and NeoForge per target listed in gradle/mod-targets.json (1.21.1, 26.3)
- Add 1.21.1 adapter source overlays under adapters/*/src/versions/1.21.1
- Add verifyModdedMatrix and per-target Java runtime verification of loader jars
- Re-inject persistent dimensions from the levels-ready hook before the watchdog starts
- Wait for queued chunks and the final save before pregen completes
- Add the 1.21.1 data version and datapack supported_formats range
- Cascade regions whose sea or shore pool loses every biome
- Use Gson calls available on the 1.21.1 runtime
This commit is contained in:
Brian Neumann-Fopiano committed 2026-10-16 10:25:19 -04:00
1 parent 0ca33068f3
commit 62062c4a95
58 files changed
+3279 -133

No files matched your search

@@ -2,6 +2,8 @@ import org.gradle.api.GradleException;
import org.objectweb.asm.ClassReader;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@@ -39,7 +41,8 @@ public final class ModdedArtifactVerifier {
private static final List<String> PRIVATE_REFERENCE_PREFIXES = List.of(
"art/arcane/iris/shadow/jpountz",
"art/arcane/iris/shadow/oshi",
"art/arcane/iris/shadow/jna"
"art/arcane/iris/shadow/jna",
"art/arcane/iris/util/gson"
);
// ASM must always be relocated: the loaders put their own copy on the module layer and a second
// org.objectweb.asm package on the same layer is a boot failure.
@@ -66,6 +69,14 @@ public final class ModdedArtifactVerifier {
private ModdedArtifactVerifier() {
}
public static void verifyJavaRuntime(File artifact, int runtimeJava) {
try (JarInputStream archive = new JarInputStream(new FileInputStream(artifact))) {
verifyJavaRuntime(archive, runtimeJava, artifact.getName());
} catch (IOException error) {
throw new GradleException("Could not verify Java " + runtimeJava + " compatibility of " + artifact, error);
}
}
public static void verify(File artifact, List<String> requiredEntries) {
verify(artifact, requiredEntries, Set.of());
}
@@ -192,6 +203,38 @@ public final class ModdedArtifactVerifier {
}
}
private static void verifyJavaRuntime(JarInputStream archive, int runtimeJava, String location) throws IOException {
JarEntry entry;
while ((entry = archive.getNextJarEntry()) != null) {
String name = entry.getName();
if (entry.isDirectory()) {
continue;
}
if (name.startsWith("META-INF/versions/")) {
String version = name.substring("META-INF/versions/".length()).split("/", 2)[0];
if (Integer.parseInt(version) > runtimeJava) {
continue;
}
}
if (name.endsWith(".jar")) {
try (JarInputStream nested = new JarInputStream(new ByteArrayInputStream(archive.readAllBytes()))) {
verifyJavaRuntime(nested, runtimeJava, location + "!/" + name);
}
} else if (name.endsWith(".class")) {
byte[] header = archive.readNBytes(8);
if (header.length != 8 || header[0] != (byte) 0xca || header[1] != (byte) 0xfe
|| header[2] != (byte) 0xba || header[3] != (byte) 0xbe) {
throw new GradleException("Invalid class file " + location + "!/" + name);
}
int major = (header[6] & 0xff) << 8 | header[7] & 0xff;
if (major > runtimeJava + 44) {
throw new GradleException(location + "!/" + name + " requires Java " + (major - 44)
+ "; target runtime is Java " + runtimeJava);
}
}
}
}
private static void verifyNestedJarDeclarations(File artifact, JarFile jar, Set<String> shippedNestedJars)
throws IOException {
String metadata = readEntryText(jar, FABRIC_METADATA);
@@ -15,7 +15,10 @@ public final class GenerationRevisionScope {
"adapters/client-common/src/main/java",
"adapters/fabric/src/main/java",
"adapters/forge/src/main/java",
"adapters/neoforge/src/main/java"
"adapters/neoforge/src/main/java",
"adapters/forge/src/versions/1.21.1/java",
"adapters/neoforge/src/versions/1.21.1/java",
"adapters/modded-common/src/versions/1.21.1/java"
);
private static final List<String> OPERATIONAL_EXCLUSIONS = List.of(
"core/src/main/java/art/arcane/iris/generation/runtime/EngineDiagnostics.java",
@@ -11,6 +11,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -38,6 +39,24 @@ public class ModdedArtifactVerifierTest {
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void rejectsClassesNewerThanSelectedRuntimeIncludingNestedJars() throws Exception {
ClassWriter writer = new ClassWriter(0);
writer.visit(Opcodes.V25, Opcodes.ACC_PUBLIC, "example/NewRuntime", null, "java/lang/Object", null);
writer.visitEnd();
Map<String, byte[]> entries = new LinkedHashMap<>();
entries.put("example/NewRuntime.class", writer.toByteArray());
File artifact = createArtifact(entries);
GradleException failure = assertThrows(GradleException.class,
() -> ModdedArtifactVerifier.verifyJavaRuntime(artifact, 21));
assertTrue(failure.getMessage().contains("requires Java 25"));
ModdedArtifactVerifier.verifyJavaRuntime(artifact, 25);
File nested = createArtifact(Map.of("META-INF/jars/library.jar", Files.readAllBytes(artifact.toPath())));
GradleException nestedFailure = assertThrows(GradleException.class,
() -> ModdedArtifactVerifier.verifyJavaRuntime(nested, 21));
assertTrue(nestedFailure.getMessage().contains("library.jar!/example/NewRuntime.class"));
}
@Test
public void acceptsMinecraftRuntimeReferences() throws Exception {
Map<String, byte[]> entries = validEntries();
@@ -166,6 +185,16 @@ public class ModdedArtifactVerifierTest {
assertTrue(failure.getMessage().contains("Iris-private runtime references"));
}
@Test
public void rejectsBukkitRelocatedGsonReferences() throws Exception {
Map<String, byte[]> entries = validEntries();
entries.put("art/arcane/iris/Test.class", "art/arcane/iris/util/gson/Gson"
.getBytes(StandardCharsets.ISO_8859_1));
GradleException failure = assertThrows(GradleException.class,
() -> ModdedArtifactVerifier.verify(createArtifact(entries), REQUIRED_ENTRIES));
assertTrue(failure.getMessage().contains("Iris-private runtime references"));
}
@Test
public void rejectsBundledMinecraftRuntimeLibrary() throws Exception {
Map<String, byte[]> entries = validEntries();