Preserved terrain across updates

- Saved chunks retain their natural geometry and generation ownership
- Future chunks blend against frozen terrain boundaries
- Build revisions capture generation source and dependencies automatically
- Native terrain queries use contained transition geometry and final height caches
- Historical searches retain recorded pack identities and placement facts
- World creation and Studio updates preserve native lifecycle ordering
- Hydrology containment and scoped content workers retain generation context
- Pregeneration validates saved completion before trusting cached progress
This commit is contained in:
Brian Neumann-Fopiano
2026-09-05 11:57:01 -04:00
parent 20ad49b9d2
commit b1e1fbc15e
214 changed files with 11985 additions and 4082 deletions
+91
View File
@@ -0,0 +1,91 @@
import art.arcane.iris.buildtools.GenerationBuildRevision
import art.arcane.iris.buildtools.GenerationRevisionScope
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)
GenerationBuildRevision.CaptureOptions revisionScope = GenerationRevisionScope.current(rootProject.projectDir.toPath())
File catalogFile = file('generation-kernels/catalog.tsv')
TaskProvider<Jar> kernelAgentJar = project(':core:agent').tasks.named('jar', Jar)
File generatedResources = layout.buildDirectory.dir('generated/generation-revision').get().asFile
File generatedCatalog = new File(generatedResources, 'META-INF/iris/generation-kernels/catalog.tsv')
File generatedRevision = new File(generatedResources, 'META-INF/iris/generation-kernels/abi-1.revision')
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 revision must include the resolved VolmLib artifact.')
}
artifacts.put('iris-agent', kernelAgentJar.get().archiveFile.get().asFile.toPath())
return artifacts
}
TaskProvider<Task> revisionResources = tasks.register('generateGenerationBuildRevision') {
group = 'build'
description = 'Captures generation sources and resolved dependencies as build revision provenance.'
dependsOn(kernelDependencies, kernelAgentJar, ":adapters:bukkit:nms:v26_2_R1:convert")
inputs.files(revisionScope.roots().collect { String source -> rootProject.file(source) })
inputs.property('revisionScope', revisionScope.toString())
inputs.files(catalogFile, kernelDependencies, kernelAgentJar.flatMap { Jar jar -> jar.archiveFile })
outputs.files(generatedRevision, generatedCatalog)
doLast {
GenerationBuildRevision.SourceManifest captured = GenerationBuildRevision.capture(revisionScope, resolvedKernelDependencies())
GenerationBuildRevision.verifyCatalog(catalogFile.toPath(), [(revisionScope.abi()): captured])
GenerationBuildRevision.write(generatedRevision.toPath(), captured)
generatedCatalog.text = catalogFile.getText('UTF-8')
}
}
TaskProvider<Task> verifyRevision = tasks.register('verifyGenerationBuildRevision') {
group = 'verification'
description = 'Verifies that the packaged revision describes the inputs of this build.'
dependsOn(revisionResources)
doLast {
GenerationBuildRevision.verifySnapshot(rootProject.projectDir.toPath(), generatedRevision.toPath(), resolvedKernelDependencies())
GenerationBuildRevision.verifyCatalog(generatedCatalog.toPath(), [(revisionScope.abi()): GenerationBuildRevision.read(generatedRevision.toPath())])
}
}
tasks.named('processResources').configure {
dependsOn(revisionResources)
from(generatedResources)
}
tasks.named('test', Test).configure {
dependsOn(revisionResources)
classpath = files(generatedResources) + classpath
}
tasks.named('check').configure { dependsOn(verifyRevision) }
tasks.withType(Jar).configureEach { dependsOn(verifyRevision) }
rootProject.tasks.named('check').configure { dependsOn(verifyRevision) }
rootProject.tasks.withType(Jar).configureEach { dependsOn(verifyRevision) }
rootProject.tasks.matching { Task task -> task.name in ['fabricJar', 'forgeJar', 'neoforgeJar'] }
.configureEach { dependsOn(verifyRevision) }
rootProject.subprojects.findAll { Project candidate -> candidate.path.startsWith(':adapters:bukkit:') }
.each { Project adapter -> adapter.tasks.withType(Jar).configureEach { dependsOn(verifyRevision) } }
-133
View File
@@ -1,133 +0,0 @@
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) } }
@@ -8,17 +8,17 @@ 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.')
throw new GradleException('The modded artifact requires the included Iris core build and its generation build revision.')
}
TaskReference kernelSealVerification = coreBuild.task(':core:verifyGenerationKernelSeals')
TaskProvider<JavaExec> resolvedSealVerification = tasks.register('verifyResolvedGenerationKernelDependencies', JavaExec) {
TaskReference buildRevisionVerification = coreBuild.task(':core:verifyGenerationBuildRevision')
TaskProvider<JavaExec> resolvedRevisionVerification = tasks.register('verifyResolvedGenerationKernelDependencies', JavaExec) {
group = 'verification'
description = 'Checks the actual bundled generation library contents against the retained kernel seal.'
dependsOn(kernelSealVerification)
description = 'Checks the actual bundled generation library contents against the current build revision.'
dependsOn(buildRevisionVerification)
classpath = files('../../buildSrc/build/libs/buildSrc.jar')
mainClass.set('art.arcane.iris.buildtools.GenerationKernelSeal')
mainClass.set('art.arcane.iris.buildtools.GenerationBuildRevision')
doFirst {
List<String> arguments = ['verify-dependencies', file('../../core/generation-kernels/abi-1.seal').absolutePath]
List<String> arguments = ['verify-dependencies', file('../../core/build/generated/generation-revision/META-INF/iris/generation-kernels/abi-1.revision').absolutePath]
for (ResolvedArtifact artifact : configurations.bundle.resolvedConfiguration.resolvedArtifacts) {
String group = artifact.moduleVersion.id.group
String name = artifact.moduleVersion.id.name
@@ -45,7 +45,7 @@ TaskProvider<JavaExec> resolvedSealVerification = tasks.register('verifyResolved
}
}
gradle.projectsEvaluated {
resolvedSealVerification.configure { dependsOn(configurations.bundle) }
resolvedRevisionVerification.configure { dependsOn(configurations.bundle) }
}
tasks.withType(Jar).configureEach { dependsOn(resolvedSealVerification) }
tasks.named('check').configure { dependsOn(resolvedSealVerification) }
tasks.withType(Jar).configureEach { dependsOn(resolvedRevisionVerification) }
tasks.named('check').configure { dependsOn(resolvedRevisionVerification) }