Added generation history

- World-local pack epochs preserve generated chunks across restart-only updates
- Kernel catalogs and source seals retain executable generation behavior across jar changes
- Crash-safe ownership, boundary, registry, semantic, and mantle records survive activation changes
- New terrain blends lower surfaces and inverted ceilings against frozen historical boundaries
- Cave, object, structure, biome, and hydrology work respects activation ownership
- Find commands merge recorded facts with eligible active predictions for biomes, regions, structures, objects, and rivers
- Bukkit, Fabric, Forge, and NeoForge route generation through retained runtime scopes
- Shutdown ordering preserves class-loader resources until world and service cleanup finishes
- Tests cover activation chains, failure recovery, retained registries, bounded lookup, and transition geometry
This commit is contained in:
Brian Neumann-Fopiano
2026-09-04 13:57:39 -04:00
parent c1bcdd0a9d
commit 30113c4133
258 changed files with 38965 additions and 1659 deletions
+133
View File
@@ -0,0 +1,133 @@
import art.arcane.iris.buildtools.GenerationKernelSeal
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
import java.nio.file.Path
Configuration kernelDependencies = configurations.create('generationKernelDependencies') {
canBeConsumed = false
canBeResolved = true
extendsFrom(configurations.implementation, configurations.slim, configurations.annotationProcessor)
}
dependencies.add(kernelDependencies.name, libs.guava)
List<String> generationSources = [
'lombok.config',
'core/agent/build.gradle',
'core/agent/src/main/java',
'core/src/main/java',
'spi/src/main/java',
'adapters/bukkit/plugin/src/main/java',
'adapters/bukkit/nms/v26_2_R1/src/main/java',
'adapters/minecraft-common/src/main/java',
'adapters/modded-common/src/main/java',
'adapters/client-common/src/main/java',
'adapters/fabric/src/main/java',
'adapters/forge/src/main/java',
'adapters/neoforge/src/main/java'
]
Map<Integer, GenerationKernelSeal.CaptureOptions> kernelScopes = [
(1): new GenerationKernelSeal.CaptureOptions(rootProject.projectDir.toPath(), 1,
'art.arcane.iris.engine.history.GenerationKernelV1', [new GenerationKernelSeal.AlgorithmVersion(1, 1)], generationSources,
['core/src/main/java/art/arcane/iris/engine/kernels'])
]
File sealDirectory = file('generation-kernels')
FileTree sealFiles = fileTree(sealDirectory) { include('abi-*.seal') }
TaskProvider<Jar> kernelAgentJar = project(':core:agent').tasks.named('jar', Jar)
Closure<Map<String, Path>> resolvedKernelDependencies = {
Map<String, Path> artifacts = new TreeMap<>()
for (ResolvedArtifact artifact : kernelDependencies.resolvedConfiguration.resolvedArtifacts) {
String group = artifact.moduleVersion.id.group
String name = artifact.moduleVersion.id.name
if (group == 'art.arcane' && name == 'spi') {
continue
}
boolean volmLib = (group == 'com.github.VolmitSoftware' && name == 'VolmLib')
|| group == 'com.github.VolmitSoftware.VolmLib'
|| (group == 'art.arcane' && name == 'shared')
String key = volmLib ? 'volmlib' : "${group}:${name}".toString()
if (artifact.classifier != null) {
key += ':' + artifact.classifier
}
if (artifacts.putIfAbsent(key, artifact.file.toPath()) != null) {
throw new GradleException("Duplicate generation dependency identity: ${key}")
}
}
if (!artifacts.containsKey('volmlib')) {
throw new GradleException('The generation seal must include the resolved VolmLib artifact.')
}
artifacts.put('iris-agent', kernelAgentJar.get().archiveFile.get().asFile.toPath())
return artifacts
}
TaskProvider<Task> verifySeals = tasks.register('verifyGenerationKernelSeals') {
group = 'verification'
description = 'Rejects generation source or dependency changes under a retained generation ABI.'
dependsOn(kernelDependencies, kernelAgentJar)
inputs.files(sealFiles, kernelDependencies, kernelAgentJar.flatMap { Jar jar -> jar.archiveFile })
doLast {
Map<String, Path> dependencies = resolvedKernelDependencies()
Map<Integer, GenerationKernelSeal.SourceManifest> manifests = new TreeMap<>()
for (Map.Entry<Integer, GenerationKernelSeal.CaptureOptions> entry : kernelScopes.entrySet()) {
File seal = new File(sealDirectory, "abi-${entry.key}.seal")
GenerationKernelSeal.SourceManifest recorded = GenerationKernelSeal.read(seal.toPath())
GenerationKernelSeal.CaptureOptions scope = entry.value
if (recorded.abi() != scope.abi() || recorded.factoryClass() != scope.factoryClass() || recorded.algorithms() != scope.algorithms()
|| recorded.roots() != scope.roots() || recorded.exclusions() != scope.exclusions()) {
throw new GradleException("Generation ABI ${entry.key} source scope no longer matches its seal.")
}
GenerationKernelSeal.verify(rootProject.projectDir.toPath(), seal.toPath(), dependencies)
manifests.put(entry.key, recorded)
}
GenerationKernelSeal.verifyCatalog(new File(sealDirectory, 'catalog.tsv').toPath(), manifests)
Set<String> expectedNames = kernelScopes.keySet().collect { Integer abi -> "abi-${abi}.seal".toString() }.toSet()
if (sealFiles.files.collect { File seal -> seal.name }.toSet() != expectedNames) {
throw new GradleException('Every retained generation seal must have an explicit build scope.')
}
}
}
tasks.register('captureGenerationKernelSeal') {
group = 'build setup'
description = 'Creates new compatibility metadata for an explicitly selected, previously unsealed generation ABI.'
dependsOn(kernelDependencies, kernelAgentJar)
doLast {
String requested = providers.gradleProperty('generationKernelAbi').orNull
if (requested == null || !(requested ==~ '[1-9][0-9]*')) {
throw new GradleException('Select a new generation ABI with -PgenerationKernelAbi=<number>.')
}
int abi = Integer.parseInt(requested)
GenerationKernelSeal.CaptureOptions scope = kernelScopes.get(abi)
if (scope == null) {
throw new GradleException("Generation ABI ${abi} has no explicit source scope.")
}
GenerationKernelSeal.SourceManifest captured = GenerationKernelSeal.capture(scope, resolvedKernelDependencies())
GenerationKernelSeal.writeNew(new File(sealDirectory, "abi-${abi}.seal").toPath(), captured)
logger.lifecycle("Sealed generation ABI ${abi}: ${GenerationKernelSeal.fingerprint(captured)}")
}
}
TaskProvider<Sync> sealResources = tasks.register('generateGenerationKernelSealResources', Sync) {
from(sealFiles)
from(new File(sealDirectory, 'catalog.tsv'))
into(layout.buildDirectory.dir('generated/kernel-seals/META-INF/iris/generation-kernels'))
}
tasks.named('processResources').configure {
dependsOn(sealResources)
from(layout.buildDirectory.dir('generated/kernel-seals'))
}
tasks.named('test', Test).configure {
dependsOn(sealResources)
classpath = files(layout.buildDirectory.dir('generated/kernel-seals')) + classpath
}
tasks.named('check').configure { dependsOn(verifySeals) }
tasks.withType(Jar).configureEach { dependsOn(verifySeals) }
rootProject.tasks.named('check').configure { dependsOn(verifySeals) }
rootProject.tasks.withType(Jar).configureEach { dependsOn(verifySeals) }
rootProject.tasks.matching { Task task -> task.name in ['fabricJar', 'forgeJar', 'neoforgeJar'] }
.configureEach { dependsOn(verifySeals) }
rootProject.subprojects.findAll { Project candidate -> candidate.path.startsWith(':adapters:bukkit:') }
.each { Project adapter -> adapter.tasks.withType(Jar).configureEach { dependsOn(verifySeals) } }
@@ -0,0 +1,51 @@
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.initialization.IncludedBuild
import org.gradle.api.tasks.TaskReference
import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar
IncludedBuild coreBuild = gradle.includedBuilds.find { IncludedBuild candidate ->
candidate.projectDir.canonicalFile == file('../..').canonicalFile
}
if (coreBuild == null) {
throw new GradleException('The modded artifact requires the included Iris core build and its generation seal.')
}
TaskReference kernelSealVerification = coreBuild.task(':core:verifyGenerationKernelSeals')
TaskProvider<JavaExec> resolvedSealVerification = tasks.register('verifyResolvedGenerationKernelDependencies', JavaExec) {
group = 'verification'
description = 'Checks the actual bundled generation library contents against the retained kernel seal.'
dependsOn(kernelSealVerification)
classpath = files('../../buildSrc/build/libs/buildSrc.jar')
mainClass.set('art.arcane.iris.buildtools.GenerationKernelSeal')
doFirst {
List<String> arguments = ['verify-dependencies', file('../../core/generation-kernels/abi-1.seal').absolutePath]
for (ResolvedArtifact artifact : configurations.bundle.resolvedConfiguration.resolvedArtifacts) {
String group = artifact.moduleVersion.id.group
String name = artifact.moduleVersion.id.name
if (group == 'art.arcane' && name in ['core', 'spi']) {
continue
}
if ("${group}:${name}".toString() in [
'org.jetbrains:annotations', 'org.jspecify:jspecify',
'com.google.errorprone:error_prone_annotations', 'com.google.j2objc:j2objc-annotations',
'org.checkerframework:checker-qual']) {
continue
}
boolean volmLib = (group == 'com.github.VolmitSoftware' && name == 'VolmLib')
|| group == 'com.github.VolmitSoftware.VolmLib'
|| (group == 'art.arcane' && name == 'shared')
String key = volmLib ? 'volmlib' : "${group}:${name}".toString()
if (artifact.classifier != null) {
key += ':' + artifact.classifier
}
arguments.add(key)
arguments.add(artifact.file.absolutePath)
}
setArgs(arguments)
}
}
gradle.projectsEvaluated {
resolvedSealVerification.configure { dependsOn(configurations.bundle) }
}
tasks.withType(Jar).configureEach { dependsOn(resolvedSealVerification) }
tasks.named('check').configure { dependsOn(resolvedSealVerification) }