diff --git a/.editorconfig b/.editorconfig
index e8a57bf1e..66b889a6a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,6 +1,10 @@
+root = true
+
[*.{kt,kts}]
-max_line_length=120
-ij_kotlin_imports_layout=*
+indent_size = 4
+indent_style = space
+max_line_length = 120
+ij_kotlin_imports_layout = *
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
insert_final_newline = true
diff --git a/src/main/kotlin/creator/custom/TemplateDescriptor.kt b/src/main/kotlin/creator/custom/TemplateDescriptor.kt
index 54890a8e3..5b6352cce 100644
--- a/src/main/kotlin/creator/custom/TemplateDescriptor.kt
+++ b/src/main/kotlin/creator/custom/TemplateDescriptor.kt
@@ -40,7 +40,7 @@ data class TemplateDescriptor(
companion object {
- const val FORMAT_VERSION = 1
+ const val FORMAT_VERSION = 2
}
}
diff --git a/src/main/kotlin/creator/custom/derivation/ExtractPaperApiVersionPropertyDerivation.kt b/src/main/kotlin/creator/custom/derivation/ExtractPaperApiVersionPropertyDerivation.kt
new file mode 100644
index 000000000..de2c57940
--- /dev/null
+++ b/src/main/kotlin/creator/custom/derivation/ExtractPaperApiVersionPropertyDerivation.kt
@@ -0,0 +1,60 @@
+/*
+ * Minecraft Development for IntelliJ
+ *
+ * https://mcdev.io/
+ *
+ * Copyright (C) 2025 minecraft-dev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, version 3.0 only.
+ *
+ * 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 Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.demonwav.mcdev.creator.custom.derivation
+
+import com.demonwav.mcdev.creator.custom.PropertyDerivation
+import com.demonwav.mcdev.creator.custom.TemplateValidationReporter
+import com.demonwav.mcdev.creator.custom.types.CreatorProperty
+import com.demonwav.mcdev.util.MinecraftVersions
+import com.demonwav.mcdev.util.SemanticVersion
+
+class ExtractPaperApiVersionPropertyDerivation : ExtractVersionMajorMinorPropertyDerivation() {
+
+ override fun derive(parentValues: List): Any? {
+ val from = parentValues[0] as SemanticVersion
+ if (from >= MinecraftVersions.MC1_20_5) {
+ return from
+ }
+
+ return super.derive(parentValues);
+ }
+
+ companion object : PropertyDerivationFactory {
+
+ override fun create(
+ reporter: TemplateValidationReporter,
+ parents: List?>?,
+ derivation: PropertyDerivation
+ ): PreparedDerivation? {
+ if (parents.isNullOrEmpty()) {
+ reporter.error("Expected a parent")
+ return null
+ }
+
+ if (!parents[0]!!.acceptsType(SemanticVersion::class.java)) {
+ reporter.error("First parent must produce a semantic version")
+ return null
+ }
+
+ return ExtractPaperApiVersionPropertyDerivation()
+ }
+ }
+}
diff --git a/src/main/kotlin/creator/custom/derivation/ExtractVersionMajorMinorPropertyDerivation.kt b/src/main/kotlin/creator/custom/derivation/ExtractVersionMajorMinorPropertyDerivation.kt
index 6d5c3ac04..c8ef54b87 100644
--- a/src/main/kotlin/creator/custom/derivation/ExtractVersionMajorMinorPropertyDerivation.kt
+++ b/src/main/kotlin/creator/custom/derivation/ExtractVersionMajorMinorPropertyDerivation.kt
@@ -25,7 +25,7 @@ import com.demonwav.mcdev.creator.custom.TemplateValidationReporter
import com.demonwav.mcdev.creator.custom.types.CreatorProperty
import com.demonwav.mcdev.util.SemanticVersion
-class ExtractVersionMajorMinorPropertyDerivation : PreparedDerivation {
+open class ExtractVersionMajorMinorPropertyDerivation : PreparedDerivation {
override fun derive(parentValues: List): Any? {
val from = parentValues[0] as SemanticVersion
diff --git a/src/main/kotlin/creator/custom/model/StringList.kt b/src/main/kotlin/creator/custom/model/StringList.kt
index 95ec00df2..9256b5b84 100644
--- a/src/main/kotlin/creator/custom/model/StringList.kt
+++ b/src/main/kotlin/creator/custom/model/StringList.kt
@@ -28,4 +28,7 @@ data class StringList(val values: List) : List by values {
@JvmOverloads
fun toString(separator: String, prefix: String = "", postfix: String = ""): String =
values.joinToString(separator, prefix, postfix)
+
+ fun toStringQuoted(): String =
+ values.joinToString(", ", transform = { '"' + it + '"' })
}
diff --git a/src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt b/src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt
new file mode 100644
index 000000000..191a3d208
--- /dev/null
+++ b/src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt
@@ -0,0 +1,82 @@
+/*
+ * Minecraft Development for IntelliJ
+ *
+ * https://mcdev.io/
+ *
+ * Copyright (C) 2025 minecraft-dev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, version 3.0 only.
+ *
+ * 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 Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.demonwav.mcdev.creator.custom.types
+
+import com.demonwav.mcdev.creator.custom.CreatorContext
+import com.demonwav.mcdev.creator.custom.TemplatePropertyDescriptor
+import com.demonwav.mcdev.util.MinecraftVersions
+import com.demonwav.mcdev.util.SemanticVersion
+import com.intellij.ui.dsl.builder.Panel
+import io.ktor.client.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.*
+import io.ktor.http.*
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.jsonArray
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
+
+open class PaperVersionCreatorProperty(
+ descriptor: TemplatePropertyDescriptor,
+ context: CreatorContext
+) : SemanticVersionCreatorProperty(descriptor, context) {
+
+ @OptIn(DelicateCoroutinesApi::class)
+ companion object {
+ val paperVersions: Map? = loadPaperVersions()?.associate { it to it.toString() }
+
+ fun loadPaperVersions(): List? {
+ val client = HttpClient()
+ return runBlocking {
+ val response = client.get("https://fill.papermc.io/v3/projects/paper")
+ if (response.status.isSuccess()) {
+ val element = Json.parseToJsonElement(response.bodyAsText())
+ return@runBlocking element.jsonObject["versions"]?.jsonObject?.values
+ ?.asSequence()
+ ?.flatMap { it.jsonArray }
+ ?.map { it.jsonPrimitive.content }
+ ?.mapNotNull { SemanticVersion.tryParse(it) }
+ // only release versions
+ ?.filter { ver -> ver.parts.all { it is SemanticVersion.Companion.VersionPart.ReleasePart } }
+ // nothing lower than 1.18.2 should be selectable
+ ?.filter { it >= MinecraftVersions.MC1_18_2 }
+ ?.toList()
+ ?.sortedDescending()
+ } else {
+ return@runBlocking null
+ }
+ }
+ }
+ }
+
+ override fun buildUi(panel: Panel) {
+ super.buildDropdownMenu(panel, paperVersions)
+ }
+
+ class Factory : CreatorPropertyFactory {
+ override fun create(
+ descriptor: TemplatePropertyDescriptor,
+ context: CreatorContext
+ ): CreatorProperty<*> = PaperVersionCreatorProperty(descriptor, context)
+ }
+}
diff --git a/src/main/kotlin/creator/custom/types/SemanticVersionCreatorProperty.kt b/src/main/kotlin/creator/custom/types/SemanticVersionCreatorProperty.kt
index 46dae66ef..2bf327a38 100644
--- a/src/main/kotlin/creator/custom/types/SemanticVersionCreatorProperty.kt
+++ b/src/main/kotlin/creator/custom/types/SemanticVersionCreatorProperty.kt
@@ -24,6 +24,7 @@ import com.demonwav.mcdev.creator.custom.CreatorContext
import com.demonwav.mcdev.creator.custom.PropertyDerivation
import com.demonwav.mcdev.creator.custom.TemplatePropertyDescriptor
import com.demonwav.mcdev.creator.custom.TemplateValidationReporter
+import com.demonwav.mcdev.creator.custom.derivation.ExtractPaperApiVersionPropertyDerivation
import com.demonwav.mcdev.creator.custom.derivation.ExtractVersionMajorMinorPropertyDerivation
import com.demonwav.mcdev.creator.custom.derivation.PreparedDerivation
import com.demonwav.mcdev.creator.custom.derivation.SelectPropertyDerivation
@@ -64,6 +65,11 @@ open class SemanticVersionCreatorProperty(
ExtractVersionMajorMinorPropertyDerivation.create(reporter, parents, derives)
}
+ "extractPaperApiVersion" -> {
+ val parents = collectDerivationParents(reporter)
+ ExtractPaperApiVersionPropertyDerivation.create(reporter, parents, derives)
+ }
+
null -> {
SelectPropertyDerivation.create(reporter, emptyList(), derives)
}
diff --git a/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt b/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt
index 5f5d2a5a7..df99c215e 100644
--- a/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt
+++ b/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt
@@ -38,7 +38,7 @@ abstract class SimpleCreatorProperty(
valueType: Class
) : CreatorProperty(descriptor, context, valueType) {
- private val options: Map? = makeOptionsList()
+ val options: Map? = makeOptionsList()
private fun makeOptionsList(): Map? {
val map = when (val options = descriptor.options) {
@@ -78,37 +78,41 @@ abstract class SimpleCreatorProperty(
override val graphProperty: GraphProperty by lazy { graph.property(defaultValue) }
- override fun buildUi(panel: Panel) {
- if (isDropdown) {
- if (graphProperty.get() !in options!!.keys) {
- graphProperty.set(defaultValue)
+ protected fun buildDropdownMenu(panel: Panel, options: Map?) {
+ if (graphProperty.get() !in options!!.keys) {
+ graphProperty.set(defaultValue)
+ }
+
+ panel.row(descriptor.translatedLabel) {
+ if (descriptor.forceDropdown == true) {
+ comboBox(options.keys, DropdownAutoRenderer())
+ .bindItem(graphProperty)
+ .enabled(descriptor.editable != false)
+ .also {
+ val component = it.component
+ ComboboxSpeedSearch.installOn(component)
+ val validation =
+ BuiltinValidations.isAnyOf(component::getSelectedItem, options.keys, component)
+ it.validationOnInput(validation)
+ it.validationOnApply(validation)
+ }
+ } else {
+ segmentedButton(options.keys) { text = options[it] ?: it.toString() }
+ .bind(graphProperty)
+ .enabled(descriptor.editable != false)
+ .maxButtonsCount(4)
+ .validation {
+ val message = MCDevBundle("creator.validation.invalid_option")
+ addInputRule(message) { it.selectedItem !in options.keys }
+ addApplyRule(message) { it.selectedItem !in options.keys }
+ }
}
+ }.propertyVisibility()
+ }
- panel.row(descriptor.translatedLabel) {
- if (descriptor.forceDropdown == true) {
- comboBox(options.keys, DropdownAutoRenderer())
- .bindItem(graphProperty)
- .enabled(descriptor.editable != false)
- .also {
- val component = it.component
- ComboboxSpeedSearch.installOn(component)
- val validation =
- BuiltinValidations.isAnyOf(component::getSelectedItem, options.keys, component)
- it.validationOnInput(validation)
- it.validationOnApply(validation)
- }
- } else {
- segmentedButton(options.keys) { text = options[it] ?: it.toString() }
- .bind(graphProperty)
- .enabled(descriptor.editable != false)
- .maxButtonsCount(4)
- .validation {
- val message = MCDevBundle("creator.validation.invalid_option")
- addInputRule(message) { it.selectedItem !in options.keys }
- addApplyRule(message) { it.selectedItem !in options.keys }
- }
- }
- }.propertyVisibility()
+ override fun buildUi(panel: Panel) {
+ if (isDropdown) {
+ buildDropdownMenu(panel, options)
} else {
buildSimpleUi(panel)
}
@@ -125,7 +129,7 @@ abstract class SimpleCreatorProperty(
isSelected: Boolean,
cellHasFocus: Boolean
): Component {
- val label = options!![value] ?: value.toString()
+ val label = options?.get(value) ?: value.toString()
return super.getListCellRendererComponent(list, label, index, isSelected, cellHasFocus)
}
}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 22f3b95d5..3f20251bd 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -214,6 +214,9 @@
+
Minecraft EULA.
creator.ui.warn.no_yarn_to_mc_match=Unable to match Yarn versions to Minecraft version
creator.ui.warn.no_fabricapi_to_mc_match=Unable to match API versions to Minecraft version