Skip to content

Commit

Permalink
add more robust mod dependency system
Browse files Browse the repository at this point in the history
  • Loading branch information
Minecraftschurli committed Feb 23, 2024
1 parent d10c049 commit 0708157
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 65 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repositories {
}

group = "com.github.minecraftschurlimods"
version = "1.3"
version = "1.4"
base.archivesName = "HelperPlugin"

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

package com.github.minecraftschurlimods.helperplugin

import net.neoforged.gradle.util.TransformerUtils
import com.github.minecraftschurlimods.helperplugin.moddependencies.ModDependency
import com.github.minecraftschurlimods.helperplugin.moddependencies.ModDependencyContainer
import net.neoforged.gradle.common.tasks.JarJar
import net.neoforged.gradle.dsl.common.runs.run.Run
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JvmVendorSpec
Expand All @@ -35,7 +39,8 @@ open class HelperExtension @Inject constructor(private val project: Project) {
@get:Nested
val mcPublish: McPublish = project.objects.newInstance(project)


val runningInCI: Property<Boolean> = project.objects.property<Boolean>()
.convention(project.providers.environmentVariable("CI").map { it.toBoolean() })
val projectType: Property<Type> = project.objects.property<Type>()
.convention(project.localGradleProperty("project_type").map { Type.valueOf(it) }.orElse(Type.MOD))
val releaseType: Property<String> = project.objects.property<String>()
Expand All @@ -47,21 +52,25 @@ open class HelperExtension @Inject constructor(private val project: Project) {
}
}.orElse("SNAPSHOT"))
val projectGroup: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod_group"; Type.LIBRARY -> "lib_group" } }))
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod.group"; Type.LIBRARY -> "lib.group" } }))
val projectId: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod_id"; Type.LIBRARY -> "lib_name" } }))
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod.id"; Type.LIBRARY -> "lib.name" } }))
val projectVersion: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod_version"; Type.LIBRARY -> "lib_version" } }))
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod.version"; Type.LIBRARY -> "lib.version" } }))
val projectName: Property<String> = project.objects.property<String>()
.convention(projectType.flatMap { when(it) { Type.MOD -> project.localGradleProperty("mod_name"); Type.LIBRARY -> projectId } })
.convention(projectType.flatMap { when(it) { Type.MOD -> project.localGradleProperty("mod.name"); Type.LIBRARY -> projectId } })
val projectCredits: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("mod.credits"))
val projectAuthors: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("mod_authors"))
.convention(project.localGradleProperty("mod.authors"))
val projectDescription: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("mod_description"))
.convention(project.localGradleProperty("mod.description"))
val projectVendor: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("vendor"))
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod.vendor"; Type.LIBRARY -> "lib.vendor" } }))
val projectUrl: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("url").orElse(gitHub.url))
.convention(project.localGradleProperty(projectType.map { when(it) { Type.MOD -> "mod.url"; Type.LIBRARY -> "lib.url" } }).orElse(gitHub.url))
val projectLogo: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("mod.logo"))
val minecraftVersion: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty("mc_version"))
val minecraftVersionRange: Property<String> = project.objects.property<String>()
Expand All @@ -76,22 +85,23 @@ open class HelperExtension @Inject constructor(private val project: Project) {
.convention(projectGroup.zip(projectId) { group, id -> "$group:$id" }.zip(fullVersion) { selector, version -> "$selector:$version" })
val generatedResourcesDir: DirectoryProperty = project.objects.directoryProperty()
.convention(project.layout.projectDirectory.dir("src/main/generated"))
val dependencies: ListProperty<Dependency> = project.objects.listProperty<Dependency>()
.value(projectType.map(TransformerUtils.guard { if (it == Type.MOD) listOf(
Dependency(
"neoforge",
neoVersionRange.get(),
"required"
),
Dependency(
"minecraft",
minecraftVersionRange.get(),
"required"
)
) else null }))
val dependencies: ModDependencyContainer = project.objects.newInstance<ModDependencyContainer>()
val modproperties: MapProperty<String, String> = project.objects.mapProperty()

fun dependency(modId: String, versionRange: String, type: String, ordering: String = "NONE", side: String = "BOTH") = dependencies.add(Dependency(modId, versionRange, type, ordering, side))
init {
dependencies {
required("neoforge") {
versionRange.set(neoVersionRange)
ordering.set(ModDependency.Ordering.NONE)
side.set(ModDependency.Side.BOTH)
}
required("minecraft") {
versionRange.set(minecraftVersionRange)
ordering.set(ModDependency.Ordering.NONE)
side.set(ModDependency.Side.BOTH)
}
}
}

open class GitHub @Inject constructor(project: Project) {
val owner: Property<String> = project.objects.property<String>()
Expand Down Expand Up @@ -161,6 +171,21 @@ open class HelperExtension @Inject constructor(private val project: Project) {

fun neoforge() = neoforgeDependency

private lateinit var jarJar: TaskProvider<JarJar>
fun withJarJar() {
if (::jarJar.isInitialized) return
val jar = project.tasks.named<Jar>("jar") {
archiveClassifier.set("slim")
}
jarJar = project.tasks.named<JarJar>("jarJar") {
archiveClassifier.set("")
with(jar.get())
}
project.artifacts.add("archives", jarJar)
publication.artifact(jarJar)
project.jarJar.component(publication)
}

private lateinit var apiSourceSet: SourceSet
fun withApiSourceSet() {
if (::apiSourceSet.isInitialized) return
Expand All @@ -181,6 +206,11 @@ open class HelperExtension @Inject constructor(private val project: Project) {
project.tasks.sourcesJar {
from(apiSourceSet.allSource)
}
if (::jarJar.isInitialized) {
jarJar {
from(apiSourceSet.output)
}
}
val apiJar = project.tasks.register<Jar>("apiJar") {
dependsOn(apiSourceSet.classesTaskName)
archiveClassifier.set("api")
Expand Down Expand Up @@ -227,16 +257,21 @@ open class HelperExtension @Inject constructor(private val project: Project) {
systemProperties.put("forge.logging.markers", "REGISTRIES")
systemProperties.put("forge.logging.console.level", "debug")
modSources.add(project.sourceSets.main)
if (runningInCI.getOrElse(false)) {
jvmArgument("-XX:+AllowEnhancedClassRedefinition")
}
}
create("client")
create("server") {
singleInstance()
programArgument("--nogui")
}
}
}

fun withDataGenRuns() {
fun withDataGenRuns(cfg: Action<Run> = Action<Run>{}) {
project.runs.create("data") {
singleInstance()
if (::dataGenSourceSet.isInitialized) {
modSource(dataGenSourceSet)
}
Expand All @@ -247,13 +282,17 @@ open class HelperExtension @Inject constructor(private val project: Project) {
programArguments.add(generatedResourcesDir.map { it.asFile.absolutePath })
programArguments.add("--existing")
programArguments.add(project.layout.projectDirectory.dir("src/main/resources/").asFile.absolutePath)
cfg.execute(this)
}
project.sourceSets.main.configure {
resources.srcDir(generatedResourcesDir)
project.sourceSets.main {
resources {
srcDir(generatedResourcesDir)
exclude(".cache")
}
}
}

fun withGameTestRuns() {
fun withGameTestRuns(cfg: Action<Run> = Action<Run>{}) {
project.runs.configureEach {
if (name != "data") {
systemProperties.put("forge.enabledGameTestNamespaces", projectId)
Expand All @@ -262,6 +301,10 @@ open class HelperExtension @Inject constructor(private val project: Project) {
}
}
}
project.runs.create("gameTestServer")
project.runs.create("gameTestServer") {
singleInstance()
jvmArgument("-ea")
cfg.execute(this)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.minecraftschurlimods.helperplugin

import com.github.minecraftschurlimods.helperplugin.modstoml.*
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.gradle.api.JavaVersion
Expand Down Expand Up @@ -117,7 +118,7 @@ class HelperPlugin : Plugin<Project> {
withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
}
named<Javadoc>("javadoc").configure {
named<Javadoc>("javadoc") {
options.encoding = "UTF-8"
(options as CoreJavadocOptions).addStringOption("Xdoclint:all,-missing", "-public")
(options as StandardJavadocDocletOptions).tags = listOf(
Expand Down Expand Up @@ -148,43 +149,47 @@ class HelperPlugin : Plugin<Project> {
"FMLModType" to helperExtension.projectType.map { it.modType }.get(),
"LICENSE" to helperExtension.license.name.get()
)
exclude("**/*.psd")
exclude("**/*.bbmodel")
}
processResources {
val files: FileCollection = project.fileTree("dir" to destinationDir.path, "include" to "**/*.json")
val jsonFiles: FileCollection = this.outputs.files.filter { it.extension == "json" }
doLast {
files.forEach {
jsonFiles.forEach {
it.writeText(JsonOutput.toJson(JsonSlurper().parse(it)))
}
}
}
if (helperExtension.projectType.get() == HelperExtension.Type.MOD) {
val generateModsToml = register<GenerateModsTomlTask>("generateModsToml") {
val modproperties = helperExtension.modproperties.orNull
val dependencies: List<Dependency>? = helperExtension.dependencies.orNull
val mcPublish = if (helperExtension.mcPublish.curseforge.isPresent || helperExtension.mcPublish.modrinth.isPresent) {
McPublish(
modsToml.set(project.provider {
val modproperties = helperExtension.modproperties.orNull
val dependencies: List<Dependency> = helperExtension.dependencies.map { Dependency(it.modId.get(), it.versionRange.get(), it.type.get().name.lowercase(), it.ordering.orNull?.name, it.side.orNull?.name) }
val mcPublish = McPublish(
helperExtension.mcPublish.modrinth.orNull,
helperExtension.mcPublish.curseforge.orNull
)
} else null
val projectId = helperExtension.projectId.get()

modsToml.set(ModsToml(
helperExtension.loader.name.get(),
helperExtension.loader.version.get(),
helperExtension.license.name.get(),
listOf(Mod(
projectId,
helperExtension.projectVersion.get(),
helperExtension.projectName.get(),
helperExtension.projectUrl.get(),
helperExtension.projectAuthors.get(),
helperExtension.projectDescription.get()
)),
mcPublish,
if (dependencies != null) mapOf(projectId to dependencies) else null,
if (!modproperties.isNullOrEmpty()) mapOf(projectId to modproperties) else null
))
val projectId = helperExtension.projectId.get()
ModsToml(
modLoader = helperExtension.loader.name.get(),
loaderVersion = helperExtension.loader.version.get(),
license = helperExtension.license.name.get(),
issueTrackerURL = helperExtension.gitHub.issuesUrl.orNull,
mods = listOf(Mod(
modId = projectId,
version = helperExtension.projectVersion.get(),
displayName = helperExtension.projectName.get(),
displayURL = helperExtension.projectUrl.orNull,
logoFile = helperExtension.projectLogo.orNull,
credits = helperExtension.projectCredits.orNull,
authors = helperExtension.projectAuthors.orNull,
description = helperExtension.projectDescription.orNull
)),
mcPublish = if (mcPublish.modrinth != null || mcPublish.curseforge != null) mcPublish else null,
dependencies = if (dependencies.isNotEmpty()) mapOf(projectId to dependencies) else null,
modproperties = if (!modproperties.isNullOrEmpty()) mapOf(projectId to modproperties) else null
)
})
}
processResources {
from(generateModsToml) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.minecraftschurlimods.helperplugin

import net.neoforged.gradle.common.extensions.JarJarExtension
import net.neoforged.gradle.dsl.common.runs.run.Run
import net.neoforged.gradle.util.TransformerUtils
import org.gradle.api.Action
Expand Down Expand Up @@ -30,6 +31,7 @@ val Project.java: JavaPluginExtension get() = this.the<JavaPluginExtension>()
val Project.sourceSets: SourceSetContainer get() = this.the<SourceSetContainer>()
val Project.publishing: PublishingExtension get() = this.the<PublishingExtension>()
val Project.runs: NamedDomainObjectContainer<Run> get() = this.extensions.getByName("runs") as NamedDomainObjectContainer<Run>
val Project.jarJar: JarJarExtension get() = this.the<JarJarExtension>()

val SourceSetContainer.api: NamedDomainObjectProvider<SourceSet> get() = named("api")
val SourceSetContainer.main: NamedDomainObjectProvider<SourceSet> get() = named("main")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.github.minecraftschurlimods.helperplugin.moddependencies

import com.github.minecraftschurlimods.helperplugin.localGradleProperty
import org.gradle.api.Project
import org.gradle.api.provider.Property
import org.gradle.kotlin.dsl.property

class ModDependency(val name: String, project: Project) {

val modId: Property<String> = project.objects.property<String>()
.convention(name)
val version: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty(modId.map { "dependency.${it}.version" }))
val versionRange: Property<String> = project.objects.property<String>()
.convention(project.localGradleProperty(modId.map { "dependency.${it}.version.range" }))
val type: Property<Type> = project.objects.property()
val ordering: Property<Ordering> = project.objects.property()
val side: Property<Side> = project.objects.property()
val modrinthId: Property<String> = project.objects.property()
val curseforgeId: Property<String> = project.objects.property()

enum class Type {
REQUIRED, OPTIONAL, INCOMPATIBLE, DISCOURAGED
}

enum class Ordering {
BEFORE, AFTER, NONE
}

enum class Side {
CLIENT, SERVER, BOTH
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.github.minecraftschurlimods.helperplugin.moddependencies

import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import javax.inject.Inject

open class ModDependencyContainer @Inject constructor(project: Project) : NamedDomainObjectContainer<ModDependency> by project.objects.domainObjectContainer(ModDependency::class.java, { name -> ModDependency(name, project) }) {
fun optional(name: String, cfg: Action<ModDependency> = Action {}) = register(name) {
type.set(ModDependency.Type.OPTIONAL)
cfg.execute(this)
}
fun required(name: String, cfg: Action<ModDependency> = Action {}) = register(name) {
type.set(ModDependency.Type.REQUIRED)
cfg.execute(this)
}

fun jei(cfg: Action<ModDependency> = Action {}) = optional("jei", cfg)
fun jade(cfg: Action<ModDependency> = Action {}) = optional("jade", cfg)
fun theoneprobe(cfg: Action<ModDependency> = Action {}) = optional("theoneprobe") {
curseforgeId.set("the-one-probe")
modrinthId.set("the-one-probe")
cfg.execute(this)
}
fun curios(cfg: Action<ModDependency> = Action {}) = optional("curios") {
side.set(ModDependency.Side.BOTH)
cfg.execute(this)
}
fun configured(cfg: Action<ModDependency> = Action {}) = optional("configured", cfg)
fun catalogue(cfg: Action<ModDependency> = Action {}) = optional("catalogue", cfg)

operator fun invoke(cfg: Action<ModDependencyContainer>): ModDependencyContainer {
cfg.execute(this)
return this
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.github.minecraftschurlimods.helperplugin
package com.github.minecraftschurlimods.helperplugin.modstoml

import com.akuleshov7.ktoml.Toml
import kotlinx.serialization.encodeToString
Expand Down
Loading

0 comments on commit 0708157

Please sign in to comment.