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

+59 -15
View File
@@ -22,6 +22,7 @@ import org.gradle.api.file.FileCopyDetails
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.FileTree
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.attributes.Bundling
import org.gradle.jvm.toolchain.JavaLanguageVersion
import javax.inject.Inject
@@ -38,10 +39,14 @@ buildscript {
plugins {
id 'java'
id 'net.fabricmc.fabric-loom' version '1.17.14'
id 'net.fabricmc.fabric-loom' version '1.17.21' apply false
id 'net.fabricmc.fabric-loom-remap' version '1.17.21' apply false
alias(libs.plugins.shadow)
}
apply from: file('../../gradle/mod-target.gradle')
apply plugin: irisModTarget.fabricRemap ? 'net.fabricmc.fabric-loom-remap' : 'net.fabricmc.fabric-loom'
apply plugin: 'art.arcane.volmit-packaging'
interface IrisFileOperations {
@@ -58,7 +63,7 @@ Properties rootProperties = new Properties()
file('../../gradle.properties').withInputStream { InputStream stream -> rootProperties.load(stream) }
String irisVersion = providers.gradleProperty('irisVersion').getOrElse(rootProperties.getProperty('irisVersion', '4.3.3'))
String minecraftVersion = providers.gradleProperty('minecraftVersion').getOrElse(rootProperties.getProperty('minecraftVersion', '26.3'))
String fabricLoaderVersion = providers.gradleProperty('fabricLoaderVersion').getOrElse(rootProperties.getProperty('fabricLoaderVersion', '0.19.5'))
String fabricLoaderVersion = providers.gradleProperty('fabricLoaderVersion').getOrElse(irisModTarget.fabricLoader.toString())
Closure<String> irisArtifactName = { String platform, String targetVersion ->
return "Iris v${project.version} [${platform}] ${targetVersion}.jar"
}
@@ -141,7 +146,11 @@ configurations.create('jij') {
dependencies {
minecraft("com.mojang:minecraft:${minecraftVersion}")
implementation("net.fabricmc:fabric-loader:${fabricLoaderVersion}")
if (irisModTarget.fabricRemap) {
mappings(loom.officialMojangMappings())
}
String modConfiguration = irisModTarget.fabricRemap ? 'modImplementation' : 'implementation'
add(modConfiguration, "net.fabricmc:fabric-loader:${fabricLoaderVersion}")
testImplementation('junit:junit:4.13.2')
testImplementation('org.mockito:mockito-core:5.23.0')
testImplementation(testFixtures('art.arcane:core'))
@@ -168,11 +177,17 @@ dependencies {
libs.fabricApi.keyMapping,
libs.fabricApi.permission
]
if (irisModTarget.fabricModules != null) {
fabricApi = ((Map<String, String>) irisModTarget.fabricModules).collect { String module, String moduleVersion ->
"net.fabricmc.fabric-api:${module}:${moduleVersion}".toString()
}
fabricApi.add("me.lucko:fabric-permissions-api:${irisModTarget.fabricPermissions}".toString())
}
fabricApi.each { Object notation ->
add('jij', notation)
add('implementation', notation)
add(modConfiguration, notation)
}
compileOnly('org.slf4j:slf4j-api:2.0.17')
compileOnly("org.slf4j:slf4j-api:${irisModTarget.slf4j}")
compileOnly(libs.spigot) {
transitive = false
}
@@ -201,21 +216,28 @@ dependencies {
libs.jaxen
]
shared.each { Object notation ->
add('bundle', notation)
add('devBundle', notation)
['bundle', 'devBundle'].each { String configuration ->
add(configuration, notation) {
if (group == 'art.arcane' && name == 'core') {
attributes {
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL))
}
}
}
}
}
}
tasks.named('compileJava', JavaCompile).configure {
options.encoding = 'UTF-8'
options.release.set(25)
options.release.set((int) irisModTarget.java)
}
tasks.named('test').configure {
}
loom {
accessWidenerPath = art.arcane.volmit.packaging.NativeAccessRules.prepare(nativeSourceImplementation, "fabric", layout.buildDirectory.dir("native-access").get().asFile)
accessWidenerPath = art.arcane.volmit.packaging.NativeAccessRules.prepare(irisModTarget.nativeAccess.toString(), "fabric", layout.buildDirectory.dir("native-access").get().asFile)
runs {
client {
runDir(providers.gradleProperty('irisClientRunDir').getOrElse('run'))
@@ -270,6 +292,13 @@ Map<String, String> nestedFabricApiJars = [
'fabric-permission-api-v1' : 'fabric-permission-api-v1.jar'
]
if (irisModTarget.fabricModules != null) {
nestedFabricApiJars = ((Map<String, String>) irisModTarget.fabricModules).collectEntries { String module, String ignored ->
[(module): "${module}.jar".toString()]
}
nestedFabricApiJars.put('fabric-permissions-api', 'fabric-permissions-api.jar')
}
FileTree staleLoaderJars = fileTree(layout.buildDirectory.dir('libs')) {
include('Iris v* [Fabric] *.jar')
include('iris-fabric-*.jar')
@@ -288,6 +317,10 @@ tasks.named('shadowJar', ShadowJar).configure {
archiveFileName.set(irisArtifactName('Fabric', "${minecraftVersion}+${fabricLoaderVersion}"))
configurations = [project.configurations.named('bundle').get()]
mergeServiceFiles()
if ((int) irisModTarget.java == 21) {
exclude('art/arcane/volmlib/util/noise/NativeBillowLoader*.class')
exclude('art/arcane/volmlib/util/noise/BillowBatch*.class')
}
exclude('META-INF/maven/**')
exclude('META-INF/proguard/**')
exclude('META-INF/*.SF')
@@ -346,28 +379,39 @@ tasks.named('shadowJar', ShadowJar).configure {
}
}
// The thin `jar`/`remapJar` outputs carry valid fabric.mod.json metadata but bundle zero
// dependencies. Installing one is an instant NoClassDefFoundError, and they sit in build/libs right
// next to the real artifact. shadowJar is the only shippable Fabric jar.
// The thin jar omits bundled dependencies. Obfuscated targets remap the complete shadow jar.
tasks.named('jar').configure {
enabled = false
}
tasks.matching { it.name == 'remapJar' }.configureEach {
enabled = false
enabled = (boolean) irisModTarget.fabricRemap
if (irisModTarget.fabricRemap) {
dependsOn(tasks.named('shadowJar'))
inputFile.set(tasks.named('shadowJar', ShadowJar).flatMap { it.archiveFile })
archiveFileName.set(irisArtifactName('Fabric', "${minecraftVersion}+${fabricLoaderVersion}"))
addNestedDependencies.set(false)
}
}
if (irisModTarget.fabricRemap) {
tasks.named('shadowJar', ShadowJar).configure {
destinationDirectory.set(layout.buildDirectory.dir('devlibs'))
}
}
tasks.named('assemble').configure {
dependsOn(tasks.named('shadowJar'))
dependsOn(tasks.named(irisModTarget.fabricRemap ? 'remapJar' : 'shadowJar'))
}
pluginPackaging {
artifacts {
create('distribution') {
taskName = 'shadowJar'
taskName = irisModTarget.fabricRemap ? 'remapJar' : 'shadowJar'
policyName = 'Iris Fabric'
prunePrefixes = ['art/arcane/volmlib/']
keepPrefixes = ['art/arcane/volmlib/util/matter/slices/']
}
}
}
apply from: file('../../gradle/modded-version-sources.gradle')
@@ -0,0 +1,78 @@
{
"schemaVersion": 1,
"id": "irisworldgen",
"version": "${version}",
"name": "Iris",
"description": "Iris World Generation Engine (Fabric adapter - native chunk generator, explicit Iris world datapack workflow, engine lifecycle)",
"authors": [
"Arcane Arts (Volmit Software)"
],
"contributors": [
"cyberpwn",
"NextdoorPsycho",
"Vatuu"
],
"contact": {
"homepage": "https://docs.volmit.com/iris/",
"issues": "https://github.com/VolmitSoftware/Iris/issues",
"sources": "https://github.com/VolmitSoftware/Iris"
},
"license": "GPL-3.0",
"icon": "assets/irisworldgen/icon.png",
"environment": "*",
"accessWidener": "volmlib.accesswidener",
"mixins": [
"volmlib.fabric.mixins.json",
"volmlib.entity.mixins.json",
{
"config": "volmlib.client.mixins.json",
"environment": "client"
}
],
"entrypoints": {
"main": [
"art.arcane.iris.fabric.IrisFabricBootstrap"
],
"client": [
"art.arcane.iris.fabric.IrisFabricClient"
]
},
"jars": [
{
"file": "META-INF/jars/fabric-api-base.jar"
},
{
"file": "META-INF/jars/fabric-registry-sync-v0.jar"
},
{
"file": "META-INF/jars/fabric-resource-loader-v0.jar"
},
{
"file": "META-INF/jars/fabric-lifecycle-events-v1.jar"
},
{
"file": "META-INF/jars/fabric-command-api-v2.jar"
},
{
"file": "META-INF/jars/fabric-events-interaction-v0.jar"
},
{
"file": "META-INF/jars/fabric-networking-api-v1.jar"
},
{
"file": "META-INF/jars/fabric-rendering-v1.jar"
},
{
"file": "META-INF/jars/fabric-key-binding-api-v1.jar"
},
{
"file": "META-INF/jars/fabric-permissions-api.jar"
}
],
"depends": {
"fabricloader": ">=0.19.5",
"minecraft": "${minecraftVersion}",
"java": ">=21",
"fabric-permissions-api-v0": "*"
}
}
@@ -0,0 +1,102 @@
package art.arcane.volmlib.nativelib.minecraft26_2.fabric;
import art.arcane.volmlib.nativelib.minecraft26_2.terrain.NativeRegistryDefinitions;
import art.arcane.volmlib.nativelib.modded.NativeLoaderOptions;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import net.minecraft.SharedConstants;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.Bootstrap;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
import org.junit.BeforeClass;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BooleanSupplier;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class NativeFabricBiomeDefinitionTest {
private static final String BIOME_REGISTRY = "minecraft:worldgen/biome";
private static final String BIOME_KEY = "iris:biomes/fabric_modified";
private static final String SOURCE_JSON = "{\"has_precipitation\":true,\"temperature\":0.8,\"downfall\":0.4,"
+ "\"effects\":{\"fog_color\":12638463,\"water_color\":4159204,\"water_fog_color\":329011,\"sky_color\":7907327},"
+ "\"carvers\":{},\"features\":[],\"spawners\":{},\"spawn_costs\":{}}";
@BeforeClass
public static void bootstrap() {
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
}
@Test
public void generatedBiomeDefinitionExcludesFabricBiomeModifications() throws Exception {
MappedRegistry<PlacedFeature> features = new MappedRegistry<>(Registries.PLACED_FEATURE, Lifecycle.stable());
Holder.Reference<PlacedFeature> ore = features.register(
ResourceKey.create(Registries.PLACED_FEATURE, ResourceLocation.parse("iris:modded_ore")),
new PlacedFeature(Holder.direct(mock(ConfiguredFeature.class)), List.of()),
RegistrationInfo.BUILT_IN);
features.freeze();
MappedRegistry<ConfiguredWorldCarver<?>> carvers = new MappedRegistry<>(Registries.CONFIGURED_CARVER, Lifecycle.stable());
carvers.freeze();
MappedRegistry<Biome> biomes = new MappedRegistry<>(Registries.BIOME, Lifecycle.stable());
RegistryAccess access = new RegistryAccess.ImmutableRegistryAccess(List.of(biomes, features, carvers));
Biome source = Biome.DIRECT_CODEC.parse(RegistryOps.create(JsonOps.INSTANCE, access),
JsonParser.parseString(SOURCE_JSON)).getOrThrow();
NativeFabricLoader loader = new NativeFabricLoader(new NativeLoaderOptions("irisworldgen", "treefeller",
BooleanSupplier::getAsBoolean));
loader.recordOriginalBiome(source);
Holder.Reference<Biome> biome = biomes.register(
ResourceKey.create(Registries.BIOME, ResourceLocation.parse(BIOME_KEY)), source, RegistrationInfo.BUILT_IN);
biomes.freeze();
addFeatureInPlace(biome.value().getGenerationSettings(), ore);
warmInPlace(biome.value());
NativeRegistryDefinitions definitions = new NativeRegistryDefinitions(() -> access, loader::unmodifiedBiome);
assertEquals(0.1F, biome.value().getBaseTemperature(), 0.0F);
assertTrue(biome.value().getGenerationSettings().features()
.get(GenerationStep.Decoration.UNDERGROUND_ORES.ordinal()).contains(ore));
assertEquals(JsonParser.parseString(definitions.canonicalDefinition(BIOME_REGISTRY, BIOME_KEY, SOURCE_JSON).value()),
JsonParser.parseString(definitions.generatedDefinition(BIOME_REGISTRY, BIOME_KEY).value()));
}
private static void addFeatureInPlace(BiomeGenerationSettings settings, Holder<PlacedFeature> feature)
throws ReflectiveOperationException {
List<HolderSet<PlacedFeature>> steps = new ArrayList<>(settings.features());
while (steps.size() <= GenerationStep.Decoration.UNDERGROUND_ORES.ordinal()) {
steps.add(HolderSet.direct());
}
steps.set(GenerationStep.Decoration.UNDERGROUND_ORES.ordinal(), HolderSet.direct(feature));
Field features = BiomeGenerationSettings.class.getDeclaredField("features");
features.setAccessible(true);
features.set(settings, List.copyOf(steps));
}
private static void warmInPlace(Biome biome) throws ReflectiveOperationException {
Constructor<Biome.ClimateSettings> climate = Biome.ClimateSettings.class.getDeclaredConstructor(
boolean.class, float.class, Biome.TemperatureModifier.class, float.class);
climate.setAccessible(true);
Field climateSettings = Biome.class.getDeclaredField("climateSettings");
climateSettings.setAccessible(true);
climateSettings.set(biome, climate.newInstance(true, 0.1F, Biome.TemperatureModifier.NONE, 0.4F));
}
}