mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-11 19:14:11 +00:00
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:
@@ -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) } }
|
||||
@@ -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) } }
|
||||
+10
-10
@@ -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) }
|
||||
Reference in New Issue
Block a user