import art.arcane.volmit.packaging.PackedJar
import art.arcane.volmit.packaging.PackagingMode
import art.arcane.volmit.packaging.NativeDevelopmentTargets
import io.papermc.paperweight.userdev.PaperweightUser
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
import io.papermc.paperweight.userdev.PaperweightUserExtension
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.api.file.CopySpec
import org.gradle.api.file.DeleteSpec
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.FileTree
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.jvm.tasks.Jar
import org.gradle.jvm.toolchain.JavaLanguageVersion
import javax.inject.Inject
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
buildscript {
repositories {
mavenCentral()
maven { url = uri('https://jitpack.io') }
}
dependencies {
String volmLibRevision = providers.gradleProperty('volmLibCoordinate').get().tokenize(':').last()
classpath("com.github.VolmitSoftware.VolmLib:packaging:${volmLibRevision}")
}
}
plugins {
id 'java'
id 'java-library'
}
apply plugin: 'art.arcane.volmit-packaging'
apply from: file('gradle/runtime-relocations.gradle')
interface IrisFileOperations {
@Inject
FileSystemOperations getFileSystemOperations()
}
IrisFileOperations irisFileOperations = objects.newInstance(IrisFileOperations)
group = 'art.arcane'
version = providers.gradleProperty('irisVersion').getOrElse('4.1.2-26.2')
project(':core') {
group = 'art.arcane'
version = rootProject.version
}
String minecraftVersion = providers.gradleProperty('minecraftVersion').getOrElse('26.3')
// The Bukkit jar retains 26.1.2 and 26.2 alongside 26.3; loader jars are 26.3-only.
String bukkitMinecraftRange = providers.gradleProperty('bukkitMinecraftRange').getOrElse('26.1.2-26.3')
String fabricLoaderVersion = providers.gradleProperty('fabricLoaderVersion').getOrElse('0.19.5')
String forgeVersion = providers.gradleProperty('forgeVersion').getOrElse('26.3-66.0.8')
String neoForgeVersion = providers.gradleProperty('neoForgeVersion').getOrElse('26.3.0.33-beta')
String volmLibCoordinate = providers.gradleProperty('volmLibCoordinate')
.orElse('com.github.VolmitSoftware:VolmLib:master-SNAPSHOT')
.get()
String useLocalVolmLib = providers.gradleProperty('useLocalVolmLib').getOrElse('true')
String localVolmLibDirectory = providers.gradleProperty('localVolmLibDirectory').getOrNull()
boolean useMavenLocal = providers.gradleProperty('useMavenLocal')
.orElse(useLocalVolmLib.equalsIgnoreCase('true') ? 'false' : 'true')
.map { String value -> value.equalsIgnoreCase('true') }
.get()
Closure loaderDisplayVersion = { String loaderVersion ->
String coordinatePrefix = "${minecraftVersion}-"
if (loaderVersion.startsWith(coordinatePrefix)) {
return loaderVersion.substring(coordinatePrefix.length())
}
return loaderVersion
}
Closure irisArtifactName = { String platform, String targetVersion ->
return "Iris v${project.version} [${platform}] ${targetVersion}.jar"
}
String bukkitArtifactName = irisArtifactName('CraftBukkit', bukkitMinecraftRange)
String fabricArtifactName = irisArtifactName('Fabric', "${minecraftVersion}+${loaderDisplayVersion(fabricLoaderVersion)}")
String forgeArtifactName = irisArtifactName('Forge', "${minecraftVersion}+${loaderDisplayVersion(forgeVersion)}")
String neoForgeArtifactName = irisArtifactName('NeoForge', "${minecraftVersion}+${loaderDisplayVersion(neoForgeVersion)}")
Map runtimeDownloadRelocations = (Map) ext.runtimeDownloadRelocations
List runtimeDownloadedPrefixes = (List) ext.runtimeDownloadedPrefixes
File pluginOutDirectory = layout.projectDirectory.dir('../PluginOuts').asFile
File legacyBukkitJar = layout.buildDirectory.file("libs/Iris-${project.version}.jar").get().asFile
File bukkitArtifact = layout.buildDirectory.file("libs/${bukkitArtifactName}").get().asFile
File consumerBukkitArtifact = layout.buildDirectory.file("consumer/${bukkitArtifactName}").get().asFile
File fabricArtifact = layout.projectDirectory.file("adapters/fabric/build/libs/${fabricArtifactName}").asFile
File forgeArtifact = layout.projectDirectory.file("adapters/forge/build/libs/${forgeArtifactName}").asFile
File neoForgeArtifact = layout.projectDirectory.file("adapters/neoforge/build/libs/${neoForgeArtifactName}").asFile
File consumerDirectory = layout.buildDirectory.dir('consumer').get().asFile
FileTree staleConsumerBukkitJars = fileTree(consumerDirectory) {
include('Iris v* [CraftBukkit] *.jar')
}
Map staleOutJars = [
CraftBukkit: 'Iris v* [CraftBukkit] *.jar',
Fabric : 'Iris v* [Fabric] *.jar',
Forge : 'Iris v* [Forge] *.jar',
NeoForge : 'Iris v* [NeoForge] *.jar'
].collectEntries { String platform, String pattern ->
[(platform): fileTree(pluginOutDirectory) { include(pattern) }]
}
apply plugin: ApiGenerator
// Where `buildAll` drops the per-platform jars for a local test server. Use the approved sibling
// Multiplexor workspace when it exists, with a repo-local fallback for fresh clones.
File multiplexorConsumerLocation = new File(rootDir, '../../[Minecraft Server]/consumers').canonicalFile
String defaultConsumerLocation = multiplexorConsumerLocation.isDirectory()
? multiplexorConsumerLocation.absolutePath
: layout.buildDirectory.dir('consumers').get().asFile.absolutePath
String consumerLocation = providers.gradleProperty('location')
.getOrElse(defaultConsumerLocation)
String bukkitConsumerPath = "${consumerLocation}/plugin-consumers/dropins/plugins"
String fabricConsumerPath = "${consumerLocation}/fabric-mod-consumers/dropins/mods"
String forgeConsumerPath = "${consumerLocation}/forge-mod-consumers/dropins/mods"
String neoForgeConsumerPath = "${consumerLocation}/neoforge-mod-consumers/dropins/mods"
List nmsBindings = ['v26_2_R1', 'v26_3_R1']
ext.nativeDevelopmentAdapters = nmsBindings
nmsBindings.each { String key ->
project(":adapters:bukkit:nms:${key}") {
apply plugin: JavaPlugin
apply plugin: PaperweightUser
NativeDevelopmentTargets.Target nativeTarget = NativeDevelopmentTargets.require(key)
dependencies.extensions.getByType(PaperweightUserDependenciesExtension)
.paperDevBundle(nativeTarget.paperBundle())
JavaPluginExtension javaExtension = extensions.getByType(JavaPluginExtension)
javaExtension.toolchain.languageVersion.set(JavaLanguageVersion.of(nativeTarget.javaVersion()))
JavaToolchainService nativeToolchains = extensions.getByType(JavaToolchainService)
extensions.configure(PaperweightUserExtension) { PaperweightUserExtension extension ->
extension.javaLauncher.set(nativeToolchains.launcherFor(javaExtension.toolchain))
}
dependencies {
implementation("com.github.VolmitSoftware.VolmLib:native-${key}:${volmLibCoordinate.tokenize(':').last()}") {
transitive = false
}
compileOnly(project(':core'))
compileOnly(volmLibCoordinate) {
transitive = false
}
compileOnly(rootProject.libs.annotations)
compileOnly(rootProject.libs.byteBuddy.core)
testImplementation('junit:junit:4.13.2')
testImplementation('org.mockito:mockito-core:5.23.0')
if (key == 'v26_3_R1') {
testImplementation(project(':probe'))
}
testImplementation(project(':core'))
testImplementation(testFixtures(project(':core')))
testImplementation("com.github.VolmitSoftware.VolmLib:native-common:${volmLibCoordinate.tokenize(':').last()}") {
transitive = false
}
testCompileOnly(volmLibCoordinate) {
transitive = false
}
testRuntimeOnly(project(':core'))
testRuntimeOnly(rootProject.libs.caffeine)
}
}
}
def included = configurations.create('included')
def nativeRuntime = configurations.create('nativeRuntime')
def publishedNativeRuntime = configurations.create('publishedNativeRuntime') {
canBeConsumed = false
transitive = false
resolutionStrategy.useGlobalDependencySubstitutionRules = false
}
repositories.configureEach { repository ->
if (repository.name != 'publishedNativeProviders') {
repository.content { notForConfigurations('publishedNativeRuntime') }
}
}
repositories.maven {
name = 'publishedNativeProviders'
url = uri('https://jitpack.io/')
content {
onlyForConfigurations('publishedNativeRuntime')
includeGroup('com.github.VolmitSoftware.VolmLib')
}
}
def nativeRuntimeOutput = layout.buildDirectory.dir('generated/native-runtime')
def nativeRuntimeRules = layout.buildDirectory.file('generated/native-runtime-keep.pro')
List nativeRuntimeModules = ['native-common'] + nmsBindings.collect { String adapter -> 'native-' + adapter }
dependencies {
nativeRuntimeModules.each { String module ->
add('nativeRuntime', "com.github.VolmitSoftware.VolmLib:${module}:${volmLibCoordinate.tokenize(':').last()}") {
transitive = false
}
add('publishedNativeRuntime', "com.github.VolmitSoftware.VolmLib:${module}:${volmLibCoordinate.tokenize(':').last()}")
}
}
def generateNativeRuntime = tasks.register('generateNativeRuntime') {
inputs.files(publishedNativeRuntime)
inputs.property('version', volmLibCoordinate.tokenize(':').last())
inputs.property('adapters', nmsBindings)
outputs.dir(nativeRuntimeOutput)
outputs.file(nativeRuntimeRules)
doLast {
Map resolved = new LinkedHashMap<>()
publishedNativeRuntime.incoming.artifacts.artifacts.each { artifact ->
resolved.put(artifact.id.componentIdentifier, artifact.file)
}
Map artifacts = NativeRuntimeArtifacts.publishedArtifacts(resolved,
nativeRuntimeModules, volmLibCoordinate.tokenize(':').last())
NativeRuntimeArtifacts.generate(artifacts, volmLibCoordinate.tokenize(':').last(),
nativeRuntimeOutput.get().asFile, nativeRuntimeRules.get().asFile)
}
}
def jarJar = configurations.create('jarJar')
dependencies {
add('included', project(path: ':core', configuration: 'shadow'))
add('included', project(path: ':adapters:bukkit:plugin', configuration: 'runtimeElements'))
add('jarJar', project(':core:agent'))
}
tasks.named('jar', Jar).configure {
inputs.files(included)
dependsOn(generateNativeRuntime)
from(nativeRuntimeOutput)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
includeEmptyDirs = false
from(jarJar)
from(provider { included.resolve().collect { zipTree(it) } }) {
exclude('languages/**')
exclude('com/fren_gor/**')
}
doFirst {
irisFileOperations.fileSystemOperations.delete { DeleteSpec spec -> spec.delete(legacyBukkitJar) }
}
archiveFileName.set(bukkitArtifactName)
}
tasks.register('iris', Copy) {
group = 'iris'
dependsOn('packedJar')
from({ tasks.named('packedJar').get().outputJar })
rename { String ignored -> bukkitArtifactName }
into(layout.buildDirectory.dir('consumer'))
doFirst {
irisFileOperations.fileSystemOperations.delete { DeleteSpec spec -> spec.delete(staleConsumerBukkitJars) }
}
}
tasks.register('buildSwiftSwamp') {
group = 'iris'
description = 'Builds every platform jar and drops them in the local BUILDS output directory.'
outputs.upToDateWhen { false }
dependsOn('iris', 'verifyModdedArtifacts')
File swiftSwampOut = file('C://VolmitSoftware/BUILDS')
Map swiftSwampSources = [
'Iris.jar' : consumerBukkitArtifact,
'Iris-Fabric.jar' : fabricArtifact,
'Iris-Forge.jar' : forgeArtifact,
'Iris-Neoforge.jar': neoForgeArtifact
]
doLast {
swiftSwampSources.each { String target, File source ->
irisFileOperations.fileSystemOperations.copy { CopySpec spec ->
spec.from(source)
spec.into(swiftSwampOut)
spec.rename { String ignored -> target }
}
}
println('')
println('=== Iris buildSwiftSwamp -> ' + swiftSwampOut + ' ===')
['Iris.jar', 'Iris-Fabric.jar', 'Iris-Forge.jar', 'Iris-Neoforge.jar'].each { String jar ->
File produced = new File(swiftSwampOut, jar)
println(String.format(' %-24s %8d KB', jar, (long) (produced.length() / 1024)))
}
}
}
tasks.register('buildBukkit', Copy) {
group = 'iris'
dependsOn('packedJar')
from({ tasks.named('packedJar').get().outputJar })
rename { String ignored -> bukkitArtifactName }
into(pluginOutDirectory)
File legacyOutJar = new File(pluginOutDirectory, "Iris-${project.version}+mc${minecraftVersion}.jar")
doFirst {
irisFileOperations.fileSystemOperations.delete { DeleteSpec spec ->
spec.delete(staleOutJars['CraftBukkit'], legacyOutJar)
}
}
}
// The three loader jars come out of nested standalone Gradle builds driven through Exec. The outer
// task therefore has to carry the full inventory of what those builds read: every shared source tree,
// every build script and version file they load, and the local VolmLib checkout when the composite
// resolves one. Anything missing from that list publishes a stale jar.
Closure resolveLocalVolmLibDirectory = { ->
String configured = localVolmLibDirectory != null && !localVolmLibDirectory.isBlank()
? localVolmLibDirectory
: System.getenv('VOLMLIB_DIR')
if (configured != null && !configured.isBlank()) {
File configuredDirectory = new File(configured)
if (!configuredDirectory.isAbsolute()) {
configuredDirectory = new File(rootDir, configured)
}
return configuredDirectory.isDirectory() ? configuredDirectory : null
}
File current = rootDir
while (current != null) {
File candidate = new File(current, 'VolmLib')
if (new File(candidate, 'settings.gradle').isFile() || new File(candidate, 'settings.gradle.kts').isFile()) {
return candidate
}
current = current.parentFile
}
return null
}
List