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/MavenArtifactVersionCreatorProperty.kt b/src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt index fcd9011ae..e0c59d2c0 100644 --- a/src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt +++ b/src/main/kotlin/creator/custom/types/MavenArtifactVersionCreatorProperty.kt @@ -54,7 +54,7 @@ class MavenArtifactVersionCreatorProperty( var versionFilter: (SemanticVersion) -> Boolean = { true } override val graphProperty: GraphProperty = graph.property(SemanticVersion(emptyList())) - private val versionsProperty = graph.property>(emptyList()) + private val versionsProperty = graph.property>(emptySet()) private val loadingVersionsProperty = graph.property(true) private val loadingVersionsStatusProperty = graph.property("") @@ -127,7 +127,7 @@ class MavenArtifactVersionCreatorProperty( descriptor.limit ?: 50 ) { result -> result.onSuccess { versions -> - versionsProperty.set(versions) + versionsProperty.set(versions.toSet()) loadingVersionsProperty.set(false) }.onFailure { exception -> loadingVersionsStatusProperty.set(exception.message ?: exception.javaClass.simpleName) 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..90866490d --- /dev/null +++ b/src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt @@ -0,0 +1,129 @@ +/* + * 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.creator.custom.TemplateValidationReporter +import com.demonwav.mcdev.update.PluginUtil +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ui.ComboboxSpeedSearch +import com.intellij.ui.JBColor +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.bindText +import com.intellij.util.ui.AsyncProcessIcon +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.Dispatchers +import kotlinx.coroutines.launch +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 { + private var paperVersions: List? = null + + suspend fun getPaperVersions(): List { + paperVersions?.let { return it } + + val client = HttpClient() + val response = client.get("https://fill.papermc.io/v3/projects/paper", block = { + this.header("User-Agent", "minecraft-dev/${PluginUtil.pluginVersion} (https://github.com/minecraft-dev/MinecraftDev)") + }) + if (response.status.isSuccess()) { + val element = Json.parseToJsonElement(response.bodyAsText()) + val result = 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() + + if (result != null) { + paperVersions = result + return result + } + } + + return emptyList() + } + } + + private val versionsProperty = graph.property>(emptySet()) + private val loadingVersionsProperty = graph.property(true) + private val loadingVersionsStatusProperty = graph.property("") + + override fun buildUi(panel: Panel) { + panel.row(descriptor.translatedLabel) { + val combobox = comboBox(versionsProperty.get()) + .bindItem(graphProperty) + .enabled(descriptor.editable != false) + .also { ComboboxSpeedSearch.installOn(it.component) } + + cell(AsyncProcessIcon(makeStorageKey("progress"))) + .visibleIf(loadingVersionsProperty) + label("").applyToComponent { foreground = JBColor.RED } + .bindText(loadingVersionsStatusProperty) + .visibleIf(loadingVersionsProperty) + + versionsProperty.afterChange { versions -> + combobox.component.removeAllItems() + for (version in versions) { + combobox.component.addItem(version) + } + } + }.propertyVisibility() + } + + override fun setupProperty(reporter: TemplateValidationReporter) { + super.setupProperty(reporter) + val scope = context.childScope("PaperVersionCreatorProperty") + scope.launch(Dispatchers.Default) { + val result = getPaperVersions() + versionsProperty.set(result.toSet()) + loadingVersionsProperty.set(false) + } + } + + 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..bfe405792 100644 --- a/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt +++ b/src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt @@ -125,7 +125,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 62af2b7a1..376351abe 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