User: joseph burton Date: 26 Feb 23 10:48 Revision: 83949ccec33f5900f9afa7453acfd67b84f16454 Summary: Minecraft new project wizard (#1933) * Forge creator almost working * Store authors and website for next time the user uses the creator * Don't allow for dialog submission before a latent step is finished * Fabric mod creator * Add modid.mixins.json to Forge project creator * Start with Architectury creator * Fix long-running tasks that need to run after one another * Apply website in Forge creator * Set the correct gradle version in the Forge project creator * Architectury should be finished but it's not working, not sure why * Add support for custom build systems via extension points * Sponge project creator, first maven implementation * Remove unsupported platforms from the readme * Add missing platforms to readme * Replace some silly code with less silly code * Add Spigot and Paper creators * Add Velocity creator * Add BungeeCord and Waterfall creator * Delete unused code * ktlint format * Apply the correct JDK version depending on the platform and version * Fix license years after merge * Improvements and fixes to JDK selector UI * Fix architectury template * Fix issues with Sponge creator * Fix IncorrectOperationException in AbstractLatentStep * Add option to create a git repo (which also creates a gitignore) * UI improvements * Add a message encouraging users to report outdated templates * Add note to project wizard outdated form warning not to request new platforms * Paper before Spigot * Remove dependency on TemplateMakerFabric * Reorganize creators into multiple files and repackage some things * Improve documentation * Improve ergonomics for build system properties, main class name, repository, issue tracker * Limit Sponge API version to 8 and above in dropdown box * Prevent class name from messing up when the project name contains dots TeamCity URL: https://ci.mcdev.io/viewModification.html?tab=vcsModificationFiles&modId=8314&personal=false Index: .github/ISSUE_TEMPLATE/bug_report.yaml =================================================================== --- .github/ISSUE_TEMPLATE/bug_report.yaml (revision 4041be848225d64c78051c358da2fe10a425b575) +++ .github/ISSUE_TEMPLATE/bug_report.yaml (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -36,7 +36,6 @@ - Architectury - Minecraft Forge - Fabric - - Lite Loader - Velocity - Mixins - BungeeCord Index: .github/ISSUE_TEMPLATE/project_wizard_outdated.yaml =================================================================== --- .github/ISSUE_TEMPLATE/project_wizard_outdated.yaml (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ .github/ISSUE_TEMPLATE/project_wizard_outdated.yaml (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,47 @@ +name: Project Wizard Outdated +description: The Minecraft project wizard is outdated +labels: ["status: unverified", "type: bug"] +body: + - type: markdown + attributes: + value: PLEASE DO NOT USE THIS TEMPLATE FOR FEATURE REQUESTS, INCLUDING REQUESTS FOR NEW PLATFORMS. + - type: input + id: plugin-version + attributes: + label: Minecraft Development for IntelliJ plugin version + validations: + required: true + - type: input + id: intellij-version + attributes: + label: IntelliJ version + validations: + required: true + - type: input + id: operating-system + attributes: + label: Operating System + validations: + required: true + - type: dropdown + id: target-platform + attributes: + label: Target platform + multiple: true + options: + - Spigot + - Paper + - Sponge + - Architectury + - Minecraft Forge + - Fabric + - Velocity + - BungeeCord + - Waterfall + validations: + required: true + - type: textarea + id: description + attributes: + label: Additional description + description: If the issue isn't obvious, please be as detailed as you can. \ No newline at end of file Index: build.gradle.kts =================================================================== --- build.gradle.kts (revision 4041be848225d64c78051c358da2fe10a425b575) +++ build.gradle.kts (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -81,7 +81,6 @@ implementation(files(gradleToolingExtensionJar)) - implementation(libs.templateMakerFabric) implementation(libs.mappingIo) implementation(libs.bundles.asm) @@ -156,10 +155,11 @@ "maven", "gradle", "Groovy", + "Kotlin", "org.toml.lang:$pluginTomlVersion", "ByteCodeViewer", - // needed dependencies for unit tests "properties", + // needed dependencies for unit tests "junit" ) Index: gradle/libs.versions.toml =================================================================== --- gradle/libs.versions.toml (revision 4041be848225d64c78051c358da2fe10a425b575) +++ gradle/libs.versions.toml (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -10,7 +10,6 @@ coroutines-jdk8 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8", version.ref = "coroutines" } coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "coroutines" } -templateMakerFabric = "com.extracraftx.minecraft:TemplateMakerFabric:0.4.1" mappingIo = "net.fabricmc:mapping-io:0.2.1" # GrammarKit Index: readme.md =================================================================== --- readme.md (revision 4041be848225d64c78051c358da2fe10a425b575) +++ readme.md (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -133,12 +133,12 @@ Supported Platforms ------------------- -- [![Bukkit Icon](src/main/resources/assets/icons/platform/Bukkit.png?raw=true) **Bukkit**](https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse) ([![Spigot Icon](src/main/resources/assets/icons/platform/Spigot.png?raw=true) Spigot](https://spigotmc.org/) and [![Paper Icon](src/main/resources/assets/icons/platform/Paper.png?raw=true) Paper](https://papermc.io/)) +- [![Spigot Icon](src/main/resources/assets/icons/platform/Spigot.png?raw=true) **Spigot**](https://spigotmc.org/) ([![Paper Icon](src/main/resources/assets/icons/platform/Paper.png?raw=true) Paper](https://papermc.io/)) - [![Sponge Icon](src/main/resources/assets/icons/platform/Sponge_dark.png?raw=true) **Sponge**](https://www.spongepowered.org/) - [![Architectury Icon](src/main/resources/assets/icons/platform/Architectury.png?raw=true) **Architectury**](https://github.com/architectury/architectury-api) - [![Forge Icon](src/main/resources/assets/icons/platform/Forge.png?raw=true) **Minecraft Forge**](https://forums.minecraftforge.net/) - [![Fabric Icon](src/main/resources/assets/icons/platform/Fabric.png?raw=true) **Fabric**](https://fabricmc.net) -- [![LiteLoader Icon](src/main/resources/assets/icons/platform/LiteLoader.png?raw=true) **LiteLoader**](http://www.liteloader.com/) -- [![MCP Icon](src/main/resources/assets/icons/platform/MCP.png?raw=true) **MCP**](http://www.modcoderpack.com/) - [![Mixins Icon](src/main/resources/assets/icons/platform/Mixins_dark.png?raw=true) **Mixins**](https://github.com/SpongePowered/Mixin) - [![BungeeCord Icon](src/main/resources/assets/icons/platform/BungeeCord.png?raw=true) **BungeeCord**](https://www.spigotmc.org/wiki/bungeecord/) ([![Waterfall Icon](src/main/resources/assets/icons/platform/Waterfall.png?raw=true) Waterfall](https://github.com/PaperMC/Waterfall)) +- [![Velocity Icon](src/main/resources/assets/icons/platform/Velocity.png?raw=true) **Velocity**](https://velocitypowered.com/) +- [![Adventure Icon](src/main/resources/assets/icons/platform/Adventure.png?raw=true) **Adventure**](https://kyori.net/) Index: src/main/kotlin/creator/BuildSystemWizardStep.form =================================================================== --- src/main/kotlin/creator/BuildSystemWizardStep.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/BuildSystemWizardStep.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,95 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/creator/BuildSystemWizardStep.kt =================================================================== --- src/main/kotlin/creator/BuildSystemWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/BuildSystemWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,113 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.exception.EmptyFieldSetupException -import com.demonwav.mcdev.creator.exception.OtherSetupException -import com.demonwav.mcdev.creator.exception.SetupException -import com.intellij.ide.util.projectWizard.ModuleWizardStep -import com.intellij.openapi.ui.MessageType -import com.intellij.openapi.ui.popup.Balloon -import com.intellij.openapi.ui.popup.JBPopupFactory -import com.intellij.ui.awt.RelativePoint -import javax.swing.JComboBox -import javax.swing.JPanel -import javax.swing.JTextField - -class BuildSystemWizardStep(private val creator: MinecraftProjectCreator) : ModuleWizardStep() { - - private lateinit var groupIdField: JTextField - private lateinit var artifactIdField: JTextField - private lateinit var versionField: JTextField - private lateinit var panel: JPanel - private lateinit var buildSystemBox: JComboBox - - override fun getComponent() = panel - - override fun updateStep() { - val previousBuildSystem = buildSystemBox.selectedItem - buildSystemBox.removeAllItems() - buildSystemBox.isEnabled = true - - val creatorConfig = creator.config ?: return - - val types = BuildSystemType.values().filter { type -> - type.creatorType.isInstance(creatorConfig) - } - - for (type in types) { - buildSystemBox.addItem(type) - } - - if (buildSystemBox.itemCount == 1) { - buildSystemBox.isEnabled = false - return - } - - if (previousBuildSystem != null) { - buildSystemBox.selectedItem = previousBuildSystem - return - } - - buildSystemBox.selectedIndex = 0 - - creatorConfig.preferredBuildSystem?.let { buildSystemBox.selectedItem = it } - } - - override fun updateDataModel() { - creator.buildSystem = createBuildSystem() - } - - private fun createBuildSystem(): BuildSystem { - val type = buildSystemBox.selectedItem as? BuildSystemType - ?: throw IllegalStateException("Selected item is not a ${BuildSystemType::class.java.name}") - - return type.create(groupIdField.text, artifactIdField.text, versionField.text) - } - - override fun validate(): Boolean { - try { - if (groupIdField.text.isEmpty()) { - throw EmptyFieldSetupException(groupIdField) - } - - if (artifactIdField.text.isEmpty()) { - throw EmptyFieldSetupException(artifactIdField) - } - - if (versionField.text.isBlank()) { - throw EmptyFieldSetupException(versionField) - } - - if (!groupIdField.text.matches(NO_WHITESPACE)) { - throw OtherSetupException("The GroupId field cannot contain any whitespace", groupIdField) - } - - if (!artifactIdField.text.matches(NO_WHITESPACE)) { - throw OtherSetupException("The ArtifactId field cannot contain any whitespace", artifactIdField) - } - } catch (e: SetupException) { - JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(e.error, MessageType.ERROR, null) - .setFadeoutTime(2000) - .createBalloon() - .show(RelativePoint.getSouthWestOf(e.j), Balloon.Position.below) - return false - } - - return true - } - - companion object { - val NO_WHITESPACE = Regex("\\S+") - } -} Index: src/main/kotlin/creator/CreatorStep.kt =================================================================== --- src/main/kotlin/creator/CreatorStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/CreatorStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,132 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.DirectorySet -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.virtualFileOrError -import com.intellij.codeInsight.actions.ReformatCodeProcessor -import com.intellij.ide.util.EditorHelper -import com.intellij.openapi.application.runReadAction -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.psi.SmartPsiElementPointer -import com.intellij.psi.util.createSmartPointer -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.nio.file.StandardOpenOption.CREATE -import java.nio.file.StandardOpenOption.TRUNCATE_EXISTING -import java.nio.file.StandardOpenOption.WRITE - -/** - * Represents a discrete kind of configuration code for a project. Project creators use these to spread implementation - * out between platforms without coupling them, and allow overriding for more complex options for specific build systems - * without coupling the build system and the platform. - */ -interface CreatorStep { - - fun runStep(indicator: ProgressIndicator) - - companion object { - private val scheduledReformats: MutableList> = mutableListOf() - fun runAllReformats() { - runWriteTask { - for (scheduledReformat in scheduledReformats) { - val file = scheduledReformat.element ?: continue - PsiDocumentManager.getInstance(file.project).getDocument(file)?.setReadOnly(false) - ReformatCodeProcessor(file, false).run() - } - } - scheduledReformats.clear() - } - - fun writeTextToFile( - project: Project, - targetDir: Path, - fileName: String, - text: String - ): VirtualFile { - if (Files.notExists(targetDir)) { - Files.createDirectories(targetDir) - } - val file = targetDir.resolve(fileName) - Files.write(file, text.toByteArray(Charsets.UTF_8), WRITE, CREATE, TRUNCATE_EXISTING) - val vFile = file.virtualFileOrError - - // Reformat the code to match their code style - runReadAction { - if (project.isDisposed) { - return@runReadAction - } - PsiManager.getInstance(project).findFile(vFile)?.let { - scheduledReformats += it.createSmartPointer() - } - } - - return vFile - } - - fun writeText(file: Path, text: String, psiManager: PsiManager? = null) { - Files.write(file, text.toByteArray(Charsets.UTF_8), CREATE, TRUNCATE_EXISTING, WRITE) - psiManager?.findFile(file.virtualFileOrError)?.let { - PsiDocumentManager.getInstance(psiManager.project).getDocument(it)?.setReadOnly(false) - ReformatCodeProcessor(it, false).run() - } - } - } -} - -class BasicJavaClassStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val className: String, - private val classText: String, - private val openInEditor: Boolean = true, - private val rootProvider: (BuildSystem) -> Path = { it.dirsOrError.sourceDirectory } -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - runWriteTask { - indicator.text = "Writing class: $className" - val files = className.split(".") - val className = files.last() - - val sourceDir = getMainClassDirectory(rootProvider(buildSystem), files) - - val classFile = CreatorStep.writeTextToFile(project, sourceDir, "$className.java", classText) - - if (openInEditor) { - // Set the editor focus on the created class - PsiManager.getInstance(project).findFile(classFile)?.let { classPsi -> - EditorHelper.openInEditor(classPsi) - } - } - } - } - - private fun getMainClassDirectory(dir: Path, files: List): Path { - val directories = files.slice(0 until files.lastIndex).toTypedArray() - val outputDir = Paths.get(dir.toAbsolutePath().toString(), *directories) - Files.createDirectories(outputDir) - return outputDir - } -} - -class CreateDirectoriesStep(private val buildSystem: BuildSystem, private val directory: Path) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - buildSystem.directories = DirectorySet.create(directory) - } -} Index: src/main/kotlin/creator/JdkComboBoxWithPreference.kt =================================================================== --- src/main/kotlin/creator/JdkComboBoxWithPreference.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/JdkComboBoxWithPreference.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,172 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator + +import com.intellij.ide.util.PropertiesComponent +import com.intellij.ide.util.projectWizard.ProjectWizardUtil +import com.intellij.ide.util.projectWizard.WizardContext +import com.intellij.ide.wizard.AbstractWizard +import com.intellij.openapi.Disposable +import com.intellij.openapi.observable.properties.ObservableMutableProperty +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JavaSdk +import com.intellij.openapi.projectRoots.JavaSdkVersion +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.roots.ui.configuration.JdkComboBox +import com.intellij.openapi.roots.ui.configuration.SdkListItem +import com.intellij.openapi.roots.ui.configuration.SdkListModel +import com.intellij.openapi.roots.ui.configuration.SdkListModelBuilder.ModelListener +import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel +import com.intellij.openapi.roots.ui.configuration.validateSdk +import com.intellij.openapi.util.Condition +import com.intellij.openapi.util.Disposer +import com.intellij.ui.dsl.builder.Cell +import com.intellij.ui.dsl.builder.Row +import javax.swing.JComponent + +internal class JdkPreferenceData( + var jdk: JavaSdkVersion, + val sdkPathByJdk: MutableMap, + var ignoreChangesForPreference: Boolean, +) + +class JdkComboBoxWithPreference internal constructor( + project: Project?, + private val model: ProjectSdksModel, + sdkFilter: Condition?, + private val preferenceData: JdkPreferenceData, +) : JdkComboBox(project, model, null, sdkFilter, null, null, null) { + private var suggestions = emptyList() + + init { + myModel.addModelListener(object : ModelListener { + override fun syncModel(model: SdkListModel) { + suggestions = model.items.filterIsInstance() + } + }) + } + + internal fun loadSuggestions(windowChild: JComponent, disposable: Disposable) { + myModel.detectItems(windowChild, disposable) + } + + internal fun getTargetJdk(project: Project?): Sdk? { + selectedJdk?.let { return it } + + return if (project != null && isProjectJdkSelected) { + ProjectRootManager.getInstance(project).projectSdk + } else { + null + } + } + + fun setPreferredJdk(version: JavaSdkVersion) { + if (version == preferenceData.jdk) { + return + } + + preferenceData.ignoreChangesForPreference = true + try { + preferenceData.jdk = version + reloadModel() + + for (jdkVersion in version.ordinal until JavaSdkVersion.values().size) { + val jdk = JavaSdkVersion.values()[jdkVersion] + + val preferredSdkPath = preferenceData.sdkPathByJdk[jdk] + if (preferredSdkPath != null) { + val sdk = model.sdks.firstOrNull { it.homePath == preferredSdkPath } + ?: suggestions.firstOrNull { it.homePath == preferredSdkPath } + if (sdk != null) { + setSelectedItem(sdk) + return + } + } + + val sdk = model.sdks.firstOrNull { JavaSdk.getInstance().getVersion(it) == jdk } + if (sdk != null) { + setSelectedItem(sdk) + return + } + } + } finally { + preferenceData.ignoreChangesForPreference = false + } + } +} + +fun Row.jdkComboBoxWithPreference( + context: WizardContext, + sdkProperty: ObservableMutableProperty, + sdkPropertyId: String +): Cell { + val sdkModel = ProjectSdksModel() + + Disposer.register(context.disposable) { + sdkModel.disposeUIResources() + } + + val project = context.project + sdkModel.reset(project) + + val preferenceData = JdkPreferenceData(JavaSdkVersion.JDK_17, mutableMapOf(), false) + + val sdkFilter = Condition { + val version = it.versionString?.let(JavaSdkVersion::fromVersionString) + ?: return@Condition true + version >= preferenceData.jdk + } + val comboBox = JdkComboBoxWithPreference(context.project, sdkModel, sdkFilter, preferenceData) + + val selectedJdkProperty = "jdk.selected.$sdkPropertyId" + val preferenceDataProperty = "jdk.preference.$sdkPropertyId" + val stateComponent = project?.let(PropertiesComponent::getInstance) ?: PropertiesComponent.getInstance() + + stateComponent.getList(preferenceDataProperty)?.let { preferenceDataStrs -> + for (preferenceDataStr in preferenceDataStrs) { + val parts = preferenceDataStr.split('=', limit = 2) + val jdk = parts.firstOrNull()?.toIntOrNull()?.let { JavaSdkVersion.values()[it] } ?: continue + val sdk = parts.last() + preferenceData.sdkPathByJdk[jdk] = sdk + } + } + + comboBox.addActionListener { + val sdk = comboBox.getTargetJdk(project) + if (sdk != null) { + stateComponent.setValue(selectedJdkProperty, sdk.name) + + if (!preferenceData.ignoreChangesForPreference) { + val jdk = JavaSdk.getInstance().getVersion(sdk) + val homePath = sdk.homePath + if (jdk != null && homePath != null) { + preferenceData.sdkPathByJdk[jdk] = homePath + stateComponent.setList( + preferenceDataProperty, + preferenceData.sdkPathByJdk.map { (jdk, sdk) -> "${jdk.ordinal}=$sdk" } + ) + } + } + } + sdkProperty.set(sdk) + } + + val lastUsedSdk = stateComponent.getValue(selectedJdkProperty) + ProjectWizardUtil.preselectJdkForNewModule(project, lastUsedSdk, comboBox) { true } + + val windowChild = context.getUserData(AbstractWizard.KEY)!!.contentPanel + comboBox.loadSuggestions(windowChild, context.disposable) + + return cell(comboBox) + .validationOnApply { validateSdk(sdkProperty, sdkModel) } + .onApply { context.projectJdk = sdkProperty.get() } +} Index: src/main/kotlin/creator/LicenseStep.kt =================================================================== --- src/main/kotlin/creator/LicenseStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/LicenseStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,41 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.platform.CommonTemplate -import com.demonwav.mcdev.util.License -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption - -class LicenseStep( - private val project: Project, - private val rootDirectory: Path, - private val license: License, - private val author: String -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - val licenseFile = rootDirectory.resolve("LICENSE") - - val fileText = CommonTemplate.applyLicenseTemplate(project, license, author) - - Files.write( - licenseFile, - fileText.toByteArray(Charsets.UTF_8), - StandardOpenOption.CREATE, - StandardOpenOption.WRITE, - StandardOpenOption.TRUNCATE_EXISTING - ) - } -} Index: src/main/kotlin/creator/MinecraftModuleBuilder.kt =================================================================== --- src/main/kotlin/creator/MinecraftModuleBuilder.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/MinecraftModuleBuilder.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -11,118 +11,43 @@ package com.demonwav.mcdev.creator import com.demonwav.mcdev.asset.PlatformAssets +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.platformtype.PlatformTypeStep +import com.demonwav.mcdev.creator.step.TemplateOutdatedStep import com.demonwav.mcdev.platform.MinecraftModuleType -import com.demonwav.mcdev.platform.architectury.creator.ArchitecturyProjectSettingsWizard -import com.demonwav.mcdev.platform.bukkit.creator.BukkitProjectSettingsWizard -import com.demonwav.mcdev.platform.bungeecord.creator.BungeeCordProjectSettingsWizard -import com.demonwav.mcdev.platform.fabric.creator.FabricProjectSettingsWizard -import com.demonwav.mcdev.platform.forge.creator.ForgeProjectSettingsWizard -import com.demonwav.mcdev.platform.liteloader.creator.LiteLoaderProjectSettingsWizard -import com.demonwav.mcdev.platform.sponge.creator.SpongeProjectSettingsWizard -import com.demonwav.mcdev.platform.velocity.creator.VelocityProjectSettingsWizard -import com.intellij.ide.util.projectWizard.JavaModuleBuilder -import com.intellij.ide.util.projectWizard.ModuleWizardStep +import com.intellij.ide.projectWizard.ProjectSettingsStep import com.intellij.ide.util.projectWizard.WizardContext -import com.intellij.openapi.Disposable -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.module.ModuleType -import com.intellij.openapi.project.DumbAwareRunnable -import com.intellij.openapi.project.DumbService +import com.intellij.ide.wizard.AbstractNewProjectWizardBuilder +import com.intellij.ide.wizard.GitNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardBaseStep +import com.intellij.ide.wizard.RootNewProjectWizardStep import com.intellij.openapi.roots.ModifiableRootModel -import com.intellij.openapi.roots.ui.configuration.ModulesProvider -import com.intellij.openapi.startup.StartupManager -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.registry.Registry -import com.intellij.openapi.vfs.LocalFileSystem -import com.intellij.openapi.vfs.VirtualFile -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -class MinecraftModuleBuilder : JavaModuleBuilder() { +class MinecraftModuleBuilder : AbstractNewProjectWizardBuilder() { - private val creator = MinecraftProjectCreator() - override fun getPresentableName() = MinecraftModuleType.NAME override fun getNodeIcon() = PlatformAssets.MINECRAFT_ICON override fun getGroupName() = MinecraftModuleType.NAME - override fun getWeight() = BUILD_SYSTEM_WEIGHT - 1 override fun getBuilderId() = "MINECRAFT_MODULE" + override fun getDescription() = "Create a new Minecraft project" - override fun isAvailable() = true // TODO: use the new project wizard system - override fun setupRootModel(modifiableRootModel: ModifiableRootModel) { - val project = modifiableRootModel.project - val (root, vFile) = createAndGetRoot() - modifiableRootModel.addContentEntry(vFile) - if (moduleJdk != null) { modifiableRootModel.sdk = moduleJdk } else { modifiableRootModel.inheritSdk() } - - val r = DumbAwareRunnable { - creator.create(root, modifiableRootModel.module) - } + } - if (project.isDisposed) { - return - } - - if ( - ApplicationManager.getApplication().isUnitTestMode || - ApplicationManager.getApplication().isHeadlessEnvironment - ) { - r.run() - return - } - - if (!project.isInitialized) { - StartupManager.getInstance(project).registerPostStartupActivity(r) - return - } - - DumbService.getInstance(project).runWhenSmart(r) - } - - private fun createAndGetRoot(): Pair { - val temp = contentEntryPath ?: throw IllegalStateException("Failed to get content entry path") - - val pathName = FileUtil.toSystemIndependentName(temp) - - val path = Paths.get(pathName) - Files.createDirectories(path) - val vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(pathName) - ?: throw IllegalStateException("Failed to refresh and file file: $path") - - return path to vFile - } - - override fun getModuleType(): ModuleType<*> = MinecraftModuleType.instance override fun getParentGroup() = MinecraftModuleType.NAME - - override fun createWizardSteps( - wizardContext: WizardContext, - modulesProvider: ModulesProvider - ): Array { - val baseSteps = arrayOf( - BuildSystemWizardStep(creator), - BukkitProjectSettingsWizard(creator), - SpongeProjectSettingsWizard(creator), - ForgeProjectSettingsWizard(creator), - FabricProjectSettingsWizard(creator), - ArchitecturyProjectSettingsWizard(creator), - LiteLoaderProjectSettingsWizard(creator), - VelocityProjectSettingsWizard(creator), - BungeeCordProjectSettingsWizard(creator) + override fun createStep(context: WizardContext) = RootNewProjectWizardStep(context).chain( + ::NewProjectWizardBaseStep, + ::GitNewProjectWizardStep, + PlatformTypeStep::create, + ::BuildSystemPropertiesStep, + ::ProjectSetupFinalizerWizardStep, + ::TemplateOutdatedStep, - ) + ) - if (Registry.`is`("mcdev.wizard.finalizer")) { - return baseSteps + ProjectSetupFinalizerWizardStep(creator, wizardContext) - } - return baseSteps - } - override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?) = - PlatformChooserWizardStep(creator) + override fun getIgnoredSteps() = listOf(ProjectSettingsStep::class.java) } Index: src/main/kotlin/creator/MinecraftModuleWizardStep.kt =================================================================== --- src/main/kotlin/creator/MinecraftModuleWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/MinecraftModuleWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,70 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.exception.SetupException -import com.demonwav.mcdev.util.toPackageName -import com.intellij.ide.util.projectWizard.ModuleWizardStep -import com.intellij.openapi.ui.MessageType -import com.intellij.openapi.ui.popup.Balloon -import com.intellij.openapi.ui.popup.JBPopupFactory -import com.intellij.ui.awt.RelativePoint -import javax.swing.JTextField -import org.apache.commons.lang.WordUtils - -abstract class MinecraftModuleWizardStep : ModuleWizardStep() { - - override fun validate(): Boolean { - try { - for (field in javaClass.declaredFields) { - val annotation = field.getAnnotation(ValidatedField::class.java) ?: continue - field.isAccessible = true - val textField = field.get(this) as? JTextField ?: continue - for (validationType in annotation.value) { - validationType.validate(textField) - } - } - } catch (e: SetupException) { - JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(e.error, MessageType.ERROR, null) - .setFadeoutTime(4000) - .createBalloon() - .show(RelativePoint.getSouthWestOf(e.j), Balloon.Position.below) - return false - } - - return true - } - - inline fun generateClassName( - buildSystem: BuildSystem, - name: String, - classNameModifier: (String) -> String = { it } - ): String { - val packageNameStart = buildSystem.groupId.toPackageName() - val packageNameEnd = buildSystem.artifactId.toPackageName() - val className = classNameModifier(name.replace(" ", "")) - return "$packageNameStart.$packageNameEnd.$className" - } - - protected fun basicUpdateStep( - creator: MinecraftProjectCreator, - pluginNameField: JTextField, - mainClassField: JTextField - ) { - val buildSystem = creator.buildSystem ?: return - - val name = WordUtils.capitalize(buildSystem.artifactId.replace('-', ' ')) - pluginNameField.text = name - - mainClassField.text = generateClassName(buildSystem, name) - } -} Index: src/main/kotlin/creator/MinecraftProjectCreator.kt =================================================================== --- src/main/kotlin/creator/MinecraftProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/MinecraftProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,146 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.exception.ProjectCreatorException -import com.demonwav.mcdev.util.invokeAndWait -import com.demonwav.mcdev.util.invokeLater -import com.demonwav.mcdev.util.virtualFileOrError -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.intellij.openapi.vfs.VfsUtil -import java.nio.file.Path - -class MinecraftProjectCreator { - - var buildSystem: BuildSystem? = null - - var config: ProjectConfig? = null - - fun create(root: Path, module: Module) { - val build = buildSystem ?: throw IllegalStateException("buildSystem not initialized") - ProgressManager.getInstance().run(CreateTask(root, module, build)) - } - - class WorkLogStep(val config: Any) { - private val steps = mutableListOf>() - private var currentStep: Pair? = null - - fun printState(sb: StringBuilder) { - sb.append(" ").appendLine(if (config is String) config else config.javaClass.name) - for ((step, indent) in steps) { - printStep(sb, step, " ", indent) - } - currentStep?.let { (step, indent) -> - printStep(sb, step, " > ", indent) - } - } - - private fun printStep(sb: StringBuilder, step: Any, baseIndent: String, indent: Int) { - repeat(indent) { - sb.append(" ") - } - sb.append(baseIndent).appendLine(if (step is String) step else step.javaClass.name) - } - - fun newCurrentStep(newStep: Any, indent: Int = 0) { - finishCurrentStep() - currentStep = newStep to indent - } - - fun finishCurrentStep() { - currentStep?.let { step -> - steps += step - } - currentStep = null - } - - companion object { - var currentLog: WorkLogStep? = null - } - } - - private inner class CreateTask( - private val root: Path, - private val module: Module, - private val build: BuildSystem - ) : Task.Backgroundable(module.project, "Setting up project", false) { - override fun shouldStartInBackground() = false - - override fun run(indicator: ProgressIndicator) { - if (module.isDisposed || project.isDisposed) { - return - } - - val workLog = mutableListOf() - - try { - // Should be empty, just make sure IntelliJ knows that - invokeAndWait { - VfsUtil.markDirtyAndRefresh(false, true, true, root.virtualFileOrError) - } - - val config = this@MinecraftProjectCreator.config ?: return - - build.configure(config, root) - - val log = newLog(config, workLog) - if (!build.buildCreator(config, root, module).getSteps().run(indicator, log)) { - return - } - config.type.type.performCreationSettingSetup(module.project) - CreatorStep.runAllReformats() - - // Tell IntelliJ about everything we've done - invokeLater { - VfsUtil.markDirtyAndRefresh(false, true, true, root.virtualFileOrError) - } - } catch (e: Exception) { - if (e is ProcessCanceledException || e.cause is ProcessCanceledException) { - // Do not log PCE. The second condition is there because LaterInvocator wraps PCEs in RuntimeExceptions - return - } - val workLogText = buildString { - appendLine("Build steps completed:") - for (workLogStep in workLog) { - workLogStep.printState(this) - } - } - throw ProjectCreatorException(workLogText, e) - } finally { - WorkLogStep.currentLog = null - } - } - - private fun Iterable.run(indicator: ProgressIndicator, workLog: WorkLogStep): Boolean { - for (step in this) { - if (module.isDisposed || project.isDisposed) { - return false - } - workLog.newCurrentStep(step) - step.runStep(indicator) - } - workLog.finishCurrentStep() - return true - } - - private fun newLog(obj: Any, workLog: MutableList): WorkLogStep { - val log = WorkLogStep(obj) - WorkLogStep.currentLog = log - workLog += log - return log - } - } -} Index: src/main/kotlin/creator/PlatformChooserWizardStep.kt =================================================================== --- src/main/kotlin/creator/PlatformChooserWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/PlatformChooserWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,90 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.architectury.creator.ArchitecturyProjectConfig -import com.demonwav.mcdev.platform.bukkit.creator.BukkitProjectConfig -import com.demonwav.mcdev.platform.bungeecord.creator.BungeeCordProjectConfig -import com.demonwav.mcdev.platform.fabric.creator.FabricProjectConfig -import com.demonwav.mcdev.platform.forge.creator.ForgeProjectConfig -import com.demonwav.mcdev.platform.liteloader.creator.LiteLoaderProjectConfig -import com.demonwav.mcdev.platform.sponge.creator.SpongeProjectConfig -import com.demonwav.mcdev.platform.velocity.creator.VelocityProjectConfig -import com.intellij.ide.util.projectWizard.ModuleWizardStep -import com.intellij.ui.components.JBRadioButton -import com.intellij.util.ui.UIUtil -import javax.swing.ButtonGroup -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel - -class PlatformChooserWizardStep(private val creator: MinecraftProjectCreator) : ModuleWizardStep() { - - private lateinit var panel: JPanel - - private lateinit var projectButtons: ButtonGroup - private lateinit var spongeIcon: JLabel - private lateinit var bukkitPluginButton: JBRadioButton - private lateinit var spigotPluginButton: JBRadioButton - private lateinit var paperPluginButton: JBRadioButton - private lateinit var spongePluginButton: JBRadioButton - private lateinit var forgeModButton: JBRadioButton - private lateinit var fabricModButton: JBRadioButton - private lateinit var architecturyModButton: JBRadioButton - private lateinit var bungeeCordPluginButton: JBRadioButton - private lateinit var waterfallPluginButton: JBRadioButton - private lateinit var velocityPluginButton: JBRadioButton - private lateinit var liteLoaderModButton: JBRadioButton - - override fun getComponent(): JComponent { - if (UIUtil.isUnderDarcula()) { - spongeIcon.icon = PlatformAssets.SPONGE_ICON_2X_DARK - } else { - spongeIcon.icon = PlatformAssets.SPONGE_ICON_2X - } - - return panel - } - - override fun updateDataModel() { - creator.config = buildConfig() - } - - override fun validate(): Boolean { - updateDataModel() - val isValid = projectButtons.selection != null - if (isValid && creator.config == null) { - throw IllegalStateException( - "A project button does not have an associated config! Make sure to add your button to buildConfig()" - ) - } - return isValid - } - - private fun buildConfig(): ProjectConfig? { - return when { - bukkitPluginButton.isSelected -> BukkitProjectConfig(PlatformType.BUKKIT) - spigotPluginButton.isSelected -> BukkitProjectConfig(PlatformType.SPIGOT) - paperPluginButton.isSelected -> BukkitProjectConfig(PlatformType.PAPER) - spongePluginButton.isSelected -> SpongeProjectConfig() - forgeModButton.isSelected -> ForgeProjectConfig() - fabricModButton.isSelected -> FabricProjectConfig() - architecturyModButton.isSelected -> ArchitecturyProjectConfig() - liteLoaderModButton.isSelected -> LiteLoaderProjectConfig() - bungeeCordPluginButton.isSelected -> BungeeCordProjectConfig(PlatformType.BUNGEECORD) - waterfallPluginButton.isSelected -> BungeeCordProjectConfig(PlatformType.WATERFALL) - velocityPluginButton.isSelected -> VelocityProjectConfig() - else -> null - } - } -} Index: src/main/kotlin/creator/ProjectChooserWizardStep.form =================================================================== --- src/main/kotlin/creator/ProjectChooserWizardStep.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/ProjectChooserWizardStep.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,274 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/creator/ProjectConfig.kt =================================================================== --- src/main/kotlin/creator/ProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/ProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,59 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.platform.PlatformType -import com.intellij.util.lang.JavaVersion - -private val bracketRegex = Regex("[\\[\\]]") -private val commaRegex = Regex("\\s*,\\s*") - -abstract class ProjectConfig { - - abstract var type: PlatformType - open val preferredBuildSystem: BuildSystemType? = null - - lateinit var pluginName: String - - var website: String? = null - fun hasWebsite() = !website.isNullOrBlank() - - val authors: MutableList = mutableListOf() - fun hasAuthors() = listContainsAtLeastOne(authors) - fun setAuthors(string: String) { - authors.clear() - authors.addAll(commaSplit(string)) - } - - var description: String? = null - fun hasDescription() = description?.isNotBlank() == true - - abstract val javaVersion: JavaVersion - - protected fun commaSplit(string: String): List { - return if (!string.isBlank()) { - string.trim().replace(bracketRegex, "").split(commaRegex).toList() - } else { - emptyList() - } - } - - protected fun listContainsAtLeastOne(list: MutableList?): Boolean { - if (list.isNullOrEmpty()) { - return false - } - - list.removeIf(String::isBlank) - - return list.size != 0 - } -} Index: src/main/kotlin/creator/ProjectCreator.kt =================================================================== --- src/main/kotlin/creator/ProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/ProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,64 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.intellij.openapi.module.Module - -/** - * This class represents a specific configuration for a project to be created. Typically these configurations represent - * ([PlatformType][com.demonwav.mcdev.platform.PlatformType], [BuildSystem][com.demonwav.mcdev.creator.buildsystem.BuildSystem]) - * pairs, but this API does not apply any such restriction. Each `BuildSystem` defines how to create a [ProjectCreator] - * instance for the given configuration using the [buildCreator][com.demonwav.mcdev.creator.buildsystem.BuildSystem.buildCreator] - * method. - * - *   - * - * In the current implementation the creation of [ProjectCreator] instances are delegated to project configurations via - * implementing the [GradleCreator][com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator] and/or - * [MavenCreator][com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator] interfaces. This allows some configurations - * to produce different [ProjectCreator] instances based on their specific configuration, such as - * [ForgeProjectConfig][com.demonwav.mcdev.platform.forge.creator.ForgeProjectConfig]. - */ -interface ProjectCreator { - - /** - * Returns the [CreatorStep]s which should be executed in order to create the project configuration represented by - * this [ProjectCreator]. - */ - fun getSteps(): Iterable -} - -typealias JavaClassTextMapper = (packageName: String, className: String) -> String - -abstract class BaseProjectCreator( - private val rootModule: Module, - private val buildSystem: BuildSystem -) : ProjectCreator { - protected val project - get() = rootModule.project - - protected fun createJavaClassStep( - qualifiedClassName: String, - mapper: JavaClassTextMapper - ): BasicJavaClassStep { - val (packageName, className) = splitPackage(qualifiedClassName) - val classText = mapper(packageName, className) - return BasicJavaClassStep(project, buildSystem, qualifiedClassName, classText) - } - - protected fun splitPackage(text: String): Pair { - val index = text.lastIndexOf('.') - val className = text.substring(index + 1) - val packageName = text.substring(0, index) - return packageName to className - } -} Index: src/main/kotlin/creator/ProjectSetupFinalizerWizardStep.kt =================================================================== --- src/main/kotlin/creator/ProjectSetupFinalizerWizardStep.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/ProjectSetupFinalizerWizardStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -10,262 +10,142 @@ package com.demonwav.mcdev.creator -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.ide.util.projectWizard.ModuleWizardStep -import com.intellij.ide.util.projectWizard.WizardContext -import com.intellij.openapi.observable.properties.PropertyGraph +import com.demonwav.mcdev.util.mapFirstNotNull +import com.demonwav.mcdev.util.toTypedArray +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.stepSequence +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.observable.properties.GraphProperty +import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.roots.ui.configuration.JdkComboBox -import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel -import com.intellij.ui.SortedComboBoxModel -import com.intellij.ui.components.Label +import com.intellij.openapi.ui.validation.AFTER_GRAPH_PROPAGATION +import com.intellij.openapi.ui.validation.validationErrorFor +import com.intellij.ui.JBColor import com.intellij.ui.dsl.builder.Panel -import com.intellij.ui.dsl.builder.Row -import com.intellij.ui.dsl.builder.bindItem -import com.intellij.ui.dsl.builder.panel -import com.intellij.util.ui.UIUtil -import javax.swing.JComponent -import org.gradle.util.GradleVersion +import com.intellij.ui.dsl.builder.Placeholder +import javax.swing.JLabel +import javax.swing.JPanel -class ProjectSetupFinalizerWizardStep( - val creator: MinecraftProjectCreator, - val context: WizardContext -) : ModuleWizardStep() { - - private val finalizers: List = - listOf(JdkProjectSetupFinalizer(), GradleProjectSetupFinalizer()) - private val finalizersWithRow: MutableMap = linkedMapOf() - private val applicableFinalizers: MutableSet = linkedSetOf() - - private val panel by lazy { - panel { - row(Label("Project finalization")) {} - finalizers.forEach { finalizer -> - val row = row("${finalizer.title}") { - panel { - with(finalizer) { - buildComponent(creator, context) +class ProjectSetupFinalizerWizardStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private val finalizers: List by lazy { + val factories = ProjectSetupFinalizer.EP_NAME.extensionList + val result = mutableListOf() + if (factories.isNotEmpty()) { + var par: NewProjectWizardStep = this + for (factory in factories) { + val finalizer = factory.create(par) + result += finalizer + par = finalizer - } - } + } + } + result - } + } - finalizersWithRow[finalizer] = row + private val step by lazy { + if (finalizers.isEmpty()) { + null + } else { + stepSequence(finalizers[0], *finalizers.asSequence().drop(1).toTypedArray()) - } - } + } + } - } - override fun isStepVisible(): Boolean = true - - override fun getComponent(): JComponent = panel - - override fun updateStep() { - applicableFinalizers.clear() - for ((finalizer, row) in finalizersWithRow) { - if (finalizer.isApplicable(creator, context)) { - applicableFinalizers.add(finalizer) - finalizer.validateConfigs(creator, context) - row.visible(true) - } else { - row.visible(false) + override fun setupUI(builder: Panel) { + step?.setupUI(builder) + if (finalizers.isNotEmpty()) { + builder.row { + cell(JPanel()) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .validation( + validationErrorFor { + finalizers.mapFirstNotNull(ProjectSetupFinalizer::validate) - } + } + ) - } - } + } + } + } - override fun updateDataModel(): Unit = applicableFinalizers.forEach { it.apply(creator, context) } - - override fun validate(): Boolean = applicableFinalizers.all { it.validateChanges(creator, context) } + override fun setupProject(project: Project) { + step?.setupProject(project) -} + } +} /** - * Used to adjust project configurations before project creation begins, or simply display a summary. - * Can also block project creation if problems are found with the configurations (such as version incompatibilities.) - */ -interface ProjectSetupFinalizer { - - val title: String - - /** - * Builds the component to display in a titled row ([title]) - */ - fun Panel.buildComponent(creator: MinecraftProjectCreator, context: WizardContext) - - /** - * Whether this finalizer makes sense to appear in the given context. + * A step applied after all other steps for all Minecraft project creators. These steps can also block project creation + * by providing extra validations. - * + * - * If `false` is returned the component of this finalizer will not be shown, and [validateConfigs], - * [validateChanges] and [apply] won't be called until it returns `true`. - * - * @return `true` if this finalizer applies to the given context, `false` otherwise + * To add custom project setup finalizers, register a [Factory] to the + * `com.demonwav.minecraft-dev.projectSetupFinalizer` extension point. - */ + */ - fun isApplicable(creator: MinecraftProjectCreator, context: WizardContext): Boolean +interface ProjectSetupFinalizer : NewProjectWizardStep { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.projectSetupFinalizer") + } /** - * Validates the existing [ProjectConfig]s of this wizard. You can also initialize + * Validates the existing settings of this wizard. * - * Finalizers are expected to display errors in their own component. - * - * @return `true` if the project setup is valid, `false` otherwise. + * @return `null` if the settings are valid, or an error message if they are invalid. */ - fun validateConfigs(creator: MinecraftProjectCreator, context: WizardContext): Boolean + fun validate(): String? = null - /** - * Validates the changes made in this finalizer's component. - * - * @return `true` if the changes are valid, `false` otherwise. - */ - fun validateChanges(creator: MinecraftProjectCreator, context: WizardContext): Boolean - - /** - * Applies the changes validated in [validateChanges] to the project configuration. - */ - fun apply(creator: MinecraftProjectCreator, context: WizardContext) + interface Factory { + fun create(parent: NewProjectWizardStep): ProjectSetupFinalizer -} + } - -class JdkProjectSetupFinalizer : ProjectSetupFinalizer { - - private val errorLabel = Label("", fontColor = UIUtil.FontColor.BRIGHTER) - .apply { - icon = UIUtil.getErrorIcon() - isVisible = false - } +} - private val sdksModel = ProjectSdksModel() - private lateinit var jdkBox: JdkComboBox - private var minimumVersion: JavaSdkVersion = JavaSdkVersion.JDK_1_8 - private fun highestJDKVersionRequired(creator: MinecraftProjectCreator): JavaSdkVersion? { - val javaVersionRequired = creator.config?.javaVersion ?: return null - return JavaSdkVersion.fromJavaVersion(javaVersionRequired).also { - minimumVersion = it ?: JavaSdkVersion.JDK_1_8 - } - } +class JdkProjectSetupFinalizer( + parent: NewProjectWizardStep +) : AbstractNewProjectWizardStep(parent), ProjectSetupFinalizer { + private val sdkProperty: GraphProperty = propertyGraph.property(null) + private var sdk by sdkProperty + private var sdkComboBox: JdkComboBoxWithPreference? = null + private var preferredJdkLabel: Placeholder? = null + private var preferredJdkReason = "these settings" - private fun isUsingCompatibleJdk(creator: MinecraftProjectCreator, sdk: Sdk): Boolean { - val requiredJdkVersion = highestJDKVersionRequired(creator) ?: return false - return JavaSdk.getInstance().isOfVersionOrHigher(sdk, requiredJdkVersion) - } + var preferredJdk: JavaSdkVersion = JavaSdkVersion.JDK_17 + private set - override val title: String = "JDK" - - override fun Panel.buildComponent(creator: MinecraftProjectCreator, context: WizardContext) { - row(errorLabel) {} - jdkBox = JdkComboBox( - context.project, - sdksModel, - { it is JavaSdk }, - { JavaSdk.getInstance().isOfVersionOrHigher(it, minimumVersion) }, - null, - null, - ) - reloadJdkBox(context) - if (jdkBox.itemCount > 0) { - jdkBox.selectedIndex = 0 + fun setPreferredJdk(value: JavaSdkVersion, reason: String) { + preferredJdk = value + preferredJdkReason = reason + sdkComboBox?.setPreferredJdk(value) + updatePreferredJdkLabel() - } + } - row("JDK version:") { - cell(jdkBox) - } - } - override fun isApplicable(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - reloadJdkBox(context) - return true - } + init { + storeToData() - private fun reloadJdkBox(context: WizardContext) { - sdksModel.syncSdks() - sdksModel.reset(context.project) - jdkBox.reloadModel() + sdkProperty.afterChange { + updatePreferredJdkLabel() - } + } - - private fun updateUi(usingCompatibleJdk: Boolean) { - if (usingCompatibleJdk) { - errorLabel.text = "" - errorLabel.isVisible = false - return - } + } - errorLabel.text = "Project requires at least Java ${minimumVersion.description}" - errorLabel.isVisible = true - } - - override fun validateConfigs(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - val projectJdk = context.projectJdk ?: return true - val usingCompatibleJdk = isUsingCompatibleJdk(creator, projectJdk) - if (!usingCompatibleJdk) { - jdkBox.setInvalidJdk(projectJdk.name) + private fun updatePreferredJdkLabel() { + val sdk = this.sdk ?: return + val version = JavaSdk.getInstance().getVersion(sdk) ?: return + if (version == preferredJdk) { + preferredJdkLabel?.component = null } else { - jdkBox.selectedJdk = sdksModel.findSdk(projectJdk.name) + preferredJdkLabel?.component = + JLabel("Java ${preferredJdk.description} is recommended for $preferredJdkReason") + .also { it.foreground = JBColor.YELLOW } } - updateUi(usingCompatibleJdk) - return usingCompatibleJdk } - override fun validateChanges(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - return isUsingCompatibleJdk(creator, jdkBox.selectedJdk ?: return false) + override fun setupUI(builder: Panel) { + with(builder) { + row("JDK:") { + val sdkComboBox = jdkComboBoxWithPreference(context, sdkProperty, "${javaClass.name}.sdk") + this@JdkProjectSetupFinalizer.sdkComboBox = sdkComboBox.component + this@JdkProjectSetupFinalizer.preferredJdkLabel = placeholder() + updatePreferredJdkLabel() - } + } - - override fun apply(creator: MinecraftProjectCreator, context: WizardContext) { - val selectedJdk = jdkBox.selectedJdk - if (selectedJdk != null) { - context.projectJdk = selectedJdk } } -} -class GradleProjectSetupFinalizer : ProjectSetupFinalizer { - - private val model = SortedComboBoxModel(Comparator.naturalOrder()) - - private val propertyGraph = PropertyGraph("GradleProjectSetupFinalizer graph") - var gradleVersionProperty = propertyGraph.lazyProperty { SemanticVersion.release() } - var gradleVersion: SemanticVersion by gradleVersionProperty - private var config: ProjectConfig? = null - - private var gradleVersionRange: VersionRange? = null - - override val title: String = "Gradle" - - override fun Panel.buildComponent(creator: MinecraftProjectCreator, context: WizardContext) { - row("Gradle version:") { - comboBox(model) - .bindItem(gradleVersionProperty) - .enabled(false) // TODO load compatible Gradle versions list + class Factory : ProjectSetupFinalizer.Factory { + override fun create(parent: NewProjectWizardStep) = JdkProjectSetupFinalizer(parent) - } - } + } +} - - override fun isApplicable(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - val buildSystem = creator.buildSystem - return buildSystem is GradleBuildSystem - } - - override fun validateConfigs(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - config = creator.config - - if (creator.buildSystem !is GradleBuildSystem) { - return true - } - - val range = (creator.config as? GradleCreator)?.compatibleGradleVersions - gradleVersionRange = range - - gradleVersion = range?.upper ?: SemanticVersion.parse(GradleVersion.current().version) - model.clear() - model.add(gradleVersion) - model.selectedItem = gradleVersion - return true - } - - override fun validateChanges(creator: MinecraftProjectCreator, context: WizardContext): Boolean { - if (creator.buildSystem !is GradleBuildSystem) { - return true - } - return gradleVersionRange == null || gradleVersion.parts.isNotEmpty() - } - - override fun apply(creator: MinecraftProjectCreator, context: WizardContext) { - (creator.buildSystem as? GradleBuildSystem)?.gradleVersion = gradleVersion - } -} Index: src/main/kotlin/creator/buildsystem/AbstractBuildSystemStep.kt =================================================================== --- src/main/kotlin/creator/buildsystem/AbstractBuildSystemStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/buildsystem/AbstractBuildSystemStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,108 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.buildsystem + +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.storeToData +import com.intellij.ide.util.projectWizard.WizardContext +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.EMPTY_LABEL +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Row + +abstract class AbstractBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) { + companion object { + private val PLATFORM_NAME_KEY = Key.create("mcdev.platformName") + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.buildSystemWizard") + } + + init { + storeToData(javaClass) + } + + abstract val platformName: String + + override val self get() = this + override val label get() = if (steps.size > 1) "Build System:" else EMPTY_LABEL + + override fun initSteps(): LinkedHashMap { + context.putUserData(PLATFORM_NAME_KEY, platformName) + return super.initSteps() + } + + override fun setupSwitcherUi(builder: Row) { + if (steps.size > 1) { + super.setupSwitcherUi(builder) + } + } + + override fun setupUI(builder: Panel) { + val stepUninitialized = step.isEmpty() + super.setupUI(builder) + + // if no value was previously set for the step (i.e. not saved from when the user previously used this wizard) + // then set the build system to the preferred one for this platform, if one exists + if (stepUninitialized) { + for (buildSystem in steps.keys) { + if (BuildSystemSupport.getInstance(platformName, buildSystem)?.preferred == true) { + step = buildSystem + break + } + } + } + } + + interface Factory : NewProjectWizardMultiStepFactory { + override fun isEnabled(context: WizardContext): Boolean { + val platformName = context.getUserData(PLATFORM_NAME_KEY) + ?: throw IllegalStateException("Platform name not set") + return BuildSystemSupport.getInstance(platformName, name) != null + } + + override fun createStep(parent: AbstractBuildSystemStep): NewProjectWizardStep { + val platformName = parent.context.getUserData(PLATFORM_NAME_KEY) + ?: throw IllegalStateException("Platform name not set") + val buildSystemSupport = BuildSystemSupport.getInstance(platformName, name) + ?: throw IllegalStateException("Build system unsupported, this factory should have been filtered out") + return buildSystemSupport.createStep(BuildSystemSupport.PRE_STEP, parent) + } + } +} + +class GradleBuildSystem : AbstractBuildSystemStep.Factory { + override val name = "Gradle" +} + +class MavenBuildSystem : AbstractBuildSystemStep.Factory { + override val name = "Maven" +} + +abstract class AbstractRunBuildSystemStep( + parent: NewProjectWizardStep, + private val buildSystemStepClass: Class +) : AbstractNewProjectWizardStep(parent) { + abstract val step: String + + override fun setupProject(project: Project) { + val buildSystemStep = findStep(buildSystemStepClass) + val buildSystemSupport = BuildSystemSupport.getInstance(buildSystemStep.platformName, buildSystemStep.step) + ?: throw IllegalStateException("Build system unsupported, this should have been filtered out") + buildSystemSupport.createStep(step, this).setupProject(project) + } +} Index: src/main/kotlin/creator/buildsystem/BuildSystem.kt =================================================================== --- src/main/kotlin/creator/buildsystem/BuildSystem.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/BuildSystem.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -10,109 +10,13 @@ package com.demonwav.mcdev.creator.buildsystem -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator -import com.demonwav.mcdev.platform.PlatformType -import com.intellij.openapi.module.Module -import java.nio.file.Path import java.util.EnumSet -import kotlin.reflect.KClass -/** - * Base class for build system project creation. - */ -abstract class BuildSystem( - val groupId: String, - val artifactId: String, - val version: String -) { - open val parent: BuildSystem? = null - val parentOrError: BuildSystem - get() = parent ?: throw IllegalStateException("Sub-module build system does not have a parent") - - abstract val type: BuildSystemType - - abstract fun buildCreator(obj: Any, rootDirectory: Path, module: Module): ProjectCreator - open fun configure(config: ProjectConfig, rootDirectory: Path) {} - - var repositories: MutableList = mutableListOf() - var dependencies: MutableList = mutableListOf() - - var directories: DirectorySet? = null - val dirsOrError: DirectorySet - get() = directories ?: throw IllegalStateException("Project structure is not yet created") - - val commonModuleName: String - get() = parentOrError.artifactId + "-common" - - /** - * Initial [CreatorStep]s to execute when creating the base of a multi-module project for this build system type. - * These steps run before the platform-specific submodule steps run. - * - * @see com.demonwav.mcdev.creator.MinecraftProjectCreator.CreateTask.run - */ - abstract fun multiModuleBaseSteps( - module: Module, - types: List, - rootDirectory: Path - ): Iterable - - /** - * Finalizer [CreatorStep]s to execute when finishing a multi-module project for this build system type. These steps - * are run after the platform-specific submodule steps are run, as well as after [multiModuleCommonSteps]. - * - * @see com.demonwav.mcdev.creator.MinecraftProjectCreator.CreateTask.run - */ - abstract fun multiModuleBaseFinalizer( - module: Module, - rootDirectory: Path - ): Iterable - - /** - * [CreatorStep]s for creating the shared common module for a multi-module project for this build system type. These - * steps run after the platform-specific submodule steps are run, and before [multiModuleBaseFinalizer]. - * - * @see com.demonwav.mcdev.creator.MinecraftProjectCreator.CreateTask.run - */ - abstract fun multiModuleCommonSteps( - module: Module, - rootDirectory: Path - ): Iterable - - /** - * Using the given [artifactId] create a new child [BuildSystem] instance which shares all of the other properties - * as this instance, except for the `artifactId`. - */ - abstract fun createSub(artifactId: String): BuildSystem +enum class BuildSystemType { + MAVEN, + GRADLE, } -enum class BuildSystemType(private val readableName: String, val creatorType: KClass<*>) { - MAVEN("Maven", MavenCreator::class) { - override fun create(groupId: String, artifactId: String, version: String): BuildSystem { - return MavenBuildSystem(groupId, artifactId, version) - } - }, - GRADLE("Gradle", GradleCreator::class) { - override fun create(groupId: String, artifactId: String, version: String): BuildSystem { - return GradleBuildSystem(groupId, artifactId, version) - } - }; - - /** - * Create a new [BuildSystem] instance using the provided artifact definition. - */ - abstract fun create(groupId: String, artifactId: String, version: String): BuildSystem - - override fun toString(): String { - return readableName - } -} - data class BuildDependency( val groupId: String = "", val artifactId: String = "", Index: src/main/kotlin/creator/buildsystem/BuildSystemPropertiesStep.kt =================================================================== --- src/main/kotlin/creator/buildsystem/BuildSystemPropertiesStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/buildsystem/BuildSystemPropertiesStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,83 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.buildsystem + +import com.demonwav.mcdev.creator.storeToData +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardBaseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.ui.validation.AFTER_GRAPH_PROPAGATION +import com.intellij.openapi.ui.validation.CHECK_ARTIFACT_ID_FORMAT +import com.intellij.openapi.ui.validation.CHECK_GROUP_ID_FORMAT +import com.intellij.openapi.ui.validation.CHECK_NON_EMPTY +import com.intellij.openapi.ui.validation.validationTextErrorIf +import com.intellij.ui.dsl.builder.COLUMNS_MEDIUM +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindText +import com.intellij.ui.dsl.builder.columns +import com.intellij.ui.dsl.builder.textValidation + +private val nonExampleValidation = validationTextErrorIf("Group ID must be changed from \"org.example\"") { + it == "org.example" +} + +private val versionValidation = validationTextErrorIf("Version must be a valid semantic version") { + SemanticVersion.tryParse(it) == null +} + +class BuildSystemPropertiesStep(private val parent: ParentStep) : AbstractNewProjectWizardStep(parent) + where ParentStep : NewProjectWizardStep, ParentStep : NewProjectWizardBaseData { + + val groupIdProperty = propertyGraph.property("org.example") + .bindStorage("${javaClass.name}.groupId") + val artifactIdProperty = propertyGraph.lazyProperty(::suggestArtifactId) + private val versionProperty = propertyGraph.property("1.0-SNAPSHOT") + .bindStorage("${javaClass.name}.version") + + var groupId by groupIdProperty + var artifactId by artifactIdProperty + var version by versionProperty + + init { + artifactIdProperty.dependsOn(parent.nameProperty, ::suggestArtifactId) + storeToData() + } + + private fun suggestArtifactId() = parent.name + + override fun setupUI(builder: Panel) { + builder.collapsibleGroup("Build System Properties") { + row("Group ID:") { + textField() + .bindText(groupIdProperty) + .columns(COLUMNS_MEDIUM) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .textValidation(CHECK_NON_EMPTY, CHECK_GROUP_ID_FORMAT, nonExampleValidation) + } + row("Artifact ID:") { + textField() + .bindText(artifactIdProperty) + .columns(COLUMNS_MEDIUM) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .textValidation(CHECK_NON_EMPTY, CHECK_ARTIFACT_ID_FORMAT) + } + row("Version:") { + textField() + .bindText(versionProperty) + .columns(COLUMNS_MEDIUM) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .textValidation(versionValidation) + } + }.expanded = true + } +} Index: src/main/kotlin/creator/buildsystem/BuildSystemSupport.kt =================================================================== --- src/main/kotlin/creator/buildsystem/BuildSystemSupport.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/buildsystem/BuildSystemSupport.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,56 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.buildsystem + +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.extensions.RequiredElement +import com.intellij.openapi.util.KeyedExtensionCollector +import com.intellij.serviceContainer.BaseKeyedLazyInstance +import com.intellij.util.KeyedLazyInstance +import com.intellij.util.xmlb.annotations.Attribute + +interface BuildSystemSupport { + companion object { + private val EP_NAME = ExtensionPointName>( + "com.demonwav.minecraft-dev.buildSystemSupport" + ) + private val COLLECTOR = KeyedExtensionCollector>(EP_NAME) + + fun getInstance(platform: String, buildSystem: String): BuildSystemSupport? = + COLLECTOR.findSingle(platform to buildSystem) + + const val PRE_STEP = "pre" + const val POST_STEP = "post" + } + + fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep + + val preferred get() = false +} + +class BuildSystemSupportEntry : BaseKeyedLazyInstance(), KeyedLazyInstance { + @Attribute("implementation") + @RequiredElement + lateinit var implementation: String + + @Attribute("platform") + @RequiredElement + lateinit var platform: String + + @Attribute("buildSystem") + @RequiredElement + lateinit var buildSystem: String + + override fun getKey() = (platform to buildSystem).toString() + + override fun getImplementationClassName() = implementation +} Index: src/main/kotlin/creator/buildsystem/BuildSystemTemplate.kt =================================================================== --- src/main/kotlin/creator/buildsystem/BuildSystemTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/BuildSystemTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,63 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem - -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.GRADLE_GITIGNORE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MAVEN_GITIGNORE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MULTI_MODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MULTI_MODULE_COMMON_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MULTI_MODULE_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MULTI_MODULE_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MULTI_MODULE_SETTINGS_GRADLE_TEMPLATE -import com.intellij.openapi.project.Project - -object BuildSystemTemplate : BaseTemplate() { - - fun applyPom(project: Project): String { - return project.applyTemplate(MULTI_MODULE_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applyCommonPom(project: Project): String { - return project.applyTemplate(MULTI_MODULE_COMMON_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_VERSION" to buildSystem.version - ) - - return project.applyTemplate(MULTI_MODULE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(MULTI_MODULE_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, buildSystem: BuildSystem, subProjects: List): String { - val props = mapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "INCLUDES" to subProjects.joinToString(", ") { "'$it'" } - ) - - return project.applyTemplate(MULTI_MODULE_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applyGradleGitignore(project: Project): String { - return project.applyTemplate(GRADLE_GITIGNORE_TEMPLATE) - } - - fun applyMavenGitignore(project: Project): String { - return project.applyTemplate(MAVEN_GITIGNORE_TEMPLATE) - } -} Index: src/main/kotlin/creator/buildsystem/DirectorySet.kt =================================================================== --- src/main/kotlin/creator/buildsystem/DirectorySet.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/DirectorySet.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,35 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem - -import java.nio.file.Files -import java.nio.file.Path - -data class DirectorySet( - val sourceDirectory: Path, - val resourceDirectory: Path, - val testSourceDirectory: Path, - val testResourceDirectory: Path -) { - companion object { - fun create(dir: Path): DirectorySet { - val sourceDirectory = dir.resolve("src/main/java") - val resourceDirectory = dir.resolve("src/main/resources") - val testSourceDirectory = dir.resolve("src/test/java") - val testResourceDirectory = dir.resolve("src/test/resources") - Files.createDirectories(sourceDirectory) - Files.createDirectories(resourceDirectory) - Files.createDirectories(testSourceDirectory) - Files.createDirectories(testResourceDirectory) - return DirectorySet(sourceDirectory, resourceDirectory, testSourceDirectory, testResourceDirectory) - } - } -} Index: src/main/kotlin/creator/buildsystem/gradle-steps.kt =================================================================== --- src/main/kotlin/creator/buildsystem/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/buildsystem/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,468 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.buildsystem + +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.step.AbstractLongRunningStep +import com.demonwav.mcdev.creator.step.AbstractReformatFilesStep +import com.demonwav.mcdev.creator.step.FixedAssetsNewProjectWizardStep +import com.demonwav.mcdev.util.MinecraftTemplates.Companion.GRADLE_WRAPPER_PROPERTIES +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.childrenOfType +import com.demonwav.mcdev.util.invokeAndWait +import com.demonwav.mcdev.util.invokeLater +import com.demonwav.mcdev.util.mapFirstNotNull +import com.demonwav.mcdev.util.runGradleTaskAndWait +import com.demonwav.mcdev.util.runWriteAction +import com.demonwav.mcdev.util.runWriteTask +import com.demonwav.mcdev.util.virtualFileOrError +import com.intellij.execution.RunManager +import com.intellij.ide.ui.UISettings +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.lang.properties.psi.PropertiesFile +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupManager +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.wm.WindowManager +import com.intellij.openapi.wm.ex.StatusBarEx +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import java.nio.file.Path +import java.util.concurrent.CountDownLatch +import org.jetbrains.kotlin.psi.KtBinaryExpression +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNameReferenceExpression +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.KtScriptInitializer +import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType +import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration +import org.jetbrains.plugins.gradle.service.project.open.canLinkAndRefreshGradleProject +import org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression +import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner + +val DEFAULT_GRADLE_VERSION = SemanticVersion.release(7, 3, 3) +val GRADLE_VERSION_KEY = Key.create("mcdev.gradleVersion") + +fun FixedAssetsNewProjectWizardStep.addGradleWrapperProperties(project: Project) { + val gradleVersion = data.getUserData(GRADLE_VERSION_KEY) ?: DEFAULT_GRADLE_VERSION + addTemplateProperties("GRADLE_WRAPPER_VERSION" to gradleVersion) + addTemplates(project, "gradle/wrapper/gradle-wrapper.properties" to GRADLE_WRAPPER_PROPERTIES) +} + +abstract class AbstractRunGradleTaskStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + abstract val task: String + override val description get() = "Running Gradle task: '$task'" + + override fun perform(project: Project) { + val outputDirectory = context.projectFileDirectory + runGradleTaskAndWait(project, Path.of(outputDirectory)) { settings -> + settings.taskNames = listOf(task) + } + } +} + +class GradleWrapperStep(parent: NewProjectWizardStep) : AbstractRunGradleTaskStep(parent) { + override val task = "wrapper" +} + +abstract class AbstractPatchGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Patching Gradle files" + + abstract fun patch(project: Project, gradleFiles: GradleFiles) + + protected fun addRepositories(project: Project, buildGradle: GradleFile?, repositories: List) { + if (buildGradle == null || repositories.isEmpty()) { + return + } + + buildGradle.psi.runWriteAction { + when (buildGradle) { + is GroovyGradleFile -> { + val reposBlock = findOrCreateGroovyBlock(project, buildGradle.psi, "repositories") + val elementFactory = GroovyPsiElementFactory.getInstance(project) + for (repo in repositories) { + if (BuildSystemType.GRADLE !in repo.buildSystems) { + continue + } + val mavenBlock = + elementFactory.createStatementFromText("maven {\n}", reposBlock) as GrMethodCallExpression + val mavenClosure = mavenBlock.closureArguments[0] + if (repo.id.isNotBlank()) { + val idStatement = + elementFactory.createStatementFromText("name = ${makeStringLiteral(repo.id)}") + mavenClosure.addStatementBefore(idStatement, null) + } + val urlStatement = + elementFactory.createStatementFromText("url = ${makeStringLiteral(repo.url)}") + mavenClosure.addStatementBefore(urlStatement, null) + reposBlock.addStatementBefore(mavenBlock, null) + } + } + + is KotlinGradleFile -> { + val script = buildGradle.psi.script?.blockExpression ?: return@runWriteAction + val reposBlock = findOrCreateKotlinBlock(project, script, "repositories") + val elementFactory = KtPsiFactory(project) + for (repo in repositories) { + if (BuildSystemType.GRADLE !in repo.buildSystems) { + continue + } + val mavenBlock = elementFactory.createExpression("maven {\n}") as KtCallExpression + val mavenLambda = mavenBlock.lambdaArguments[0].getLambdaExpression()!!.bodyExpression!! + if (repo.id.isNotBlank()) { + val idStatement = elementFactory.createAssignment("name = ${makeStringLiteral(repo.id)}") + mavenLambda.addBefore(idStatement, mavenLambda.rBrace) + } + val urlStatement = elementFactory.createAssignment("url = uri(${makeStringLiteral(repo.url)})") + mavenLambda.addBefore(urlStatement, mavenLambda.rBrace) + reposBlock.addBefore(mavenBlock, reposBlock.rBrace) + } + } + } + } + } + + protected fun addDependencies(project: Project, buildGradle: GradleFile?, dependencies: List) { + if (buildGradle == null || dependencies.isEmpty()) { + return + } + + buildGradle.psi.runWriteAction { + when (buildGradle) { + is GroovyGradleFile -> { + val depsBlock = findOrCreateGroovyBlock(project, buildGradle.psi, "dependencies") + val elementFactory = GroovyPsiElementFactory.getInstance(project) + for (dep in dependencies) { + val gradleConfig = dep.gradleConfiguration ?: continue + val stmt = elementFactory.createStatementFromText( + "$gradleConfig \"${escapeGString(dep.groupId)}:${ + escapeGString(dep.artifactId) + }:${escapeGString(dep.version)}\"", + depsBlock + ) + depsBlock.addStatementBefore(stmt, null) + } + } + + is KotlinGradleFile -> { + val script = buildGradle.psi.script?.blockExpression ?: return@runWriteAction + val depsBlock = findOrCreateKotlinBlock(project, script, "dependencies") + val elementFactory = KtPsiFactory(project) + for (dep in dependencies) { + val gradleConfig = dep.gradleConfiguration ?: continue + val stmt = elementFactory.createExpression( + "$gradleConfig(\"${escapeGString(dep.groupId)}:${ + escapeGString(dep.artifactId) + }:${escapeGString(dep.version)}\")" + ) + depsBlock.addBefore(stmt, depsBlock.rBrace) + } + } + } + } + } + + protected fun addPlugins(project: Project, buildGradle: GradleFile?, plugins: List) { + if (buildGradle == null || plugins.isEmpty()) { + return + } + + buildGradle.psi.runWriteAction { + fun makePluginStatement(plugin: GradlePlugin, kotlin: Boolean): String { + return buildString { + if (kotlin) { + append("id(${makeStringLiteral(plugin.id)})") + } else { + append("id ${makeStringLiteral(plugin.id)}") + } + plugin.version?.let { append(" version ${makeStringLiteral(it)}") } + if (!plugin.apply) { + append(" apply false") + } + } + } + + when (buildGradle) { + is GroovyGradleFile -> { + val pluginsBlock = findOrCreateGroovyBlock(project, buildGradle.psi, "plugins", first = true) + val elementFactory = GroovyPsiElementFactory.getInstance(project) + for (plugin in plugins) { + val stmt = elementFactory.createStatementFromText(makePluginStatement(plugin, false)) + pluginsBlock.addStatementBefore(stmt, null) + } + } + is KotlinGradleFile -> { + val script = buildGradle.psi.script?.blockExpression ?: return@runWriteAction + val pluginsBlock = findOrCreateKotlinBlock(project, script, "plugins", first = true) + val elementFactory = KtPsiFactory(project) + for (plugin in plugins) { + val stmt = elementFactory.createExpression(makePluginStatement(plugin, true)) + pluginsBlock.addBefore(stmt, pluginsBlock.rBrace) + } + } + } + } + } + + protected fun makeStringLiteral(str: String): String { + return "\"${escapeGString(str)}\"" + } + + private fun escapeGString(str: String): String { + return StringUtil.escapeStringCharacters(str.length, str, "\"\$", StringBuilder()).toString() + } + + protected fun findGroovyBlock(element: GrStatementOwner, name: String): GrClosableBlock? { + return element.statements + .mapFirstNotNull { call -> + if (call is GrMethodCallExpression && call.callReference?.methodName == name) { + call.closureArguments.firstOrNull() + } else { + null + } + } + } + + protected fun findOrCreateGroovyBlock( + project: Project, + element: GrStatementOwner, + name: String, + first: Boolean = false + ): GrClosableBlock { + findGroovyBlock(element, name)?.let { return it } + val block = GroovyPsiElementFactory.getInstance(project).createStatementFromText("$name {\n}", element) + val anchor = if (first) { + element.statements.firstOrNull() + } else { + null + } + return (element.addStatementBefore(block, anchor) as GrMethodCallExpression).closureArguments.first() + } + + protected fun findKotlinBlock(element: KtBlockExpression, name: String): KtBlockExpression? { + return element.childrenOfType() + .flatMap { it.childrenOfType() } + .mapFirstNotNull { call -> + if ((call.calleeExpression as? KtNameReferenceExpression)?.getReferencedName() == name) { + call.lambdaArguments.firstOrNull()?.getLambdaExpression()?.bodyExpression + } else { + null + } + } + } + + protected fun findOrCreateKotlinBlock( + project: Project, + element: KtBlockExpression, + name: String, + first: Boolean = false + ): KtBlockExpression { + findKotlinBlock(element, name)?.let { return it } + val block = KtPsiFactory(project).createExpression("$name {\n}") + val addedBlock = if (first) { + element.addAfter(block, element.lBrace) + } else { + element.addBefore(block, element.rBrace) + } + return (addedBlock as KtCallExpression).lambdaArguments.first().getLambdaExpression()!!.bodyExpression!! + } + + protected fun KtPsiFactory.createAssignment(text: String): KtBinaryExpression { + return this.createBlock(text).firstStatement as KtBinaryExpression + } + + override fun perform(project: Project) { + invokeAndWait { + if (project.isDisposed) { + return@invokeAndWait + } + + runWriteTask { + val rootDir = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) + ?: return@runWriteTask + val gradleFiles = GradleFiles(project, rootDir) + NonProjectFileWritingAccessProvider.disableChecksDuring { + patch(project, gradleFiles) + gradleFiles.commit() + } + } + } + } + + class GradleFiles( + private val project: Project, + private val rootDir: VirtualFile + ) { + private val lazyBuildGradle = lazy { + val file = rootDir.findChild("build.gradle") ?: rootDir.findChild("build.gradle.kts") + ?: return@lazy null + makeGradleFile(file) + } + private val lazySettingsGradle = lazy { + val file = rootDir.findChild("settings.gradle") ?: rootDir.findChild("settings.gradle.kts") + ?: return@lazy null + makeGradleFile(file) + } + private val lazyGradleProperties = lazy { + val file = rootDir.findChild("gradle.properties") ?: return@lazy null + PsiManager.getInstance(project).findFile(file) as? PropertiesFile + } + + val buildGradle by lazyBuildGradle + val settingsGradle by lazySettingsGradle + val gradleProperties by lazyGradleProperties + + private fun makeGradleFile(virtualFile: VirtualFile): GradleFile? { + val psi = PsiManager.getInstance(project).findFile(virtualFile) ?: return null + return when (psi) { + is GroovyFile -> GroovyGradleFile(psi) + is KtFile -> KotlinGradleFile(psi) + else -> null + } + } + + fun commit() { + val files = mutableListOf() + if (lazyBuildGradle.isInitialized()) { + buildGradle?.psi?.let { files += it } + } + if (lazySettingsGradle.isInitialized()) { + settingsGradle?.psi?.let { files += it } + } + if (lazyGradleProperties.isInitialized()) { + (gradleProperties as? PsiFile)?.let { files += it } + } + + val psiDocumentManager = PsiDocumentManager.getInstance(project) + val fileDocumentManager = FileDocumentManager.getInstance() + for (file in files) { + val document = psiDocumentManager.getDocument(file) ?: continue + fileDocumentManager.saveDocument(document) + } + } + } + + sealed class GradleFile { + abstract val psi: PsiFile + } + class GroovyGradleFile(override val psi: GroovyFile) : GradleFile() + class KotlinGradleFile(override val psi: KtFile) : GradleFile() +} + +open class GradleImportStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Importing Gradle project" + + open val additionalRunTasks = emptyList() + + override fun perform(project: Project) { + val rootDirectory = Path.of(context.projectFileDirectory) + val buildSystemProps = findStep>() + + // Tell IntelliJ to import this project + rootDirectory.virtualFileOrError.refresh(false, true) + + val latch = CountDownLatch(1) + + invokeLater(project.disposed) { + val path = rootDirectory.toAbsolutePath().toString() + if (canLinkAndRefreshGradleProject(path, project, false)) { + linkAndRefreshGradleProject(path, project) + showProgress(project) + } + + StartupManager.getInstance(project).runAfterOpened { + latch.countDown() + } + } + + // Set up the run config + // Get the gradle external task type, this is what sets it as a gradle task + addRunTaskConfiguration(project, rootDirectory, buildSystemProps, "build") + for (tasks in additionalRunTasks) { + addRunTaskConfiguration(project, rootDirectory, buildSystemProps, tasks) + } + + if (!ApplicationManager.getApplication().isDispatchThread) { + latch.await() + } + } + + private fun addRunTaskConfiguration( + project: Project, + rootDirectory: Path, + buildSystemProps: BuildSystemPropertiesStep<*>, + task: String + ) { + val gradleType = GradleExternalTaskConfigurationType.getInstance() + + val runManager = RunManager.getInstance(project) + val runConfigName = buildSystemProps.artifactId + ' ' + task + + val runConfiguration = GradleRunConfiguration(project, gradleType.factory, runConfigName) + + // Set relevant gradle values + runConfiguration.settings.externalProjectPath = rootDirectory.toAbsolutePath().toString() + runConfiguration.settings.executionName = runConfigName + runConfiguration.settings.taskNames = listOf(task) + + runConfiguration.isAllowRunningInParallel = false + + val settings = runManager.createConfiguration( + runConfiguration, + gradleType.factory + ) + + settings.isActivateToolWindowBeforeRun = true + settings.storeInLocalWorkspace() + + runManager.addConfiguration(settings) + if (runManager.selectedConfiguration == null) { + runManager.selectedConfiguration = settings + } + } +} + +class ReformatBuildGradleStep(parent: NewProjectWizardStep) : AbstractReformatFilesStep(parent) { + override fun addFilesToReformat() { + addFileToReformat("build.gradle") + addFileToReformat("build.gradle.kts") + } +} + +// Show the background processes window for setup tasks +private fun showProgress(project: Project) { + if (!UISettings.getInstance().showStatusBar || UISettings.getInstance().presentationMode) { + return + } + + val statusBar = WindowManager.getInstance().getStatusBar(project) as? StatusBarEx ?: return + statusBar.isProcessWindowOpen = true +} + +data class GradlePlugin( + val id: String, + val version: String? = null, + val apply: Boolean = true, +) Index: src/main/kotlin/creator/buildsystem/gradle/GradleBuildSystem.kt =================================================================== --- src/main/kotlin/creator/buildsystem/gradle/GradleBuildSystem.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/gradle/GradleBuildSystem.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,114 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem.gradle - -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemTemplate -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import java.nio.file.Path -import java.util.Locale - -class GradleBuildSystem( - groupId: String, - artifactId: String, - version: String, - override val parent: GradleBuildSystem? = null -) : BuildSystem(groupId, artifactId, version) { - - override val type = BuildSystemType.GRADLE - - var gradleVersion: SemanticVersion = DEFAULT_WRAPPER_VERSION - - override fun createSub(artifactId: String): BuildSystem { - return GradleBuildSystem(this.groupId, artifactId, this.version, this) - } - - override fun multiModuleBaseSteps( - module: Module, - types: List, - rootDirectory: Path - ): Iterable { - val project = module.project - - val baseName = artifactId.lowercase(Locale.ENGLISH) - val names = mutableListOf("$baseName-common") - names += types.map { "$baseName-${it.name.lowercase(Locale.ENGLISH)}" } - - val buildText = BuildSystemTemplate.applyBuildGradle(project, this) - val propText = BuildSystemTemplate.applyGradleProp(project) - val settingsText = BuildSystemTemplate.applySettingsGradle(project, this, names) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - GradleSetupStep(project, rootDirectory, this, files), - GradleWrapperStep(project, rootDirectory, this) - ) - } - - override fun multiModuleBaseFinalizer(module: Module, rootDirectory: Path): Iterable { - return listOf( - GradleGitignoreStep(module.project, rootDirectory), - BasicGradleFinalizerStep(module, rootDirectory, this) - ) - } - - override fun multiModuleCommonSteps(module: Module, rootDirectory: Path): Iterable { - return listOf(CreateDirectoriesStep(this, rootDirectory)) - } - - override fun buildCreator(obj: Any, rootDirectory: Path, module: Module): ProjectCreator { - if (obj !is GradleCreator) { - throw IllegalStateException("Cannot create a Gradle module from ${obj.javaClass.name}") - } - return obj.buildGradleCreator(rootDirectory, module, this) - } - - override fun configure(config: ProjectConfig, rootDirectory: Path) { - if (config is GradleCreator) { - config.configureRootGradle(rootDirectory, this) - } - } - - companion object { - val DEFAULT_WRAPPER_VERSION = SemanticVersion.release(7, 3, 3) - } -} - -/** - * A [ProjectConfig][com.demonwav.mcdev.creator.ProjectConfig] must implement this interface in order to support - * creating `Gradle` projects. - */ -interface GradleCreator { - - val compatibleGradleVersions: VersionRange? - - fun buildGradleCreator(rootDirectory: Path, module: Module, buildSystem: GradleBuildSystem): ProjectCreator - - /** - * This method allows extra configuration of the root [GradleBuildSystem] before any [CreatorStep]s have been - * created or executed. Not typically needed. - */ - fun configureRootGradle(rootDirectory: Path, buildSystem: GradleBuildSystem) {} -} - -data class GradlePlugin( - val id: String, - val version: String? = null, - val apply: Boolean = true, -) Index: src/main/kotlin/creator/buildsystem/gradle/gradle-steps.kt =================================================================== --- src/main/kotlin/creator/buildsystem/gradle/gradle-steps.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/gradle/gradle-steps.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,360 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem.gradle - -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.CreatorStep.Companion.writeText -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemTemplate -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.DirectorySet -import com.demonwav.mcdev.util.ifNotEmpty -import com.demonwav.mcdev.util.invokeLater -import com.demonwav.mcdev.util.runGradleTaskAndWait -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.virtualFileOrError -import com.intellij.codeInsight.actions.ReformatCodeProcessor -import com.intellij.execution.RunManager -import com.intellij.ide.ui.UISettings -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.wm.WindowManager -import com.intellij.openapi.wm.ex.StatusBarEx -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiFileFactory -import com.intellij.psi.PsiManager -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption.CREATE -import java.nio.file.StandardOpenOption.TRUNCATE_EXISTING -import java.nio.file.StandardOpenOption.WRITE -import org.jetbrains.plugins.gradle.service.execution.GradleExternalTaskConfigurationType -import org.jetbrains.plugins.gradle.service.execution.GradleRunConfiguration -import org.jetbrains.plugins.gradle.service.project.open.canLinkAndRefreshGradleProject -import org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject -import org.jetbrains.plugins.groovy.GroovyLanguage -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression - -class SimpleGradleSetupStep( - private val project: Project, - private val rootDirectory: Path, - private val buildSystem: BuildSystem, - private val gradleFiles: GradleFiles, - private val kotlinScript: Boolean = false -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - runWriteTask { - if (project.isDisposed) { - return@runWriteTask - } - - buildSystem.directories = - DirectorySet.create(rootDirectory) - val (buildGradle, gradleProp, settingsGradle) = setupGradleFiles( - rootDirectory, - gradleFiles, - kotlinScript - ) - - val psiManager = PsiManager.getInstance(project) - writeText( - buildGradle, - gradleFiles.buildGradle, - psiManager - ) - if (gradleProp != null && gradleFiles.gradleProperties != null) { - writeText( - gradleProp, - gradleFiles.gradleProperties, - psiManager - ) - } - if (settingsGradle != null && gradleFiles.settingsGradle != null) { - writeText( - settingsGradle, - gradleFiles.settingsGradle, - psiManager - ) - } - } - } -} - -class GradleSetupStep( - private val project: Project, - private val rootDirectory: Path, - private val buildSystem: BuildSystem, - private val gradleFiles: GradleFiles, - private val kotlinScript: Boolean = false -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val (_, gradleProp, settingsGradle) = setupGradleFiles(rootDirectory, gradleFiles, kotlinScript) - - runWriteTask { - if (project.isDisposed) { - return@runWriteTask - } - - val buildGradlePsi = addBuildGradleDependencies(project, buildSystem, gradleFiles.buildGradle, kotlinScript) - val psiManager = PsiManager.getInstance(project) - psiManager.findDirectory(rootDirectory.virtualFileOrError)?.let { dir -> - dir.findFile(buildGradlePsi.name)?.delete() - val newFile = dir.add(buildGradlePsi) as? PsiFile ?: return@let - ReformatCodeProcessor(newFile, false).run() - } - - if (gradleProp != null && gradleFiles.gradleProperties != null) { - writeText(gradleProp, gradleFiles.gradleProperties, psiManager) - } - if (settingsGradle != null && gradleFiles.settingsGradle != null) { - writeText(settingsGradle, gradleFiles.settingsGradle, psiManager) - } - } - } -} - -data class GradleFiles( - val buildGradle: T, - val gradleProperties: T?, - val settingsGradle: T? -) - -fun setupGradleFiles(dir: Path, givenFiles: GradleFiles, kotlinScript: Boolean = false): GradleFiles { - return GradleFiles( - dir.resolve(if (kotlinScript) "build.gradle.kts" else "build.gradle"), - givenFiles.gradleProperties?.let { dir.resolve("gradle.properties") }, - givenFiles.settingsGradle?.let { dir.resolve(if (kotlinScript) "settings.gradle.kts" else "settings.gradle") }, - ).apply { - Files.deleteIfExists(buildGradle) - Files.createFile(buildGradle) - gradleProperties?.let { Files.deleteIfExists(it); Files.createFile(it) } - settingsGradle?.let { Files.deleteIfExists(it); Files.createFile(it) } - } -} - -fun addBuildGradleDependencies( - project: Project, - buildSystem: BuildSystem, - text: String, - kotlinScript: Boolean = false -): PsiFile { - val file = PsiFileFactory.getInstance(project).createFileFromText(GroovyLanguage, text) - return file.runWriteAction { - val fileName = if (kotlinScript) "build.gradle.kts" else "build.gradle" - file.name = fileName - - val groovyFile = file as GroovyFile - - buildSystem.repositories.asSequence() - .filter { it.buildSystems.contains(BuildSystemType.GRADLE) } - .map { "maven {name = '${it.id}'\nurl = '${it.url}'\n}" } - .toList() - .ifNotEmpty { reps -> appendExpressions(project, groovyFile, "repositories", reps) } - - buildSystem.dependencies.asSequence() - .filter { it.gradleConfiguration != null } - .map { "${it.gradleConfiguration} '${it.groupId}:${it.artifactId}:${it.version}'" } - .toList() - .ifNotEmpty { deps -> appendExpressions(project, groovyFile, "dependencies", deps) } - - return@runWriteAction file - } -} - -class AddGradlePluginStep( - private val project: Project, - private val rootDirectory: Path, - private val plugins: Collection, - private val kotlinScript: Boolean = false -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val fileName = if (kotlinScript) "build.gradle.kts" else "build.gradle" - val virtualFile = rootDirectory.resolve(fileName).virtualFileOrError - runWriteTask { - if (project.isDisposed) { - return@runWriteTask - } - - val file = PsiManager.getInstance(project).findFile(virtualFile) - ?: throw IllegalStateException("Could not find $fileName") - file.runWriteAction { - if (project.isDisposed) { - return@runWriteAction - } - - val groovyFile = file as GroovyFile - - plugins.asSequence() - .map { plugin -> - buildString { - append("id \"${plugin.id}\"") - plugin.version?.let { append(" version \"$it\"") } - if (!plugin.apply) { - append(" apply false") - } - } - } - .toList() - .ifNotEmpty { plugins -> appendExpressions(project, groovyFile, "plugins", plugins) } - - ReformatCodeProcessor(file, false).run() - } - } - } -} - -private fun appendExpressions( - project: Project, - file: GroovyFile, - name: String, - expressions: Iterable -) { - // Get the block so we can start working with it - val block = getClosableBlockByName(file, name) - ?: throw IllegalStateException("Failed to parse build.gradle files") - - // Create a super expression with all the expressions tied together - val expressionText = expressions.joinToString("\n") - - // We can't create each expression and add them to the file...that won't work. Groovy requires a new line - // from one method call expression to another, and there's no way to (easily) put whitespace in Psi because Psi is - // stupid. So instead we make the whole thing as one big clump and insert it into the block. - val fakeFile = GroovyPsiElementFactory.getInstance(project).createGroovyFile(expressionText, false, null) - val last = block.children.last() - block.addBefore(fakeFile, last) -} - -private fun getClosableBlockByName(element: PsiElement, name: String) = - element.children.asSequence() - .filter { - // We want to find the child which has a GrReferenceExpression with the right name - it.children.any { child -> child is GrReferenceExpression && child.text == name } - }.map { - // We want to find the grandchild which is a GrClosable block - it.children.mapNotNull { child -> child as? GrClosableBlock }.firstOrNull() - }.filterNotNull() - .firstOrNull() - -class BasicGradleFinalizerStep( - private val module: Module, - private val rootDirectory: Path, - private val buildSystem: BuildSystem, - private vararg val additionalRunTasks: String -) : CreatorStep { - private val project - get() = module.project - - override fun runStep(indicator: ProgressIndicator) { - // Tell IntelliJ to import this project - rootDirectory.virtualFileOrError.refresh(false, true) - - invokeLater(module.disposed) { - val path = rootDirectory.toAbsolutePath().toString() - if (canLinkAndRefreshGradleProject(path, project, false)) { - linkAndRefreshGradleProject(path, project) - showProgress(project) - } - } - - // Set up the run config - // Get the gradle external task type, this is what sets it as a gradle task - addRunTaskConfiguration("build") - for (tasks in additionalRunTasks) { - addRunTaskConfiguration(tasks) - } - } - - private fun addRunTaskConfiguration(task: String) { - val gradleType = GradleExternalTaskConfigurationType.getInstance() - - val runManager = RunManager.getInstance(project) - val runConfigName = buildSystem.artifactId + ' ' + task - - val runConfiguration = GradleRunConfiguration(project, gradleType.factory, runConfigName) - - // Set relevant gradle values - runConfiguration.settings.externalProjectPath = rootDirectory.toAbsolutePath().toString() - runConfiguration.settings.executionName = runConfigName - runConfiguration.settings.taskNames = listOf(task) - - runConfiguration.isAllowRunningInParallel = false - - val settings = runManager.createConfiguration( - runConfiguration, - gradleType.factory - ) - - settings.isActivateToolWindowBeforeRun = true - settings.storeInLocalWorkspace() - - runManager.addConfiguration(settings) - if (runManager.selectedConfiguration == null) { - runManager.selectedConfiguration = settings - } - } -} - -class GradleWrapperStep( - private val project: Project, - private val rootDirectory: Path, - private val buildSystem: GradleBuildSystem -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val wrapperVersion = buildSystem.gradleVersion - - // Setup gradle wrapper - // We'll write the properties file to ensure it sets up with the right version - val wrapperDir = rootDirectory.resolve("gradle/wrapper") - Files.createDirectories(wrapperDir) - val wrapperProp = wrapperDir.resolve("gradle-wrapper.properties") - - val text = "distributionUrl=https\\://services.gradle.org/distributions/gradle-$wrapperVersion-bin.zip\n" - - Files.write(wrapperProp, text.toByteArray(Charsets.UTF_8), CREATE, WRITE, TRUNCATE_EXISTING) - - indicator.text = "Setting up Gradle Wrapper" - indicator.text2 = "Running Gradle task: 'wrapper'" - runGradleTaskAndWait(project, rootDirectory) { settings -> - settings.taskNames = listOf("wrapper") - } - indicator.text2 = null - } -} - -// Show the background processes window for setup tasks -private fun showProgress(project: Project) { - if (!UISettings.getInstance().showStatusBar || UISettings.getInstance().presentationMode) { - return - } - - val statusBar = WindowManager.getInstance().getStatusBar(project) as? StatusBarEx ?: return - statusBar.isProcessWindowOpen = true -} - -class GradleGitignoreStep( - private val project: Project, - private val rootDirectory: Path -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val gitignoreFile = rootDirectory.resolve(".gitignore") - - val fileText = BuildSystemTemplate.applyGradleGitignore(project) - - Files.write(gitignoreFile, fileText.toByteArray(Charsets.UTF_8), CREATE, WRITE, TRUNCATE_EXISTING) - } -} Index: src/main/kotlin/creator/buildsystem/maven-steps.kt =================================================================== --- src/main/kotlin/creator/buildsystem/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/buildsystem/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,169 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.buildsystem + +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.getVersionJson +import com.demonwav.mcdev.creator.step.AbstractLongRunningStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AbstractReformatFilesStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.FixedAssetsNewProjectWizardStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.util.invokeAndWait +import com.demonwav.mcdev.util.runWriteAction +import com.demonwav.mcdev.util.runWriteTask +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.fileEditor.impl.NonProjectFileWritingAccessProvider +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiManager +import com.intellij.psi.xml.XmlFile +import com.intellij.psi.xml.XmlTag +import com.intellij.util.xml.DomManager +import java.nio.file.Path +import java.util.concurrent.TimeUnit +import kotlinx.coroutines.runBlocking +import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel +import org.jetbrains.idea.maven.project.importing.MavenImportingManager + +private val pluginVersions by lazy { + runBlocking { + getVersionJson>("maven.json") + } +} + +fun FixedAssetsNewProjectWizardStep.addDefaultMavenProperties() { + addTemplateProperties(pluginVersions) +} + +abstract class AbstractPatchPomStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Patching pom.xml" + + open fun patchPom(model: MavenDomProjectModel, root: XmlTag) { + setupCore(model) + setupName(model) + setupInfo(root) + } + + protected fun setupCore(model: MavenDomProjectModel) { + val buildSystemProps = findStep>() + model.groupId.value = buildSystemProps.groupId + model.artifactId.value = buildSystemProps.artifactId + model.version.value = buildSystemProps.version + } + + protected fun setupName(model: MavenDomProjectModel) { + val name = data.getUserData(AbstractModNameStep.KEY) ?: return + model.name.value = name + } + + protected fun setupInfo(root: XmlTag) { + val website = data.getUserData(WebsiteStep.KEY) + val description = data.getUserData(DescriptionStep.KEY) + + val properties = root.findFirstSubTag("properties") + if (!website.isNullOrBlank()) { + val url = root.createChildTag("url", null, website, false) + root.addAfter(url, properties) + } + + if (!description.isNullOrBlank()) { + val descriptionTag = root.createChildTag("description", null, description, false) + root.addBefore(descriptionTag, properties) + } + } + + protected fun setupDependencies( + model: MavenDomProjectModel, + repositories: List, + dependencies: List + ) { + for ((id, url, types) in repositories) { + if (!types.contains(BuildSystemType.MAVEN)) { + continue + } + val repository = model.repositories.addRepository() + repository.id.value = id + repository.url.value = url + } + + for ((depGroupId, depArtifactId, depVersion, scope) in dependencies) { + if (scope == null) { + continue + } + val dependency = model.dependencies.addDependency() + dependency.groupId.value = depGroupId + dependency.artifactId.value = depArtifactId + dependency.version.value = depVersion + dependency.scope.value = scope + } + } + + override fun perform(project: Project) { + invokeAndWait { + if (project.isDisposed) { + return@invokeAndWait + } + + runWriteTask { + val pomFile = VfsUtil.findFile(Path.of(context.projectFileDirectory, "pom.xml"), true) + ?: return@runWriteTask + val pomPsi = PsiManager.getInstance(project).findFile(pomFile) as? XmlFile ?: return@runWriteTask + + pomPsi.name = "pom.xml" + + NonProjectFileWritingAccessProvider.disableChecksDuring { + pomPsi.runWriteAction { + val manager = DomManager.getDomManager(project) + val mavenProjectXml = + manager.getFileElement(pomPsi, MavenDomProjectModel::class.java)?.rootElement + ?: return@runWriteAction + + val root = pomPsi.rootTag ?: return@runWriteAction + + patchPom(mavenProjectXml, root) + + // The maven importer requires that the document is saved to disk + val document = PsiDocumentManager.getInstance(project).getDocument(pomPsi) + ?: return@runWriteAction + FileDocumentManager.getInstance().saveDocument(document) + } + } + } + } + } +} + +class ReformatPomStep(parent: NewProjectWizardStep) : AbstractReformatFilesStep(parent) { + override fun addFilesToReformat() { + addFileToReformat("pom.xml") + } +} + +class MavenImportStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Importing Maven project" + + override fun perform(project: Project) { + val pomFile = VfsUtil.findFile(Path.of(context.projectFileDirectory).resolve("pom.xml"), true) + ?: return + val promise = invokeAndWait { + if (project.isDisposed) { + return@invokeAndWait null + } + MavenImportingManager.getInstance(project).linkAndImportFile(pomFile) + } ?: return + + promise.blockingGet(Int.MAX_VALUE, TimeUnit.SECONDS) + } +} Index: src/main/kotlin/creator/buildsystem/maven/MavenBuildSystem.kt =================================================================== --- src/main/kotlin/creator/buildsystem/maven/MavenBuildSystem.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/maven/MavenBuildSystem.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,111 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem.maven - -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemTemplate -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.platform.PlatformType -import com.intellij.openapi.module.Module -import java.nio.file.Path -import java.util.Locale - -class MavenBuildSystem( - groupId: String, - artifactId: String, - version: String, - override val parent: MavenBuildSystem? = null -) : BuildSystem(groupId, artifactId, version) { - - override val type = BuildSystemType.MAVEN - - override fun createSub(artifactId: String): BuildSystem { - return MavenBuildSystem(this.groupId, artifactId, this.version, this) - } - - override fun multiModuleBaseSteps( - module: Module, - types: List, - rootDirectory: Path - ): Iterable { - val project = module.project - val pomText = BuildSystemTemplate.applyPom(project) - - val baseName = artifactId.lowercase(Locale.ENGLISH) - val moduleNames = mutableListOf("$baseName-common") - moduleNames += types.map { "$baseName-${it.name.lowercase(Locale.ENGLISH)}" } - - return listOf( - BasicMavenStep( - project = project, - rootDirectory = rootDirectory, - buildSystem = this, - config = null, - pomText = pomText, - parts = listOf(BasicMavenStep.setupCore(), BasicMavenStep.setupModules(moduleNames)) - ) - ) - } - - override fun multiModuleBaseFinalizer(module: Module, rootDirectory: Path): Iterable { - return listOf( - MavenGitignoreStep(module.project, rootDirectory), - BasicMavenFinalizerStep(module, rootDirectory) - ) - } - - override fun multiModuleCommonSteps(module: Module, rootDirectory: Path): Iterable { - val project = module.project - val pomText = BuildSystemTemplate.applyCommonPom(project) - return listOf( - CreateDirectoriesStep(this, rootDirectory), - BasicMavenStep( - project = project, - rootDirectory = rootDirectory, - buildSystem = this, - config = null, - pomText = pomText, - parts = listOf(BasicMavenStep.setupSubCore(this.parentOrError.artifactId)) - ) - ) - } - - override fun buildCreator(obj: Any, rootDirectory: Path, module: Module): ProjectCreator { - if (obj !is MavenCreator) { - throw IllegalStateException("Cannot create a Maven module from ${obj.javaClass.name}") - } - return obj.buildMavenCreator(rootDirectory, module, this) - } - - override fun configure(config: ProjectConfig, rootDirectory: Path) { - if (config is MavenCreator) { - config.configureRootMaven(rootDirectory, this) - } - } -} - -/** - * A [ProjectConfig][com.demonwav.mcdev.creator.ProjectConfig] must implement this interface in order to support - * creating `Maven` projects. - */ -interface MavenCreator { - fun buildMavenCreator(rootDirectory: Path, module: Module, buildSystem: MavenBuildSystem): ProjectCreator - - /** - * This method allows extra configuration of the root [MavenBuildSystem] before any [CreatorStep]s have been - * created or executed. Not typically needed. - */ - fun configureRootMaven(rootDirectory: Path, buildSystem: MavenBuildSystem) {} -} Index: src/main/kotlin/creator/buildsystem/maven/maven-steps.kt =================================================================== --- src/main/kotlin/creator/buildsystem/maven/maven-steps.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/buildsystem/maven/maven-steps.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,250 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.buildsystem.maven - -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.buildsystem.BuildDependency -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemTemplate -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.DirectorySet -import com.demonwav.mcdev.creator.getVersionJson -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.util.invokeLater -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.virtualFile -import com.intellij.codeInsight.actions.ReformatCodeProcessor -import com.intellij.execution.RunManager -import com.intellij.lang.xml.XMLLanguage -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFileFactory -import com.intellij.psi.PsiManager -import com.intellij.psi.xml.XmlFile -import com.intellij.psi.xml.XmlTag -import com.intellij.util.xml.DomManager -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption.CREATE -import java.nio.file.StandardOpenOption.TRUNCATE_EXISTING -import java.nio.file.StandardOpenOption.WRITE -import kotlinx.coroutines.runBlocking -import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel -import org.jetbrains.idea.maven.execution.MavenRunConfigurationType -import org.jetbrains.idea.maven.execution.MavenRunnerParameters -import org.jetbrains.idea.maven.project.MavenProjectsManager - -typealias MavenStepFunc = (BasicMavenStep, MavenDomProjectModel, XmlTag) -> Unit - -class BasicMavenStep( - private val project: Project, - private val rootDirectory: Path, - private val buildSystem: BuildSystem, - private val config: ProjectConfig?, - private val pomText: String, - private val parts: Iterable = defaultParts -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - Files.createDirectories(rootDirectory) - - runWriteTask { - if (project.isDisposed) { - return@runWriteTask - } - val pomPsi = PsiFileFactory.getInstance(project).createFileFromText(XMLLanguage.INSTANCE, pomText) - ?: return@runWriteTask - - pomPsi.name = "pom.xml" - - val pomXmlPsi = pomPsi as XmlFile - pomPsi.runWriteAction { - if (project.isDisposed) { - return@runWriteAction - } - val manager = DomManager.getDomManager(project) - val mavenProjectXml = manager.getFileElement(pomXmlPsi, MavenDomProjectModel::class.java)?.rootElement - ?: return@runWriteAction - - val root = pomXmlPsi.rootTag ?: return@runWriteAction - - for (part in parts) { - MinecraftProjectCreator.WorkLogStep.currentLog?.newCurrentStep(part, 1) - part(this, mavenProjectXml, root) - } - MinecraftProjectCreator.WorkLogStep.currentLog?.finishCurrentStep() - - val vRootDir = rootDirectory.virtualFile - ?: throw IllegalStateException("Unable to find root directory: $rootDirectory") - val dir = PsiManager.getInstance(project).findDirectory(vRootDir) ?: return@runWriteAction - dir.findFile(pomPsi.name)?.delete() - dir.add(pomPsi) - - vRootDir.refresh(false, false) - val pomFile = vRootDir.findChild(pomPsi.name) ?: return@runWriteAction - - // Reformat the code to match their code style - PsiManager.getInstance(project).findFile(pomFile)?.let { - ReformatCodeProcessor(it, false).run() - } - } - } - } - - companion object { - val pluginVersions by lazy { - runBlocking { - getVersionJson>("maven.json") - } - } - - private val defaultParts = listOf(setupDirs(), setupCore(), setupName(), setupInfo(), setupDependencies()) - - fun setupDirs(): MavenStepFunc = { step, _, _ -> - step.buildSystem.directories = DirectorySet.create(step.rootDirectory) - } - - fun setupCore(): MavenStepFunc = { step, model, _ -> - model.groupId.value = step.buildSystem.groupId - model.artifactId.value = step.buildSystem.artifactId - model.version.value = step.buildSystem.version - } - - fun setupSubCore(parentArtifactId: String): MavenStepFunc { - return { step, model, _ -> - model.mavenParent.groupId.value = step.buildSystem.groupId - model.mavenParent.artifactId.value = parentArtifactId - model.mavenParent.version.value = step.buildSystem.version - model.artifactId.value = step.buildSystem.artifactId - } - } - - @Suppress("MemberVisibilityCanBePrivate") - fun setupName(): MavenStepFunc = { step, model, _ -> - model.name.value = step.config?.pluginName - } - - fun setupSubName(type: PlatformType): MavenStepFunc = { step, model, _ -> - model.name.value = step.config?.pluginName + " " + type.normalName - } - - fun setupInfo(): MavenStepFunc = { step, _, root -> - val properties = root.findFirstSubTag("properties") - - if (step.config?.hasWebsite() == true) { - val url = root.createChildTag("url", null, step.config.website, false) - root.addAfter(url, properties) - } - - if (step.config?.hasDescription() == true) { - val description = root.createChildTag("description", null, step.config.description, false) - root.addBefore(description, properties) - } - } - - fun setupDependencies(): MavenStepFunc = { step, model, _ -> - for ((id, url, types) in step.buildSystem.repositories) { - if (!types.contains(BuildSystemType.MAVEN)) { - continue - } - val repository = model.repositories.addRepository() - repository.id.value = id - repository.url.value = url - } - - for ((depGroupId, depArtifactId, depVersion, scope) in step.buildSystem.dependencies) { - if (scope == null) { - continue - } - val dependency = model.dependencies.addDependency() - dependency.groupId.value = depGroupId - dependency.artifactId.value = depArtifactId - dependency.version.value = depVersion - dependency.scope.value = scope - } - } - - fun setupModules(moduleNames: Iterable): MavenStepFunc = { _, model, _ -> - for (moduleName in moduleNames) { - val mod = model.modules.addModule() - mod.stringValue = moduleName - } - } - } -} - -class BasicMavenFinalizerStep( - private val rootModule: Module, - private val rootDirectory: Path -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - if (rootModule.isDisposed || rootModule.project.isDisposed) { - return - } - - val project = rootModule.project - - val pomFile = rootDirectory.resolve("pom.xml") - val vPomFile = pomFile.virtualFile ?: throw IllegalStateException("Could not find file: $pomFile") - - // Force Maven to setup the project - invokeLater(project.disposed) { - val manager = MavenProjectsManager.getInstance(project) - manager.addManagedFilesOrUnignore(listOf(vPomFile)) - manager.importingSettings.isDownloadDocsAutomatically = true - manager.importingSettings.isDownloadSourcesAutomatically = true - - // Setup the default Maven run config - val params = MavenRunnerParameters() - params.workingDirPath = rootDirectory.toAbsolutePath().toString() - params.goals = listOf("clean", "package") - val runnerSettings = MavenRunConfigurationType - .createRunnerAndConfigurationSettings(null, null, params, project) - runnerSettings.name = rootModule.name + " build" - runnerSettings.storeInLocalWorkspace() - - val runManager = RunManager.getInstance(project) - runManager.addConfiguration(runnerSettings) - if (runManager.selectedConfiguration == null) { - runManager.selectedConfiguration = runnerSettings - } - } - } -} - -class CommonModuleDependencyStep(private val buildSystem: BuildSystem) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - buildSystem.dependencies.add( - BuildDependency( - buildSystem.groupId, - buildSystem.commonModuleName, - "\${project.version}", - mavenScope = "compile" - ) - ) - } -} - -class MavenGitignoreStep( - private val project: Project, - private val rootDirectory: Path -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val gitignoreFile = rootDirectory.resolve(".gitignore") - - val fileText = BuildSystemTemplate.applyMavenGitignore(project) - - Files.write(gitignoreFile, fileText.toByteArray(Charsets.UTF_8), CREATE, WRITE, TRUNCATE_EXISTING) - } -} Index: src/main/kotlin/creator/creator-utils.kt =================================================================== --- src/main/kotlin/creator/creator-utils.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/creator-utils.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,358 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator + +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.FixedAssetsNewProjectWizardStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.fileTemplates.FileTemplateManager +import com.intellij.ide.starters.local.GeneratorTemplateFile +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.GitNewProjectWizardData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.stepSequence +import com.intellij.openapi.observable.properties.ObservableMutableProperty +import com.intellij.openapi.observable.properties.ObservableProperty +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.RecursionManager +import java.time.ZonedDateTime + +var NewProjectWizardStep.gitEnabled + get() = data.getUserData(GitNewProjectWizardData.KEY)!!.git + set(value) { + data.getUserData(GitNewProjectWizardData.KEY)!!.git = value + } + +fun FixedAssetsNewProjectWizardStep.addGradleGitignore(project: Project) { + addTemplates(project, ".gitignore" to MinecraftTemplates.GRADLE_GITIGNORE_TEMPLATE) +} + +fun FixedAssetsNewProjectWizardStep.addMavenGitignore(project: Project) { + addTemplates(project, ".gitignore" to MinecraftTemplates.MAVEN_GITIGNORE_TEMPLATE) +} + +fun FixedAssetsNewProjectWizardStep.addTemplates(project: Project, vararg templates: Pair) { + addTemplates(project, templates.toMap()) +} + +fun FixedAssetsNewProjectWizardStep.addTemplates(project: Project, templates: Map) { + val manager = FileTemplateManager.getInstance(project) + addAssets(templates.map { (path, template) -> GeneratorTemplateFile(path, manager.getJ2eeTemplate(template)) }) +} + +fun FixedAssetsNewProjectWizardStep.addLicense(project: Project) { + val license = data.getUserData(LicenseStep.KEY) ?: return + val authors = data.getUserData(AuthorsStep.KEY) ?: return + addTemplateProperties( + "YEAR" to ZonedDateTime.now().year, + "AUTHOR" to authors.joinToString(", "), + ) + addTemplates(project, "LICENSE" to "${license.id}.txt") +} + +fun splitPackage(text: String): Pair { + val index = text.lastIndexOf('.') + val className = text.substring(index + 1) + val packageName = text.substring(0, index) + return packageName to className +} + +private val stepClassToKey = mutableMapOf, Key<*>>() + +@Suppress("UNCHECKED_CAST") +@PublishedApi +internal fun getOrCreateClassKey(clazz: Class) = + stepClassToKey.computeIfAbsent(clazz) { + Key.create(it.name) + } as Key + +private val stepClassToWhenAvailableKey = mutableMapOf, Key<*>>() + +@Suppress("UNCHECKED_CAST") +@PublishedApi +internal fun getWhenAvailableKey(clazz: Class) = + stepClassToWhenAvailableKey[clazz] as Key Unit>>? + +@Suppress("UNCHECKED_CAST") +@PublishedApi +internal fun getOrCreateWhenAvailableKey(clazz: Class) = + stepClassToWhenAvailableKey.computeIfAbsent(clazz) { + Key.create(it.name) + } as Key Unit>> + +inline fun T.storeToData() { + storeToData(T::class.java) +} + +fun T.storeToData(clazz: Class) { + data.putUserData(getOrCreateClassKey(clazz), this) + getWhenAvailableKey(clazz)?.let { whenAvailableKey -> + data.getUserData(whenAvailableKey)?.let { whenAvailable -> + for (func in whenAvailable) { + func(this) + } + data.putUserData(whenAvailableKey, null) + } + } +} + +inline fun NewProjectWizardStep.findStep(): T { + return findStep(T::class.java) +} + +fun NewProjectWizardStep.findStep(clazz: Class): T { + return data.getUserData(getOrCreateClassKey(clazz)) + ?: throw IllegalStateException("Could not find required step ${clazz.name}") +} + +inline fun NewProjectWizardStep.whenStepAvailable(noinline func: (T) -> Unit) { + val value = data.getUserData(getOrCreateClassKey(T::class.java)) + if (value != null) { + func(value) + } else { + val whenAvailableKey = getOrCreateWhenAvailableKey(T::class.java) + val whenAvailable = data.getUserData(whenAvailableKey) + ?: mutableListOf<(T) -> Unit>().also { data.putUserData(whenAvailableKey, it) } + whenAvailable += func + } +} + +private val updateWhenChangedGuard = + RecursionManager.createGuard>("mcdev.updateWhenChangedGuard") + +fun ObservableMutableProperty.updateWhenChanged(dependency: ObservableProperty<*>, suggestor: () -> T) { + dependency.afterChange { + updateWhenChangedGuard.doPreventingRecursion(this, false) { + set(suggestor()) + } + } +} + +class EmptyStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + return stepSequence(this, s1, s2, s3, s4, s5) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + return stepSequence(this, s1, s2, s3, s4, s5, s6) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7, + f7: (T7) -> T8 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep, + T8 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + val s7 = f7(s6) + return stepSequence(this, s1, s2, s3, s4, s5, s6, s7) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7, + f7: (T7) -> T8, + f8: (T8) -> T9 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep, + T8 : NewProjectWizardStep, + T9 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + val s7 = f7(s6) + val s8 = f8(s7) + return stepSequence(this, s1, s2, s3, s4, s5, s6, s7, s8) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7, + f7: (T7) -> T8, + f8: (T8) -> T9, + f9: (T9) -> T10 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep, + T8 : NewProjectWizardStep, + T9 : NewProjectWizardStep, + T10 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + val s7 = f7(s6) + val s8 = f8(s7) + val s9 = f9(s8) + return stepSequence(this, s1, s2, s3, s4, s5, s6, s7, s8, s9) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7, + f7: (T7) -> T8, + f8: (T8) -> T9, + f9: (T9) -> T10, + f10: (T10) -> T11 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep, + T8 : NewProjectWizardStep, + T9 : NewProjectWizardStep, + T10 : NewProjectWizardStep, + T11 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + val s7 = f7(s6) + val s8 = f8(s7) + val s9 = f9(s8) + val s10 = f10(s9) + return stepSequence(this, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10) +} + +fun T1.chain( + f1: (T1) -> T2, + f2: (T2) -> T3, + f3: (T3) -> T4, + f4: (T4) -> T5, + f5: (T5) -> T6, + f6: (T6) -> T7, + f7: (T7) -> T8, + f8: (T8) -> T9, + f9: (T9) -> T10, + f10: (T10) -> T11, + f11: (T11) -> T12 +): NewProjectWizardStep + where T1 : NewProjectWizardStep, + T2 : NewProjectWizardStep, + T3 : NewProjectWizardStep, + T4 : NewProjectWizardStep, + T5 : NewProjectWizardStep, + T6 : NewProjectWizardStep, + T7 : NewProjectWizardStep, + T8 : NewProjectWizardStep, + T9 : NewProjectWizardStep, + T10 : NewProjectWizardStep, + T11 : NewProjectWizardStep, + T12 : NewProjectWizardStep { + + val s1 = f1(this) + val s2 = f2(s1) + val s3 = f3(s2) + val s4 = f4(s3) + val s5 = f5(s4) + val s6 = f6(s5) + val s7 = f7(s6) + val s8 = f8(s7) + val s9 = f9(s8) + val s10 = f10(s9) + val s11 = f11(s10) + return stepSequence(this, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11) +} Index: src/main/kotlin/creator/exception/ProjectCreatorException.kt =================================================================== --- src/main/kotlin/creator/exception/ProjectCreatorException.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/exception/ProjectCreatorException.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,13 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.exception - -class ProjectCreatorException(message: String, cause: Throwable) : Exception(message, cause) Index: src/main/kotlin/creator/exception/SetupException.kt =================================================================== --- src/main/kotlin/creator/exception/SetupException.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/exception/SetupException.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,43 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.creator.exception - -import javax.swing.JComponent - -sealed class SetupException(val j: JComponent) : Exception() { - - abstract val error: String -} - -class EmptyFieldSetupException(j: JComponent) : SetupException(j) { - override val error: String - get() = "Please fill in all required fields" -} - -class BadListSetupException(j: JComponent) : SetupException(j) { - override val error: String - get() = "Please enter as a comma separated list" -} - -class EmptyInputSetupException(j: JComponent) : SetupException(j) { - override val error: String - get() = "Please fill in all required fields" -} - -class InvalidClassNameException(j: JComponent) : SetupException(j) { - override val error: String - get() = "Class Name must be a valid Java identifier and cannot be the default package" -} - -class OtherSetupException(private val msg: String, j: JComponent) : SetupException(j) { - override val error: String - get() = "$msg" -} Index: src/main/kotlin/creator/field-validation.kt =================================================================== --- src/main/kotlin/creator/field-validation.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/creator/field-validation.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -10,42 +10,8 @@ package com.demonwav.mcdev.creator -import com.demonwav.mcdev.creator.exception.BadListSetupException -import com.demonwav.mcdev.creator.exception.EmptyInputSetupException -import com.demonwav.mcdev.creator.exception.InvalidClassNameException import com.demonwav.mcdev.util.isJavaKeyword -import javax.swing.JTextField -@Target(AnnotationTarget.FIELD) -@Retention(AnnotationRetention.RUNTIME) -annotation class ValidatedField(vararg val value: ValidatedFieldType) - -enum class ValidatedFieldType { - NON_BLANK { - override fun validate(field: JTextField) { - if (field.text.isBlank()) { - throw EmptyInputSetupException(field) - } - } - }, - CLASS_NAME { - override fun validate(field: JTextField) { - if (!isValidClassName(field.text)) { - throw InvalidClassNameException(field) - } - } - }, - LIST { - override fun validate(field: JTextField) { - if (!field.text.matches(listPattern)) { - throw BadListSetupException(field) - } - } - }; - - abstract fun validate(field: JTextField) -} - fun isValidClassName(className: String): Boolean { // default package if (!className.contains('.')) { @@ -72,5 +38,3 @@ return true } - -private val listPattern = Regex("""(\s*(\w+)\s*(,\s*\w+\s*)*,?|\[?\s*(\w+)\s*(,\s*\w+\s*)*])?""") Index: src/main/kotlin/creator/platformtype/ModPlatformStep.kt =================================================================== --- src/main/kotlin/creator/platformtype/ModPlatformStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/platformtype/ModPlatformStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,39 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.platformtype + +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.openapi.extensions.ExtensionPointName + +/** + * The step to select a mod platform. + * + * To add custom mod platforms, register a [Factory] to the `com.demonwav.minecraft-dev.modPlatformWizard` extension + * point. + */ +class ModPlatformStep( + parent: PlatformTypeStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.modPlatformWizard") + } + + override val self = this + override val label = "Platform:" + + class TypeFactory : PlatformTypeStep.Factory { + override val name = "Mod" + override fun createStep(parent: PlatformTypeStep) = ModPlatformStep(parent) + } + + interface Factory : NewProjectWizardMultiStepFactory +} Index: src/main/kotlin/creator/platformtype/PlatformTypeStep.kt =================================================================== --- src/main/kotlin/creator/platformtype/PlatformTypeStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/platformtype/PlatformTypeStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,40 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.platformtype + +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.NewProjectWizardBaseData +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.extensions.ExtensionPointName + +/** + * The step to select the platform type (mod/plugin). + * + * To add custom platform types, register a [Factory] to the `com.demonwav.minecraft-dev.platformTypeWizard` extension + * point. + */ +class PlatformTypeStep private constructor( + parent: NewProjectWizardStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME), + NewProjectWizardBaseData by parent as NewProjectWizardBaseData { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.platformTypeWizard") + + fun

create(parent: P) where P : NewProjectWizardStep, P : NewProjectWizardBaseData = + PlatformTypeStep(parent) + } + + override val self = this + override val label = "Platform Type:" + + interface Factory : NewProjectWizardMultiStepFactory +} Index: src/main/kotlin/creator/platformtype/PluginPlatformStep.kt =================================================================== --- src/main/kotlin/creator/platformtype/PluginPlatformStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/platformtype/PluginPlatformStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,39 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.platformtype + +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.openapi.extensions.ExtensionPointName + +/** + * The step to select a mod platform. + * + * To add custom mod platforms, register a [Factory] to the `com.demonwav.minecraft-dev.pluginPlatformWizard` extension + * point. + */ +class PluginPlatformStep( + parent: PlatformTypeStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.pluginPlatformWizard") + } + + override val self = this + override val label = "Platform:" + + class TypeFactory : PlatformTypeStep.Factory { + override val name = "Plugin" + override fun createStep(parent: PlatformTypeStep) = PluginPlatformStep(parent) + } + + interface Factory : NewProjectWizardMultiStepFactory +} Index: src/main/kotlin/creator/step/AbstractCollapsibleStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractCollapsibleStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractCollapsibleStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,36 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.ui.dsl.builder.Panel + +abstract class AbstractCollapsibleStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private val child by lazy { createStep() } + + abstract val title: String + + protected abstract fun createStep(): NewProjectWizardStep + + override fun setupUI(builder: Panel) { + with(builder) { + collapsibleGroup(title) { + child.setupUI(this) + } + } + } + + override fun setupProject(project: Project) { + child.setupProject(project) + } +} Index: src/main/kotlin/creator/step/AbstractLatentStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractLatentStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractLatentStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,157 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.util.asyncIO +import com.demonwav.mcdev.util.capitalize +import com.demonwav.mcdev.util.invokeLater +import com.demonwav.mcdev.util.onHidden +import com.demonwav.mcdev.util.onShown +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.Disposable +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.validation.AFTER_GRAPH_PROPAGATION +import com.intellij.openapi.ui.validation.validationErrorFor +import com.intellij.openapi.util.Disposer +import com.intellij.ui.JBColor +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Placeholder +import com.intellij.ui.dsl.builder.panel +import com.intellij.util.ui.AsyncProcessIcon +import javax.swing.JLabel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.swing.Swing + +/** + * Used for when a long-running task is required to fully construct the wizard steps, for example when downloading + * Minecraft versions. + */ +abstract class AbstractLatentStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + companion object { + private val LOGGER = logger>() + } + + private var hasComputedData = false + private var step: NewProjectWizardStep? = null + + /** + * Description of this step displayed to the user. + * + * This should be in sentence case starting with a lower case letter, and starting with a verb in the present tense, + * like a Git commit message. + * + * For example, "download Minecraft versions" would be an appropriate description. + */ + protected abstract val description: String + + private fun doComputeData(placeholder: Placeholder, lifetime: Disposable) { + if (hasComputedData) { + return + } + hasComputedData = true + + var disposed = false + Disposer.register(lifetime) { + hasComputedData = false + disposed = true + } + + CoroutineScope(Dispatchers.Swing).launch { + if (disposed) { + return@launch + } + + val result = asyncIO { + try { + computeData() + } catch (e: Throwable) { + LOGGER.error(e) + null + } + }.await() + + if (disposed) { + return@launch + } + + invokeLater { + if (disposed) { + return@invokeLater + } + + if (result == null) { + placeholder.component = panel { + row { + val label = label("Unable to $description") + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .validation(validationErrorFor { "Unable to $description" }) + label.component.foreground = JBColor.RED + } + } + } else { + val s = createStep(result) + step = s + val panel = panel { + s.setupUI(this) + } + placeholder.component = panel + } + } + } + } + + protected abstract suspend fun computeData(): T? + + protected abstract fun createStep(data: T): NewProjectWizardStep + + override fun setupUI(builder: Panel) { + lateinit var placeholder: Placeholder + with(builder) { + row { + placeholder = placeholder() + } + } + placeholder.component = panel { + row(description.capitalize()) { + cell( + AsyncProcessIcon("$javaClass.computeData").also { component -> + var lifetime: Disposable? = null + component.onShown { + lifetime?.let(Disposer::dispose) + lifetime = Disposer.newDisposable().also { lifetime -> + Disposer.register(context.disposable, lifetime) + doComputeData(placeholder, lifetime) + } + } + component.onHidden { + lifetime?.let(Disposer::dispose) + lifetime = null + } + } + ) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .validation( + validationErrorFor { + "Haven't finished $description" + } + ) + } + } + } + + override fun setupProject(project: Project) { + step?.setupProject(project) + } +} Index: src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractLongRunningAssetsStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,29 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project + +abstract class AbstractLongRunningAssetsStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + protected val assets = object : FixedAssetsNewProjectWizardStep(parent) { + override fun setupAssets(project: Project) { + outputDirectory = context.projectFileDirectory + this@AbstractLongRunningAssetsStep.setupAssets(project) + } + } + + abstract fun setupAssets(project: Project) + + override fun perform(project: Project) { + assets.setupProject(project) + } +} Index: src/main/kotlin/creator/step/AbstractLongRunningStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractLongRunningStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractLongRunningStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,83 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.progress.ProgressManager +import com.intellij.openapi.progress.Task +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.UserDataHolderEx +import java.util.concurrent.ConcurrentLinkedQueue + +private typealias TaskQueue = ConcurrentLinkedQueue + +/** + * Creator steps that either take a long time to complete, or need to be run after other steps that take a long time to + * complete. + * + * These steps show an indeterminate progress bar to the user while they are running. + */ +abstract class AbstractLongRunningStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + + /** + * The text to display on the progress bar + */ + abstract val description: String + + abstract fun perform(project: Project) + + final override fun setupProject(project: Project) { + val newQueue = TaskQueue() + val queue = (data as UserDataHolderEx).putUserDataIfAbsent(TASK_QUEUE_KEY, newQueue) + queue += this + if (queue === newQueue) { + startTaskQueue(project, queue) + } + } + + private fun startTaskQueue(project: Project, queue: TaskQueue) { + ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Your project is being created") { + override fun run(indicator: ProgressIndicator) { + if (project.isDisposed) { + return + } + + indicator.text = "Your project is being created" + var currentQueue = queue + while (true) { + while (true) { + val task = currentQueue.poll() ?: break + indicator.text2 = task.description + if (project.isDisposed) { + return + } + task.perform(project) + if (project.isDisposed) { + return + } + } + if ((data as UserDataHolderEx).replace(TASK_QUEUE_KEY, currentQueue, null)) { + break + } + currentQueue = data.getUserData(TASK_QUEUE_KEY) ?: break + } + indicator.text2 = null + } + }) + } + + companion object { + private val TASK_QUEUE_KEY = Key.create("${AbstractLongRunningStep::class.java.name}.queue") + } +} Index: src/main/kotlin/creator/step/AbstractReformatFilesStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractReformatFilesStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractReformatFilesStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,53 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.util.runWriteTask +import com.intellij.codeInsight.actions.ReformatCodeProcessor +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import java.nio.file.Path + +abstract class AbstractReformatFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Reformatting files" + + private val filesToReformat = mutableListOf() + + fun addFileToReformat(file: String) { + filesToReformat += file + } + + abstract fun addFilesToReformat() + + override fun perform(project: Project) { + addFilesToReformat() + + val rootDir = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) ?: return + val psiManager = PsiManager.getInstance(project) + val files = ReadAction.compute, Throwable> { + filesToReformat.mapNotNull { path -> + VfsUtil.findRelativeFile(rootDir, *path.split('/').toTypedArray())?.let(psiManager::findFile) + }.toTypedArray() + } + files.ifEmpty { return } + + runWriteTask { + WriteCommandAction.writeCommandAction(project, *files).withGlobalUndo().run { + ReformatCodeProcessor(project, files, null, false).run() + } + } + } +} Index: src/main/kotlin/creator/step/AbstractSelectVersionStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractSelectVersionStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractSelectVersionStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,62 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.util.PropertiesComponent +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.ui.ComboBox +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Row +import com.intellij.ui.dsl.builder.bindItem + +abstract class AbstractSelectVersionStep>( + parent: NewProjectWizardStep, + val versions: List +) : AbstractNewProjectWizardStep(parent) { + protected abstract val label: String + + val versionProperty = propertyGraph.property("") + .bindStorage("${javaClass.name}.selectedVersion") + var version by versionProperty + + protected lateinit var versionBox: ComboBox + + override fun setupUI(builder: Panel) { + with(builder) { + row(label) { + setupRow(this) + } + } + } + + open fun setupRow(builder: Row) { + with(builder) { + val box = comboBox(versions.sortedDescending().map(Any::toString)).bindItem(versionProperty) + val selectedItem = box.component.selectedItem + if (selectedItem is String) { + version = selectedItem + } + versionBox = box.component + + // fix the selection to the latest version if it was previously at the latest version + val props = PropertiesComponent.getInstance() + val latestVersionProp = "${javaClass.name}.latestVersion" + val prevLatestVersion = props.getValue(latestVersionProp) + val latestVersion = versions.maxOrNull()?.toString() + if (version == prevLatestVersion) { + version = latestVersion ?: "" + } + props.setValue(latestVersionProp, latestVersion) + } + } +} Index: src/main/kotlin/creator/step/AbstractVersionChainStep.kt =================================================================== --- src/main/kotlin/creator/step/AbstractVersionChainStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/AbstractVersionChainStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,215 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStepBase +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.RoamingType +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.service +import com.intellij.openapi.observable.properties.ObservableMutableProperty +import com.intellij.openapi.ui.ComboBox +import com.intellij.ui.CollectionComboBoxModel +import com.intellij.ui.dsl.builder.Cell +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Row +import com.intellij.ui.dsl.builder.bindItem + +private class VersionProperties( + val step: AbstractVersionChainStep, + val versionProperties: Array>>, + val preferredVersions: Array>, Comparable<*>>>, +) { + init { + loadPreferredVersions() + + var propertyChangeCount = 0L + + for ((i, prop) in versionProperties.withIndex()) { + prop.afterChange { value -> + val prevPropertyChangeCount = ++propertyChangeCount + + val versionsAbove = versionProperties.take(i).map(ObservableMutableProperty>::get) + val newestVersion = step.getAvailableVersions(versionsAbove).sortedDescending().first() + if (value == newestVersion) { + preferredVersions[i].remove(versionsAbove) + } else { + preferredVersions[i][versionsAbove] = value + } + + for (j in (i + 1) until versionProperties.size) { + val versionsAboveChild = + versionProperties.take(j).map(ObservableMutableProperty>::get) + val preferredVersion = preferredVersions[j][versionsAboveChild] + step.comboBoxes?.let { comboBoxes -> + step.setSelectableItems(j, step.getAvailableVersions(versionsAboveChild).sortedDescending()) + if (preferredVersion != null) { + comboBoxes[j].selectedItem = preferredVersion + } else { + comboBoxes[j].selectedIndex = 0 + } + } ?: run { + versionProperties[j].set( + preferredVersion ?: step.getAvailableVersions(versionsAboveChild).first() + ) + } + + // the above code could have triggered a recursive property change which would have dealt with the + // rest of what we're going to do here + if (propertyChangeCount != prevPropertyChangeCount) { + return@afterChange + } + } + + savePreferredVersions() + } + } + } + + private fun savePreferredVersions() { + val stateComponent = PreferredVersionStateComponent.getInstance() + val preferredVersions = this.preferredVersions.map { m -> + m.map { (key, value) -> key.map(Comparable<*>::toString) to value.toString() }.toMap() + } + stateComponent.set("${step.javaClass.name}.preferredVersions", preferredVersions) + } + + private fun loadPreferredVersions() { + val stateComponent = PreferredVersionStateComponent.getInstance() + val preferredVersions = stateComponent.get("${step.javaClass.name}.preferredVersions") ?: return + for ((i, preferences) in preferredVersions.withIndex()) { + if (i >= this.preferredVersions.size) { + break + } + + preferenceEntryLoop@ + for ((versionsAbove, version) in preferences) { + if (versionsAbove.size != i) { + continue@preferenceEntryLoop + } + + val parsedVersionsAbove = mutableListOf>() + for (versionAbove in versionsAbove) { + parsedVersionsAbove += step.getAvailableVersions(parsedVersionsAbove) + .firstOrNull { it.toString() == versionAbove } + ?: continue@preferenceEntryLoop + } + val parsedVersion = step.getAvailableVersions(parsedVersionsAbove) + .firstOrNull { it.toString() == version } + ?: continue@preferenceEntryLoop + + this.preferredVersions[i][parsedVersionsAbove] = parsedVersion + } + + val preferredVersion = + this.preferredVersions[i][versionProperties.take(i).map(ObservableMutableProperty>::get)] + if (preferredVersion != null) { + versionProperties[i].set(preferredVersion) + } + } + } +} + +/** + * This class replaces chains of [AbstractNewProjectWizardMultiStepBase]s. The problem with the latter approach is that + * widgets become improperly aligned. + */ +abstract class AbstractVersionChainStep( + parent: NewProjectWizardStep, + private vararg val labels: String +) : AbstractNewProjectWizardStep(parent) { + private val versionProperties by lazy { + val versionProperties = mutableListOf>>() + for (i in labels.indices) { + versionProperties += propertyGraph.property( + getAvailableVersions(versionProperties.map(ObservableMutableProperty>::get)).first() + ) + } + val preferredVersions = labels.indices.map { mutableMapOf>, Comparable<*>>() } + VersionProperties(this, versionProperties.toTypedArray(), preferredVersions.toTypedArray()) + } + + internal var comboBoxes: Array>>? = null + + abstract fun getAvailableVersions(versionsAbove: List>): List> + + fun getVersionProperty(index: Int) = versionProperties.versionProperties[index] + + fun getVersion(index: Int) = versionProperties.versionProperties[index].get() + + fun getVersionBox(index: Int) = comboBoxes?.let { it[index] } + + open fun setSelectableItems(index: Int, items: List>) { + getVersionBox(index)!!.model = CollectionComboBoxModel(items) + } + + open fun createComboBox(row: Row, index: Int, items: List>): Cell>> { + return row.comboBox(items) + } + + override fun setupUI(builder: Panel) { + val comboBoxes = mutableListOf>>() + with(builder) { + for ((i, label) in labels.withIndex()) { + row(label) { + val comboBox = createComboBox( + this, i, + getAvailableVersions( + versionProperties.versionProperties + .take(i).map(ObservableMutableProperty>::get) + ).sortedDescending() + ).bindItem(versionProperties.versionProperties[i]) + comboBoxes += comboBox.component + } + } + } + this.comboBoxes = comboBoxes.toTypedArray() + } +} + +private typealias PreferredVersionStateValue = List, String>> + +@Service +@State( + name = "PreferredVersions", + storages = [Storage("mcdev.CreatorPreferredVersions.xml", roamingType = RoamingType.DISABLED)] +) +class PreferredVersionStateComponent : PersistentStateComponent> { + private var state = mutableMapOf() + + fun get(key: String) = state[key] + + fun set(key: String, value: PreferredVersionStateValue) { + state[key] = value + } + + override fun getState() = state + override fun loadState(state: MutableMap) { + this.state = state + } + + companion object { + fun getInstance() = service() + } +} + +private fun List>.sortedDescending(): List> { + fun > sortImpl(list: List>): List> { + @Suppress("UNCHECKED_CAST") + return (list as List).sortedByDescending { it } + } + // pretend we're strings to make the compiler happy + return sortImpl(this) +} Index: src/main/kotlin/creator/step/FixedAssetsNewProjectWizardStep.kt =================================================================== --- src/main/kotlin/creator/step/FixedAssetsNewProjectWizardStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/FixedAssetsNewProjectWizardStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,180 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.codeInsight.actions.ReformatCodeProcessor +import com.intellij.ide.projectView.ProjectView +import com.intellij.ide.projectWizard.generators.AssetsNewProjectWizardStep +import com.intellij.ide.starters.local.GeneratorAsset +import com.intellij.ide.starters.local.GeneratorEmptyDirectory +import com.intellij.ide.starters.local.GeneratorResourceFile +import com.intellij.ide.starters.local.GeneratorTemplateFile +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.StartupManager +import com.intellij.openapi.util.io.NioFiles +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiManager +import java.io.IOException +import java.nio.file.Files +import java.nio.file.Path + +/** + * Fixed version of [AssetsNewProjectWizardStep], to be removed in 2022.3 when + * [IDEA-297489 is fixed](https://github.com/JetBrains/intellij-community/commit/fefae70bf621f3181ee9f2d0815c43d0325cd6c4). + * + * Written to be drop-in replaced with [AssetsNewProjectWizardStep] when it's ready. + */ +abstract class FixedAssetsNewProjectWizardStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + lateinit var outputDirectory: String + private val assets = arrayListOf() + val templateProperties = hashMapOf() + private val filesToOpen = hashSetOf() + + fun addAssets(vararg assets: Any) = addAssets(assets.toList()) + + fun addAssets(assets: Iterable) { + assets.mapTo(this.assets) { asset -> + when (asset) { + is GeneratorAsset -> GeneratorAssetDelegate(asset) + is FixedGeneratorAsset -> asset + else -> throw IllegalArgumentException("$asset is not a valid asset") + } + } + } + + fun addTemplateProperties(vararg properties: Pair) = addTemplateProperties(properties.toMap()) + + fun addTemplateProperties(properties: Map) = templateProperties.putAll(properties) + + fun addFilesToOpen(vararg relativeCanonicalPaths: String) = addFilesToOpen(relativeCanonicalPaths.toList()) + + fun addFilesToOpen(relativeCanonicalPaths: Iterable) { + relativeCanonicalPaths.mapTo(filesToOpen) { "$outputDirectory/$it" } + } + + abstract fun setupAssets(project: Project) + + override fun setupProject(project: Project) { + setupAssets(project) + + WriteAction.runAndWait { + val generatedFiles = mutableSetOf() + for (asset in assets) { + generateFile(asset)?.let { generatedFiles += it } + } + + runWhenCreated(project) { + fixupFiles(project, generatedFiles) + } + } + } + + fun runWhenCreated(project: Project, action: () -> Unit) { + if (ApplicationManager.getApplication().isUnitTestMode) { + action() + } else { + StartupManager.getInstance(project).runAfterOpened { + ApplicationManager.getApplication().invokeLater(action, project.disposed) + } + } + } + + private fun generateFile(asset: FixedGeneratorAsset): VirtualFile? { + return when (asset) { + is GeneratorAssetDelegate -> when (val delegate = asset.delegate) { + is GeneratorTemplateFile -> generateFile(delegate) + is GeneratorResourceFile -> generateFile(delegate) + is GeneratorEmptyDirectory -> generateFile(delegate) + } + is GeneratorFile -> generateFile(asset) + } + } + + private fun generateFile(asset: GeneratorTemplateFile): VirtualFile? { + val code = try { + asset.template.getText(templateProperties) + } catch (e: Exception) { + throw IOException("Unable to process template", e) + } + + val pathStr = "$outputDirectory/${asset.targetFileName}" + val path = Path.of(pathStr) + path.parent?.let(NioFiles::createDirectories) + Files.writeString(path, code) + + return VfsUtil.findFile(path, true) + } + + private fun generateFile(asset: GeneratorResourceFile): VirtualFile? { + val content = asset.resource.openStream().use { it.readAllBytes() } + + val pathStr = "$outputDirectory/${asset.targetFileName}" + val path = Path.of(pathStr) + path.parent?.let(NioFiles::createDirectories) + Files.write(path, content) + + return VfsUtil.findFile(path, true) + } + + private fun generateFile(asset: GeneratorEmptyDirectory): VirtualFile? { + val pathStr = "$outputDirectory/${asset.targetFileName}" + val path = Path.of(pathStr) + NioFiles.createDirectories(path) + return VfsUtil.findFile(path, true) + } + + private fun generateFile(asset: GeneratorFile): VirtualFile? { + val pathStr = "$outputDirectory/${asset.targetFileName}" + val path = Path.of(pathStr) + path.parent?.let(NioFiles::createDirectories) + Files.write(path, asset.content) + + return VfsUtil.findFile(path, true) + } + + private fun fixupFiles(project: Project, generatedFiles: Iterable) { + val psiManager = PsiManager.getInstance(project) + val psiFiles = generatedFiles.mapNotNull { psiManager.findFile(it) } + + ReformatCodeProcessor(project, psiFiles.toTypedArray(), null, false).run() + + val fileEditorManager = FileEditorManager.getInstance(project) + val projectView = ProjectView.getInstance(project) + for (file in generatedFiles) { + if (file.path in filesToOpen) { + fileEditorManager.openFile(file, true) + projectView.select(null, file, false) + } + } + } +} + +// This can be removed when https://github.com/JetBrains/intellij-community/pull/2304 is merged +sealed class FixedGeneratorAsset { + abstract val targetFileName: String +} + +data class GeneratorAssetDelegate(val delegate: GeneratorAsset) : FixedGeneratorAsset() { + override val targetFileName get() = delegate.targetFileName +} + +class GeneratorFile( + override val targetFileName: String, + val content: ByteArray, +) : FixedGeneratorAsset() { + constructor(targetFileName: String, contents: String) : this(targetFileName, contents.encodeToByteArray()) +} Index: src/main/kotlin/creator/step/LicenseStep.kt =================================================================== --- src/main/kotlin/creator/step/LicenseStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/LicenseStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,44 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.util.License +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.observable.util.transform +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindItem + +class LicenseStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + val licenseProperty = propertyGraph.property(License.ALL_RIGHTS_RESERVED.id) + .bindStorage("${javaClass.name}.license") + var license by licenseProperty + + override fun setupUI(builder: Panel) { + with(builder) { + row("License:") { + comboBox(License.values().toList()) + .bindItem(licenseProperty.transform({ License.byId(it) ?: License.ALL_RIGHTS_RESERVED }) { it.id }) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, License.byId(license)) + } + + companion object { + val KEY = Key.create("${LicenseStep::class.java.name}.license") + } +} Index: src/main/kotlin/creator/step/MainClassStep.kt =================================================================== --- src/main/kotlin/creator/step/MainClassStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/MainClassStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,82 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.updateWhenChanged +import com.demonwav.mcdev.creator.whenStepAvailable +import com.demonwav.mcdev.util.toJavaClassName +import com.demonwav.mcdev.util.toPackageName +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.COLUMNS_LARGE +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindText +import com.intellij.ui.dsl.builder.columns + +class MainClassStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private fun suggestMainClassName(): String { + val buildSystemProps = findStep>() + + if (buildSystemProps.artifactId.contains('.')) { + // if the artifact id is invalid, don't confuse ourselves by copying its dots + return className + } + + return buildSystemProps.groupId.toPackageName() + + ".${buildSystemProps.artifactId.toPackageName()}" + + ".${findStep().name.toJavaClassName()}" + } + + private fun suggestGroupId(): String { + val parts = className.split('.').dropLast(2) + return if (parts.isEmpty()) { + findStep>().groupId + } else { + parts.joinToString(".") + } + } + + val classNameProperty = propertyGraph.lazyProperty(::suggestMainClassName) + var className by classNameProperty + init { + whenStepAvailable> { buildSystemStep -> + classNameProperty.updateWhenChanged(buildSystemStep.groupIdProperty, ::suggestMainClassName) + classNameProperty.updateWhenChanged(buildSystemStep.artifactIdProperty, ::suggestMainClassName) + + buildSystemStep.groupIdProperty.updateWhenChanged(classNameProperty, ::suggestGroupId) + } + whenStepAvailable { modNameStep -> + classNameProperty.updateWhenChanged(modNameStep.nameProperty, ::suggestMainClassName) + } + } + + override fun setupUI(builder: Panel) { + with(builder) { + row("Main Class:") { + textField() + .columns(COLUMNS_LARGE) + .bindText(classNameProperty) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, className) + } + + companion object { + val KEY = Key.create("${MainClassStep::class.java.name}.className") + } +} Index: src/main/kotlin/creator/step/McVersionStep.kt =================================================================== --- src/main/kotlin/creator/step/McVersionStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/McVersionStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,87 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.onShown +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel + +class SimpleMcVersionStep( + parent: NewProjectWizardStep, + versions: List +) : AbstractSelectVersionStep(parent, versions) { + override val label = "Minecraft Version:" + + override fun setupUI(builder: Panel) { + super.setupUI(builder) + versionProperty.afterChange { + applyJdkVersion() + } + versionBox.onShown { + applyJdkVersion() + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, SemanticVersion.tryParse(version)) + applyJdkVersion() + } + + private fun applyJdkVersion() { + val version = SemanticVersion.tryParse(version) ?: return + findStep().setPreferredJdk( + MinecraftVersions.requiredJavaVersion(version), + "Minecraft $version" + ) + } + + companion object { + val KEY = Key.create("${SimpleMcVersionStep::class.java.name}.version") + } +} + +abstract class AbstractMcVersionChainStep( + parent: NewProjectWizardStep, + vararg otherLabels: String +) : AbstractVersionChainStep(parent, *(listOf("Minecraft Version:") + otherLabels).toTypedArray()) { + companion object { + const val MINECRAFT_VERSION = 0 + } + + override fun setupUI(builder: Panel) { + super.setupUI(builder) + getVersionProperty(MINECRAFT_VERSION).afterChange { + applyJdkVersion() + } + getVersionBox(MINECRAFT_VERSION)!!.onShown { + applyJdkVersion() + } + } + + override fun setupProject(project: Project) { + super.setupProject(project) + applyJdkVersion() + } + + private fun applyJdkVersion() { + val version = SemanticVersion.tryParse(getVersion(MINECRAFT_VERSION).toString()) ?: return + findStep().setPreferredJdk( + MinecraftVersions.requiredJavaVersion(version), + "Minecraft ${getVersion(MINECRAFT_VERSION)}" + ) + } +} Index: src/main/kotlin/creator/step/ModNameStep.kt =================================================================== --- src/main/kotlin/creator/step/ModNameStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/ModNameStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,66 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.creator.storeToData +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardBaseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.validation.AFTER_GRAPH_PROPAGATION +import com.intellij.openapi.ui.validation.CHECK_NON_EMPTY +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.COLUMNS_MEDIUM +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindText +import com.intellij.ui.dsl.builder.columns +import com.intellij.ui.dsl.builder.textValidation + +abstract class AbstractModNameStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private val baseData = data.getUserData(NewProjectWizardBaseData.KEY) + ?: throw IllegalStateException("Mod name step created without base step") + val nameProperty = propertyGraph.property(baseData.name) + var name by nameProperty + init { + baseData.nameProperty.afterChange { name = it } + storeToData() + } + + abstract val label: String + + override fun setupUI(builder: Panel) { + with(builder) { + row(label) { + textField() + .bindText(nameProperty) + .columns(COLUMNS_MEDIUM) + .validationRequestor(AFTER_GRAPH_PROPAGATION(propertyGraph)) + .textValidation(CHECK_NON_EMPTY) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, name) + } + + companion object { + val KEY = Key.create("${AbstractModNameStep::class.java.name}.name") + } +} + +class ModNameStep(parent: NewProjectWizardStep) : AbstractModNameStep(parent) { + override val label = "Mod Name:" +} + +class PluginNameStep(parent: NewProjectWizardStep) : AbstractModNameStep(parent) { + override val label = "Plugin Name:" +} Index: src/main/kotlin/creator/step/OptionalSteps.kt =================================================================== --- src/main/kotlin/creator/step/OptionalSteps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/OptionalSteps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,201 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.creator.updateWhenChanged +import com.intellij.ide.users.LocalUserSettings +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardBaseData.Companion.baseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.COLUMNS_LARGE +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindText +import com.intellij.ui.dsl.builder.columns + +abstract class AbstractOptionalStringStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + protected abstract val label: String + protected open val bindToStorage = false + + val valueProperty = propertyGraph.property("").apply { + if (bindToStorage) { + bindStorage("${this@AbstractOptionalStringStep.javaClass.name}.value") + } + } + var value by valueProperty + + override fun setupUI(builder: Panel) { + with(builder) { + row(label) { + textField() + .bindText(valueProperty) + .columns(COLUMNS_LARGE) + } + } + } +} + +abstract class AbstractOptionalStringBasedOnProjectNameStep( + parent: NewProjectWizardStep +) : AbstractOptionalStringStep(parent) { + private val formatProperty = propertyGraph.property("").bindStorage("${javaClass.name}.format") + var format by formatProperty + + init { + if (format.isNotEmpty()) { + value = suggestValue() + } + valueProperty.updateWhenChanged(formatProperty, ::suggestValue) + valueProperty.updateWhenChanged(baseData.nameProperty, ::suggestValue) + formatProperty.updateWhenChanged(valueProperty, ::suggestFormat) + } + + private fun suggestValue() = format.replace(PROJECT_NAME_PLACEHOLDER, baseData.name) + + private fun suggestFormat(): String { + val index = value.indexOf(baseData.name) + if (index == -1) { + return value + } + if (value.indexOf(baseData.name, startIndex = index + baseData.name.length) != -1) { + // don't change format if there are multiple instances of the project name + return format + } + return value.replace(baseData.name, PROJECT_NAME_PLACEHOLDER) + } + + companion object { + const val PROJECT_NAME_PLACEHOLDER = "{PROJECT_NAME}" + } +} + +class DescriptionStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Description:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${DescriptionStep::class.java.name}.description") + } +} + +class AuthorsStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Authors:" + override val bindToStorage = true + + override fun setupProject(project: Project) { + data.putUserData(KEY, parseAuthors(value)) + } + + companion object { + val KEY = Key.create>("${AuthorsStep::class.java.name}.authors") + + private val bracketRegex = Regex("[\\[\\]]") + private val commaRegex = Regex("\\s*,\\s*") + + fun parseAuthors(string: String): List { + return if (string.isNotBlank()) { + string.trim().replace(bracketRegex, "").split(commaRegex).toList() + } else { + emptyList() + } + } + } +} + +class WebsiteStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Website:" + override val bindToStorage = true + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${WebsiteStep::class.java.name}.website") + } +} + +class RepositoryStep(parent: NewProjectWizardStep) : AbstractOptionalStringBasedOnProjectNameStep(parent) { + override val label = "Repository:" + + init { + if (format.isEmpty()) { + format = "https://github.com/${LocalUserSettings.userName}/$PROJECT_NAME_PLACEHOLDER" + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${RepositoryStep::class.java.name}.repository") + } +} + +class IssueTrackerStep(parent: NewProjectWizardStep) : AbstractOptionalStringBasedOnProjectNameStep(parent) { + override val label = "Issue Tracker:" + + init { + if (format.isEmpty()) { + format = "https://${LocalUserSettings.userName}/$PROJECT_NAME_PLACEHOLDER/issues" + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${IssueTrackerStep::class.java.name}.issueTracker") + } +} + +class UpdateUrlStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Update URL:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${UpdateUrlStep::class.java.name}.updateUrl") + } +} + +class DependStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Depend:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, AuthorsStep.parseAuthors(value)) + } + + companion object { + val KEY = Key.create>("${DependStep::class.java.name}.depend") + } +} + +class SoftDependStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Soft Depend:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, AuthorsStep.parseAuthors(value)) + } + + companion object { + val KEY = Key.create>("${SoftDependStep::class.java.name}.depend") + } +} Index: src/main/kotlin/creator/step/TemplateOutdatedStep.kt =================================================================== --- src/main/kotlin/creator/step/TemplateOutdatedStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/TemplateOutdatedStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,41 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.demonwav.mcdev.update.PluginUtil +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.application.ApplicationInfo +import com.intellij.openapi.util.SystemInfoRt +import com.intellij.ui.dsl.builder.Panel +import java.net.URLEncoder +import java.nio.charset.StandardCharsets + +class TemplateOutdatedStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + override fun setupUI(builder: Panel) { + with(builder) { + separator() + row { + val issueUrl = "https://github.com/minecraft-dev/MinecraftDev/issues/new" + + "?template=project_wizard_outdated.yaml" + + "&plugin-version=${PluginUtil.pluginVersion.urlEncode()}" + + "&intellij-version=${ApplicationInfo.getInstance().build.asString().urlEncode()}" + + "&operating-system=${SystemInfoRt.OS_NAME.urlEncode()}" + text( + "Is the Minecraft project wizard outdated? " + + "Create an issue on the MinecraftDev issue tracker." + ) + } + } + } + + private fun String.urlEncode() = URLEncoder.encode(this, StandardCharsets.UTF_8) +} Index: src/main/kotlin/creator/step/UseMixinsStep.kt =================================================================== --- src/main/kotlin/creator/step/UseMixinsStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/UseMixinsStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,42 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.observable.util.bindBooleanStorage +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindSelected + +class UseMixinsStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + val useMixinsProperty = propertyGraph.property(false) + .bindBooleanStorage("${javaClass.name}.useMixins") + var useMixins by useMixinsProperty + + override fun setupUI(builder: Panel) { + with(builder) { + row("Use Mixins:") { + checkBox("") + .bindSelected(useMixinsProperty) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, useMixins) + } + + companion object { + val KEY = Key.create("${UseMixinsStep::class.java.name}.useMixins") + } +} Index: src/main/kotlin/creator/step/WaitForSmartModeStep.kt =================================================================== --- src/main/kotlin/creator/step/WaitForSmartModeStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/creator/step/WaitForSmartModeStep.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,28 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.creator.step + +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.project.Project + +/** + * This step shows to the user that we're waiting for smart mode as opposed to taking a while doing something else. + * Note that dumb mode may occur immediately after this step, and subsequent steps must not assume smart mode is active. + * Thus, this step is for UX purposes only. + */ +class WaitForSmartModeStep(parent: NewProjectWizardStep) : AbstractLongRunningStep(parent) { + override val description = "Indexing" + + override fun perform(project: Project) { + DumbService.getInstance(project).waitForSmartMode() + } +} Index: src/main/kotlin/facet/MinecraftFacetEditorTab.kt =================================================================== --- src/main/kotlin/facet/MinecraftFacetEditorTab.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/facet/MinecraftFacetEditorTab.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -306,8 +306,7 @@ private const val FORGE = SPONGE + 1 private const val FABRIC = FORGE + 1 private const val ARCHITECTURY = FABRIC + 1 - private const val LITELOADER = ARCHITECTURY + 1 - private const val MCP = LITELOADER + 1 + private const val MCP = ARCHITECTURY + 1 private const val MIXIN = MCP + 1 private const val BUNGEECORD = MIXIN + 1 private const val WATERFALL = BUNGEECORD + 1 @@ -322,7 +321,6 @@ PlatformType.FORGE, PlatformType.FABRIC, PlatformType.ARCHITECTURY, - PlatformType.LITELOADER, PlatformType.MCP, PlatformType.MIXIN, PlatformType.BUNGEECORD, @@ -339,7 +337,6 @@ FORGE, FABRIC, ARCHITECTURY, - LITELOADER, MCP, MIXIN, BUNGEECORD, Index: src/main/kotlin/facet/MinecraftLibraryKinds.kt =================================================================== --- src/main/kotlin/facet/MinecraftLibraryKinds.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/facet/MinecraftLibraryKinds.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -19,7 +19,6 @@ import com.demonwav.mcdev.platform.bungeecord.framework.WATERFALL_LIBRARY_KIND import com.demonwav.mcdev.platform.fabric.framework.FABRIC_LIBRARY_KIND import com.demonwav.mcdev.platform.forge.framework.FORGE_LIBRARY_KIND -import com.demonwav.mcdev.platform.liteloader.framework.LITELOADER_LIBRARY_KIND import com.demonwav.mcdev.platform.mcp.framework.MCP_LIBRARY_KIND import com.demonwav.mcdev.platform.mixin.framework.MIXIN_LIBRARY_KIND import com.demonwav.mcdev.platform.sponge.framework.SPONGE_LIBRARY_KIND @@ -33,7 +32,6 @@ FORGE_LIBRARY_KIND, FABRIC_LIBRARY_KIND, ARCHITECTURY_LIBRARY_KIND, - LITELOADER_LIBRARY_KIND, MCP_LIBRARY_KIND, MIXIN_LIBRARY_KIND, BUNGEECORD_LIBRARY_KIND, Index: src/main/kotlin/platform/CommonTemplate.kt =================================================================== --- src/main/kotlin/platform/CommonTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/CommonTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,30 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform - -import com.demonwav.mcdev.util.License -import com.intellij.openapi.project.Project -import java.time.ZonedDateTime - -object CommonTemplate : BaseTemplate() { - - fun applyLicenseTemplate( - project: Project, - license: License, - author: String - ): String { - val props = mapOf( - "YEAR" to ZonedDateTime.now().year.toString(), - "AUTHOR" to author - ) - return project.applyTemplate("${license.id}.txt", props) - } -} Index: src/main/kotlin/platform/MinecraftModuleType.kt =================================================================== --- src/main/kotlin/platform/MinecraftModuleType.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/MinecraftModuleType.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -11,13 +11,11 @@ package com.demonwav.mcdev.platform import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleBuilder import com.intellij.openapi.module.JavaModuleType import com.intellij.openapi.module.ModuleTypeManager class MinecraftModuleType : JavaModuleType() { - override fun createModuleBuilder() = MinecraftModuleBuilder() override fun getIcon() = PlatformAssets.MINECRAFT_ICON override fun getNodeIcon(isOpened: Boolean) = PlatformAssets.MINECRAFT_ICON override fun getName() = NAME Index: src/main/kotlin/platform/PlatformType.kt =================================================================== --- src/main/kotlin/platform/PlatformType.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/PlatformType.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -28,8 +28,6 @@ import com.demonwav.mcdev.platform.fabric.framework.FABRIC_LIBRARY_KIND import com.demonwav.mcdev.platform.forge.ForgeModuleType import com.demonwav.mcdev.platform.forge.framework.FORGE_LIBRARY_KIND -import com.demonwav.mcdev.platform.liteloader.LiteLoaderModuleType -import com.demonwav.mcdev.platform.liteloader.framework.LITELOADER_LIBRARY_KIND import com.demonwav.mcdev.platform.mcp.McpModuleType import com.demonwav.mcdev.platform.mcp.framework.MCP_LIBRARY_KIND import com.demonwav.mcdev.platform.mixin.MixinModuleType @@ -42,25 +40,23 @@ enum class PlatformType( val type: AbstractModuleType<*>, - val normalName: String, val versionJson: String? = null, private val parent: PlatformType? = null ) { - BUKKIT(BukkitModuleType, "Bukkit", "bukkit.json"), - SPIGOT(SpigotModuleType, "Spigot", "spigot.json", BUKKIT), - PAPER(PaperModuleType, "Paper", "paper.json", SPIGOT), - ARCHITECTURY(ArchitecturyModuleType, "Architectury"), - FORGE(ForgeModuleType, "Forge"), - FABRIC(FabricModuleType, "Fabric"), - SPONGE(SpongeModuleType, "Sponge"), - BUNGEECORD(BungeeCordModuleType, "BungeeCord", "bungeecord_v2.json"), - WATERFALL(WaterfallModuleType, "Waterfall", "waterfall.json", BUNGEECORD), - VELOCITY(VelocityModuleType, "Velocity", "velocity.json"), - LITELOADER(LiteLoaderModuleType, "LiteLoader"), - MIXIN(MixinModuleType, "Mixin"), - MCP(McpModuleType, "MCP"), - ADVENTURE(AdventureModuleType, "Adventure"); + BUKKIT(BukkitModuleType, "bukkit.json"), + SPIGOT(SpigotModuleType, "spigot.json", BUKKIT), + PAPER(PaperModuleType, "paper.json", SPIGOT), + ARCHITECTURY(ArchitecturyModuleType), + FORGE(ForgeModuleType), + FABRIC(FabricModuleType), + SPONGE(SpongeModuleType), + BUNGEECORD(BungeeCordModuleType, "bungeecord_v2.json"), + WATERFALL(WaterfallModuleType, "waterfall.json", BUNGEECORD), + VELOCITY(VelocityModuleType, "velocity.json"), + MIXIN(MixinModuleType), + MCP(McpModuleType), + ADVENTURE(AdventureModuleType); private val children = mutableListOf() @@ -85,7 +81,6 @@ ARCHITECTURY_LIBRARY_KIND -> ARCHITECTURY FORGE_LIBRARY_KIND -> FORGE FABRIC_LIBRARY_KIND -> FABRIC - LITELOADER_LIBRARY_KIND -> LITELOADER MCP_LIBRARY_KIND -> MCP MIXIN_LIBRARY_KIND -> MIXIN BUNGEECORD_LIBRARY_KIND -> BUNGEECORD Index: src/main/kotlin/platform/architectury/ArchitecturyVersion.kt =================================================================== --- src/main/kotlin/platform/architectury/ArchitecturyVersion.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/architectury/ArchitecturyVersion.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,85 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.architectury + +import com.demonwav.mcdev.creator.selectProxy +import com.demonwav.mcdev.update.PluginUtil +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.fromJson +import com.github.kittinunf.fuel.core.FuelManager +import com.github.kittinunf.fuel.core.requests.suspendable +import com.github.kittinunf.fuel.coroutines.awaitString +import com.google.gson.Gson +import com.google.gson.annotations.SerializedName +import java.io.IOException + +class ArchitecturyVersion private constructor( + val versions: Map>, +) { + + fun getArchitecturyVersions(mcVersion: SemanticVersion): List { + return try { + val architecturyVersions = versions[mcVersion] + ?: throw IOException("Could not find any architectury versions for $mcVersion") + architecturyVersions.take(50) + } catch (e: IOException) { + e.printStackTrace() + emptyList() + } + } + + data class ModrinthVersionApi( + @SerializedName("version_number") + val versionNumber: String, + @SerializedName("game_versions") + val gameVersions: List, + ) + + companion object { + + suspend fun downloadData(): ArchitecturyVersion? { + try { + val url = "https://api.modrinth.com/v2/project/architectury-api/version" + val manager = FuelManager() + manager.proxy = selectProxy(url) + + val response = manager.get(url) + .header("User-Agent", PluginUtil.useragent) + .suspendable() + .awaitString() + + val data = Gson().fromJson>(response) + + val apiVersionMap = HashMap>() + + for (version in data) { + val apiVersion = SemanticVersion.parse(version.versionNumber.substringBeforeLast('+')) + + for (gameVersion in version.gameVersions) { + val parsed = SemanticVersion.tryParse(gameVersion) ?: continue + val set = apiVersionMap.computeIfAbsent(parsed) { HashSet() } + set += apiVersion + } + } + + val apiVersionMapList = HashMap>() + for ((mcVersion, archList) in apiVersionMap.entries) { + apiVersionMapList[mcVersion] = archList.sortedDescending() + } + + return ArchitecturyVersion(apiVersionMapList) + } catch (e: Exception) { + e.printStackTrace() + return null + } + } + } +} Index: src/main/kotlin/platform/architectury/creator/ArchitecturyProjectConfig.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/ArchitecturyProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/creator/ArchitecturyProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,78 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class ArchitecturyProjectConfig : ProjectConfig(), GradleCreator { - - var mcVersion: SemanticVersion = SemanticVersion.release() - var forgeVersion: SemanticVersion = SemanticVersion.release() - var forgeVersionText: String = "" - var fabricLoaderVersion = SemanticVersion.release() - var fabricApiVersion: SemanticVersion = SemanticVersion.release() - var architecturyApiVersion: SemanticVersion = SemanticVersion.release() - var loomVersion = SemanticVersion.release() - private var gradleVersion = SemanticVersion.release() - val architecturyGroup: String - get() = when { - architecturyApiVersion >= SemanticVersion.release(2, 0, 10) -> "dev.architectury" - else -> "me.shedaniel" - } - val architecturyPackage: String - get() = when { - architecturyApiVersion >= SemanticVersion.release(2, 0, 10) -> "dev.architectury" - else -> "me.shedaniel.architectury" - } - var modRepo: String? = null - fun hasRepo() = !modRepo.isNullOrBlank() - var modIssue: String? = null - fun hasIssue() = !modIssue.isNullOrBlank() - var fabricApi = true - var architecturyApi = true - var mixins = false - var license: License? = null - - override var type = PlatformType.ARCHITECTURY - - override val preferredBuildSystem = BuildSystemType.GRADLE - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(mcVersion) - - override val compatibleGradleVersions: VersionRange - get() = VersionRange.fixed(gradleVersion) - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return ArchitecturyProjectCreator( - rootDirectory, - module, - buildSystem, - this - ) - } -} Index: src/main/kotlin/platform/architectury/creator/ArchitecturyProjectCreator.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/ArchitecturyProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/creator/ArchitecturyProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,435 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.gradle.SimpleGradleSetupStep -import com.demonwav.mcdev.platform.fabric.EntryPoint -import com.demonwav.mcdev.platform.fabric.util.FabricConstants -import com.demonwav.mcdev.platform.forge.util.ForgeConstants -import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData -import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor -import com.demonwav.mcdev.util.runGradleTaskAndWait -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.runWriteTaskInSmartMode -import com.intellij.json.JsonLanguage -import com.intellij.json.psi.JsonArray -import com.intellij.json.psi.JsonElementGenerator -import com.intellij.json.psi.JsonFile -import com.intellij.json.psi.JsonObject -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleManager -import com.intellij.openapi.module.ModuleType -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.text.StringUtil -import com.intellij.psi.PsiFileFactory -import java.nio.file.Files -import java.nio.file.Path -import org.gradle.internal.impldep.org.apache.commons.io.FileUtils - -class ArchitecturyProjectCreator( - private val rootDirectory: Path, - private val rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: ArchitecturyProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - private val commonModule: Module = project.runWriteTaskInSmartMode { - ModuleManager.getInstance(rootModule.project) - .newModule(rootDirectory.resolve("common"), ModuleType.get(rootModule).id) - } - private val forgeModule: Module = project.runWriteTaskInSmartMode { - ModuleManager.getInstance(rootModule.project) - .newModule(rootDirectory.resolve("forge"), ModuleType.get(rootModule).id) - } - private val fabricModule: Module = project.runWriteTaskInSmartMode { - ModuleManager.getInstance(rootModule.project) - .newModule(rootDirectory.resolve("fabric"), ModuleType.get(rootModule).id) - } - - override fun getSteps(): Iterable { - val steps = mutableListOf() - steps += ArchitecturyCommonProjectCreator( - rootDirectory.resolve("common"), - commonModule, - buildSystem, - config - ).getSteps() - steps += ArchitecturyForgeProjectCreator( - rootDirectory.resolve("forge"), - forgeModule, - buildSystem, - config - ).getSteps() - steps += ArchitecturyFabricProjectCreator( - rootDirectory.resolve("fabric"), - fabricModule, - buildSystem, - config - ).getSteps() - steps += listOf( - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - GradleFiles( - ArchitecturyTemplate.applyBuildGradle(project, buildSystem, config), - ArchitecturyTemplate.applyGradleProp(project, buildSystem, config), - ArchitecturyTemplate.applySettingsGradle(project, buildSystem, config) - ) - ), - GradleWrapperStep(project, rootDirectory, buildSystem), - GenRunsStep(project, rootDirectory), - GradleGitignoreStep(project, rootDirectory), - CleanUpStep(rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - return steps - } - - class GenRunsStep( - private val project: Project, - private val rootDirectory: Path - ) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - indicator.text = "Setting up project" - indicator.text2 = "Running Gradle task: 'genIntellijRuns'" - runGradleTaskAndWait(project, rootDirectory) { settings -> - settings.taskNames = listOf("genIntellijRuns") - settings.vmOptions = "-Xmx1G" - } - indicator.text2 = null - } - } - - class CleanUpStep( - private val rootDirectory: Path - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - FileUtils.deleteDirectory(rootDirectory.resolve("src").toFile()) - } - } -} - -class ArchitecturyCommonProjectCreator( - private val rootDirectory: Path, - rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: ArchitecturyProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - override fun getSteps(): Iterable { - return listOf( - CreateDirectoriesStep(buildSystem, rootDirectory), - ArchitecturyCommonMixinStep(project, buildSystem, config), - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - GradleFiles(ArchitecturyTemplate.applyCommonBuildGradle(project, buildSystem, config), null, null) - ), - setupMainClassStep() - ) - } - - private fun setupMainClassStep(): BasicJavaClassStep { - return BasicJavaClassStep( - project, - buildSystem, - buildSystem.groupId + "." + buildSystem.artifactId + "." + config.pluginName.replace(" ", ""), - ArchitecturyTemplate.applyCommonMainClass( - project, - buildSystem, - config, - buildSystem.groupId + "." + buildSystem.artifactId, - config.pluginName.replace(" ", "") - ) - ) - } - - class ArchitecturyCommonMixinStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ArchitecturyProjectConfig - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - if (config.mixins) { - val text = ArchitecturyTemplate.applyCommonMixinConfigTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, "${buildSystem.artifactId}-common.mixins.json", text) - } - } - } - } -} - -class ArchitecturyForgeProjectCreator( - private val rootDirectory: Path, - rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: ArchitecturyProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - override fun getSteps(): Iterable { - return listOf( - CreateDirectoriesStep(buildSystem, rootDirectory), - ArchitecturyForgeMixinStep(project, buildSystem, config), - ArchitecturyForgeResourcesStep(project, buildSystem, config), - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - GradleFiles( - ArchitecturyTemplate.applyForgeBuildGradle(project, buildSystem, config), - ArchitecturyTemplate.applyForgeGradleProp(project, buildSystem, config), - null - ) - ), - setupMainClassStep() - ) - } - - private fun setupMainClassStep(): BasicJavaClassStep { - return BasicJavaClassStep( - project, - buildSystem, - buildString { - append(buildSystem.groupId) - append(".") - append(buildSystem.artifactId) - append(".forge.") - append(config.pluginName.replace(" ", "")) - append("Forge") - }, - ArchitecturyTemplate.applyForgeMainClass( - project, - buildSystem, - config, - buildSystem.groupId + "." + buildSystem.artifactId, - config.pluginName.replace(" ", "") - ) - ) - } - - class ArchitecturyForgeMixinStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ArchitecturyProjectConfig - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - if (config.mixins) { - val text = ArchitecturyTemplate.applyForgeMixinConfigTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, "${buildSystem.artifactId}.mixins.json", text) - } - } - } - } - - class ArchitecturyForgeResourcesStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ArchitecturyProjectConfig - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val modsTomlText = ArchitecturyTemplate.applyModsToml(project, buildSystem, config) - val packDescriptor = ForgePackDescriptor.forMcVersion(config.mcVersion) ?: ForgePackDescriptor.FORMAT_3 - val additionalData = ForgePackAdditionalData.forMcVersion(config.mcVersion) - val packMcmetaText = - ArchitecturyTemplate.applyPackMcmeta(project, buildSystem.artifactId, packDescriptor, additionalData) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, ForgeConstants.PACK_MCMETA, packMcmetaText) - val meta = dir.resolve("META-INF") - Files.createDirectories(meta) - CreatorStep.writeTextToFile(project, meta, ForgeConstants.MODS_TOML, modsTomlText) - } - } - } -} - -class ArchitecturyFabricProjectCreator( - private val rootDirectory: Path, - rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: ArchitecturyProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - override fun getSteps(): Iterable { - return listOf( - CreateDirectoriesStep(buildSystem, rootDirectory), - ArchitecturyFabricMixinStep(project, buildSystem, config), - ArchitecturyFabricResourcesStep(project, buildSystem, config), - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - GradleFiles( - ArchitecturyTemplate.applyFabricBuildGradle(project, buildSystem, config), - null, - null - ) - ), - setupMainClassStep() - ) - } - - private fun setupMainClassStep(): BasicJavaClassStep { - return BasicJavaClassStep( - project, - buildSystem, - buildString { - append(buildSystem.groupId) - append(".") - append(buildSystem.artifactId) - append(".fabric.") - append(config.pluginName.replace(" ", "")) - append("Fabric") - }, - ArchitecturyTemplate.applyFabricMainClass( - project, - buildSystem, - config, - buildSystem.groupId + "." + buildSystem.artifactId, - config.pluginName.replace(" ", "") - ) - ) - } - - class ArchitecturyFabricMixinStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ArchitecturyProjectConfig - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - if (config.mixins) { - val text = ArchitecturyTemplate.applyFabricMixinConfigTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, "${buildSystem.artifactId}.mixins.json", text) - } - } - } - } - - class ArchitecturyFabricResourcesStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ArchitecturyProjectConfig - ) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val text = ArchitecturyTemplate.applyFabricModJsonTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - - indicator.text = "Indexing" - - project.runWriteTaskInSmartMode { - indicator.text = "Creating 'fabric.mod.json'" - - val file = PsiFileFactory.getInstance(project).createFileFromText(JsonLanguage.INSTANCE, text) - file.runWriteAction { - val jsonFile = file as JsonFile - val json = jsonFile.topLevelValue as? JsonObject ?: return@runWriteAction - val generator = JsonElementGenerator(project) - - (json.findProperty("authors")?.value as? JsonArray)?.let { authorsArray -> - for (i in config.authors.indices) { - if (i != 0) { - authorsArray.addBefore(generator.createComma(), authorsArray.lastChild) - } - authorsArray.addBefore( - generator.createStringLiteral(config.authors[i]), - authorsArray.lastChild - ) - } - } - - (json.findProperty("contact")?.value as? JsonObject)?.let { contactObject -> - val properties = mutableListOf>() - val website = config.website - if (!website.isNullOrBlank()) { - properties += "website" to website - } - val repo = config.modRepo - if (!repo.isNullOrBlank()) { - properties += "repo" to repo - } - val issues = config.modIssue - if (!issues.isNullOrBlank()) { - properties += "issues" to issues - } - for (i in properties.indices) { - if (i != 0) { - contactObject.addBefore(generator.createComma(), contactObject.lastChild) - } - val key = StringUtil.escapeStringCharacters(properties[i].first) - val value = "\"" + StringUtil.escapeStringCharacters(properties[i].second) + "\"" - contactObject.addBefore(generator.createProperty(key, value), contactObject.lastChild) - } - } - - (json.findProperty("entrypoints")?.value as? JsonObject)?.let { entryPointsObject -> - val entryPointsByCategory = listOf( - EntryPoint( - "main", - EntryPoint.Type.CLASS, - buildString { - append(buildSystem.groupId) - append(".") - append(buildSystem.artifactId) - append(".fabric.") - append(config.pluginName.replace(" ", "")) - append("Fabric") - }, - FabricConstants.MOD_INITIALIZER - ) - ) - .groupBy { it.category } - .asSequence() - .sortedBy { it.key } - .toList() - for (i in entryPointsByCategory.indices) { - val entryPointCategory = entryPointsByCategory[i] - if (i != 0) { - entryPointsObject.addBefore(generator.createComma(), entryPointsObject.lastChild) - } - val values = generator.createValue("[]") - for (j in entryPointCategory.value.indices) { - if (j != 0) { - values.addBefore(generator.createComma(), values.lastChild) - } - val entryPointReference = entryPointCategory.value[j].computeReference(project) - val value = generator.createStringLiteral(entryPointReference) - values.addBefore(value, values.lastChild) - } - val key = StringUtil.escapeStringCharacters(entryPointCategory.key) - val prop = generator.createProperty(key, "[]") - prop.value?.replace(values) - entryPointsObject.addBefore(prop, entryPointsObject.lastChild) - } - } - } - CreatorStep.writeTextToFile(project, dir, FabricConstants.FABRIC_MOD_JSON, file.text) - } - } - } -} Index: src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,402 +0,0 @@ - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/creator/ArchitecturyProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,341 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.platform.architectury.version.ArchitecturyVersion -import com.demonwav.mcdev.platform.architectury.version.FabricVersion -import com.demonwav.mcdev.platform.forge.version.ForgeVersion -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.asyncIO -import com.demonwav.mcdev.util.modUpdateStep -import com.intellij.openapi.diagnostic.logger -import com.intellij.ui.CollectionComboBoxModel -import com.intellij.ui.EnumComboBoxModel -import java.awt.event.ActionListener -import javax.swing.JCheckBox -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JProgressBar -import javax.swing.JTextField -import kotlin.math.min -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing - -class ArchitecturyProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - @ValidatedField(NON_BLANK) - private lateinit var modNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var panel: JPanel - private lateinit var title: JLabel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - private lateinit var repositoryField: JTextField - private lateinit var issueField: JTextField - private lateinit var licenseBox: JComboBox - private lateinit var mixinsCheckbox: JCheckBox - private lateinit var architecturyCheckbox: JCheckBox - private lateinit var fabricCheckbox: JCheckBox - private lateinit var minecraftVersionBox: JComboBox - private lateinit var forgeVersionBox: JComboBox - private lateinit var fabricVersionBox: JComboBox - private lateinit var fabricApiVersionBox: JComboBox - private lateinit var architecturyApiVersionBox: JComboBox - private lateinit var loadingBar: JProgressBar - private lateinit var minecraftVersionLabel: JLabel - private lateinit var errorLabel: JLabel - - private var config: ArchitecturyProjectConfig? = null - - private data class ArchitecturyVersions( - var fabricVersion: FabricVersion, - var forgeVersion: ForgeVersion, - var architecturyVersion: ArchitecturyVersion - ) - - private var versions: ArchitecturyVersions? = null - - private var currentJob: Job? = null - - private val forgeVersionBoxListener = ActionListener { - val selectedVersion = forgeVersionBox.selectedItem as? SemanticVersion ?: return@ActionListener - val supportedMixinVersion = selectedVersion >= SemanticVersion.release(31, 2, 45) - - mixinsCheckbox.isEnabled = supportedMixinVersion - if (!supportedMixinVersion) { - mixinsCheckbox.isSelected = false - } - } - - private val minecraftBoxActionListener: ActionListener = ActionListener { - CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - updateForm() - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - } - } - - override fun getComponent(): JComponent { - return panel - } - - override fun updateStep() { - val (conf) = modUpdateStep(creator, modNameField) ?: return - config = conf - - title.icon = PlatformAssets.ARCHITECTURY_ICON_2X - title.text = "Architectury Settings" - - minecraftVersionLabel.text = "Minecraft Version" - - licenseBox.model = EnumComboBoxModel(License::class.java) - licenseBox.selectedItem = License.ALL_RIGHTS_RESERVED - - if (versions != null || currentJob?.isActive == true) { - return - } - currentJob = updateVersions() - } - - private fun setForgeVersion(data: Data) { - forgeVersionBox.model = CollectionComboBoxModel(data.forgeVersions.subList(0, min(50, data.forgeVersions.size))) - forgeVersionBox.selectedIndex = data.forgeSelectedIndex - } - - private fun setFabricVersion(data: Data) { - fabricVersionBox.model = CollectionComboBoxModel( - data.fabricVersions.subList(0, min(50, data.fabricVersions.size)) - ) - fabricVersionBox.selectedIndex = data.fabricSelectedIndex - } - - private fun setFabricApiVersion(data: Data) { - fabricApiVersionBox.model = CollectionComboBoxModel( - data.fabricApiVersions.subList(0, min(50, data.fabricApiVersions.size)) - ) - fabricApiVersionBox.selectedIndex = data.fabricApiSelectedIndex - } - - private fun setArchitecturyApiVersion(data: Data) { - architecturyApiVersionBox.model = CollectionComboBoxModel( - data.architecturyApiVersions.subList(0, min(50, data.architecturyApiVersions.size)) - ) - architecturyApiVersionBox.selectedIndex = data.architecturyApiSelectedIndex - } - - private val version: SemanticVersion? - get() = minecraftVersionBox.selectedItem as? SemanticVersion - - override fun validate(): Boolean { - return super.validate() && !loadingBar.isVisible - } - - override fun isStepVisible(): Boolean { - return creator.config is ArchitecturyProjectConfig - } - - override fun onStepLeaving() { - currentJob?.cancel() - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.modNameField.text - conf.description = this.descriptionField.text - conf.website = this.websiteField.text - - conf.modRepo = this.repositoryField.text - conf.modIssue = this.issueField.text - - conf.setAuthors(this.authorsField.text) - - conf.mcVersion = this.version ?: SemanticVersion.release() - - (this.forgeVersionBox.selectedItem as SemanticVersion).let { version -> - val versionString = version.toString() - val forgeVersion = this.versions?.forgeVersion ?: return@let - conf.forgeVersionText = forgeVersion.versions.first { it.endsWith(versionString) } - conf.forgeVersion = version - } - (this.fabricVersionBox.selectedItem as SemanticVersion).let { version -> - conf.fabricLoaderVersion = version - } - (this.fabricApiVersionBox.selectedItem as SemanticVersion).let { version -> - conf.fabricApiVersion = version - } - (this.architecturyApiVersionBox.selectedItem as SemanticVersion).let { version -> - conf.architecturyApiVersion = version - } - - conf.fabricApi = fabricCheckbox.isSelected - conf.architecturyApi = architecturyCheckbox.isSelected - conf.mixins = mixinsCheckbox.isSelected - conf.license = licenseBox.selectedItem as? License ?: License.ALL_RIGHTS_RESERVED - } - - private fun mcVersionUpdate(data: Data) { - forgeVersionBox.removeActionListener(forgeVersionBoxListener) - setForgeVersion(data) - forgeVersionBox.addActionListener(forgeVersionBoxListener) - forgeVersionBoxListener.actionPerformed(null) - - fabricCheckbox.addActionListener { - if (fabricCheckbox.isSelected) { - architecturyCheckbox.isEnabled = true - } else { - architecturyCheckbox.isEnabled = false - architecturyCheckbox.isSelected = false - } - } - - setFabricVersion(data) - setFabricApiVersion(data) - setArchitecturyApiVersion(data) - } - - private fun updateVersions() = CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - try { - downloadVersions() - val data = updateForm() - if (data != null) { - updateMcForm(data) - } - } catch (e: Exception) { - LOGGER.error("Failed to update versions form", e) - error() - } - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - - currentJob = null - } - - fun error() { - errorLabel.isVisible = true - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - } - - private suspend fun downloadVersions() = coroutineScope { - val fabricVersionJob = asyncIO { FabricVersion.downloadData() } - val forgeVersionJob = asyncIO { ForgeVersion.downloadData() } - val architecturyApiVersionJob = asyncIO { ArchitecturyVersion.downloadData() } - - versions = ArchitecturyVersions( - fabricVersionJob.await() ?: return@coroutineScope, - forgeVersionJob.await() ?: return@coroutineScope, - architecturyApiVersionJob.await() ?: return@coroutineScope, - ) - } - - private suspend fun updateForm(): Data? = coroutineScope { - try { - val vers = versions ?: return@coroutineScope null - - val selectedVersion = version ?: vers.forgeVersion.sortedMcVersions.firstOrNull() - ?: return@coroutineScope null - - val fabricVersionsJob = asyncIO { vers.fabricVersion.getFabricVersions(selectedVersion) } - val forgeVersionsJob = asyncIO { vers.forgeVersion.getForgeVersions(selectedVersion) } - val fabricApiVersionsJob = asyncIO { vers.fabricVersion.getFabricApiVersions(selectedVersion) } - val architecturyApiVersionsJob = asyncIO { - vers.architecturyVersion.getArchitecturyVersions(selectedVersion) - } - - // awaitAll is better than calling .await() individually - val ( - fabricVersions, - forgeVersions, - fabricApiVersions, - architecturyApiVersions, - ) = listOf( - fabricVersionsJob, - forgeVersionsJob, - fabricApiVersionsJob, - architecturyApiVersionsJob - ).awaitAll() - - val data = Data(0, fabricVersions, 0, forgeVersions, 0, fabricApiVersions, 0, architecturyApiVersions, 0) - - mcVersionUpdate(data) - - return@coroutineScope data - } catch (e: Exception) { - // log error manually - something is weird about intellij & coroutine exception handling - LOGGER.error("Error while updating Architectury form version fields", e) - return@coroutineScope null - } - } - - private fun updateMcForm(data: Data) { - val vers = versions ?: return - - minecraftVersionBox.removeActionListener(minecraftBoxActionListener) - minecraftVersionBox.removeAllItems() - - // make copy, so the next 2 operations don't mess up the map - val mcVersions = vers.architecturyVersion.versions.keys.toCollection(LinkedHashSet()) - mcVersions.retainAll(vers.forgeVersion.sortedMcVersions.toSet()) - // Fabric also targets preview versions which aren't semver - // The other option would be to try to parse all of them and catching any exceptions - // But exceptions are slow, so this should be more efficient - val fabricMcVersions = vers.fabricVersion.versions.minecraftVersions.mapTo(HashSet()) { it.name } - mcVersions.retainAll { fabricMcVersions.contains(it.toString()) } - - minecraftVersionBox.model = CollectionComboBoxModel(mcVersions.sortedDescending()) - minecraftVersionBox.selectedIndex = data.mcSelectedIndex - minecraftVersionBox.addActionListener(minecraftBoxActionListener) - } - - private data class Data( - val mcSelectedIndex: Int, - val fabricVersions: List, - val fabricSelectedIndex: Int, - val forgeVersions: List, - val forgeSelectedIndex: Int, - val fabricApiVersions: List, - val fabricApiSelectedIndex: Int, - val architecturyApiVersions: List, - val architecturyApiSelectedIndex: Int - ) - - companion object { - private val LOGGER = logger() - } -} Index: src/main/kotlin/platform/architectury/creator/ArchitecturyTemplate.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/ArchitecturyTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/creator/ArchitecturyTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,327 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.forge.util.ForgeConstants -import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData -import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftTemplates -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.toPackageName -import com.intellij.openapi.project.Project - -object ArchitecturyTemplate : BaseTemplate() { - private fun Project.applyGradleTemplate( - templateName: String, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - val props = mutableMapOf( - "GROUP_ID" to buildSystem.groupId, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "VERSION" to buildSystem.version, - "MC_VERSION" to config.mcVersion.toString(), - "FORGE_VERSION" to config.forgeVersionText, - "FABRIC_LOADER_VERSION" to config.fabricLoaderVersion.toString(), - "FABRIC_API_VERSION" to config.fabricApiVersion.toString(), - "ARCHITECTURY_API_VERSION" to config.architecturyApiVersion.toString(), - "ARCHITECTURY_GROUP" to config.architecturyGroup, - "LOOM_VERSION" to config.loomVersion.toString(), - "JAVA_VERSION" to config.javaVersion.feature - ) - if (config.fabricApi) { - props["FABRIC_API"] = "true" - } - if (config.architecturyApi) { - props["ARCHITECTURY_API"] = "true" - } - return applyTemplate(templateName, props) - } - - fun applyBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate(MinecraftTemplates.ARCHITECTURY_BUILD_GRADLE_TEMPLATE, buildSystem, config) - } - - fun applyGradleProp( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_GRADLE_PROPERTIES_TEMPLATE, - buildSystem, - config - ) - } - - fun applyMultiModuleBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_SUBMODULE_BUILD_GRADLE_TEMPLATE, - buildSystem, - config - ) - } - - fun applyMultiModuleGradleProp( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE, - buildSystem, - config - ) - } - - fun applySettingsGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_SETTINGS_GRADLE_TEMPLATE, - buildSystem, - config - ) - } - - fun applyCommonBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_COMMON_BUILD_GRADLE_TEMPLATE, - buildSystem, - config - ) - } - - fun applyForgeBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_FORGE_BUILD_GRADLE_TEMPLATE, - buildSystem, - config - ) - } - - fun applyForgeGradleProp( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_FORGE_GRADLE_PROPERTIES_TEMPLATE, - buildSystem, - config - ) - } - - fun applyFabricBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - return project.applyGradleTemplate( - MinecraftTemplates.ARCHITECTURY_FABRIC_BUILD_GRADLE_TEMPLATE, - buildSystem, - config - ) - } - - fun applyFabricModJsonTemplate( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - val props = mutableMapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_DESCRIPTION" to (config.description ?: ""), - "MOD_ENVIRONMENT" to "*", - "FABRIC_LOADER_VERSION" to config.fabricLoaderVersion.toString(), - "FABRIC_API_VERSION" to config.fabricApiVersion.toString(), - "ARCHITECTURY_API_VERSION" to config.architecturyApiVersion.toString(), - "MC_VERSION" to config.mcVersion.toString(), - "JAVA_VERSION" to config.javaVersion.feature, - "LICENSE" to ((config.license ?: License.ALL_RIGHTS_RESERVED).id) - ) - if (config.mixins) { - props["MIXINS"] = "true" - } - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FABRIC_MOD_JSON_TEMPLATE, props) - } - - fun applyModsToml(project: Project, buildSystem: BuildSystem, config: ArchitecturyProjectConfig): String { - val hasDisplayTestInManifest = config.forgeVersion >= ForgeConstants.DISPLAY_TEST_MANIFEST_VERSION - val nextMcVersion = when (val part = config.mcVersion.parts.getOrNull(1)) { - // Mimics the code used to get the next Minecraft version in Forge's MDK - // https://github.com/MinecraftForge/MinecraftForge/blob/0ff8a596fc1ef33d4070be89dd5cb4851f93f731/build.gradle#L884 - is SemanticVersion.Companion.VersionPart.ReleasePart -> (part.version + 1).toString() - null -> "?" - else -> part.versionString - } - val props = mutableMapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "DISPLAY_TEST" to hasDisplayTestInManifest, - "FORGE_SPEC_VERSION" to config.forgeVersion.parts[0].versionString, - "ARCHITECTURY_API_VERSION" to config.architecturyApiVersion.toString(), - "MC_VERSION" to config.mcVersion.toString(), - "MC_NEXT_VERSION" to "1.$nextMcVersion", - "LICENSE" to config.license.toString() - ) - props["DESCRIPTION"] = config.description ?: "" - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.joinToString(", ") - } - if (config.hasWebsite()) { - props["WEBSITE"] = config.website.toString() - } - if (config.hasIssue()) { - props["ISSUE"] = config.modIssue.toString() - } - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FORGE_MODS_TOML_TEMPLATE, props) - } - - fun applyPackMcmeta( - project: Project, - artifactId: String, - pack: ForgePackDescriptor, - additionalData: ForgePackAdditionalData? - ): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId, - "PACK_FORMAT" to pack.format.toString(), - "PACK_COMMENT" to pack.comment, - "FORGE_DATA" to additionalData, - ) - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FORGE_PACK_MCMETA_TEMPLATE, props) - } - - fun applyCommonMixinConfigTemplate( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - val packageName = buildSystem.groupId.toPackageName() + "." + buildSystem.artifactId - val props = mapOf( - "PACKAGE_NAME" to packageName, - "JAVA_VERSION" to config.javaVersion.feature - ) - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_COMMON_MIXINS_JSON_TEMPLATE, props) - } - - fun applyForgeMixinConfigTemplate( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - val packageName = buildSystem.groupId.toPackageName() + "." + buildSystem.artifactId - val props = mapOf( - "PACKAGE_NAME" to packageName, - "JAVA_VERSION" to config.javaVersion.feature - ) - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FORGE_MIXINS_JSON_TEMPLATE, props) - } - - fun applyFabricMixinConfigTemplate( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig - ): String { - val packageName = buildSystem.groupId.toPackageName() + "." + buildSystem.artifactId - val props = mapOf( - "PACKAGE_NAME" to packageName, - "JAVA_VERSION" to config.javaVersion.feature - ) - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FABRIC_MIXINS_JSON_TEMPLATE, props) - } - - fun applyCommonMainClass( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_COMMON_MAIN_CLASS_TEMPLATE, props) - } - - fun applyForgeMainClass( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig, - packageName: String, - className: String - ): String { - val props = mutableMapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version, - "ARCHITECTURY_PACKAGE" to config.architecturyPackage - ) - - if (config.architecturyApi) { - props["ARCHITECTURY_API"] = "true" - } - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FORGE_MAIN_CLASS_TEMPLATE, props) - } - - fun applyFabricMainClass( - project: Project, - buildSystem: BuildSystem, - config: ArchitecturyProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(MinecraftTemplates.ARCHITECTURY_FABRIC_MAIN_CLASS_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/architectury/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/architectury/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,237 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.architectury.creator + +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addLicense +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.IssueTrackerStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.architectury.ArchitecturyVersion +import com.demonwav.mcdev.platform.fabric.util.FabricApiVersions +import com.demonwav.mcdev.platform.fabric.util.FabricVersions +import com.demonwav.mcdev.platform.forge.util.ForgeConstants +import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData +import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor +import com.demonwav.mcdev.platform.forge.version.ForgeVersion +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.toJavaClassName +import com.demonwav.mcdev.util.toPackageName +import com.intellij.ide.starters.local.GeneratorEmptyDirectory +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project + +class ArchitecturyVersionData( + val forgeVersions: ForgeVersion, + val fabricVersions: FabricVersions, + val fabricApiVersions: FabricApiVersions, + val architecturyVersions: ArchitecturyVersion, +) + +private val NewProjectWizardStep.architecturyPackage: String get() { + val apiVersion = data.getUserData(ArchitecturyVersionChainStep.ARCHITECTURY_API_VERSION_KEY) + return when { + apiVersion == null || apiVersion >= SemanticVersion.release(2, 0, 10) -> "dev.architectury" + else -> "me.shedaniel.architectury" + } +} + +class ArchitecturyProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Adding Architectury project files (phase 1)" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false + val javaVersion = findStep().preferredJdk.ordinal + val packageName = "${buildSystemProps.groupId.toPackageName()}.${buildSystemProps.artifactId.toPackageName()}" + val mcVersion = data.getUserData(ArchitecturyVersionChainStep.MC_VERSION_KEY) ?: return + val modName = data.getUserData(AbstractModNameStep.KEY) ?: return + val forgeVersion = data.getUserData(ArchitecturyVersionChainStep.FORGE_VERSION_KEY) ?: return + val fabricLoaderVersion = data.getUserData(ArchitecturyVersionChainStep.FABRIC_LOADER_VERSION_KEY) ?: return + val fabricApiVersion = data.getUserData(ArchitecturyVersionChainStep.FABRIC_API_VERSION_KEY) + val archApiVersion = data.getUserData(ArchitecturyVersionChainStep.ARCHITECTURY_API_VERSION_KEY) + val license = data.getUserData(LicenseStep.KEY) ?: return + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val website = data.getUserData(WebsiteStep.KEY) ?: "" + val issueTracker = data.getUserData(IssueTrackerStep.KEY) ?: "" + val description = data.getUserData(DescriptionStep.KEY) ?: "" + + val hasDisplayTestInManifest = forgeVersion >= ForgeConstants.DISPLAY_TEST_MANIFEST_VERSION + val nextMcVersion = when (val part = mcVersion.parts.getOrNull(1)) { + // Mimics the code used to get the next Minecraft version in Forge's MDK + // https://github.com/MinecraftForge/MinecraftForge/blob/0ff8a596fc1ef33d4070be89dd5cb4851f93f731/build.gradle#L884 + is SemanticVersion.Companion.VersionPart.ReleasePart -> (part.version + 1).toString() + null -> "?" + else -> part.versionString + } + + assets.addAssets( + GeneratorEmptyDirectory("common/src/main/java"), + GeneratorEmptyDirectory("common/src/main/resources"), + GeneratorEmptyDirectory("forge/src/main/java"), + GeneratorEmptyDirectory("forge/src/main/resources"), + GeneratorEmptyDirectory("fabric/src/main/java"), + GeneratorEmptyDirectory("fabric/src/main/resources"), + ) + + val packDescriptor = ForgePackDescriptor.forMcVersion(mcVersion) ?: ForgePackDescriptor.FORMAT_3 + val packAdditionalData = ForgePackAdditionalData.forMcVersion(mcVersion) + + assets.addTemplateProperties( + "ARTIFACT_ID" to buildSystemProps.artifactId, + "PACK_FORMAT" to packDescriptor.format, + "PACK_COMMENT" to packDescriptor.comment, + "PACKAGE_NAME" to packageName, + "JAVA_VERSION" to javaVersion, + "MOD_NAME" to modName, + "DISPLAY_TEST" to hasDisplayTestInManifest, + "FORGE_SPEC_VERSION" to forgeVersion.parts[0].versionString, + "MC_VERSION" to mcVersion, + "MC_NEXT_VERSION" to "1.$nextMcVersion", + "LICENSE" to license, + "DESCRIPTION" to description, + "MOD_DESCRIPTION" to description, + "MOD_ENVIRONMENT" to "*", + "FABRIC_LOADER_VERSION" to fabricLoaderVersion, + ) + + if (fabricApiVersion != null) { + assets.addTemplateProperties( + "FABRIC_API_VERSION" to fabricApiVersion, + ) + } + + if (archApiVersion != null) { + assets.addTemplateProperties( + "ARCHITECTURY_API_VERSION" to archApiVersion, + ) + } + + if (authors.isNotEmpty()) { + assets.addTemplateProperties("AUTHOR_LIST" to authors.joinToString(", ")) + } + + if (website.isNotBlank()) { + assets.addTemplateProperties("WEBSITE" to website) + } + + if (issueTracker.isNotBlank()) { + assets.addTemplateProperties("ISSUE" to issueTracker) + } + + if (packAdditionalData != null) { + assets.addTemplateProperties( + "FORGE_DATA" to packAdditionalData, + ) + } + + if (useMixins) { + assets.addTemplateProperties( + "MIXINS" to "true" + ) + val commonMixinsFile = "common/src/main/resources/${buildSystemProps.artifactId}-common.mixins.json" + val forgeMixinsFile = "forge/src/main/resources/${buildSystemProps.artifactId}.mixins.json" + val fabricMixinsFile = "fabric/src/main/resources/${buildSystemProps.artifactId}.mixins.json" + assets.addTemplates( + project, + commonMixinsFile to MinecraftTemplates.ARCHITECTURY_COMMON_MIXINS_JSON_TEMPLATE, + forgeMixinsFile to MinecraftTemplates.ARCHITECTURY_FORGE_MIXINS_JSON_TEMPLATE, + fabricMixinsFile to MinecraftTemplates.ARCHITECTURY_FABRIC_MIXINS_JSON_TEMPLATE, + ) + } + + assets.addTemplates( + project, + "forge/src/main/resources/pack.mcmeta" to MinecraftTemplates.ARCHITECTURY_FORGE_PACK_MCMETA_TEMPLATE, + "forge/src/main/resources/META-INF/mods.toml" to MinecraftTemplates.ARCHITECTURY_FORGE_MODS_TOML_TEMPLATE, + "fabric/src/main/resources/fabric.mod.json" to MinecraftTemplates.ARCHITECTURY_FABRIC_MOD_JSON_TEMPLATE, + ) + + assets.addLicense(project) + } +} + +abstract class ArchitecturyMainClassStep( + parent: NewProjectWizardStep, + phase: Int +) : AbstractLongRunningAssetsStep(parent) { + abstract val projectDir: String + abstract val template: String + abstract fun getClassName(packageName: String, className: String): String + + override val description = "Adding Architectury project files (phase $phase)" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val modName = data.getUserData(AbstractModNameStep.KEY) ?: return + val useArchApi = data.getUserData(ArchitecturyVersionChainStep.ARCHITECTURY_API_VERSION_KEY) != null + + val packageName = "${buildSystemProps.groupId.toPackageName()}.${buildSystemProps.artifactId.toPackageName()}" + val className = modName.toJavaClassName() + assets.addTemplateProperties( + "PACKAGE_NAME" to packageName, + "CLASS_NAME" to className, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "MOD_NAME" to modName, + "MOD_VERSION" to buildSystemProps.version, + "ARCHITECTURY_PACKAGE" to architecturyPackage, + ) + if (useArchApi) { + assets.addTemplateProperties("ARCHITECTURY_API" to "true") + } + + val mainClass = getClassName(packageName, className) + assets.addTemplates(project, "$projectDir/src/main/java/${mainClass.replace('.', '/')}.java" to template) + } +} + +class ArchitecturyCommonMainClassStep(parent: NewProjectWizardStep) : ArchitecturyMainClassStep(parent, 2) { + override val projectDir = "common" + override val template = MinecraftTemplates.ARCHITECTURY_COMMON_MAIN_CLASS_TEMPLATE + + override fun getClassName(packageName: String, className: String) = "$packageName.$className" +} + +class ArchitecturyForgeMainClassStep(parent: NewProjectWizardStep) : ArchitecturyMainClassStep(parent, 3) { + override val projectDir = "forge" + override val template = MinecraftTemplates.ARCHITECTURY_FORGE_MAIN_CLASS_TEMPLATE + + override fun getClassName(packageName: String, className: String) = "$packageName.forge.${className}Forge" +} + +class ArchitecturyFabricMainClassStep(parent: NewProjectWizardStep) : ArchitecturyMainClassStep(parent, 4) { + override val projectDir = "fabric" + override val template = MinecraftTemplates.ARCHITECTURY_FABRIC_MAIN_CLASS_TEMPLATE + + override fun getClassName(packageName: String, className: String) = "$packageName.fabric.${className}Fabric" +} + +class ArchitecturyBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Architectury" +} + +class ArchitecturyPostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, ArchitecturyBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/architectury/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/architectury/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,108 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.architectury.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +private val NewProjectWizardStep.architecturyGroup: String get() { + val apiVersion = data.getUserData(ArchitecturyVersionChainStep.ARCHITECTURY_API_VERSION_KEY) + return when { + apiVersion == null || apiVersion >= SemanticVersion.release(2, 0, 10) -> "dev.architectury" + else -> "me.shedaniel" + } +} + +class ArchitecturyGradleSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> ArchitecturyGradleFilesStep(parent).chain(::GradleWrapperStep) + BuildSystemSupport.POST_STEP -> GradleImportStep(parent) + else -> EmptyStep(parent) + } + } +} + +class ArchitecturyGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val modName = data.getUserData(AbstractModNameStep.KEY) ?: return + val mcVersion = data.getUserData(ArchitecturyVersionChainStep.MC_VERSION_KEY) ?: return + val forgeVersion = data.getUserData(ArchitecturyVersionChainStep.FORGE_VERSION_KEY) ?: return + val fabricLoaderVersion = data.getUserData(ArchitecturyVersionChainStep.FABRIC_LOADER_VERSION_KEY) ?: return + val fabricApiVersion = data.getUserData(ArchitecturyVersionChainStep.FABRIC_API_VERSION_KEY) + val archApiVersion = data.getUserData(ArchitecturyVersionChainStep.ARCHITECTURY_API_VERSION_KEY) + val javaVersion = findStep().preferredJdk.ordinal + + assets.addTemplateProperties( + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "MOD_NAME" to modName, + "VERSION" to buildSystemProps.version, + "MC_VERSION" to mcVersion, + "FORGE_VERSION" to "$mcVersion-$forgeVersion", + "FABRIC_LOADER_VERSION" to fabricLoaderVersion, + "ARCHITECTURY_GROUP" to architecturyGroup, + "JAVA_VERSION" to javaVersion + ) + + if (fabricApiVersion != null) { + assets.addTemplateProperties( + "FABRIC_API_VERSION" to fabricApiVersion, + "FABRIC_API" to "true", + ) + } + + if (archApiVersion != null) { + assets.addTemplateProperties( + "ARCHITECTURY_API_VERSION" to archApiVersion, + "ARCHITECTURY_API" to "true", + ) + } + + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.ARCHITECTURY_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.ARCHITECTURY_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.ARCHITECTURY_SETTINGS_GRADLE_TEMPLATE, + "common/build.gradle" to MinecraftTemplates.ARCHITECTURY_COMMON_BUILD_GRADLE_TEMPLATE, + "forge/build.gradle" to MinecraftTemplates.ARCHITECTURY_FORGE_BUILD_GRADLE_TEMPLATE, + "forge/gradle.properties" to MinecraftTemplates.ARCHITECTURY_FORGE_GRADLE_PROPERTIES_TEMPLATE, + "fabric/build.gradle" to MinecraftTemplates.ARCHITECTURY_FABRIC_BUILD_GRADLE_TEMPLATE, + ) + + assets.addGradleWrapperProperties(project) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} Index: src/main/kotlin/platform/architectury/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/architectury/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/architectury/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,203 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.architectury.creator + +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.platformtype.ModPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractMcVersionChainStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.IssueTrackerStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.ModNameStep +import com.demonwav.mcdev.creator.step.RepositoryStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.architectury.ArchitecturyVersion +import com.demonwav.mcdev.platform.fabric.util.FabricApiVersions +import com.demonwav.mcdev.platform.fabric.util.FabricVersions +import com.demonwav.mcdev.platform.forge.version.ForgeVersion +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.demonwav.mcdev.util.bindEnabled +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.observable.util.bindBooleanStorage +import com.intellij.openapi.observable.util.transform +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.util.Key +import com.intellij.ui.JBColor +import com.intellij.ui.dsl.builder.Cell +import com.intellij.ui.dsl.builder.EMPTY_LABEL +import com.intellij.ui.dsl.builder.Row +import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.bindText +import com.intellij.util.IncorrectOperationException +import kotlinx.coroutines.coroutineScope + +class ArchitecturyPlatformStep(parent: ModPlatformStep) : AbstractLatentStep(parent) { + override val description = "download Forge, Fabric and Architectury versions" + + override suspend fun computeData() = coroutineScope { + val forgeJob = asyncIO { ForgeVersion.downloadData() } + val fabricJob = asyncIO { FabricVersions.downloadData() } + val fabricApiJob = asyncIO { FabricApiVersions.downloadData() } + val archJob = asyncIO { ArchitecturyVersion.downloadData() } + + val forge = forgeJob.await() ?: return@coroutineScope null + val fabric = fabricJob.await() ?: return@coroutineScope null + val fabricApi = fabricApiJob.await() ?: return@coroutineScope null + val arch = archJob.await() ?: return@coroutineScope null + + ArchitecturyVersionData(forge, fabric, fabricApi, arch) + } + + override fun createStep(data: ArchitecturyVersionData): NewProjectWizardStep { + return ArchitecturyVersionChainStep(this, data).chain( + ::UseMixinsStep, + ::ModNameStep, + ::LicenseStep, + ::ArchitecturyOptionalSettingsStep, + ::ArchitecturyBuildSystemStep, + ::ArchitecturyProjectFilesStep, + ::ArchitecturyCommonMainClassStep, + ::ArchitecturyForgeMainClassStep, + ::ArchitecturyFabricMainClassStep, + ::ArchitecturyPostBuildSystemStep, + ) + } + + class Factory : ModPlatformStep.Factory { + override val name = "Architectury" + override fun createStep(parent: ModPlatformStep) = ArchitecturyPlatformStep(parent) + } +} + +class ArchitecturyVersionChainStep( + parent: NewProjectWizardStep, + private val versionData: ArchitecturyVersionData +) : AbstractMcVersionChainStep( + parent, + "Forge Version:", + "Fabric Loader Version:", + "Fabric API Version:", + "Architectury API Version:", +) { + companion object { + private const val FORGE_VERSION = 1 + private const val FABRIC_LOADER_VERSION = 2 + private const val FABRIC_API_VERSION = 3 + private const val ARCHITECTURY_API_VERSION = 4 + + val MC_VERSION_KEY = + Key.create("${ArchitecturyVersionChainStep::class.java.name}.mcVersion") + val FORGE_VERSION_KEY = + Key.create("${ArchitecturyVersionChainStep::class.java.name}.forgeVersion") + val FABRIC_LOADER_VERSION_KEY = + Key.create("${ArchitecturyVersionChainStep::class.java.name}.fabricLoaderVersion") + val FABRIC_API_VERSION_KEY = + Key.create("${ArchitecturyVersionChainStep::class.java.name}.fabricApiVersion") + val ARCHITECTURY_API_VERSION_KEY = + Key.create("${ArchitecturyVersionChainStep::class.java.name}.architecturyApiVersion") + } + + private val mcVersions by lazy { + versionData.architecturyVersions.versions.keys + .intersect(versionData.forgeVersions.sortedMcVersions.toSet()) + .intersect( + versionData.fabricVersions.game.mapNotNullTo(mutableSetOf()) { + SemanticVersion.tryParse(it.version) + } + ) + .toList() + } + + private val useFabricApiProperty = propertyGraph.property(true) + .bindBooleanStorage("${javaClass.name}.useFabricApi") + private var useFabricApi by useFabricApiProperty + + private val useArchApiProperty = propertyGraph.property(true) + .bindBooleanStorage("${javaClass.name}.useArchApi") + private var useArchApi by useArchApiProperty + + override fun createComboBox(row: Row, index: Int, items: List>): Cell>> { + return when (index) { + FABRIC_API_VERSION -> { + val comboBox = super.createComboBox(row, index, items).bindEnabled(useFabricApiProperty) + row.checkBox("Use Fabric API").bindSelected(useFabricApiProperty) + row.label(EMPTY_LABEL).bindText( + getVersionProperty(MINECRAFT_VERSION).transform { mcVersion -> + val versionStr = mcVersion.toString() + val matched = versionData.fabricApiVersions.versions.any { versionStr in it.gameVersions } + if (matched) { + EMPTY_LABEL + } else { + "Unable to match API versions to Minecraft version" + } + } + ).bindEnabled(useFabricApiProperty).component.foreground = JBColor.YELLOW + comboBox + } + ARCHITECTURY_API_VERSION -> { + val comboBox = super.createComboBox(row, index, items).bindEnabled(useArchApiProperty) + row.checkBox("Use Architectury API").bindSelected(useArchApiProperty) + comboBox + } + else -> super.createComboBox(row, index, items) + } + } + + override fun getAvailableVersions(versionsAbove: List>): List> { + val mcVersion by lazy { versionsAbove[MINECRAFT_VERSION] as SemanticVersion } + + return when (versionsAbove.size) { + MINECRAFT_VERSION -> mcVersions + FORGE_VERSION -> versionData.forgeVersions.getForgeVersions(mcVersion) + FABRIC_LOADER_VERSION -> versionData.fabricVersions.loader + FABRIC_API_VERSION -> { + val versionStr = mcVersion.toString() + val apiVersions = versionData.fabricApiVersions.versions + .filter { versionStr in it.gameVersions } + .map { it.version } + apiVersions.ifEmpty { versionData.fabricApiVersions.versions.map { it.version } } + } + ARCHITECTURY_API_VERSION -> versionData.architecturyVersions.getArchitecturyVersions(mcVersion) + else -> throw IncorrectOperationException() + } + } + + override fun setupProject(project: Project) { + super.setupProject(project) + data.putUserData(MC_VERSION_KEY, getVersion(MINECRAFT_VERSION) as SemanticVersion) + data.putUserData(FORGE_VERSION_KEY, getVersion(FORGE_VERSION) as SemanticVersion) + data.putUserData(FABRIC_LOADER_VERSION_KEY, getVersion(FABRIC_LOADER_VERSION) as SemanticVersion) + if (useFabricApi) { + data.putUserData(FABRIC_API_VERSION_KEY, getVersion(FABRIC_API_VERSION) as SemanticVersion) + } + if (useArchApi) { + data.putUserData(ARCHITECTURY_API_VERSION_KEY, getVersion(ARCHITECTURY_API_VERSION) as SemanticVersion) + } + } +} + +class ArchitecturyOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::RepositoryStep, + ::IssueTrackerStep, + ) +} Index: src/main/kotlin/platform/architectury/version/ArchitecturyVersion.kt =================================================================== --- src/main/kotlin/platform/architectury/version/ArchitecturyVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/version/ArchitecturyVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,87 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.version - -import com.demonwav.mcdev.creator.selectProxy -import com.demonwav.mcdev.update.PluginUtil -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.fromJson -import com.github.kittinunf.fuel.core.FuelManager -import com.github.kittinunf.fuel.core.requests.suspendable -import com.github.kittinunf.fuel.coroutines.awaitString -import com.google.gson.Gson -import com.google.gson.annotations.SerializedName -import com.intellij.openapi.diagnostic.logger -import java.io.IOException - -class ArchitecturyVersion private constructor( - val versions: Map>, -) { - - fun getArchitecturyVersions(mcVersion: SemanticVersion): List { - return try { - val architecturyVersions = versions[mcVersion] - ?: throw IOException("Could not find any architectury versions for $mcVersion") - architecturyVersions.take(50) - } catch (e: IOException) { - e.printStackTrace() - emptyList() - } - } - - data class ModrinthVersionApi( - @SerializedName("version_number") - val versionNumber: String, - @SerializedName("game_versions") - val gameVersions: List, - ) - - companion object { - private val LOGGER = logger() - - suspend fun downloadData(): ArchitecturyVersion? { - try { - val url = "https://api.modrinth.com/v2/project/architectury-api/version" - val manager = FuelManager() - manager.proxy = selectProxy(url) - - val response = manager.get(url) - .header("User-Agent", PluginUtil.useragent) - .suspendable() - .awaitString() - - val data = Gson().fromJson>(response) - - val apiVersionMap = HashMap>() - - for (version in data) { - val apiVersion = SemanticVersion.parse(version.versionNumber.substringBeforeLast('+')) - - for (gameVersion in version.gameVersions) { - val parsed = SemanticVersion.parse(gameVersion) - val set = apiVersionMap.computeIfAbsent(parsed) { HashSet() } - set += apiVersion - } - } - - val apiVersionMapList = HashMap>() - for ((mcVersion, archList) in apiVersionMap.entries) { - apiVersionMapList[mcVersion] = archList.sortedDescending() - } - - return ArchitecturyVersion(apiVersionMapList) - } catch (e: IOException) { - LOGGER.error("Failed to retrieve Architectury version data", e) - } - return null - } - } -} Index: src/main/kotlin/platform/architectury/version/FabricVersion.kt =================================================================== --- src/main/kotlin/platform/architectury/version/FabricVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/architectury/version/FabricVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,65 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.architectury.version - -import com.demonwav.mcdev.util.SemanticVersion -import com.extracraftx.minecraft.templatemakerfabric.data.DataProvider -import com.extracraftx.minecraft.templatemakerfabric.data.holders.LoaderVersion -import com.intellij.openapi.diagnostic.logger -import java.io.IOException - -class FabricVersion private constructor(val versions: DataProvider) { - - fun getFabricVersions(mcVersion: SemanticVersion): List { - val versionText = mcVersion.toString() - return versions.getFilteredLoaderVersions( - versions.getDefaultLoomVersion( - versions.getFilteredYarnVersions( - versions.getNormalizedMinecraftVersion(versionText) - ).firstOrNull() - ) - ) - .map { loaderVersion: LoaderVersion -> - SemanticVersion.parse(loaderVersion.toString()) - } - .sortedDescending() - .take(50) - .toList() - } - - fun getFabricApiVersions(mcVersion: SemanticVersion): List { - val versionText = mcVersion.toString() - return versions.sortedFabricApiVersions.filter { indexedFabricApiVersion -> - indexedFabricApiVersion.mcVersion.equals( - versionText - ) - }.map { indexedFabricApiVersion -> SemanticVersion.parse(indexedFabricApiVersion.mavenVersion) } - .sortedDescending().take(50) - } - - companion object { - private val LOGGER = logger() - private val dataProvider: DataProvider = DataProvider() - - fun downloadData(): FabricVersion? { - try { - dataProvider.loaderVersions - dataProvider.loomVersions - dataProvider.yarnVersions - dataProvider.fabricApiVersions - return FabricVersion(dataProvider) - } catch (e: IOException) { - LOGGER.error("Failed to retrieve Fabric version data", e) - } - return null - } - } -} Index: src/main/kotlin/platform/bukkit/creator/BukkitProjectConfig.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/BukkitProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/creator/BukkitProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,86 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bukkit.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.bukkit.BukkitLikeConfiguration -import com.demonwav.mcdev.platform.bukkit.data.LoadOrder -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class BukkitProjectConfig(override var type: PlatformType) : - ProjectConfig(), BukkitLikeConfiguration, MavenCreator, GradleCreator { - - override lateinit var mainClass: String - - var loadOrder: LoadOrder = LoadOrder.POSTWORLD - var minecraftVersion: String = "" - val semanticMinecraftVersion: SemanticVersion - get() = if (minecraftVersion.isBlank()) SemanticVersion.release() else SemanticVersion.parse(minecraftVersion) - - var prefix: String? = null - fun hasPrefix() = prefix?.isNotBlank() == true - - var loadBefore: MutableList = mutableListOf() - fun hasLoadBefore() = listContainsAtLeastOne(loadBefore) - fun setLoadBefore(string: String) { - loadBefore.clear() - loadBefore.addAll(commaSplit(string)) - } - - override val dependencies = mutableListOf() - override fun hasDependencies() = listContainsAtLeastOne(dependencies) - override fun setDependencies(string: String) { - dependencies.clear() - dependencies.addAll(commaSplit(string)) - } - - override val softDependencies = mutableListOf() - override fun hasSoftDependencies() = listContainsAtLeastOne(softDependencies) - override fun setSoftDependencies(string: String) { - softDependencies.clear() - softDependencies.addAll(commaSplit(string)) - } - - override val preferredBuildSystem = BuildSystemType.MAVEN - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(semanticMinecraftVersion) - - override val compatibleGradleVersions: VersionRange? = null - - override fun buildMavenCreator( - rootDirectory: Path, - module: Module, - buildSystem: MavenBuildSystem - ): ProjectCreator { - return BukkitMavenCreator(rootDirectory, module, buildSystem, this) - } - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return BukkitGradleCreator(rootDirectory, module, buildSystem, this) - } -} Index: src/main/kotlin/platform/bukkit/creator/BukkitProjectCreator.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/BukkitProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/creator/BukkitProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,188 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bukkit.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.BuildDependency -import com.demonwav.mcdev.creator.buildsystem.BuildRepository -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleSetupStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenGitignoreStep -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import java.nio.file.Path - -sealed class BukkitProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: T, - protected val config: BukkitProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - protected fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - BukkitTemplate.applyMainClass(project, packageName, className) - } - } - - protected fun setupDependencyStep(): BukkitDependenciesStep { - val mcVersion = config.minecraftVersion - return BukkitDependenciesStep(buildSystem, config.type, mcVersion) - } - - protected fun setupYmlStep(): PluginYmlStep { - return PluginYmlStep(project, buildSystem, config) - } -} - -class BukkitMavenCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: MavenBuildSystem, - config: BukkitProjectConfig -) : BukkitProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val pomText = BukkitTemplate.applyPom(project) - return listOf( - setupDependencyStep(), - BasicMavenStep(project, rootDirectory, buildSystem, config, pomText), - setupMainClassStep(), - setupYmlStep(), - MavenGitignoreStep(project, rootDirectory), - BasicMavenFinalizerStep(rootModule, rootDirectory) - ) - } -} - -class BukkitGradleCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: BukkitProjectConfig -) : BukkitProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val buildText = BukkitTemplate.applyBuildGradle(project, buildSystem, config) - val propText = BukkitTemplate.applyGradleProp(project) - val settingsText = BukkitTemplate.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - setupDependencyStep(), - CreateDirectoriesStep(buildSystem, rootDirectory), - GradleSetupStep(project, rootDirectory, buildSystem, files), - setupMainClassStep(), - setupYmlStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - } -} - -open class BukkitDependenciesStep( - protected val buildSystem: BuildSystem, - protected val type: PlatformType, - protected val mcVersion: String -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - when (type) { - PlatformType.PAPER -> { - buildSystem.repositories.add( - BuildRepository( - "papermc-repo", - "https://repo.papermc.io/repository/maven-public/" - ) - ) - val paperGroupId = when { - SemanticVersion.parse(mcVersion) >= MinecraftVersions.MC1_17 -> "io.papermc.paper" - else -> "com.destroystokyo.paper" - } - buildSystem.dependencies.add( - BuildDependency( - paperGroupId, - "paper-api", - "$mcVersion-R0.1-SNAPSHOT", - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - addSonatype(buildSystem.repositories) - } - PlatformType.SPIGOT -> { - spigotRepo(buildSystem.repositories) - buildSystem.dependencies.add( - BuildDependency( - "org.spigotmc", - "spigot-api", - "$mcVersion-R0.1-SNAPSHOT", - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - addSonatype(buildSystem.repositories) - } - PlatformType.BUKKIT -> { - spigotRepo(buildSystem.repositories) - buildSystem.dependencies.add( - BuildDependency( - "org.bukkit", - "bukkit", - "$mcVersion-R0.1-SNAPSHOT", - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - } - else -> {} - } - } - - protected fun addSonatype(buildRepositories: MutableList) { - buildRepositories.add(BuildRepository("sonatype", "https://oss.sonatype.org/content/groups/public/")) - } - - private fun spigotRepo(list: MutableList) { - list.add( - BuildRepository( - "spigotmc-repo", - "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" - ) - ) - } -} - -class PluginYmlStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: BukkitProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val text = BukkitTemplate.applyPluginYml(project, config, buildSystem) - CreatorStep.writeTextToFile(project, buildSystem.dirsOrError.resourceDirectory, "plugin.yml", text) - } -} Index: src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,299 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/creator/BukkitProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,131 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bukkit.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.creator.getVersionSelector -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.bukkit.data.LoadOrder -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JTextField -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import kotlinx.coroutines.withContext - -class BukkitProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - @ValidatedField(NON_BLANK) - private lateinit var pluginNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var panel: JPanel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - private lateinit var prefixField: JTextField - private lateinit var loadOrderBox: JComboBox<*> - private lateinit var loadBeforeField: JTextField - - @ValidatedField(LIST) - private lateinit var dependField: JTextField - private lateinit var softDependField: JTextField - private lateinit var title: JLabel - private lateinit var minecraftVersionBox: JComboBox - private lateinit var errorLabel: JLabel - - private var config: BukkitProjectConfig? = null - - private var versionsLoaded: Boolean = false - - override fun getComponent(): JComponent { - return panel - } - - override fun isStepVisible(): Boolean { - return creator.config is BukkitProjectConfig - } - - override fun updateStep() { - config = creator.config as? BukkitProjectConfig - if (config == null) { - return - } - val conf = config ?: return - - basicUpdateStep(creator, pluginNameField, mainClassField) - - when (conf.type) { - PlatformType.BUKKIT -> { - title.icon = PlatformAssets.BUKKIT_ICON_2X - title.text = "Bukkit Settings" - } - PlatformType.SPIGOT -> { - title.icon = PlatformAssets.SPIGOT_ICON_2X - title.text = "Spigot Settings" - } - PlatformType.PAPER -> { - title.icon = PlatformAssets.PAPER_ICON_2X - title.text = "Paper Settings" - } - else -> { - } - } - - if (versionsLoaded) { - return - } - - versionsLoaded = true - CoroutineScope(Dispatchers.Swing).launch { - try { - withContext(Dispatchers.IO) { getVersionSelector(conf.type) }.set(minecraftVersionBox) - } catch (e: Exception) { - errorLabel.isVisible = true - } - } - } - - override fun validate(): Boolean { - return super.validate() && minecraftVersionBox.selectedItem != null - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.pluginNameField.text - conf.mainClass = this.mainClassField.text - conf.description = this.descriptionField.text - conf.website = this.websiteField.text - - conf.loadOrder = if (this.loadOrderBox.selectedIndex == 0) LoadOrder.POSTWORLD else LoadOrder.STARTUP - conf.prefix = this.prefixField.text - conf.minecraftVersion = this.minecraftVersionBox.selectedItem as String - - conf.setLoadBefore(this.loadBeforeField.text) - conf.setAuthors(this.authorsField.text) - conf.setDependencies(this.dependField.text) - conf.setSoftDependencies(this.softDependField.text) - } -} Index: src/main/kotlin/platform/bukkit/creator/BukkitTemplate.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/BukkitTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/creator/BukkitTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,151 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bukkit.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.bukkit.BukkitLikeConfiguration -import com.demonwav.mcdev.platform.bukkit.BukkitModuleType -import com.demonwav.mcdev.platform.bukkit.data.LoadOrder -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_PLUGIN_YML_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_SUBMODULE_POM_TEMPLATE -import com.intellij.openapi.project.Project - -object BukkitTemplate : BaseTemplate() { - - fun applyMainClass( - project: Project, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE" to packageName, - "CLASS_NAME" to className - ) - - return project.applyTemplate(BUKKIT_MAIN_CLASS_TEMPLATE, props) - } - - fun applyPom(project: Project): String { - return project.applyTemplate(BUKKIT_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applySubPom(project: Project): String { - return project.applyTemplate(BUKKIT_SUBMODULE_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem, config: BukkitProjectConfig): String { - val props = mapOf( - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_VERSION" to buildSystem.version, - "JAVA_VERSION" to config.javaVersion.feature - ) - - return project.applyTemplate(BUKKIT_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(BUKKIT_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(BUKKIT_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName - ) - - return project.applyTemplate(BUKKIT_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyPluginYml( - project: Project, - config: BukkitProjectConfig, - buildSystem: BuildSystem - ): String { - fun bukkitDeps(props: MutableMap, configuration: BukkitLikeConfiguration) { - if (configuration.hasDependencies()) { - props["DEPEND"] = configuration.dependencies.toString() - } - if (configuration.hasSoftDependencies()) { - props["SOFT_DEPEND"] = configuration.softDependencies.toString() - } - } - - val props = bukkitMain(buildSystem.type, config) - - if (config.hasPrefix()) { - props["PREFIX"] = config.prefix ?: throw IllegalStateException("prefix is null when not blank") - } - - if (config.loadOrder != LoadOrder.POSTWORLD) { - props["LOAD"] = LoadOrder.STARTUP.name - } - - if (config.hasLoadBefore()) { - props["LOAD_BEFORE"] = config.loadBefore.toString() - } - - bukkitDeps(props, config) - - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.toString() - } - - if (config.hasDescription()) { - props["DESCRIPTION"] = config.description - ?: throw IllegalStateException("description is null when not blank") - } - - if (config.hasWebsite()) { - props["WEBSITE"] = config.website ?: throw IllegalStateException("website is null when not blank") - } - - // Plugins targeting 1.13 or newer need an explicit api declaration flag - // This is the major and minor version separated by a dot without the patch version. ex: 1.15 even for 1.15.2 - val mcVersion = config.semanticMinecraftVersion - if (mcVersion >= BukkitModuleType.API_TAG_VERSION) { - props["API_VERSION"] = mcVersion.take(2).toString() - } - - return project.applyTemplate(BUKKIT_PLUGIN_YML_TEMPLATE, props) - } - - fun bukkitMain(type: BuildSystemType, config: C): MutableMap - where C : ProjectConfig, - C : BukkitLikeConfiguration { - val version = when (type) { - BuildSystemType.GRADLE -> "\${version}" - BuildSystemType.MAVEN -> "\${project.version}" - } - - return mutableMapOf( - "MAIN" to config.mainClass, - "VERSION" to version, - "NAME" to config.pluginName - ) - } -} Index: src/main/kotlin/platform/bukkit/creator/LoadOrder.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/LoadOrder.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/LoadOrder.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,18 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +enum class LoadOrder(private val myName: String) { + STARTUP("Startup"), + POSTWORLD("Post World"); + + override fun toString() = myName +} Index: src/main/kotlin/platform/bukkit/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,116 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.creator.step.SoftDependStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.bukkit.BukkitModuleType +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key + +class BukkitProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating project files" + + override fun setupAssets(project: Project) { + val pluginName = data.getUserData(AbstractModNameStep.KEY) ?: return + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val versionRef = data.getUserData(VERSION_REF_KEY) ?: "\${version}" + val prefix = data.getUserData(BukkitLogPrefixStep.KEY) ?: "" + val loadOrder = data.getUserData(BukkitLoadOrderStep.KEY) ?: return + val loadBefore = data.getUserData(BukkitLoadBeforeStep.KEY) ?: emptyList() + val deps = data.getUserData(DependStep.KEY) ?: emptyList() + val softDeps = data.getUserData(SoftDependStep.KEY) ?: emptyList() + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val website = data.getUserData(WebsiteStep.KEY) ?: "" + val mcVersion = data.getUserData(SimpleMcVersionStep.KEY) ?: return + + val (packageName, className) = splitPackage(mainClass) + + assets.addTemplateProperties( + "MAIN" to mainClass, + "VERSION" to versionRef, + "NAME" to pluginName, + "PACKAGE" to packageName, + "CLASS_NAME" to className, + ) + + if (prefix.isNotBlank()) { + assets.addTemplateProperties("PREFIX" to prefix) + } + + if (loadOrder != LoadOrder.POSTWORLD) { + assets.addTemplateProperties("LOAD" to loadOrder.name) + } + + if (loadBefore.isNotEmpty()) { + assets.addTemplateProperties("LOAD_BEFORE" to loadBefore) + } + + if (deps.isNotEmpty()) { + assets.addTemplateProperties("DEPEND" to deps) + } + + if (softDeps.isNotEmpty()) { + assets.addTemplateProperties("SOFT_DEPEND" to softDeps) + } + + if (authors.isNotEmpty()) { + assets.addTemplateProperties("AUTHOR_LIST" to authors) + } + + if (description.isNotBlank()) { + assets.addTemplateProperties("DESCRIPTION" to description) + } + + if (website.isNotEmpty()) { + assets.addTemplateProperties("WEBSITE" to website) + } + + if (mcVersion >= BukkitModuleType.API_TAG_VERSION) { + assets.addTemplateProperties("API_VERSION" to mcVersion.take(2)) + } + + assets.addTemplates( + project, + "src/main/resources/plugin.yml" to MinecraftTemplates.BUKKIT_PLUGIN_YML_TEMPLATE, + "src/main/java/${mainClass.replace('.', '/')}.java" to MinecraftTemplates.BUKKIT_MAIN_CLASS_TEMPLATE, + ) + } + + companion object { + val VERSION_REF_KEY = Key.create("${BukkitProjectFilesStep::class.java.name}.versionRef") + } +} + +class BukkitBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Bukkit" +} + +class BukkitPostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, BukkitBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/bukkit/creator/bukkit-platforms.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/bukkit-platforms.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/bukkit-platforms.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,81 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.platform.PlatformType +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion + +class SpigotPlatformStep(parent: BukkitPlatformStep) : AbstractBukkitPlatformStep(parent, PlatformType.SPIGOT) { + override fun getRepositories(mcVersion: SemanticVersion) = listOf( + BuildRepository( + "spigotmc-repo", + "https://hub.spigotmc.org/nexus/content/repositories/snapshots/" + ), + BuildRepository( + "sonatype", + "https://oss.sonatype.org/content/groups/public/" + ), + ) + + override fun getDependencies(mcVersion: SemanticVersion) = listOf( + BuildDependency( + "org.spigotmc", + "spigot-api", + "$mcVersion-R0.1-SNAPSHOT", + mavenScope = "provided", + gradleConfiguration = "compileOnly", + ) + ) + + class Factory : BukkitPlatformStep.Factory { + override val name = "Spigot" + + override fun createStep(parent: BukkitPlatformStep) = SpigotPlatformStep(parent) + } +} + +class PaperPlatformStep(parent: BukkitPlatformStep) : AbstractBukkitPlatformStep(parent, PlatformType.PAPER) { + override fun getRepositories(mcVersion: SemanticVersion) = listOf( + BuildRepository( + "papermc-repo", + "https://repo.papermc.io/repository/maven-public/" + ), + BuildRepository( + "sonatype", + "https://oss.sonatype.org/content/groups/public/" + ), + ) + + override fun getDependencies(mcVersion: SemanticVersion): List { + val paperGroupId = when { + mcVersion >= MinecraftVersions.MC1_17 -> "io.papermc.paper" + else -> "com.destroystokyo.paper" + } + return listOf( + BuildDependency( + paperGroupId, + "paper-api", + "$mcVersion-R0.1-SNAPSHOT", + mavenScope = "provided", + gradleConfiguration = "compileOnly" + ) + ) + } + + class Factory : BukkitPlatformStep.Factory { + override val name = "Paper" + + override fun createStep(parent: BukkitPlatformStep) = PaperPlatformStep(parent) + } +} Index: src/main/kotlin/platform/bukkit/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,81 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchGradleFilesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.ReformatBuildGradleStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +class BukkitGradleSupport : BuildSystemSupport { + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> BukkitGradleFilesStep(parent).chain( + ::BukkitPatchBuildGradleStep, + ::GradleWrapperStep + ) + BuildSystemSupport.POST_STEP -> GradleImportStep(parent).chain(::ReformatBuildGradleStep) + else -> EmptyStep(parent) + } + } +} + +class BukkitGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val javaVersion = findStep().preferredJdk.ordinal + assets.addTemplateProperties( + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "PLUGIN_VERSION" to buildSystemProps.version, + "JAVA_VERSION" to javaVersion, + ) + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.BUKKIT_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.BUKKIT_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.BUKKIT_SETTINGS_GRADLE_TEMPLATE, + ) + assets.addGradleWrapperProperties(project) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} + +class BukkitPatchBuildGradleStep(parent: NewProjectWizardStep) : AbstractPatchGradleFilesStep(parent) { + override fun patch(project: Project, gradleFiles: GradleFiles) { + val platform = data.getUserData(AbstractBukkitPlatformStep.KEY) ?: return + val mcVersion = data.getUserData(SimpleMcVersionStep.KEY) ?: return + val repositories = platform.getRepositories(mcVersion) + val dependencies = platform.getDependencies(mcVersion) + addRepositories(project, gradleFiles.buildGradle, repositories) + addDependencies(project, gradleFiles.buildGradle, dependencies) + } +} Index: src/main/kotlin/platform/bukkit/creator/maven-steps.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,65 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.addMavenGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchPomStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.MavenImportStep +import com.demonwav.mcdev.creator.buildsystem.ReformatPomStep +import com.demonwav.mcdev.creator.buildsystem.addDefaultMavenProperties +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.psi.xml.XmlTag +import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel + +class BukkitMavenSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> BukkitMavenFilesStep(parent).chain(::BukkitPatchPomStep) + BuildSystemSupport.POST_STEP -> MavenImportStep(parent).chain(::ReformatPomStep) + else -> EmptyStep(parent) + } + } +} + +class BukkitMavenFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Maven files" + + override fun setupAssets(project: Project) { + data.putUserData(BukkitProjectFilesStep.VERSION_REF_KEY, "\${project.version}") + assets.addDefaultMavenProperties() + assets.addTemplates(project, "pom.xml" to MinecraftTemplates.BUKKIT_POM_TEMPLATE) + if (gitEnabled) { + assets.addMavenGitignore(project) + } + } +} + +class BukkitPatchPomStep(parent: NewProjectWizardStep) : AbstractPatchPomStep(parent) { + override fun patchPom(model: MavenDomProjectModel, root: XmlTag) { + super.patchPom(model, root) + val platform = data.getUserData(AbstractBukkitPlatformStep.KEY) ?: return + val mcVersion = data.getUserData(SimpleMcVersionStep.KEY) ?: return + val repositories = platform.getRepositories(mcVersion) + val dependencies = platform.getDependencies(mcVersion) + setupDependencies(model, repositories, dependencies) + } +} Index: src/main/kotlin/platform/bukkit/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/bukkit/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bukkit/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,165 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bukkit.creator + +import com.demonwav.mcdev.creator.PlatformVersion +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.getVersionSelector +import com.demonwav.mcdev.creator.platformtype.PluginPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractOptionalStringStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.PluginNameStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.creator.step.SoftDependStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.PlatformType +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.observable.util.transform +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel +import kotlinx.coroutines.coroutineScope + +class BukkitPlatformStep( + parent: PluginPlatformStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.bukkitPlatformWizard") + } + + override val self = this + override val label = "Bukkit Platform:" + + class PlatformFactory : PluginPlatformStep.Factory { + override val name = "Bukkit" + + override fun createStep(parent: PluginPlatformStep) = BukkitPlatformStep(parent) + } + + interface Factory : NewProjectWizardMultiStepFactory +} + +abstract class AbstractBukkitPlatformStep( + parent: BukkitPlatformStep, + private val platform: PlatformType +) : AbstractLatentStep(parent) { + override val description = "download versions" + + override suspend fun computeData() = coroutineScope { + try { + asyncIO { getVersionSelector(platform) }.await() + } catch (e: Throwable) { + null + } + } + + override fun createStep(data: PlatformVersion) = + SimpleMcVersionStep(this, data.versions.mapNotNull(SemanticVersion::tryParse)).chain( + ::PluginNameStep, + ::MainClassStep, + ::BukkitOptionalSettingsStep, + ::BukkitBuildSystemStep, + ::BukkitProjectFilesStep, + ::BukkitPostBuildSystemStep, + ) + + override fun setupProject(project: Project) { + data.putUserData(KEY, this) + super.setupProject(project) + } + + abstract fun getRepositories(mcVersion: SemanticVersion): List + + abstract fun getDependencies(mcVersion: SemanticVersion): List + + companion object { + val KEY = Key.create("${AbstractBukkitPlatformStep::class.java.name}.platform") + } +} + +class BukkitOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::BukkitLogPrefixStep, + ::BukkitLoadOrderStep, + ::BukkitLoadBeforeStep, + ::DependStep, + ::SoftDependStep, + ) +} + +class BukkitLogPrefixStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Log Prefix:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, value) + } + + companion object { + val KEY = Key.create("${BukkitLogPrefixStep::class.java.name}.logPrefix") + } +} + +class BukkitLoadOrderStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private val loadOrderProperty = propertyGraph.property(LoadOrder.POSTWORLD) + private var loadOrder by loadOrderProperty + + init { + loadOrderProperty.transform(LoadOrder::name, LoadOrder::valueOf) + .bindStorage("${javaClass.name}.loadOrder") + } + + override fun setupUI(builder: Panel) { + with(builder) { + row("Load at:") { + segmentedButton(LoadOrder.values().toList(), LoadOrder::toString) + .bind(loadOrderProperty) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, loadOrder) + } + + companion object { + val KEY = Key.create("${BukkitLoadOrderStep::class.java.name}.loadOrder") + } +} + +class BukkitLoadBeforeStep(parent: NewProjectWizardStep) : AbstractOptionalStringStep(parent) { + override val label = "Load Before:" + + override fun setupProject(project: Project) { + data.putUserData(KEY, AuthorsStep.parseAuthors(value)) + } + + companion object { + val KEY = Key.create>("${BukkitLoadBeforeStep::class.java.name}.loadBefore") + } +} Index: src/main/kotlin/platform/bukkit/data/LoadOrder.kt =================================================================== --- src/main/kotlin/platform/bukkit/data/LoadOrder.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bukkit/data/LoadOrder.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,16 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bukkit.data - -enum class LoadOrder { - STARTUP, - POSTWORLD -} Index: src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectConfig.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,74 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bungeecord.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.bukkit.BukkitLikeConfiguration -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class BungeeCordProjectConfig(override var type: PlatformType) : - ProjectConfig(), MavenCreator, GradleCreator, BukkitLikeConfiguration { - - override lateinit var mainClass: String - - var minecraftVersion = "" - val semanticMinecraftVersion: SemanticVersion - get() = if (minecraftVersion.isBlank()) SemanticVersion.release() else SemanticVersion.parse(minecraftVersion) - - override val dependencies = mutableListOf() - override fun hasDependencies() = listContainsAtLeastOne(dependencies) - override fun setDependencies(string: String) { - dependencies.clear() - dependencies.addAll(commaSplit(string)) - } - - override val softDependencies = mutableListOf() - override fun hasSoftDependencies() = listContainsAtLeastOne(softDependencies) - override fun setSoftDependencies(string: String) { - softDependencies.clear() - softDependencies.addAll(commaSplit(string)) - } - - override val preferredBuildSystem = BuildSystemType.MAVEN - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(semanticMinecraftVersion) - - override val compatibleGradleVersions: VersionRange? = null - - override fun buildMavenCreator( - rootDirectory: Path, - module: Module, - buildSystem: MavenBuildSystem - ): ProjectCreator { - return BungeeCordMavenCreator(rootDirectory, module, buildSystem, this) - } - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return BungeeCordGradleCreator(rootDirectory, module, buildSystem, this) - } -} Index: src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectCreator.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,157 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bungeecord.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.BuildDependency -import com.demonwav.mcdev.creator.buildsystem.BuildRepository -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleSetupStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenGitignoreStep -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.bukkit.creator.BukkitDependenciesStep -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import java.nio.file.Path - -sealed class BungeeCordProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: T, - protected val config: BungeeCordProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - protected fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - BungeeCordTemplate.applyMainClass(project, packageName, className) - } - } - - protected fun setupDependencyStep(): BungeeCordDependenciesStep { - val mcVersion = config.minecraftVersion - return BungeeCordDependenciesStep(buildSystem, config.type, mcVersion) - } - - protected fun setupYmlStep(): BungeeYmlStep { - return BungeeYmlStep(project, buildSystem, config) - } -} - -class BungeeCordMavenCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: MavenBuildSystem, - config: BungeeCordProjectConfig -) : BungeeCordProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val pomText = BungeeCordTemplate.applyPom(project) - return listOf( - setupDependencyStep(), - BasicMavenStep(project, rootDirectory, buildSystem, config, pomText), - setupMainClassStep(), - setupYmlStep(), - MavenGitignoreStep(project, rootDirectory), - BasicMavenFinalizerStep(rootModule, rootDirectory) - ) - } -} - -class BungeeCordGradleCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: BungeeCordProjectConfig -) : BungeeCordProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val buildText = BungeeCordTemplate.applyBuildGradle(project, buildSystem) - val projectText = BungeeCordTemplate.applyGradleProp(project) - val settingsText = BungeeCordTemplate.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, projectText, settingsText) - - return listOf( - setupDependencyStep(), - CreateDirectoriesStep(buildSystem, rootDirectory), - GradleSetupStep(project, rootDirectory, buildSystem, files), - setupMainClassStep(), - setupYmlStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - } -} - -class BungeeCordDependenciesStep( - buildSystem: BuildSystem, - type: PlatformType, - mcVersion: String -) : BukkitDependenciesStep(buildSystem, type, mcVersion) { - override fun runStep(indicator: ProgressIndicator) { - addSonatype(buildSystem.repositories) - when (type) { - PlatformType.WATERFALL -> { - buildSystem.repositories.add( - BuildRepository( - "papermc-repo", - "https://repo.papermc.io/repository/maven-public/" - ) - ) - buildSystem.dependencies.add( - BuildDependency( - "io.github.waterfallmc", - "waterfall-api", - "$mcVersion-SNAPSHOT", - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - } - PlatformType.BUNGEECORD -> { - buildSystem.dependencies.add( - BuildDependency( - "net.md-5", - "bungeecord-api", - mcVersion, - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - } - else -> { - } - } - } -} - -class BungeeYmlStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: BungeeCordProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val text = BungeeCordTemplate.applyBungeeYml(project, config, buildSystem) - CreatorStep.writeTextToFile(project, buildSystem.dirsOrError.resourceDirectory, "bungee.yml", text) - } -} Index: src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,234 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bungeecord/creator/BungeeCordProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,119 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bungeecord.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.creator.getVersionSelector -import com.demonwav.mcdev.platform.PlatformType -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JTextField -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import kotlinx.coroutines.withContext - -class BungeeCordProjectSettingsWizard( - private val creator: MinecraftProjectCreator -) : MinecraftModuleWizardStep() { - - private lateinit var panel: JPanel - - @ValidatedField(NON_BLANK) - private lateinit var pluginNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorField: JTextField - - @ValidatedField(LIST) - private lateinit var dependField: JTextField - private lateinit var softDependField: JTextField - private lateinit var title: JLabel - private lateinit var minecraftVersionBox: JComboBox - private lateinit var errorLabel: JLabel - - private var config: BungeeCordProjectConfig? = null - - private var versionsLoaded: Boolean = false - - override fun getComponent(): JComponent { - return panel - } - - override fun validate(): Boolean { - return super.validate() && minecraftVersionBox.selectedItem != null - } - - override fun updateStep() { - config = creator.config as? BungeeCordProjectConfig - if (config == null) { - return - } - val conf = config ?: return - - basicUpdateStep(creator, pluginNameField, mainClassField) - - when (conf.type) { - PlatformType.BUNGEECORD -> { - title.icon = PlatformAssets.BUNGEECORD_ICON_2X - title.text = "BungeeCord Settings" - } - PlatformType.WATERFALL -> { - title.icon = PlatformAssets.WATERFALL_ICON_2X - title.text = "Waterfall Settings" - } - else -> {} - } - - if (versionsLoaded) { - return - } - - versionsLoaded = true - CoroutineScope(Dispatchers.Swing).launch { - try { - withContext(Dispatchers.IO) { getVersionSelector(conf.type) }.set(minecraftVersionBox) - } catch (e: Exception) { - errorLabel.isVisible = true - } - } - } - - override fun isStepVisible(): Boolean { - return creator.config is BungeeCordProjectConfig - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.pluginNameField.text - conf.mainClass = this.mainClassField.text - conf.description = this.descriptionField.text - conf.minecraftVersion = this.minecraftVersionBox.selectedItem as String - - conf.setAuthors(this.authorField.text) - conf.setDependencies(this.dependField.text) - conf.setSoftDependencies(this.softDependField.text) - } -} Index: src/main/kotlin/platform/bungeecord/creator/BungeeCordTemplate.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/BungeeCordTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/bungeecord/creator/BungeeCordTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,98 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.bungeecord.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.bukkit.creator.BukkitTemplate -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUKKIT_PLUGIN_YML_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.BUNGEECORD_SUBMODULE_POM_TEMPLATE -import com.intellij.openapi.project.Project - -object BungeeCordTemplate : BaseTemplate() { - - fun applyMainClass( - project: Project, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE" to packageName, - "CLASS_NAME" to className - ) - - return project.applyTemplate(BUNGEECORD_MAIN_CLASS_TEMPLATE, props) - } - - fun applyPom(project: Project): String { - return project.applyTemplate(BUNGEECORD_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applySubPom(project: Project): String { - return project.applyTemplate(BUNGEECORD_SUBMODULE_POM_TEMPLATE, BasicMavenStep.pluginVersions) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_VERSION" to buildSystem.version - ) - - return project.applyTemplate(BUNGEECORD_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(BUNGEECORD_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(BUNGEECORD_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName - ) - - return project.applyTemplate(BUNGEECORD_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyBungeeYml( - project: Project, - config: BungeeCordProjectConfig, - buildSystem: BuildSystem - ): String { - val props = BukkitTemplate.bukkitMain(buildSystem.type, config) - - if (config.hasAuthors()) { - // BungeeCord only supports one author - props["AUTHOR"] = config.authors[0] - } - - if (config.hasDescription()) { - props["DESCRIPTION"] = config.description - ?: throw IllegalStateException("description is null when not blank") - } - - return project.applyTemplate(BUKKIT_PLUGIN_YML_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/bungeecord/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bungeecord/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,92 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bungeecord.creator + +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.SoftDependStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key + +class BungeeProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating project files" + + override fun setupAssets(project: Project) { + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val (packageName, className) = splitPackage(mainClass) + val versionRef = data.getUserData(VERSION_REF_KEY) ?: "\${version}" + val pluginName = data.getUserData(AbstractModNameStep.KEY) ?: return + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val depend = data.getUserData(DependStep.KEY) ?: emptyList() + val softDepend = data.getUserData(SoftDependStep.KEY) ?: emptyList() + + assets.addTemplateProperties( + "PACKAGE" to packageName, + "CLASS_NAME" to className, + "MAIN" to mainClass, + "VERSION" to versionRef, + "NAME" to pluginName, + ) + + if (authors.isNotEmpty()) { + assets.addTemplateProperties( + "AUTHOR" to authors.joinToString(", ") + ) + } + if (description.isNotBlank()) { + assets.addTemplateProperties( + "DESCRIPTION" to description + ) + } + if (depend.isNotEmpty()) { + assets.addTemplateProperties( + "DEPEND" to depend + ) + } + if (softDepend.isNotEmpty()) { + assets.addTemplateProperties( + "SOFT_DEPEND" to softDepend + ) + } + + assets.addTemplates( + project, + "src/main/resources/bungee.yml" to MinecraftTemplates.BUNGEECORD_PLUGIN_YML_TEMPLATE, + "src/main/java/${mainClass.replace('.', '/')}.java" to MinecraftTemplates.BUNGEECORD_MAIN_CLASS_TEMPLATE, + ) + } + + companion object { + val VERSION_REF_KEY = Key.create("${BungeeProjectFilesStep::class.java.name}.versionRef") + } +} + +class BungeeBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "BungeeCord" +} + +class BungeePostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, BungeeBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/bungeecord/creator/bungee-platforms.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/bungee-platforms.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bungeecord/creator/bungee-platforms.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,64 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bungeecord.creator + +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.platform.PlatformType +import com.demonwav.mcdev.util.SemanticVersion + +class BungeeMainPlatformStep(parent: BungeePlatformStep) : AbstractBungeePlatformStep(parent, PlatformType.BUNGEECORD) { + override fun getRepositories(mcVersion: SemanticVersion) = listOf( + BuildRepository("sonatype", "https://oss.sonatype.org/content/groups/public/") + ) + + override fun getDependencies(mcVersion: SemanticVersion) = listOf( + BuildDependency( + "net.md-5", + "bungeecord-api", + mcVersion.toString(), + mavenScope = "provided", + gradleConfiguration = "compileOnly" + ) + ) + + class Factory : BungeePlatformStep.Factory { + override val name = "BungeeCord" + + override fun createStep(parent: BungeePlatformStep) = BungeeMainPlatformStep(parent) + } +} + +class WaterfallPlatformStep(parent: BungeePlatformStep) : AbstractBungeePlatformStep(parent, PlatformType.WATERFALL) { + override fun getRepositories(mcVersion: SemanticVersion) = listOf( + BuildRepository("sonatype", "https://oss.sonatype.org/content/groups/public/"), + BuildRepository( + "papermc-repo", + "https://repo.papermc.io/repository/maven-public/" + ), + ) + + override fun getDependencies(mcVersion: SemanticVersion) = listOf( + BuildDependency( + "io.github.waterfallmc", + "waterfall-api", + "$mcVersion-SNAPSHOT", + mavenScope = "provided", + gradleConfiguration = "compileOnly" + ), + ) + + class Factory : BungeePlatformStep.Factory { + override val name = "Waterfall" + + override fun createStep(parent: BungeePlatformStep) = WaterfallPlatformStep(parent) + } +} Index: src/main/kotlin/platform/bungeecord/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bungeecord/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,81 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bungeecord.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchGradleFilesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.ReformatBuildGradleStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardBaseData.Companion.baseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +class BungeeGradleSupport : BuildSystemSupport { + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> BungeeGradleFilesStep(parent).chain( + ::BungeePatchBuildGradleStep, + ::GradleWrapperStep + ) + BuildSystemSupport.POST_STEP -> GradleImportStep(parent).chain(::ReformatBuildGradleStep) + else -> EmptyStep(parent) + } + } +} + +class BungeeGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + val projectName = baseData.name + val buildSystemProps = findStep>() + assets.addTemplateProperties( + "PROJECT_NAME" to projectName, + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "PLUGIN_VERSION" to buildSystemProps.version, + ) + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.BUNGEECORD_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.BUNGEECORD_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.BUNGEECORD_SETTINGS_GRADLE_TEMPLATE, + ) + assets.addGradleWrapperProperties(project) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} + +class BungeePatchBuildGradleStep(parent: NewProjectWizardStep) : AbstractPatchGradleFilesStep(parent) { + override fun patch(project: Project, gradleFiles: GradleFiles) { + val platform = data.getUserData(AbstractBungeePlatformStep.KEY) ?: return + val mcVersion = data.getUserData(SimpleMcVersionStep.KEY) ?: return + val repositories = platform.getRepositories(mcVersion) + val dependencies = platform.getDependencies(mcVersion) + addRepositories(project, gradleFiles.buildGradle, repositories) + addDependencies(project, gradleFiles.buildGradle, dependencies) + } +} Index: src/main/kotlin/platform/bungeecord/creator/maven-steps.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bungeecord/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,65 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bungeecord.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.addMavenGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchPomStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.MavenImportStep +import com.demonwav.mcdev.creator.buildsystem.ReformatPomStep +import com.demonwav.mcdev.creator.buildsystem.addDefaultMavenProperties +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.psi.xml.XmlTag +import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel + +class BungeeMavenSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> BungeeMavenFilesStep(parent).chain(::BungeePatchPomStep) + BuildSystemSupport.POST_STEP -> MavenImportStep(parent).chain(::ReformatPomStep) + else -> EmptyStep(parent) + } + } +} + +class BungeeMavenFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Maven files" + + override fun setupAssets(project: Project) { + data.putUserData(BungeeProjectFilesStep.VERSION_REF_KEY, "\${project.version}") + assets.addDefaultMavenProperties() + assets.addTemplates(project, "pom.xml" to MinecraftTemplates.BUNGEECORD_POM_TEMPLATE) + if (gitEnabled) { + assets.addMavenGitignore(project) + } + } +} + +class BungeePatchPomStep(parent: NewProjectWizardStep) : AbstractPatchPomStep(parent) { + override fun patchPom(model: MavenDomProjectModel, root: XmlTag) { + super.patchPom(model, root) + val platform = data.getUserData(AbstractBungeePlatformStep.KEY) ?: return + val mcVersion = data.getUserData(SimpleMcVersionStep.KEY) ?: return + val repositories = platform.getRepositories(mcVersion) + val dependencies = platform.getDependencies(mcVersion) + setupDependencies(model, repositories, dependencies) + } +} Index: src/main/kotlin/platform/bungeecord/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/bungeecord/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/bungeecord/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,105 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.bungeecord.creator + +import com.demonwav.mcdev.creator.PlatformVersion +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.getVersionSelector +import com.demonwav.mcdev.creator.platformtype.PluginPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.PluginNameStep +import com.demonwav.mcdev.creator.step.SimpleMcVersionStep +import com.demonwav.mcdev.creator.step.SoftDependStep +import com.demonwav.mcdev.platform.PlatformType +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.intellij.ide.wizard.AbstractNewProjectWizardMultiStep +import com.intellij.ide.wizard.NewProjectWizardMultiStepFactory +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import kotlinx.coroutines.coroutineScope + +class BungeePlatformStep( + parent: PluginPlatformStep +) : AbstractNewProjectWizardMultiStep(parent, EP_NAME) { + companion object { + val EP_NAME = ExtensionPointName("com.demonwav.minecraft-dev.bungeePlatformWizard") + } + + override val self = this + override val label = "Bungee Platform:" + + class PlatformFactory : PluginPlatformStep.Factory { + override val name = "BungeeCord" + + override fun createStep(parent: PluginPlatformStep) = BungeePlatformStep(parent) + } + + interface Factory : NewProjectWizardMultiStepFactory +} + +abstract class AbstractBungeePlatformStep( + parent: BungeePlatformStep, + private val platform: PlatformType +) : AbstractLatentStep(parent) { + override val description = "download versions" + + override suspend fun computeData() = coroutineScope { + try { + asyncIO { getVersionSelector(platform) }.await() + } catch (e: Throwable) { + null + } + } + + override fun createStep(data: PlatformVersion) = + SimpleMcVersionStep(this, data.versions.mapNotNull(SemanticVersion::tryParse)).chain( + ::PluginNameStep, + ::MainClassStep, + ::BungeeOptionalSettingsStep, + ::BungeeBuildSystemStep, + ::BungeeProjectFilesStep, + ::BungeePostBuildSystemStep, + ) + + override fun setupProject(project: Project) { + data.putUserData(KEY, this) + super.setupProject(project) + } + + abstract fun getRepositories(mcVersion: SemanticVersion): List + + abstract fun getDependencies(mcVersion: SemanticVersion): List + + companion object { + val KEY = Key.create("${AbstractBungeePlatformStep::class.java.name}.platform") + } +} + +class BungeeOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::DependStep, + ::SoftDependStep, + ) +} Index: src/main/kotlin/platform/fabric/creator/FabricMcVersion.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricMcVersion.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/creator/FabricMcVersion.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,20 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.creator + +class FabricMcVersion( + private val ordinal: Int, + val version: String, + val stable: Boolean, +) : Comparable { + override fun toString() = version + override fun compareTo(other: FabricMcVersion) = ordinal.compareTo(other.ordinal) +} Index: src/main/kotlin/platform/fabric/creator/FabricProjectConfig.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/fabric/creator/FabricProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,76 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.fabric.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.fabric.EntryPoint -import com.demonwav.mcdev.platform.forge.inspections.sideonly.Side -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class FabricProjectConfig : ProjectConfig(), GradleCreator { - - var yarnVersion = "" - var yarnClassifier: String? = "v2" - - // Minecraft does not follow semver in the snapshots - var mcVersion = "" - var semanticMcVersion = SemanticVersion.release() - var loaderVersion = SemanticVersion.release() - var apiVersion: SemanticVersion? = null - var apiMavenLocation: String? = null - var loomVersion = SemanticVersion.release() - var gradleVersion = SemanticVersion.release() - var environment = Side.NONE - var entryPoints: List = arrayListOf() - var modRepo: String? = null - var mixins = false - var genSources = true - var license: License? = null - - override var type = PlatformType.FABRIC - - override val preferredBuildSystem = BuildSystemType.GRADLE - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(semanticMcVersion) - - override val compatibleGradleVersions: VersionRange - get() = VersionRange.fixed(gradleVersion) - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return FabricProjectCreator( - rootDirectory, - module, - buildSystem, - this - ) - } - - override fun configureRootGradle(rootDirectory: Path, buildSystem: GradleBuildSystem) { - buildSystem.gradleVersion = - if (semanticMcVersion >= MinecraftVersions.MC1_17) SemanticVersion.release(7, 4, 2) else gradleVersion - } -} Index: src/main/kotlin/platform/fabric/creator/FabricProjectCreator.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/fabric/creator/FabricProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,383 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.fabric.creator - -import com.demonwav.mcdev.asset.MCDevBundle -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.LicenseStep -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.gradle.SimpleGradleSetupStep -import com.demonwav.mcdev.platform.fabric.EntryPoint -import com.demonwav.mcdev.platform.fabric.util.FabricConstants -import com.demonwav.mcdev.util.addAnnotation -import com.demonwav.mcdev.util.addImplements -import com.demonwav.mcdev.util.addMethod -import com.demonwav.mcdev.util.invokeLater -import com.demonwav.mcdev.util.runGradleTaskAndWait -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTask -import com.demonwav.mcdev.util.runWriteTaskInSmartMode -import com.demonwav.mcdev.util.virtualFile -import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils -import com.intellij.codeInsight.generation.OverrideImplementUtil -import com.intellij.codeInsight.generation.PsiMethodMember -import com.intellij.ide.util.EditorHelper -import com.intellij.json.JsonLanguage -import com.intellij.json.psi.JsonArray -import com.intellij.json.psi.JsonElementGenerator -import com.intellij.json.psi.JsonFile -import com.intellij.json.psi.JsonObject -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.util.text.StringUtil -import com.intellij.psi.JavaDirectoryService -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiFileFactory -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiModifier -import com.intellij.psi.PsiModifierListOwner -import com.intellij.util.IncorrectOperationException -import java.nio.file.Files -import java.nio.file.Path -import java.util.Locale - -class FabricProjectCreator( - private val rootDirectory: Path, - private val rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: FabricProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - override fun getSteps(): Iterable { - val buildText = FabricTemplate.applyBuildGradle(project, buildSystem, config) - val propText = FabricTemplate.applyGradleProp(project, buildSystem, config) - val settingsText = FabricTemplate.applySettingsGradle(project, buildSystem, config) - val files = GradleFiles(buildText, propText, settingsText) - - val steps = mutableListOf( - SimpleGradleSetupStep(project, rootDirectory, buildSystem, files), - GradleWrapperStep(project, rootDirectory, buildSystem) - ) - if (config.genSources) { - steps += GenSourcesStep(project, rootDirectory) - } - steps += GradleGitignoreStep(project, rootDirectory) - config.license?.let { - steps += LicenseStep(project, rootDirectory, it, config.authors.joinToString(", ")) - } - steps += BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - if (config.mixins) { - steps += MixinConfigStep(project, buildSystem, config) - } - createPostSteps(steps) - steps += FabricModJsonStep(project, buildSystem, config) - return steps - } - - private fun createPostSteps(steps: MutableList) { - for (entry in config.entryPoints.groupBy { it.className }.entries.sortedBy { it.key }) { - steps += CreateEntryPointStep(project, buildSystem, entry.key, entry.value) - } - } -} - -class GenSourcesStep( - private val project: Project, - private val rootDirectory: Path -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - indicator.text = "Setting up project" - indicator.text2 = "Running Gradle task: 'genSources'" - runGradleTaskAndWait(project, rootDirectory) { settings -> - settings.taskNames = listOf("genSources") - settings.vmOptions = "-Xmx1G" - } - indicator.text2 = null - } -} - -class FabricModJsonStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: FabricProjectConfig -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - val text = FabricTemplate.applyFabricModJsonTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - - indicator.text = "Indexing" - - project.runWriteTaskInSmartMode { - indicator.text = "Creating 'fabric.mod.json'" - - val file = PsiFileFactory.getInstance(project).createFileFromText(JsonLanguage.INSTANCE, text) - file.runWriteAction { - val jsonFile = file as JsonFile - val json = jsonFile.topLevelValue as? JsonObject ?: return@runWriteAction - val generator = JsonElementGenerator(project) - - (json.findProperty("authors")?.value as? JsonArray)?.let { authorsArray -> - for (i in config.authors.indices) { - if (i != 0) { - authorsArray.addBefore(generator.createComma(), authorsArray.lastChild) - } - authorsArray.addBefore(generator.createStringLiteral(config.authors[i]), authorsArray.lastChild) - } - } - - (json.findProperty("contact")?.value as? JsonObject)?.let { contactObject -> - val properties = mutableListOf>() - val website = config.website - if (!website.isNullOrBlank()) { - properties += "website" to website - } - val repo = config.modRepo - if (!repo.isNullOrBlank()) { - properties += "repo" to repo - } - for (i in properties.indices) { - if (i != 0) { - contactObject.addBefore(generator.createComma(), contactObject.lastChild) - } - val key = StringUtil.escapeStringCharacters(properties[i].first) - val value = "\"" + StringUtil.escapeStringCharacters(properties[i].second) + "\"" - contactObject.addBefore(generator.createProperty(key, value), contactObject.lastChild) - } - } - - (json.findProperty("entrypoints")?.value as? JsonObject)?.let { entryPointsObject -> - val entryPointsByCategory = config.entryPoints - .groupBy { it.category } - .asSequence() - .sortedBy { it.key } - .toList() - for (i in entryPointsByCategory.indices) { - val entryPointCategory = entryPointsByCategory[i] - if (i != 0) { - entryPointsObject.addBefore(generator.createComma(), entryPointsObject.lastChild) - } - val values = generator.createValue("[]") - for (j in entryPointCategory.value.indices) { - if (j != 0) { - values.addBefore(generator.createComma(), values.lastChild) - } - val entryPointReference = entryPointCategory.value[j].computeReference(project) - val value = generator.createStringLiteral(entryPointReference) - values.addBefore(value, values.lastChild) - } - val key = StringUtil.escapeStringCharacters(entryPointCategory.key) - val prop = generator.createProperty(key, "[]") - prop.value?.replace(values) - entryPointsObject.addBefore(prop, entryPointsObject.lastChild) - } - } - } - CreatorStep.writeTextToFile(project, dir, FabricConstants.FABRIC_MOD_JSON, file.text) - } - } -} - -class MixinConfigStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: FabricProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val text = FabricTemplate.applyMixinConfigTemplate(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, "${buildSystem.artifactId}.mixins.json", text) - } - } -} - -class CreateEntryPointStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val qualifiedClassName: String, - private val entryPoints: List -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val dirs = buildSystem.dirsOrError - - indicator.text = "Indexing" - - val dotIndex = qualifiedClassName.lastIndexOf('.') - val packageName = if (dotIndex == -1) { - "" - } else { - qualifiedClassName.substring(0, dotIndex) - } - val className = qualifiedClassName.substring(dotIndex + 1) - - var directory = dirs.sourceDirectory - for (part in packageName.split(".")) { - directory = directory.resolve(part) - } - if (Files.notExists(directory)) { - Files.createDirectories(directory) - } - - val virtualDir = directory.virtualFile ?: return - - project.runWriteTaskInSmartMode { - indicator.text = "Writing class: $className" - - val psiDir = PsiManager.getInstance(project).findDirectory(virtualDir) ?: return@runWriteTaskInSmartMode - val clazz = try { - JavaDirectoryService.getInstance().createClass(psiDir, className) - } catch (e: IncorrectOperationException) { - invokeLater { - val message = MCDevBundle.message( - "intention.error.cannot.create.class.message", - className, - e.localizedMessage - ) - Messages.showErrorDialog( - project, - message, - MCDevBundle.message("intention.error.cannot.create.class.title") - ) - } - return@runWriteTaskInSmartMode - } - - val editor = EditorHelper.openInEditor(clazz) - - clazz.containingFile.runWriteAction { - val clientEntryPoints = entryPoints.filter { it.category == "client" } - val serverEntryPoints = entryPoints.filter { it.category == "server" } - val otherEntryPoints = entryPoints.filter { it.category != "client" && it.category != "server" } - val entryPointsByInterface = entryPoints - .filter { it.type == EntryPoint.Type.CLASS } - .groupBy { it.interfaceName } - .entries - .sortedBy { it.key } - val entryPointsByMethodNameAndSig = entryPoints - .filter { it.type == EntryPoint.Type.METHOD } - .groupBy { entryPoint -> - val functionalMethod = entryPoint.findFunctionalMethod(project) ?: return@groupBy null - val paramTypes = functionalMethod.parameterList.parameters.map { it.type.canonicalText } - (entryPoint.methodName ?: functionalMethod.name) to paramTypes - } - .entries - .mapNotNull { it.key?.let { k -> k to it.value } } - .sortedBy { it.first.first } - - val elementFactory = JavaPsiFacade.getElementFactory(project) - - var isClientClass = false - var isServerClass = false - if (clientEntryPoints.isNotEmpty()) { - if (serverEntryPoints.isEmpty() && otherEntryPoints.isEmpty()) { - addEnvironmentAnnotation(clazz, "CLIENT") - isClientClass = true - } else { - addSidedInterfaceEntryPoints(entryPointsByInterface, clazz, editor, "client") - } - } else if (serverEntryPoints.isNotEmpty()) { - if (clientEntryPoints.isEmpty() && otherEntryPoints.isEmpty()) { - addEnvironmentAnnotation(clazz, "SERVER") - isServerClass = true - } else { - addSidedInterfaceEntryPoints(entryPointsByInterface, clazz, editor, "server") - } - } - - for (eps in entryPointsByInterface) { - clazz.addImplements(eps.key) - } - implementAll(clazz, editor) - - for (eps in entryPointsByMethodNameAndSig) { - val functionalMethod = eps.second.first().findFunctionalMethod(project) ?: continue - val newMethod = clazz.addMethod(functionalMethod) ?: continue - val methodName = eps.first.first - newMethod.nameIdentifier?.replace(elementFactory.createIdentifier(methodName)) - newMethod.modifierList.setModifierProperty(PsiModifier.PUBLIC, true) - newMethod.modifierList.setModifierProperty(PsiModifier.STATIC, true) - newMethod.modifierList.setModifierProperty(PsiModifier.ABSTRACT, false) - CreateFromUsageUtils.setupMethodBody(newMethod) - if (!isClientClass && eps.second.all { it.category == "client" }) { - addEnvironmentAnnotation(newMethod, "CLIENT") - } else if (!isServerClass && eps.second.all { it.category == "server" }) { - addEnvironmentAnnotation(newMethod, "SERVER") - } - } - } - } - } - - private fun addSidedInterfaceEntryPoints( - entryPointsByInterface: List>>, - clazz: PsiClass, - editor: Editor, - side: String - ) { - val capsSide = side.uppercase(Locale.ENGLISH) - var needsInterfaceFix = false - for (eps in entryPointsByInterface) { - if (eps.value.all { it.category == side }) { - addEnvironmentInterfaceAnnotation(clazz, capsSide, eps.key) - clazz.addImplements(eps.key) - needsInterfaceFix = true - } - } - if (needsInterfaceFix) { - implementAll(clazz, editor) - for (method in clazz.methods) { - if (!method.hasAnnotation(FabricConstants.ENVIRONMENT_ANNOTATION)) { - addEnvironmentAnnotation(method, capsSide) - } - } - } - } - - private fun addEnvironmentAnnotation(owner: PsiModifierListOwner, envType: String) { - owner.addAnnotation("@${FabricConstants.ENVIRONMENT_ANNOTATION}(${FabricConstants.ENV_TYPE}.$envType)") - } - - private fun addEnvironmentInterfaceAnnotation( - owner: PsiModifierListOwner, - envType: String, - interfaceQualifiedName: String - ) { - val annotationText = "@${FabricConstants.ENVIRONMENT_INTERFACE_ANNOTATION}(" + - "value=${FabricConstants.ENV_TYPE}.$envType," + - "itf=$interfaceQualifiedName.class" + - ")" - owner.addAnnotation(annotationText) - } - - private fun implementAll(clazz: PsiClass, editor: Editor) { - val methodsToImplement = OverrideImplementUtil.getMethodsToOverrideImplement(clazz, true) - .map { PsiMethodMember(it) } - OverrideImplementUtil.overrideOrImplementMethodsInRightPlace( - editor, - clazz, - methodsToImplement, - false, - true - ) - } -} Index: src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,408 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/fabric/creator/FabricProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,414 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.fabric.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.platform.fabric.EntryPoint -import com.demonwav.mcdev.platform.fabric.util.FabricConstants -import com.demonwav.mcdev.platform.forge.inspections.sideonly.Side -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.asyncIO -import com.demonwav.mcdev.util.modUpdateStep -import com.demonwav.mcdev.util.toPackageName -import com.extracraftx.minecraft.templatemakerfabric.data.DataProvider -import com.intellij.openapi.ui.ComboBox -import com.intellij.ui.CollectionComboBoxModel -import com.intellij.ui.ToolbarDecorator -import com.intellij.ui.table.JBTable -import com.intellij.util.ui.EditableModel -import com.intellij.util.ui.table.ComboBoxTableCellEditor -import java.awt.event.ActionListener -import java.awt.event.ComponentAdapter -import java.awt.event.ComponentEvent -import java.util.Collections -import java.util.Locale -import javax.swing.JCheckBox -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JProgressBar -import javax.swing.JTextField -import javax.swing.table.AbstractTableModel -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import org.apache.commons.lang.WordUtils - -class FabricProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - // Initialize ALL custom fields in createUIComponents, otherwise they are null until after that point! - @ValidatedField(NON_BLANK) - private lateinit var modNameField: JTextField - private lateinit var panel: JPanel - private lateinit var title: JLabel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - private lateinit var repositoryField: JTextField - private lateinit var minecraftVersionBox: JComboBox - private lateinit var loaderVersionBox: JComboBox - private lateinit var yarnVersionBox: JComboBox - private lateinit var loomVersionBox: JComboBox - private lateinit var licenseBox: JComboBox - private lateinit var useFabricApiCheckbox: JCheckBox - private lateinit var fabricApiBox: JComboBox - private lateinit var environmentBox: JComboBox - private lateinit var mixinsCheckbox: JCheckBox - private lateinit var decompileMcCheckbox: JCheckBox - private lateinit var loadingBar: JProgressBar - private lateinit var minecraftVersionLabel: JLabel - private lateinit var entryPointsTable: JPanel - private lateinit var entryPoints: ArrayList - private lateinit var tableModel: EntryPointTableModel - private lateinit var yarnWarning: JLabel - private lateinit var errorLabel: JLabel - - private var config: FabricProjectConfig? = null - - private var dataProvider: DataProvider? = null - - private var currentJob: Job? = null - - private var initializedEntryPointsTable = false - - private val minecraftBoxActionListener: ActionListener = ActionListener { - yarnVersionBox.selectedItem = null - loaderVersionBox.selectedItem = null - loomVersionBox.selectedItem = null - fabricApiBox.selectedItem = null - updateForm() - } - - init { - yarnWarning.isVisible = false - errorLabel.isVisible = false - } - - fun createUIComponents() { - entryPoints = arrayListOf() - - tableModel = EntryPointTableModel(entryPoints) - val entryPointsTable = JBTable(tableModel) - entryPointsTable.setDefaultEditor(EntryPoint.Type::class.java, ComboBoxTableCellEditor.INSTANCE) - fun resizeColumns() { - val model = entryPointsTable.columnModel - val totalWidth = model.totalColumnWidth - model.getColumn(0).preferredWidth = (totalWidth * 0.1).toInt() - model.getColumn(1).preferredWidth = (totalWidth * 0.1).toInt() - model.getColumn(2).preferredWidth = (totalWidth * 0.3).toInt() - model.getColumn(3).preferredWidth = (totalWidth * 0.3).toInt() - model.getColumn(4).preferredWidth = (totalWidth * 0.2).toInt() - } - resizeColumns() - entryPointsTable.addComponentListener( - object : ComponentAdapter() { - override fun componentResized(e: ComponentEvent?) { - resizeColumns() - } - } - ) - this.entryPointsTable = ToolbarDecorator.createDecorator(entryPointsTable).createPanel() - - licenseBox = ComboBox(CollectionComboBoxModel(enumValues().toList())) - licenseBox.selectedItem = License.MIT - } - - override fun getComponent(): JComponent { - return panel - } - - override fun updateStep() { - val (conf, buildSystem) = modUpdateStep(creator, modNameField) ?: return - config = conf - - if (!initializedEntryPointsTable) { - val packageName = "${buildSystem.groupId.toPackageName()}.${buildSystem.artifactId.toPackageName()}" - val className = buildSystem.artifactId.replace('-', ' ').let { WordUtils.capitalize(it) }.replace(" ", "") - entryPoints.add( - EntryPoint( - "main", - EntryPoint.Type.CLASS, - "$packageName.$className", - FabricConstants.MOD_INITIALIZER - ) - ) - entryPoints.add( - EntryPoint( - "client", - EntryPoint.Type.CLASS, - "$packageName.client.${className}Client", - FabricConstants.CLIENT_MOD_INITIALIZER - ) - ) - tableModel.fireTableDataChanged() - entryPointsTable.revalidate() - initializedEntryPointsTable = true - } - - title.icon = PlatformAssets.FABRIC_ICON_2X - title.text = "Fabric Settings" - - minecraftVersionLabel.text = "Minecraft Version" - - if (dataProvider != null || currentJob?.isActive == true) { - return - } - currentJob = updateVersions() - } - - private val mcVersion: String? - get() = minecraftVersionBox.selectedItem as? String - - private val yarnVersion: String? - get() = yarnVersionBox.selectedItem as? String - - private val loomVersion: String? - get() = loomVersionBox.selectedItem as? String - - private val loaderVersion: String? - get() = loaderVersionBox.selectedItem as? String - - private val fabricApiVersion: String? - get() = fabricApiBox.selectedItem as? String - - override fun validate(): Boolean { - return super.validate() && !loadingBar.isVisible - } - - override fun isStepVisible(): Boolean { - return creator.config is FabricProjectConfig - } - - override fun onStepLeaving() { - currentJob?.cancel() - } - - fun error() { - errorLabel.isVisible = true - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - } - - override fun updateDataModel() { - val conf = config ?: return - conf.pluginName = modNameField.text - conf.description = descriptionField.text - conf.website = websiteField.text - - conf.setAuthors(authorsField.text) - conf.modRepo = repositoryField.text - - conf.yarnVersion = yarnVersion ?: "$mcVersion+build.1" - val yarnVersionObj = dataProvider?.yarnVersions?.firstOrNull { it.name == yarnVersion } - conf.yarnClassifier = if (yarnVersionObj?.hasV2Mappings == false) { - null - } else { - "v2" - } - conf.mcVersion = mcVersion ?: "" - val normalizedMcVersion = dataProvider?.getNormalizedMinecraftVersion(mcVersion)?.normalized - conf.semanticMcVersion = normalizedMcVersion?.let { SemanticVersion.parse(it) } ?: SemanticVersion.release() - val loaderVer = loaderVersion - if (loaderVer != null) { - conf.loaderVersion = SemanticVersion.parse(loaderVer) - } - val api = if (useFabricApiCheckbox.isSelected) { - dataProvider?.fabricApiVersions?.firstOrNull { it.name == fabricApiVersion } - } else { - null - } - conf.apiVersion = api?.mavenVersion?.let { SemanticVersion.parse(it) } - conf.apiMavenLocation = api?.mavenLocation - conf.gradleVersion = when (dataProvider?.loomVersions?.firstOrNull { it.name == loomVersion }?.gradle) { - 4 -> SemanticVersion.release(4, 10, 3) - 5 -> SemanticVersion.release(5, 6, 4) - else -> SemanticVersion.release(6, 9) - } - val loomVer = loomVersion - if (loomVer != null) { - conf.loomVersion = SemanticVersion.parse(loomVer) - } - if (conf.loomVersion >= SemanticVersion.release(0, 7)) { - // TemplateMakerFabric incorrectly indicates loom 0.8 requires Gradle 6... - conf.gradleVersion = SemanticVersion.release(7, 3) - } - conf.environment = when ((environmentBox.selectedItem as? String)?.lowercase(Locale.ENGLISH)) { - "client" -> Side.CLIENT - "server" -> Side.SERVER - else -> Side.NONE - } - conf.license = licenseBox.selectedItem as? License - conf.entryPoints = entryPoints.filter { it.valid } - conf.mixins = mixinsCheckbox.isSelected - conf.genSources = decompileMcCheckbox.isSelected - } - - private fun updateVersions() = CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - try { - dataProvider = downloadVersions() - updateForm() - } catch (e: Exception) { - e.printStackTrace() - error() - } - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - - currentJob = null - } - - private suspend fun downloadVersions(): DataProvider? = coroutineScope { - // prefetch the data - val dataProvider = DataProvider() - val minecraftVersionJob = asyncIO { runCatching { dataProvider.minecraftVersions }.getOrNull() } - val fabricApiVersionJob = asyncIO { runCatching { dataProvider.fabricApiVersions }.getOrNull() } - val yarnVersionJob = asyncIO { runCatching { dataProvider.yarnVersions }.getOrNull() } - val loomVersionJob = asyncIO { runCatching { dataProvider.loomVersions }.getOrNull() } - val loaderVersionJob = asyncIO { runCatching { dataProvider.loaderVersions }.getOrNull() } - - val results = listOf( - minecraftVersionJob, - fabricApiVersionJob, - yarnVersionJob, - loomVersionJob, - loaderVersionJob, - ).awaitAll() - - if (results.any { it == null }) { - return@coroutineScope null - } - - return@coroutineScope dataProvider - } - - private fun updateForm() { - val dp = dataProvider ?: return - - val mcVer = mcVersion ?: dp.minecraftVersions.firstOrNull { it.stable }?.name - val mcVerObj = dp.minecraftVersions.firstOrNull { it.name == mcVer } - - val yarnVer = yarnVersion ?: mcVerObj?.let { mvo -> - dp.getFilteredYarnVersions(mvo).firstOrNull()?.name - } - val yarnVerObj = dp.yarnVersions.firstOrNull { it.name == yarnVer } - - val loomVer = loomVersion ?: yarnVerObj?.let { dp.getDefaultLoomVersion(it) }?.name - val loomVerObj = dp.loomVersions.firstOrNull { it.name == loomVer } - - val loaderVer = loaderVersion ?: loomVerObj?.let { lvo -> - dp.getFilteredLoaderVersions(lvo).firstOrNull()?.name - } - - val fabricVer = fabricApiVersion ?: mcVerObj?.let { mvo -> - dp.getDefaultFabricApiVersion(mvo) - }?.let { dp.sortedFabricApiVersions[it] }?.name - - minecraftVersionBox.removeActionListener(minecraftBoxActionListener) - minecraftVersionBox.model = CollectionComboBoxModel(dp.minecraftVersions.map { it.name }) - minecraftVersionBox.selectedItem = mcVer - minecraftVersionBox.addActionListener(minecraftBoxActionListener) - yarnVersionBox.model = CollectionComboBoxModel(dp.yarnVersions.map { it.name }) - yarnVersionBox.selectedItem = yarnVer - loomVersionBox.model = CollectionComboBoxModel(dp.loomVersions.map { it.name }) - loomVersionBox.selectedItem = loomVer - loaderVersionBox.model = CollectionComboBoxModel(dp.loaderVersions.map { it.name }) - loaderVersionBox.selectedItem = loaderVer - fabricApiBox.model = CollectionComboBoxModel(dp.fabricApiVersions.map { it.name }) - fabricApiBox.selectedItem = fabricVer - useFabricApiCheckbox.isSelected = fabricVer != null - } - - class EntryPointTableModel(private val entryPoints: ArrayList) : AbstractTableModel(), EditableModel { - - override fun getColumnName(col: Int) = when (col) { - 0 -> "Category" - 1 -> "Type" - 2 -> "Class" - 3 -> "Interface" - else -> "Method Name" - } - - override fun getRowCount() = entryPoints.size - - override fun getColumnCount() = 5 - - override fun getValueAt(row: Int, col: Int): Any? = when (col) { - 0 -> entryPoints[row].category - 1 -> entryPoints[row].type - 2 -> entryPoints[row].className - 3 -> entryPoints[row].interfaceName - else -> entryPoints[row].methodName - } - - override fun isCellEditable(row: Int, col: Int): Boolean { - return col != 4 || entryPoints.getOrNull(row)?.type == EntryPoint.Type.METHOD - } - - override fun setValueAt(value: Any?, row: Int, col: Int) { - when (col) { - 0 -> entryPoints[row] = entryPoints[row].copy(category = value.toString()) - 1 -> entryPoints[row] = entryPoints[row].copy(type = parseEntryPointType(value)) - 2 -> entryPoints[row] = entryPoints[row].copy(className = value.toString()) - 3 -> entryPoints[row] = entryPoints[row].copy(interfaceName = value.toString()) - 4 -> entryPoints[row] = entryPoints[row].copy(methodName = value.toString()) - } - fireTableCellUpdated(row, col) - } - - private fun parseEntryPointType(value: Any?): EntryPoint.Type { - return when (value) { - is EntryPoint.Type -> value - else -> enumValues().firstOrNull { - it.name.equals(value.toString(), ignoreCase = true) - } ?: EntryPoint.Type.CLASS - } - } - - override fun removeRow(idx: Int) { - entryPoints.removeAt(idx) - } - - override fun exchangeRows(oldIndex: Int, newIndex: Int) { - Collections.swap(entryPoints, oldIndex, newIndex) - } - - override fun canExchangeRows(oldIndex: Int, newIndex: Int) = true - - override fun addRow() { - entryPoints.add(EntryPoint("", EntryPoint.Type.CLASS, "", "", "")) - } - - override fun getColumnClass(col: Int): Class<*> { - return if (col == 1) { - EntryPoint.Type::class.java - } else { - String::class.java - } - } - } -} Index: src/main/kotlin/platform/fabric/creator/FabricTemplate.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/FabricTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/fabric/creator/FabricTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,138 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.fabric.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.forge.inspections.sideonly.Side -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_MIXINS_JSON_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_MOD_JSON_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.toPackageName -import com.intellij.openapi.project.Project - -object FabricTemplate : BaseTemplate() { - - private fun Project.applyGradleTemplate( - templateName: String, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - val props = mutableMapOf( - "GROUP_ID" to buildSystem.groupId, - "ARTIFACT_ID" to buildSystem.artifactId, - "VERSION" to buildSystem.version, - "MC_VERSION" to config.mcVersion, - "YARN_MAPPINGS" to config.yarnVersion, - "LOADER_VERSION" to config.loaderVersion.toString(), - "LOOM_VERSION" to config.loomVersion.toString(), - "JAVA_VERSION" to config.javaVersion.feature - ) - config.yarnClassifier?.let { - props["YARN_CLASSIFIER"] = it - } - config.apiVersion?.let { - props["API_VERSION"] = it.toString() - } - config.apiMavenLocation?.let { - props["API_MAVEN_LOCATION"] = it - } - - return applyTemplate(templateName, props) - } - - fun applyBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - return project.applyGradleTemplate(FABRIC_BUILD_GRADLE_TEMPLATE, buildSystem, config) - } - - fun applyMultiModuleBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - return project.applyGradleTemplate(FABRIC_SUBMODULE_BUILD_GRADLE_TEMPLATE, buildSystem, config) - } - - fun applySettingsGradle( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - return project.applyGradleTemplate(FABRIC_SETTINGS_GRADLE_TEMPLATE, buildSystem, config) - } - - fun applyGradleProp( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - return project.applyGradleTemplate(FABRIC_GRADLE_PROPERTIES_TEMPLATE, buildSystem, config) - } - - fun applyMultiModuleGradleProp( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - return project.applyGradleTemplate(FABRIC_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE, buildSystem, config) - } - - fun applyFabricModJsonTemplate( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - val props = mutableMapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_DESCRIPTION" to (config.description ?: ""), - "MOD_ENVIRONMENT" to when (config.environment) { - Side.CLIENT -> "client" - Side.SERVER -> "server" - else -> "*" - }, - "LOADER_VERSION" to config.loaderVersion.toString(), - "MC_VERSION" to config.semanticMcVersion.toString(), - "JAVA_VERSION" to config.javaVersion.feature, - "LICENSE" to ((config.license ?: License.ALL_RIGHTS_RESERVED).id) - ) - config.apiVersion?.let { - props["API_VERSION"] = it.toString() - } - if (config.mixins) { - props["MIXINS"] = "true" - } - - return project.applyTemplate(FABRIC_MOD_JSON_TEMPLATE, props) - } - - fun applyMixinConfigTemplate( - project: Project, - buildSystem: BuildSystem, - config: FabricProjectConfig - ): String { - val packageName = "${buildSystem.groupId.toPackageName()}.${buildSystem.artifactId.toPackageName()}.mixin" - val props = mapOf( - "PACKAGE_NAME" to packageName, - "JAVA_VERSION" to config.javaVersion.feature - ) - return project.applyTemplate(FABRIC_MIXINS_JSON_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/fabric/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,295 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.creator + +import com.demonwav.mcdev.asset.MCDevBundle +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addLicense +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.RepositoryStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.fabric.EntryPoint +import com.demonwav.mcdev.platform.fabric.util.FabricConstants +import com.demonwav.mcdev.platform.forge.inspections.sideonly.Side +import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_MIXINS_JSON_TEMPLATE +import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FABRIC_MOD_JSON_TEMPLATE +import com.demonwav.mcdev.util.addImplements +import com.demonwav.mcdev.util.addMethod +import com.demonwav.mcdev.util.invokeLater +import com.demonwav.mcdev.util.runWriteAction +import com.demonwav.mcdev.util.runWriteTaskInSmartMode +import com.demonwav.mcdev.util.toJavaClassName +import com.demonwav.mcdev.util.toPackageName +import com.intellij.codeInsight.actions.ReformatCodeProcessor +import com.intellij.codeInsight.generation.OverrideImplementUtil +import com.intellij.ide.starters.local.GeneratorEmptyDirectory +import com.intellij.ide.util.EditorHelper +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.json.psi.JsonArray +import com.intellij.json.psi.JsonElementGenerator +import com.intellij.json.psi.JsonFile +import com.intellij.json.psi.JsonObject +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.psi.JavaDirectoryService +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiManager +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.IncorrectOperationException +import java.nio.file.Path +import java.util.concurrent.CountDownLatch + +class FabricDumbModeFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Adding Fabric project files (phase 1)" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false + val javaVersion = findStep().preferredJdk.ordinal + + if (useMixins) { + val packageName = + "${buildSystemProps.groupId.toPackageName()}.${buildSystemProps.artifactId.toPackageName()}.mixin" + assets.addTemplateProperties( + "PACKAGE_NAME" to packageName, + "JAVA_VERSION" to javaVersion, + ) + val mixinsJsonFile = "src/main/resources/${buildSystemProps.artifactId}.mixins.json" + assets.addTemplates(project, mixinsJsonFile to FABRIC_MIXINS_JSON_TEMPLATE) + } + + assets.addLicense(project) + + assets.addAssets( + GeneratorEmptyDirectory("src/main/java"), + GeneratorEmptyDirectory("src/main/resources"), + ) + } +} + +class FabricSmartModeFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Adding Fabric project files (phase 2)" + + private lateinit var entryPoints: List + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val modName = data.getUserData(AbstractModNameStep.KEY) ?: return + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val environment = data.getUserData(FabricEnvironmentStep.KEY) ?: Side.NONE + val envName = when (environment) { + Side.CLIENT -> "client" + Side.SERVER -> "server" + else -> "*" + } + val loaderVersion = data.getUserData(FabricVersionChainStep.LOADER_VERSION_KEY) ?: return + val mcVersion = data.getUserData(FabricVersionChainStep.MC_VERSION_KEY) ?: return + val javaVersion = findStep().preferredJdk.ordinal + val license = data.getUserData(LicenseStep.KEY) ?: return + val apiVersion = data.getUserData(FabricVersionChainStep.API_VERSION_KEY) + val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false + + val packageName = "${buildSystemProps.groupId.toPackageName()}.${buildSystemProps.artifactId.toPackageName()}" + val mainClassName = "$packageName.${modName.toJavaClassName()}" + val clientClassName = "$packageName.client.${modName.toJavaClassName()}Client" + entryPoints = listOf( + EntryPoint("main", EntryPoint.Type.CLASS, mainClassName, FabricConstants.MOD_INITIALIZER), + EntryPoint("client", EntryPoint.Type.CLASS, clientClassName, FabricConstants.CLIENT_MOD_INITIALIZER), + ) // TODO: un-hardcode? + + assets.addTemplateProperties( + "ARTIFACT_ID" to buildSystemProps.artifactId, + "MOD_NAME" to StringUtil.escapeStringCharacters(modName), + "MOD_DESCRIPTION" to StringUtil.escapeStringCharacters(description), + "MOD_ENVIRONMENT" to envName, + "LOADER_VERSION" to loaderVersion, + "MC_VERSION" to mcVersion, + "JAVA_VERSION" to javaVersion, + "LICENSE" to license.id, + ) + + if (apiVersion != null) { + assets.addTemplateProperties("API_VERSION" to apiVersion) + } + + if (useMixins) { + assets.addTemplateProperties("MIXINS" to "true") + } + + assets.addTemplates(project, "src/main/resources/fabric.mod.json" to FABRIC_MOD_JSON_TEMPLATE) + } + + private fun fixupFabricModJson(project: Project) { + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val website = data.getUserData(WebsiteStep.KEY) + val repo = data.getUserData(RepositoryStep.KEY) + + val fabricModJsonFile = + VfsUtil.findFile(Path.of(context.projectFileDirectory, "src", "main", "resources", "fabric.mod.json"), true) + ?: return + val jsonFile = PsiManager.getInstance(project).findFile(fabricModJsonFile) as? JsonFile ?: return + val json = jsonFile.topLevelValue as? JsonObject ?: return + val generator = JsonElementGenerator(project) + + jsonFile.runWriteAction { + (json.findProperty("authors")?.value as? JsonArray)?.let { authorsArray -> + for (i in authors.indices) { + if (i != 0) { + authorsArray.addBefore(generator.createComma(), authorsArray.lastChild) + } + authorsArray.addBefore(generator.createStringLiteral(authors[i]), authorsArray.lastChild) + } + } + + (json.findProperty("contact")?.value as? JsonObject)?.let { contactObject -> + val properties = mutableListOf>() + if (!website.isNullOrBlank()) { + properties += "website" to website + } + if (!repo.isNullOrBlank()) { + properties += "repo" to repo + } + for (i in properties.indices) { + if (i != 0) { + contactObject.addBefore(generator.createComma(), contactObject.lastChild) + } + val key = StringUtil.escapeStringCharacters(properties[i].first) + val value = "\"" + StringUtil.escapeStringCharacters(properties[i].second) + "\"" + contactObject.addBefore(generator.createProperty(key, value), contactObject.lastChild) + } + } + + (json.findProperty("entrypoints")?.value as? JsonObject)?.let { entryPointsObject -> + val entryPointsByCategory = entryPoints + .groupBy { it.category } + .asSequence() + .sortedBy { it.key } + .toList() + for (i in entryPointsByCategory.indices) { + val entryPointCategory = entryPointsByCategory[i] + if (i != 0) { + entryPointsObject.addBefore(generator.createComma(), entryPointsObject.lastChild) + } + val values = generator.createValue("[]") + for (j in entryPointCategory.value.indices) { + if (j != 0) { + values.addBefore(generator.createComma(), values.lastChild) + } + val entryPointReference = entryPointCategory.value[j].computeReference(project) + val value = generator.createStringLiteral(entryPointReference) + values.addBefore(value, values.lastChild) + } + val key = StringUtil.escapeStringCharacters(entryPointCategory.key) + val prop = generator.createProperty(key, "[]") + prop.value?.replace(values) + entryPointsObject.addBefore(prop, entryPointsObject.lastChild) + } + } + + ReformatCodeProcessor(project, jsonFile, null, false).run() + } + } + + private fun createEntryPoints(project: Project) { + val root = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) ?: return + val psiManager = PsiManager.getInstance(project) + + val generatedClasses = mutableSetOf() + + for (entryPoint in entryPoints) { + // find the class, and create it if it doesn't exist + val clazz = JavaPsiFacade.getInstance(project).findClass( + entryPoint.className, + GlobalSearchScope.projectScope(project) + ) ?: run { + val packageName = entryPoint.className.substringBeforeLast('.', missingDelimiterValue = "") + val className = entryPoint.className.substringAfterLast('.') + + val dir = VfsUtil.createDirectoryIfMissing(root, "src/main/java/${packageName.replace('.', '/')}") + val psiDir = psiManager.findDirectory(dir) ?: return@run null + try { + JavaDirectoryService.getInstance().createClass(psiDir, className) + } catch (e: IncorrectOperationException) { + invokeLater { + val message = MCDevBundle.message( + "intention.error.cannot.create.class.message", + className, + e.localizedMessage + ) + Messages.showErrorDialog( + project, + message, + MCDevBundle.message("intention.error.cannot.create.class.title") + ) + } + return + } + } ?: continue + + clazz.containingFile.runWriteAction { + clazz.addImplements(entryPoint.interfaceName) + + val methodsToImplement = OverrideImplementUtil.getMethodsToOverrideImplement(clazz, true) + val methods = OverrideImplementUtil.overrideOrImplementMethodCandidates(clazz, methodsToImplement, true) + for (method in methods) { + clazz.addMethod(method) + } + } + + generatedClasses += clazz + } + + for (clazz in generatedClasses) { + ReformatCodeProcessor(project, clazz.containingFile, null, false).run() + EditorHelper.openInEditor(clazz) + } + } + + override fun perform(project: Project) { + super.perform(project) + val latch = CountDownLatch(1) + assets.runWhenCreated(project) { + project.runWriteTaskInSmartMode { + try { + fixupFabricModJson(project) + createEntryPoints(project) + } finally { + latch.countDown() + } + } + } + latch.await() + } +} + +class FabricBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Fabric" +} + +class FabricPostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, FabricBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/fabric/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,82 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +class FabricGradleSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> FabricGradleFilesStep(parent).chain(::GradleWrapperStep) + BuildSystemSupport.POST_STEP -> GradleImportStep(parent) + else -> EmptyStep(parent) + } + } +} + +class FabricGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val mcVersion = data.getUserData(FabricVersionChainStep.MC_VERSION_KEY) ?: return + val yarnVersion = data.getUserData(FabricVersionChainStep.YARN_VERSION_KEY) ?: return + val loaderVersion = data.getUserData(FabricVersionChainStep.LOADER_VERSION_KEY) ?: return + val loomVersion = "1.0-SNAPSHOT" // TODO + val javaVersion = findStep().preferredJdk.ordinal + val apiVersion = data.getUserData(FabricVersionChainStep.API_VERSION_KEY) + + assets.addTemplateProperties( + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "VERSION" to buildSystemProps.version, + "MC_VERSION" to mcVersion, + "YARN_MAPPINGS" to yarnVersion, + "LOADER_VERSION" to loaderVersion, + "LOOM_VERSION" to loomVersion, + "JAVA_VERSION" to javaVersion, + ) + + if (apiVersion != null) { + assets.addTemplateProperties("API_VERSION" to apiVersion) + } + + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.FABRIC_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.FABRIC_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.FABRIC_SETTINGS_GRADLE_TEMPLATE, + ) + + assets.addGradleWrapperProperties(project) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} Index: src/main/kotlin/platform/fabric/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/fabric/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,261 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.creator + +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.platformtype.ModPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractMcVersionChainStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.ModNameStep +import com.demonwav.mcdev.creator.step.RepositoryStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WaitForSmartModeStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.fabric.util.FabricApiVersions +import com.demonwav.mcdev.platform.fabric.util.FabricVersions +import com.demonwav.mcdev.platform.forge.inspections.sideonly.Side +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.demonwav.mcdev.util.bindEnabled +import com.intellij.ide.wizard.AbstractNewProjectWizardStep +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.observable.util.bindBooleanStorage +import com.intellij.openapi.observable.util.bindStorage +import com.intellij.openapi.observable.util.transform +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.openapi.util.Key +import com.intellij.ui.JBColor +import com.intellij.ui.dsl.builder.Cell +import com.intellij.ui.dsl.builder.EMPTY_LABEL +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.Row +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.bindSelected +import com.intellij.ui.dsl.builder.bindText +import com.intellij.util.IncorrectOperationException +import kotlinx.coroutines.coroutineScope + +class FabricPlatformStep( + parent: ModPlatformStep +) : AbstractLatentStep>(parent) { + override val description = "download Fabric versions" + + override suspend fun computeData() = coroutineScope { + val fabricVersions = asyncIO { FabricVersions.downloadData() } + val fabricApiVersions = asyncIO { FabricApiVersions.downloadData() } + fabricVersions.await()?.let { a -> fabricApiVersions.await()?.let { b -> a to b } } + } + + override fun createStep(data: Pair): NewProjectWizardStep { + val (fabricVersions, apiVersions) = data + return FabricVersionChainStep(this, fabricVersions, apiVersions) + .chain( + ::FabricEnvironmentStep, + ::UseMixinsStep, + ::ModNameStep, + ::LicenseStep, + ::FabricOptionalSettingsStep, + ::FabricBuildSystemStep, + ::FabricDumbModeFilesStep, + ::FabricPostBuildSystemStep, + ::WaitForSmartModeStep, + ::FabricSmartModeFilesStep, + ) + } + + class Factory : ModPlatformStep.Factory { + override val name = "Fabric" + override fun createStep(parent: ModPlatformStep) = FabricPlatformStep(parent) + } +} + +class FabricVersionChainStep( + parent: NewProjectWizardStep, + private val fabricVersions: FabricVersions, + private val apiVersions: FabricApiVersions +) : AbstractMcVersionChainStep(parent, "Loader Version:", "Yarn Version:", "API Version:") { + companion object { + private const val LOADER_VERSION = 1 + private const val YARN_VERSION = 2 + private const val API_VERSION = 3 + + val MC_VERSION_KEY = Key.create("${FabricVersionChainStep::class.java.name}.mcVersion") + val LOADER_VERSION_KEY = Key.create("${FabricVersionChainStep::class.java.name}.loaderVersion") + val YARN_VERSION_KEY = Key.create("${FabricVersionChainStep::class.java.name}.yarnVersion") + val API_VERSION_KEY = Key.create("${FabricVersionChainStep::class.java.name}.apiVersion") + } + + private val showSnapshotsProperty = propertyGraph.property(false) + .bindBooleanStorage("${javaClass.name}.showSnapshots") + private var showSnapshots by showSnapshotsProperty + + private val useApiProperty = propertyGraph.property(true) + .bindBooleanStorage("${javaClass.name}.useApi") + private var useApi by useApiProperty + + init { + showSnapshotsProperty.afterChange { updateVersionBox() } + } + + private val mcVersions by lazy { + fabricVersions.game.mapIndexed { index, version -> + FabricMcVersion(fabricVersions.game.size - 1 - index, version.version, version.stable) + } + } + + override fun createComboBox(row: Row, index: Int, items: List>): Cell>> { + return when (index) { + MINECRAFT_VERSION -> { + val comboBox = super.createComboBox(row, index, items) + row.checkBox("Show snapshots").bindSelected(showSnapshotsProperty) + comboBox + } + YARN_VERSION -> { + val comboBox = super.createComboBox(row, index, items) + row.label(EMPTY_LABEL).bindText( + getVersionProperty(MINECRAFT_VERSION).transform { mcVersion -> + mcVersion as FabricMcVersion + val matched = fabricVersions.mappings.any { it.gameVersion == mcVersion.version } + if (matched) { + EMPTY_LABEL + } else { + "Unable to match Yarn versions to Minecraft version" + } + } + ).component.foreground = JBColor.YELLOW + comboBox + } + API_VERSION -> { + val comboBox = super.createComboBox(row, index, items).bindEnabled(useApiProperty) + row.checkBox("Use Fabric API").bindSelected(useApiProperty) + row.label(EMPTY_LABEL).bindText( + getVersionProperty(MINECRAFT_VERSION).transform { mcVersion -> + mcVersion as FabricMcVersion + val matched = apiVersions.versions.any { mcVersion.version in it.gameVersions } + if (matched) { + EMPTY_LABEL + } else { + "Unable to match API versions to Minecraft version" + } + } + ).bindEnabled(useApiProperty).component.foreground = JBColor.YELLOW + comboBox + } + else -> super.createComboBox(row, index, items) + } + } + + override fun getAvailableVersions(versionsAbove: List>): List> { + return when (versionsAbove.size) { + MINECRAFT_VERSION -> mcVersions + LOADER_VERSION -> fabricVersions.loader + YARN_VERSION -> { + val mcVersion = versionsAbove[MINECRAFT_VERSION] as FabricMcVersion + val filteredVersions = fabricVersions.mappings.mapNotNull { mapping -> + mapping.version.takeIf { mapping.gameVersion == mcVersion.version } + } + filteredVersions.ifEmpty { fabricVersions.mappings.map { it.version } } + } + API_VERSION -> { + val mcVersion = versionsAbove[MINECRAFT_VERSION] as FabricMcVersion + val filteredVersions = apiVersions.versions.mapNotNull { api -> + api.version.takeIf { mcVersion.version in api.gameVersions } + } + filteredVersions.ifEmpty { apiVersions.versions.map { it.version } } + } + else -> throw IncorrectOperationException() + } + } + + override fun setupUI(builder: Panel) { + super.setupUI(builder) + if (!showSnapshots) { + updateVersionBox() + } + } + + private fun updateVersionBox() { + val versionBox = getVersionBox(MINECRAFT_VERSION) ?: return + val selectedItem = versionBox.selectedItem + versionBox.removeAllItems() + for (gameVer in mcVersions) { + if (showSnapshots || gameVer.stable) { + versionBox.addItem(gameVer) + } + } + versionBox.selectedItem = selectedItem + } + + override fun setupProject(project: Project) { + super.setupProject(project) + data.putUserData(MC_VERSION_KEY, (getVersion(MINECRAFT_VERSION) as FabricMcVersion).version) + data.putUserData(LOADER_VERSION_KEY, getVersion(LOADER_VERSION) as SemanticVersion) + data.putUserData(YARN_VERSION_KEY, (getVersion(YARN_VERSION) as FabricVersions.YarnVersion).name) + if (useApi) { + data.putUserData(API_VERSION_KEY, getVersion(API_VERSION) as SemanticVersion) + } + } +} + +class FabricEnvironmentStep(parent: NewProjectWizardStep) : AbstractNewProjectWizardStep(parent) { + private val environmentProperty = propertyGraph.property(Side.NONE) + init { + environmentProperty.transform(Side::name, Side::valueOf).bindStorage("${javaClass.name}.side") + } + private var environment by environmentProperty + + override fun setupUI(builder: Panel) { + with(builder) { + row("Environment:") { + comboBox(listOf("Both", "Client", "Server")) + .bindItem( + environmentProperty.transform({ + when (it) { + Side.CLIENT -> "Client" + Side.SERVER -> "Server" + else -> "Both" + } + }, { + when (it) { + "Client" -> Side.CLIENT + "Server" -> Side.SERVER + else -> Side.NONE + } + }) + ) + } + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, environment) + } + + companion object { + val KEY = Key.create("${FabricEnvironmentStep::class.java.name}.environment") + } +} + +class FabricOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::RepositoryStep + ) +} Index: src/main/kotlin/platform/fabric/util/FabricApiVersions.kt =================================================================== --- src/main/kotlin/platform/fabric/util/FabricApiVersions.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/util/FabricApiVersions.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,78 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.util + +import com.demonwav.mcdev.creator.selectProxy +import com.demonwav.mcdev.update.PluginUtil +import com.demonwav.mcdev.util.SemanticVersion +import com.github.kittinunf.fuel.core.FuelManager +import com.github.kittinunf.fuel.core.requests.suspendable +import com.google.gson.JsonParser +import com.google.gson.JsonSyntaxException +import com.intellij.openapi.diagnostic.logger +import java.io.IOException + +private val LOGGER = logger() + +class FabricApiVersions(val versions: List) { + class Version(val gameVersions: List, val version: SemanticVersion) + + companion object { + suspend fun downloadData(): FabricApiVersions? { + try { + val url = "https://api.modrinth.com/v2/project/P7dR8mSH/version" + val manager = FuelManager() + manager.proxy = selectProxy(url) + + val response = manager.get(url) + .header("User-Agent", PluginUtil.useragent) + .suspendable() + .await() + + val versions = mutableListOf() + response.body().toStream().use { stream -> + val json = JsonParser.parseReader(stream.reader())?.asJsonArray ?: return null + versionLoop@ + for (ver in json) { + val version = ver?.asJsonObject ?: return null + val files = version["files"]?.asJsonArray ?: return null + for (file in files) { + val fileObj = file?.asJsonObject ?: return null + val filename = fileObj["filename"]?.asString ?: return null + if (!filename.startsWith("fabric-api-")) { + continue@versionLoop + } + } + val versionNumber = version["version_number"]?.asString?.let(SemanticVersion::tryParse) + ?: return null + val gameVersions = version["game_versions"]?.asJsonArray ?: return null + val gameVersionsList = mutableListOf() + for (gameVer in gameVersions) { + val gameVersion = gameVer?.asString ?: return null + gameVersionsList += gameVersion + } + versions += Version(gameVersionsList, versionNumber) + } + } + return FabricApiVersions(versions) + } catch (e: IOException) { + LOGGER.error(e) + } catch (e: JsonSyntaxException) { + LOGGER.error(e) + } catch (e: IllegalStateException) { + LOGGER.error(e) + } catch (e: UnsupportedOperationException) { + LOGGER.error(e) + } + return null + } + } +} Index: src/main/kotlin/platform/fabric/util/FabricVersions.kt =================================================================== --- src/main/kotlin/platform/fabric/util/FabricVersions.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/fabric/util/FabricVersions.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,89 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.fabric.util + +import com.demonwav.mcdev.creator.selectProxy +import com.demonwav.mcdev.update.PluginUtil +import com.demonwav.mcdev.util.SemanticVersion +import com.github.kittinunf.fuel.core.FuelManager +import com.github.kittinunf.fuel.core.requests.suspendable +import com.google.gson.JsonParser +import com.google.gson.JsonSyntaxException +import com.intellij.openapi.diagnostic.logger +import java.io.IOException + +private val LOGGER = logger() + +class FabricVersions(val game: List, val mappings: List, val loader: List) { + class Game(val version: String, val stable: Boolean) + class Mappings(val gameVersion: String, val version: YarnVersion) + + class YarnVersion(val name: String, val build: Int) : Comparable { + override fun toString() = name + override fun compareTo(other: YarnVersion) = build.compareTo(other.build) + } + + companion object { + suspend fun downloadData(): FabricVersions? { + try { + val url = "https://meta.fabricmc.net/v2/versions" + val manager = FuelManager() + manager.proxy = selectProxy(url) + + val response = manager.get(url) + .header("User-Agent", PluginUtil.useragent) + .suspendable() + .await() + + val gameList = mutableListOf() + val mappingsList = mutableListOf() + val loaderList = mutableListOf() + response.body().toStream().use { stream -> + val json = JsonParser.parseReader(stream.reader())?.asJsonObject ?: return null + + val game = json["game"]?.asJsonArray ?: return null + for (version in game) { + val versionObj = version?.asJsonObject ?: return null + val gameVer = versionObj["version"]?.asString ?: return null + val stable = versionObj["stable"]?.asBoolean ?: return null + gameList += Game(gameVer, stable) + } + + val mappings = json["mappings"]?.asJsonArray ?: return null + for (mapping in mappings) { + val mappingObj = mapping?.asJsonObject ?: return null + val gameVersion = mappingObj["gameVersion"]?.asString ?: return null + val version = mappingObj["version"]?.asString ?: return null + val build = mappingObj["build"]?.asInt ?: return null + mappingsList += Mappings(gameVersion, YarnVersion(version, build)) + } + + val loaders = json["loader"]?.asJsonArray ?: return null + for (loader in loaders) { + val loaderObj = loader?.asJsonObject ?: return null + val version = loaderObj["version"]?.asString?.let(SemanticVersion::tryParse) ?: return null + loaderList += version + } + } + return FabricVersions(gameList, mappingsList, loaderList) + } catch (e: IOException) { + LOGGER.error(e) + } catch (e: JsonSyntaxException) { + LOGGER.error(e) + } catch (e: IllegalStateException) { + LOGGER.error(e) + } catch (e: UnsupportedOperationException) { + LOGGER.error(e) + } + return null + } + } +} Index: src/main/kotlin/platform/forge/creator/Fg2Template.kt =================================================================== --- src/main/kotlin/platform/forge/creator/Fg2Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/Fg2Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,116 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.forge.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.forge.ForgeModuleType -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MCMOD_INFO_TEMPLATE -import com.demonwav.mcdev.util.SemanticVersion -import com.intellij.openapi.project.Project - -object Fg2Template : BaseTemplate() { - - fun applyMainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FORGE_MAIN_CLASS_TEMPLATE, props) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem, mcVersion: SemanticVersion): String { - val props = mapOf( - "FORGEGRADLE_VERSION" to fgVersion(mcVersion), - "GROUP_ID" to buildSystem.groupId, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FORGE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp( - project: Project, - config: ForgeProjectConfig - ): String { - val props = mapOf( - "FORGE_VERSION" to config.forgeVersionText, - "MCP_VERSION" to config.mcpVersion.mcpVersion - ) - - return project.applyTemplate(FORGE_GRADLE_PROPERTIES_TEMPLATE, props) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(FORGE_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem, mcVersion: SemanticVersion): String { - val props = mapOf( - "FORGEGRADLE_VERSION" to fgVersion(mcVersion), - "ARTIFACT_ID" to buildSystem.artifactId, - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName - ) - - return project.applyTemplate(FORGE_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyMcmodInfo(project: Project, buildSystem: BuildSystem, config: ForgeProjectConfig): String { - val props = mutableMapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName - ) - props["DESCRIPTION"] = config.description ?: "" - config.website?.let { url -> - if (url.isNotBlank()) { - props["URL"] = url - } - } - config.updateUrl?.let { url -> - if (url.isNotBlank()) { - props["UPDATE_URL"] = url - } - } - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.joinToString(", ") { "\"$it\"" } - } - - return project.applyTemplate(MCMOD_INFO_TEMPLATE, props) - } - - private fun fgVersion(mcVersion: SemanticVersion): String { - return if (mcVersion >= ForgeModuleType.FG23_MC_VERSION) { - "2.3" - } else { - "2.2" - } - } -} Index: src/main/kotlin/platform/forge/creator/Fg3Template.kt =================================================================== --- src/main/kotlin/platform/forge/creator/Fg3Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/Fg3Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,270 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.forge.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.forge.util.ForgeConstants -import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData -import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_1_17_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_1_18_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_1_19_3_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_1_19_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FG3_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.FORGE_MIXINS_JSON_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.MODS_TOML_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.PACK_MCMETA_TEMPLATE -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.toPackageName -import com.intellij.openapi.project.Project - -object Fg3Template : BaseTemplate() { - - fun applyMainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FG3_MAIN_CLASS_TEMPLATE, props) - } - - fun apply1_17MainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FG3_1_17_MAIN_CLASS_TEMPLATE, props) - } - - fun apply1_18MainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FG3_1_18_MAIN_CLASS_TEMPLATE, props) - } - - fun apply1_19MainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FG3_1_19_MAIN_CLASS_TEMPLATE, props) - } - - fun apply1_19_3MainClass( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - packageName: String, - className: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "MOD_VERSION" to buildSystem.version - ) - - return project.applyTemplate(FG3_1_19_3_MAIN_CLASS_TEMPLATE, props) - } - - fun applyBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - modName: String, - hasData: Boolean - ): String { - val (channel, version) = config.mcpVersion.mcpVersion.split('_', limit = 2) - val props = mutableMapOf( - "MOD_NAME" to modName, - "MCP_CHANNEL" to channel, - "MCP_VERSION" to version, - "MCP_MC_VERSION" to config.mcpVersion.mcVersion.toString(), - "FORGE_VERSION" to config.forgeVersionText, - "GROUP_ID" to buildSystem.groupId, - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_VERSION" to buildSystem.version, - "JAVA_VERSION" to config.javaVersion.feature - ) - if (hasData) { - props["HAS_DATA"] = "true" - } - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.joinToString(", ") - } - if (config.mixins) { - props["MIXINS"] = "true" - } - if (config.forgeVersion >= SemanticVersion.release(39, 0, 88)) { - props["GAME_TEST_FRAMEWORK"] = "true" - } - - return project.applyTemplate(FG3_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(FG3_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(FG3_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: ForgeProjectConfig, - modName: String, - hasData: Boolean - ): String { - val (channel, version) = config.mcpVersion.mcpVersion.split('_', limit = 2) - val props = mutableMapOf( - "MOD_NAME" to modName, - "MCP_CHANNEL" to channel, - "MCP_VERSION" to version, - "MCP_MC_VERSION" to config.mcpVersion.mcVersion.toString(), - "FORGE_VERSION" to config.forgeVersionText, - "ARTIFACT_ID" to buildSystem.artifactId, - "JAVA_VERSION" to if (config.mcVersion < MinecraftVersions.MC1_17) 8 else 16, - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName - ) - if (hasData) { - props["HAS_DATA"] = "true" - } - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.joinToString(", ") - } - if (config.mixins) { - props["MIXINS"] = "true" - } - - return project.applyTemplate(FG3_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyModsToml(project: Project, buildSystem: BuildSystem, config: ForgeProjectConfig): String { - val hasDisplayTestInManifest = config.forgeVersion >= ForgeConstants.DISPLAY_TEST_MANIFEST_VERSION - val nextMcVersion = when (val part = config.mcVersion.parts.getOrNull(1)) { - // Mimics the code used to get the next Minecraft version in Forge's MDK - // https://github.com/MinecraftForge/MinecraftForge/blob/0ff8a596fc1ef33d4070be89dd5cb4851f93f731/build.gradle#L884 - is SemanticVersion.Companion.VersionPart.ReleasePart -> (part.version + 1).toString() - null -> "?" - else -> part.versionString - } - val props = mutableMapOf( - "ARTIFACT_ID" to buildSystem.artifactId, - "MOD_NAME" to config.pluginName, - "DISPLAY_TEST" to hasDisplayTestInManifest, - "FORGE_SPEC_VERSION" to config.forgeVersion.parts[0].versionString, - "MC_VERSION" to config.mcVersion.toString(), - "MC_NEXT_VERSION" to "1.$nextMcVersion", - "LICENSE" to config.license.toString() - ) - props["DESCRIPTION"] = config.description ?: "" - config.updateUrl?.let { url -> - if (url.isNotBlank()) { - props["UPDATE_URL"] = url - } - } - config.website?.let { url -> - if (url.isNotBlank()) { - props["WEBSITE"] = url - } - } - if (config.hasAuthors()) { - props["AUTHOR_LIST"] = config.authors.joinToString(", ") - } - - return project.applyTemplate(MODS_TOML_TEMPLATE, props) - } - - fun applyPackMcmeta( - project: Project, - artifactId: String, - pack: ForgePackDescriptor, - additionalData: ForgePackAdditionalData? - ): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId, - "PACK_FORMAT" to pack.format.toString(), - "PACK_COMMENT" to pack.comment, - "FORGE_DATA" to additionalData, - ) - - return project.applyTemplate(PACK_MCMETA_TEMPLATE, props) - } - - fun applyMixinConfigTemplate( - project: Project, - buildSystem: BuildSystem - ): String { - val groupId = buildSystem.groupId.toPackageName() - val artifactId = buildSystem.artifactId.toPackageName() - val packageName = "$groupId.$artifactId.mixin" - val props = mapOf( - "PACKAGE_NAME" to packageName, - "ARTIFACT_ID" to artifactId - ) - return project.applyTemplate(FORGE_MIXINS_JSON_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/forge/creator/ForgeProjectConfig.kt =================================================================== --- src/main/kotlin/platform/forge/creator/ForgeProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/ForgeProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,86 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.forge.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.forge.ForgeModuleType -import com.demonwav.mcdev.platform.mcp.McpVersionPair -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.demonwav.mcdev.util.until -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class ForgeProjectConfig : ProjectConfig(), GradleCreator { - - lateinit var mainClass: String - - var updateUrl: String? = null - - override var type: PlatformType = PlatformType.FORGE - - var mcpVersion = McpVersionPair("", SemanticVersion.release()) - var forgeVersionText: String = "" - var forgeVersion: SemanticVersion = SemanticVersion.release() - var mcVersion: SemanticVersion = SemanticVersion.release() - var mixins = false - var license = License.ALL_RIGHTS_RESERVED - - override val preferredBuildSystem = BuildSystemType.GRADLE - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(mcVersion) - - override val compatibleGradleVersions: VersionRange - get() = when { - isFg3(mcVersion, forgeVersion) -> Fg3ProjectCreator.FG5_WRAPPER_VERSION until null - else -> VersionRange.fixed(Fg2ProjectCreator.FG_WRAPPER_VERSION) - } - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return if (isFg3(mcVersion, forgeVersion)) { - if (mcVersion >= ForgeModuleType.FG3_MC_VERSION) { - Fg3ProjectCreator(rootDirectory, module, buildSystem, this) - } else { - Fg3Mc112ProjectCreator(rootDirectory, module, buildSystem, this) - } - } else { - Fg2ProjectCreator(rootDirectory, module, buildSystem, this, mcVersion) - } - } - - override fun configureRootGradle( - rootDirectory: Path, - buildSystem: GradleBuildSystem - ) { - buildSystem.gradleVersion = if (isFg3(mcVersion, forgeVersion)) { - Fg3ProjectCreator.FG5_WRAPPER_VERSION - } else { - Fg2ProjectCreator.FG_WRAPPER_VERSION - } - } - - private fun isFg3(mcVersion: SemanticVersion, forgeVersion: SemanticVersion): Boolean { - return mcVersion >= ForgeModuleType.FG3_MC_VERSION || forgeVersion >= ForgeModuleType.FG3_FORGE_VERSION - } -} Index: src/main/kotlin/platform/forge/creator/ForgeProjectCreator.kt =================================================================== --- src/main/kotlin/platform/forge/creator/ForgeProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/ForgeProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,306 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.forge.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.LicenseStep -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.gradle.SimpleGradleSetupStep -import com.demonwav.mcdev.platform.forge.util.ForgeConstants -import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData -import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.runGradleTaskAndWait -import com.demonwav.mcdev.util.runWriteTask -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardOpenOption.CREATE -import java.nio.file.StandardOpenOption.TRUNCATE_EXISTING -import java.nio.file.StandardOpenOption.WRITE -import java.util.Locale - -class Fg2ProjectCreator( - private val rootDirectory: Path, - private val rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: ForgeProjectConfig, - private val mcVersion: SemanticVersion -) : BaseProjectCreator(rootModule, buildSystem) { - - private fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - Fg2Template.applyMainClass(project, buildSystem, config, packageName, className) - } - } - - override fun getSteps(): Iterable { - val buildText = Fg2Template.applyBuildGradle(project, buildSystem, mcVersion) - val propText = Fg2Template.applyGradleProp(project, config) - val settingsText = Fg2Template.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - files - ), - setupMainClassStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - McmodInfoStep(project, buildSystem, config), - SetupDecompWorkspaceStep(project, rootDirectory), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem), - ForgeRunConfigsStep(buildSystem, rootDirectory, config, CreatedModuleType.SINGLE) - ) - } - - companion object { - val FG_WRAPPER_VERSION = SemanticVersion.release(4, 10, 3) - } -} - -open class Fg3ProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: GradleBuildSystem, - protected val config: ForgeProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - private fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - if (config.mcVersion >= MinecraftVersions.MC1_19_3) { - Fg3Template.apply1_19_3MainClass(project, buildSystem, config, packageName, className) - } else if (config.mcVersion >= MinecraftVersions.MC1_19) { - Fg3Template.apply1_19MainClass(project, buildSystem, config, packageName, className) - } else if (config.mcVersion >= MinecraftVersions.MC1_18) { - Fg3Template.apply1_18MainClass(project, buildSystem, config, packageName, className) - } else if (config.mcVersion >= MinecraftVersions.MC1_17) { - Fg3Template.apply1_17MainClass(project, buildSystem, config, packageName, className) - } else { - Fg3Template.applyMainClass(project, buildSystem, config, packageName, className) - } - } - } - - protected fun transformModName(modName: String?): String { - modName ?: return "examplemod" - return modName.lowercase(Locale.ENGLISH).replace(" ", "") - } - - protected fun createGradleFiles(hasData: Boolean): GradleFiles { - val modName = transformModName(config.pluginName) - val buildText = Fg3Template.applyBuildGradle(project, buildSystem, config, modName, hasData) - val propText = Fg3Template.applyGradleProp(project) - val settingsText = Fg3Template.applySettingsGradle(project, buildSystem.artifactId) - return GradleFiles(buildText, propText, settingsText) - } - - override fun getSteps(): Iterable { - val files = createGradleFiles(hasData = true) - val steps = mutableListOf( - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - files - ), - setupMainClassStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - Fg3ProjectFilesStep(project, buildSystem, config), - Fg3CompileJavaStep(project, rootDirectory), - GradleGitignoreStep(project, rootDirectory), - LicenseStep(project, rootDirectory, config.license, config.authors.joinToString(", ")), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem), - ForgeRunConfigsStep(buildSystem, rootDirectory, config, CreatedModuleType.SINGLE) - ) - - if (config.mixins) { - steps += MixinConfigStep(project, buildSystem) - } - - return steps - } - - companion object { - val FG5_WRAPPER_VERSION = SemanticVersion.release(7, 5, 1) - } -} - -class Fg3Mc112ProjectCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: ForgeProjectConfig -) : Fg3ProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - private fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - Fg2Template.applyMainClass(project, buildSystem, config, packageName, className) - } - } - - override fun getSteps(): Iterable { - val files = createGradleFiles(hasData = false) - - return listOf( - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - files - ), - setupMainClassStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - McmodInfoStep(project, buildSystem, config), - Fg3CompileJavaStep(project, rootDirectory), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem), - ForgeRunConfigsStep(buildSystem, rootDirectory, config, CreatedModuleType.SINGLE) - ) - } -} - -class SetupDecompWorkspaceStep( - private val project: Project, - private val rootDirectory: Path -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - indicator.text = "Setting up project" - indicator.text2 = "Running Gradle task: 'setupDecompWorkspace'" - runGradleTaskAndWait(project, rootDirectory) { settings -> - settings.taskNames = listOf("setupDecompWorkspace") - settings.vmOptions = "-Xmx2G" - } - indicator.text2 = null - } -} - -class McmodInfoStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ForgeProjectConfig -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - val text = Fg2Template.applyMcmodInfo(project, buildSystem, config) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, ForgeConstants.MCMOD_INFO, text) - } - } -} - -class Fg3ProjectFilesStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: ForgeProjectConfig -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - val modsTomlText = Fg3Template.applyModsToml(project, buildSystem, config) - val packDescriptor = ForgePackDescriptor.forMcVersion(config.mcVersion) ?: ForgePackDescriptor.FORMAT_3 - val additionalData = ForgePackAdditionalData.forMcVersion(config.mcVersion) - val packMcmetaText = - Fg3Template.applyPackMcmeta(project, buildSystem.artifactId, packDescriptor, additionalData) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, ForgeConstants.PACK_MCMETA, packMcmetaText) - val meta = dir.resolve("META-INF") - Files.createDirectories(meta) - CreatorStep.writeTextToFile(project, meta, ForgeConstants.MODS_TOML, modsTomlText) - } - } -} - -class Fg3CompileJavaStep( - private val project: Project, - private val rootDirectory: Path -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - indicator.text = "Setting up classpath" - indicator.text2 = "Running Gradle task: 'compileJava'" - runGradleTaskAndWait(project, rootDirectory) { settings -> - settings.taskNames = listOf("compileJava") - } - indicator.text2 = null - } -} - -class MixinConfigStep( - private val project: Project, - private val buildSystem: BuildSystem -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val text = Fg3Template.applyMixinConfigTemplate(project, buildSystem) - val dir = buildSystem.dirsOrError.resourceDirectory - runWriteTask { - CreatorStep.writeTextToFile(project, dir, "${buildSystem.artifactId}.mixins.json", text) - } - } -} - -enum class CreatedModuleType { - SINGLE, MULTI -} - -class ForgeRunConfigsStep( - private val buildSystem: BuildSystem, - private val rootDirectory: Path, - private val config: ForgeProjectConfig, - private val createdModuleType: CreatedModuleType -) : CreatorStep { - - override fun runStep(indicator: ProgressIndicator) { - val gradleDir = rootDirectory.resolve(".gradle") - Files.createDirectories(gradleDir) - val hello = gradleDir.resolve(HELLO) - - val task = if (createdModuleType == CreatedModuleType.MULTI) { - ":${buildSystem.artifactId}:genIntellijRuns" - } else { - "genIntellijRuns" - } - - // We don't use `rootModule.name` here because Gradle will change the name of the module to match - // what was set as the artifactId once it imports the project - val moduleName = if (createdModuleType == CreatedModuleType.MULTI) { - "${buildSystem.parentOrError.artifactId}.${buildSystem.artifactId}" - } else { - buildSystem.artifactId - } - - val fileContents = moduleName + "\n" + - config.mcVersion + "\n" + - config.forgeVersion + "\n" + - task - - Files.write(hello, fileContents.toByteArray(Charsets.UTF_8), CREATE, TRUNCATE_EXISTING, WRITE) - } - - companion object { - const val HELLO = ".hello_from_mcdev" - } -} Index: src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,320 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/creator/ForgeProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,277 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.forge.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.platform.forge.version.ForgeVersion -import com.demonwav.mcdev.platform.mcp.McpVersionPair -import com.demonwav.mcdev.platform.mcp.version.McpVersion -import com.demonwav.mcdev.platform.mcp.version.McpVersionEntry -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.asyncIO -import com.demonwav.mcdev.util.modUpdateStep -import com.intellij.ui.CollectionComboBoxModel -import com.intellij.ui.EnumComboBoxModel -import java.awt.event.ActionListener -import javax.swing.JCheckBox -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JProgressBar -import javax.swing.JTextField -import kotlin.math.min -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing - -class ForgeProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - @ValidatedField(NON_BLANK) - private lateinit var modNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var panel: JPanel - private lateinit var title: JLabel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - private lateinit var updateUrlField: JTextField - private lateinit var licenseBox: JComboBox - private lateinit var mixinsCheckbox: JCheckBox - private lateinit var minecraftVersionBox: JComboBox - private lateinit var forgeVersionBox: JComboBox - private lateinit var mcpVersionBox: JComboBox - private lateinit var loadingBar: JProgressBar - private lateinit var minecraftVersionLabel: JLabel - private lateinit var mcpWarning: JLabel - private lateinit var errorLabel: JLabel - - private var config: ForgeProjectConfig? = null - - private data class ForgeVersions( - var mcpVersion: McpVersion, - var forgeVersion: ForgeVersion - ) - - private var versions: ForgeVersions? = null - - private var currentJob: Job? = null - - private val mcpBoxActionListener = ActionListener { - mcpWarning.isVisible = (mcpVersionBox.selectedItem as? McpVersionEntry)?.isRed == true - } - - private val forgeVersionBoxListener = ActionListener { - val selectedVersion = forgeVersionBox.selectedItem as? SemanticVersion ?: return@ActionListener - val supportedMixinVersion = selectedVersion >= SemanticVersion.release(31, 2, 45) - val mcpMappingsVersion = selectedVersion <= SemanticVersion.release(37, 0, 0) - - mixinsCheckbox.isEnabled = supportedMixinVersion - if (!supportedMixinVersion) { - mixinsCheckbox.isSelected = false - } - - mcpVersionBox.isEnabled = mcpMappingsVersion - mcpWarning.isVisible = mcpMappingsVersion - if (mcpMappingsVersion) { - mcpBoxActionListener.actionPerformed(null) - } - } - - private val minecraftBoxActionListener: ActionListener = ActionListener { - CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - updateForm() - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - } - } - - init { - mcpWarning.isVisible = false - } - - override fun getComponent(): JComponent { - return panel - } - - override fun updateStep() { - val (conf, buildSystem) = modUpdateStep(creator, modNameField) ?: return - config = conf - - mainClassField.text = generateClassName(buildSystem, modNameField.text) - - title.icon = PlatformAssets.FORGE_ICON_2X - title.text = "Forge Settings" - - minecraftVersionLabel.text = "Minecraft Version" - - licenseBox.model = EnumComboBoxModel(License::class.java) - licenseBox.selectedItem = License.ALL_RIGHTS_RESERVED - - if (versions != null || currentJob?.isActive == true) { - return - } - currentJob = updateVersions() - } - - private fun setForgeVersion(data: Data) { - forgeVersionBox.model = CollectionComboBoxModel(data.forgeVersions.subList(0, min(50, data.forgeVersions.size))) - forgeVersionBox.selectedIndex = data.forgeSelectedIndex - } - - private val version: SemanticVersion? - get() = minecraftVersionBox.selectedItem as? SemanticVersion - - override fun validate(): Boolean { - return super.validate() && !loadingBar.isVisible - } - - override fun isStepVisible(): Boolean { - return creator.config is ForgeProjectConfig - } - - override fun onStepLeaving() { - currentJob?.cancel() - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.modNameField.text - conf.mainClass = this.mainClassField.text - conf.description = this.descriptionField.text - conf.website = this.websiteField.text - - conf.setAuthors(this.authorsField.text) - conf.updateUrl = this.updateUrlField.text - - conf.mcVersion = this.version ?: SemanticVersion.release() - conf.mcpVersion = if (conf.mcVersion >= MinecraftVersions.MC1_17) { - McpVersionPair("official_" + conf.mcVersion, conf.mcVersion) - } else { - (this.mcpVersionBox.selectedItem as McpVersionEntry).versionPair - } - - (this.forgeVersionBox.selectedItem as SemanticVersion).let { version -> - val versionString = version.toString() - val forgeVersion = this.versions?.forgeVersion ?: return@let - conf.forgeVersionText = forgeVersion.versions.first { it.endsWith(versionString) } - conf.forgeVersion = version - } - - conf.mixins = mixinsCheckbox.isSelected - conf.license = licenseBox.selectedItem as? License ?: License.ALL_RIGHTS_RESERVED - } - - private fun mcVersionUpdate(data: Data) { - mcpVersionBox.removeActionListener(mcpBoxActionListener) - mcpVersionBox.model = CollectionComboBoxModel(data.mcpVersions.subList(0, min(50, data.mcpVersions.size))) - mcpVersionBox.selectedIndex = 0 - mcpVersionBox.addActionListener(mcpBoxActionListener) - mcpBoxActionListener.actionPerformed(null) - - forgeVersionBox.removeActionListener(forgeVersionBoxListener) - setForgeVersion(data) - forgeVersionBox.addActionListener(forgeVersionBoxListener) - forgeVersionBoxListener.actionPerformed(null) - } - - private fun updateVersions() = CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - try { - downloadVersions() - val data = updateForm() - if (data != null) { - updateMcForm(data) - } - } catch (e: Exception) { - error() - } - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - - currentJob = null - } - - fun error() { - errorLabel.isVisible = true - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - } - - private suspend fun downloadVersions() = coroutineScope { - val mcpVersionJob = asyncIO { McpVersion.downloadData() } - val forgeVersionJob = asyncIO { ForgeVersion.downloadData() } - - versions = ForgeVersions( - mcpVersionJob.await() ?: return@coroutineScope, - forgeVersionJob.await() ?: return@coroutineScope - ) - } - - private suspend fun updateForm(): Data? = coroutineScope { - val vers = versions ?: return@coroutineScope null - - val selectedVersion = version ?: vers.forgeVersion.sortedMcVersions.firstOrNull() ?: return@coroutineScope null - - val mcpVersionListJob = asyncIO { vers.mcpVersion.getMcpVersionList(selectedVersion) } - val forgeVersionsJob = asyncIO { vers.forgeVersion.getForgeVersions(selectedVersion) } - - val mcpVersionList = mcpVersionListJob.await() - val forgeVersions = forgeVersionsJob.await() - - val data = Data(0, mcpVersionList, forgeVersions, 0) - - mcVersionUpdate(data) - - return@coroutineScope data - } - - private fun updateMcForm(data: Data) { - val vers = versions ?: return - - minecraftVersionBox.removeActionListener(minecraftBoxActionListener) - minecraftVersionBox.removeAllItems() - - minecraftVersionBox.model = CollectionComboBoxModel(vers.forgeVersion.sortedMcVersions) - minecraftVersionBox.selectedIndex = data.mcSelectedIndex - minecraftVersionBox.addActionListener(minecraftBoxActionListener) - } - - private data class Data( - val mcSelectedIndex: Int, - val mcpVersions: List, - val forgeVersions: List, - val forgeSelectedIndex: Int - ) -} Index: src/main/kotlin/platform/forge/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/forge/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/forge/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,139 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.forge.creator + +import com.demonwav.mcdev.creator.addLicense +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.UpdateUrlStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.forge.util.ForgeConstants +import com.demonwav.mcdev.platform.forge.util.ForgePackAdditionalData +import com.demonwav.mcdev.platform.forge.util.ForgePackDescriptor +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project + +class ForgeProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Forge project files" + + override fun setupAssets(project: Project) { + val mcVersion = data.getUserData(ForgeVersionChainStep.MC_VERSION_KEY) ?: return + val forgeVersion = data.getUserData(ForgeVersionChainStep.FORGE_VERSION_KEY) ?: return + val (mainPackageName, mainClassName) = splitPackage(data.getUserData(MainClassStep.KEY) ?: return) + val buildSystemProps = findStep>() + val modName = data.getUserData(AbstractModNameStep.KEY) ?: return + val license = data.getUserData(LicenseStep.KEY) ?: return + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val updateUrl = data.getUserData(UpdateUrlStep.KEY) ?: "" + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val website = data.getUserData(WebsiteStep.KEY) ?: "" + + val nextMcVersion = when (val part = mcVersion.parts.getOrNull(1)) { + // Mimics the code used to get the next Minecraft version in Forge's MDK + // https://github.com/MinecraftForge/MinecraftForge/blob/0ff8a596fc1ef33d4070be89dd5cb4851f93f731/build.gradle#L884 + is SemanticVersion.Companion.VersionPart.ReleasePart -> (part.version + 1).toString() + null -> "?" + else -> part.versionString + } + + val packDescriptor = ForgePackDescriptor.forMcVersion(mcVersion) ?: ForgePackDescriptor.FORMAT_3 + val additionalPackData = ForgePackAdditionalData.forMcVersion(mcVersion) + + assets.addTemplateProperties( + "PACKAGE_NAME" to mainPackageName, + "CLASS_NAME" to mainClassName, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "MOD_NAME" to modName, + "MOD_VERSION" to buildSystemProps.version, + "DISPLAY_TEST" to (forgeVersion >= ForgeConstants.DISPLAY_TEST_MANIFEST_VERSION), + "FORGE_SPEC_VERSION" to forgeVersion.parts[0].versionString, + "MC_VERSION" to mcVersion, + "MC_NEXT_VERSION" to "1.$nextMcVersion", + "LICENSE" to license, + "DESCRIPTION" to description, + "PACK_FORMAT" to packDescriptor.format, + "PACK_COMMENT" to packDescriptor.comment, + "FORGE_DATA" to (additionalPackData ?: ""), + ) + + if (updateUrl.isNotBlank()) { + assets.addTemplateProperties("UPDATE_URL" to updateUrl) + } + + if (authors.isNotEmpty()) { + assets.addTemplateProperties("AUTHOR_LIST" to authors.joinToString(", ")) + } + + if (website.isNotBlank()) { + assets.addTemplateProperties("WEBSITE" to website) + } + + val mainClassTemplate = when { + mcVersion >= MinecraftVersions.MC1_19_3 -> MinecraftTemplates.FG3_1_19_3_MAIN_CLASS_TEMPLATE + mcVersion >= MinecraftVersions.MC1_19 -> MinecraftTemplates.FG3_1_19_MAIN_CLASS_TEMPLATE + mcVersion >= MinecraftVersions.MC1_18 -> MinecraftTemplates.FG3_1_18_MAIN_CLASS_TEMPLATE + mcVersion >= MinecraftVersions.MC1_17 -> MinecraftTemplates.FG3_1_17_MAIN_CLASS_TEMPLATE + else -> MinecraftTemplates.FG3_MAIN_CLASS_TEMPLATE + } + + assets.addTemplates( + project, + "src/main/java/${mainPackageName.replace('.', '/')}/$mainClassName.java" to mainClassTemplate, + "src/main/resources/pack.mcmeta" to MinecraftTemplates.PACK_MCMETA_TEMPLATE, + "src/main/resources/META-INF/mods.toml" to MinecraftTemplates.MODS_TOML_TEMPLATE, + ) + + assets.addLicense(project) + } +} + +// Needs to be a separate step from above because of PACKAGE_NAME being different +class ForgeMixinsJsonStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating mixins json" + + override fun setupAssets(project: Project) { + val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false + if (useMixins) { + val buildSystemProps = findStep>() + assets.addTemplateProperties( + "PACKAGE_NAME" to "${buildSystemProps.groupId}.${buildSystemProps.artifactId}.mixin", + "ARTIFACT_ID" to buildSystemProps.artifactId, + ) + val mixinsJsonFile = "src/main/resources/${buildSystemProps.artifactId}.mixins.json" + assets.addTemplates(project, mixinsJsonFile to MinecraftTemplates.FORGE_MIXINS_JSON_TEMPLATE) + } + } +} + +class ForgeBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Forge" +} + +class ForgePostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, ForgeBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/forge/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/forge/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/forge/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,141 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.forge.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractRunGradleTaskStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GRADLE_VERSION_KEY +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.util.lang.JavaVersion +import java.util.Locale + +private val fg5WrapperVersion = SemanticVersion.release(7, 5, 1) + +const val MAGIC_RUN_CONFIGS_FILE = ".hello_from_mcdev" + +class ForgeGradleSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> ForgeGradleFilesStep(parent).chain(::GradleWrapperStep) + BuildSystemSupport.POST_STEP -> ForgeCompileJavaStep(parent).chain(::GradleImportStep) + else -> EmptyStep(parent) + } + } +} + +class ForgeGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + private fun transformModName(modName: String): String { + return modName.lowercase(Locale.ENGLISH).replace(" ", "") + } + + override fun setupAssets(project: Project) { + val mcVersion = data.getUserData(ForgeVersionChainStep.MC_VERSION_KEY) ?: return + val forgeVersion = data.getUserData(ForgeVersionChainStep.FORGE_VERSION_KEY) ?: return + val modName = transformModName(data.getUserData(AbstractModNameStep.KEY) ?: return) + val buildSystemProps = findStep>() + val javaVersion = context.projectJdk.versionString?.let(JavaVersion::parse) + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false + + data.putUserData(GRADLE_VERSION_KEY, fg5WrapperVersion) + + assets.addTemplateProperties( + "MOD_NAME" to modName, + "MCP_CHANNEL" to "official", + "MCP_VERSION" to mcVersion, + "MCP_MC_VERSION" to mcVersion, + "FORGE_VERSION" to "$mcVersion-$forgeVersion", + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "MOD_VERSION" to buildSystemProps.version, + "HAS_DATA" to "true", + ) + + if (javaVersion != null) { + assets.addTemplateProperties("JAVA_VERSION" to javaVersion.feature) + } + + if (authors.isNotEmpty()) { + assets.addTemplateProperties("AUTHOR_LIST" to authors.joinToString(", ")) + } + + if (useMixins) { + assets.addTemplateProperties("MIXINS" to "true") + } + + if (forgeVersion >= SemanticVersion.release(39, 0, 88)) { + assets.addTemplateProperties("GAME_TEST_FRAMEWORK" to "true") + } + + if (mcVersion <= MinecraftVersions.MC1_16_5) { + assets.addTemplateProperties( + "MCP_CHANNEL" to "snapshot", + "MCP_VERSION" to "20210309", + ) + } + + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.FG3_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.FG3_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.FG3_SETTINGS_GRADLE_TEMPLATE, + ) + + assets.addGradleWrapperProperties(project) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + + WriteAction.runAndWait { + val dir = VfsUtil.createDirectoryIfMissing( + LocalFileSystem.getInstance(), + "${assets.outputDirectory}/.gradle" + ) + ?: throw IllegalStateException("Unable to create .gradle directory") + val file = dir.findOrCreateChildData(this, MAGIC_RUN_CONFIGS_FILE) + val fileContents = buildSystemProps.artifactId + "\n" + + mcVersion + "\n" + + forgeVersion + "\n" + + "genIntellijRuns" + VfsUtil.saveText(file, fileContents) + } + } +} + +class ForgeCompileJavaStep(parent: NewProjectWizardStep) : AbstractRunGradleTaskStep(parent) { + override val task = "compileJava" +} Index: src/main/kotlin/platform/forge/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/forge/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/forge/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,99 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.forge.creator + +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.platformtype.ModPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractMcVersionChainStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.ModNameStep +import com.demonwav.mcdev.creator.step.UpdateUrlStep +import com.demonwav.mcdev.creator.step.UseMixinsStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.forge.version.ForgeVersion +import com.demonwav.mcdev.util.MinecraftVersions +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key +import com.intellij.util.IncorrectOperationException +import kotlinx.coroutines.coroutineScope + +private val minSupportedMcVersion = MinecraftVersions.MC1_16_5 + +class ForgePlatformStep(parent: ModPlatformStep) : AbstractLatentStep(parent) { + override val description = "fetch Forge versions" + + override suspend fun computeData() = coroutineScope { + asyncIO { ForgeVersion.downloadData() }.await() + } + + override fun createStep(data: ForgeVersion) = ForgeVersionChainStep(this, data) + .chain( + ::ModNameStep, + ::MainClassStep, + ::UseMixinsStep, + ::LicenseStep, + ::ForgeOptionalSettingsStep, + ::ForgeBuildSystemStep, + ::ForgeProjectFilesStep, + ::ForgeMixinsJsonStep, + ::ForgePostBuildSystemStep, + ) + + class Factory : ModPlatformStep.Factory { + override val name = "Forge" + override fun createStep(parent: ModPlatformStep) = ForgePlatformStep(parent) + } +} + +class ForgeVersionChainStep( + parent: NewProjectWizardStep, + private val forgeVersionData: ForgeVersion +) : AbstractMcVersionChainStep(parent, "Forge Version:") { + companion object { + private const val FORGE_VERSION = 1 + + val MC_VERSION_KEY = Key.create("${ForgeVersionChainStep::class.java}.mcVersion") + val FORGE_VERSION_KEY = Key.create("${ForgeVersionChainStep::class.java}.forgeVersion") + } + + override fun getAvailableVersions(versionsAbove: List>): List> { + return when (versionsAbove.size) { + MINECRAFT_VERSION -> forgeVersionData.sortedMcVersions.filter { it >= minSupportedMcVersion } + FORGE_VERSION -> forgeVersionData.getForgeVersions(versionsAbove[MINECRAFT_VERSION] as SemanticVersion) + else -> throw IncorrectOperationException() + } + } + + override fun setupProject(project: Project) { + super.setupProject(project) + data.putUserData(MC_VERSION_KEY, getVersion(MINECRAFT_VERSION) as SemanticVersion) + data.putUserData(FORGE_VERSION_KEY, getVersion(FORGE_VERSION) as SemanticVersion) + } +} + +class ForgeOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::UpdateUrlStep + ) +} Index: src/main/kotlin/platform/forge/gradle/ForgeRunConfigDataService.kt =================================================================== --- src/main/kotlin/platform/forge/gradle/ForgeRunConfigDataService.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/forge/gradle/ForgeRunConfigDataService.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -11,7 +11,7 @@ package com.demonwav.mcdev.platform.forge.gradle import com.demonwav.mcdev.platform.forge.ForgeModuleType -import com.demonwav.mcdev.platform.forge.creator.ForgeRunConfigsStep +import com.demonwav.mcdev.platform.forge.creator.MAGIC_RUN_CONFIGS_FILE import com.demonwav.mcdev.util.SemanticVersion import com.demonwav.mcdev.util.invokeAndWait import com.demonwav.mcdev.util.invokeLater @@ -57,7 +57,7 @@ val baseDir = project.guessProjectDir() ?: return val baseDirPath = baseDir.localFile.toPath() - val hello = baseDirPath.resolve(Paths.get(".gradle", ForgeRunConfigsStep.HELLO)) + val hello = baseDirPath.resolve(Paths.get(".gradle", MAGIC_RUN_CONFIGS_FILE)) if (!Files.isRegularFile(hello)) { return } Index: src/main/kotlin/platform/liteloader/LiteLoaderFileIconProvider.kt =================================================================== --- src/main/kotlin/platform/liteloader/LiteLoaderFileIconProvider.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/LiteLoaderFileIconProvider.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,37 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader - -import com.demonwav.mcdev.MinecraftSettings -import com.demonwav.mcdev.facet.MinecraftFacet -import com.intellij.ide.FileIconProvider -import com.intellij.openapi.module.ModuleUtilCore -import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.VirtualFile -import javax.swing.Icon - -class LiteLoaderFileIconProvider : FileIconProvider { - override fun getIcon(file: VirtualFile, flags: Int, project: Project?): Icon? { - project ?: return null - - if (!MinecraftSettings.instance.isShowProjectPlatformIcons) { - return null - } - - val module = ModuleUtilCore.findModuleForFile(file, project) ?: return null - val liteloaderModule = MinecraftFacet.getInstance(module, LiteLoaderModuleType) ?: return null - - if (file == liteloaderModule.litemodJson) { - return liteloaderModule.icon - } - return null - } -} Index: src/main/kotlin/platform/liteloader/LiteLoaderModule.kt =================================================================== --- src/main/kotlin/platform/liteloader/LiteLoaderModule.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/LiteLoaderModule.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,50 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.facet.MinecraftFacet -import com.demonwav.mcdev.platform.AbstractModule -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.liteloader.util.LiteLoaderConstants -import com.demonwav.mcdev.util.SourceType -import com.demonwav.mcdev.util.nullable -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiMethod -import org.jetbrains.uast.UClass -import org.jetbrains.uast.UIdentifier -import org.jetbrains.uast.toUElementOfType - -class LiteLoaderModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) { - - var litemodJson by nullable { facet.findFile(LiteLoaderConstants.LITEMOD_JSON, SourceType.RESOURCE) } - private set - - override val moduleType = LiteLoaderModuleType - override val type = PlatformType.LITELOADER - override val icon = PlatformAssets.LITELOADER_ICON - - override fun isEventClassValid(eventClass: PsiClass, method: PsiMethod?) = true - - override fun writeErrorMessageForEventParameter(eventClass: PsiClass, method: PsiMethod) = "" - - override fun shouldShowPluginIcon(element: PsiElement?): Boolean { - val identifier = element?.toUElementOfType() - ?: return false - return identifier.uastParent is UClass && identifier.name.startsWith("LiteMod") - } - - override fun dispose() { - super.dispose() - litemodJson = null - } -} Index: src/main/kotlin/platform/liteloader/LiteLoaderModuleType.kt =================================================================== --- src/main/kotlin/platform/liteloader/LiteLoaderModuleType.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/LiteLoaderModuleType.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,32 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.facet.MinecraftFacet -import com.demonwav.mcdev.platform.AbstractModuleType -import com.demonwav.mcdev.platform.PlatformType - -object LiteLoaderModuleType : AbstractModuleType("", "") { - - private const val ID = "LITELOADER_MODULE_TYPE" - - val IGNORED_ANNOTATIONS = emptyList() - val LISTENER_ANNOTATIONS = emptyList() - - override val platformType = PlatformType.LITELOADER - override val icon = PlatformAssets.LITELOADER_ICON - override val id = ID - override val ignoredAnnotations = IGNORED_ANNOTATIONS - override val listenerAnnotations = LISTENER_ANNOTATIONS - - override fun generateModule(facet: MinecraftFacet) = LiteLoaderModule(facet) -} Index: src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectConfig.kt =================================================================== --- src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,58 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.forge.creator.Fg2ProjectCreator -import com.demonwav.mcdev.platform.mcp.McpVersionPair -import com.demonwav.mcdev.util.MinecraftVersions -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class LiteLoaderProjectConfig : ProjectConfig(), GradleCreator { - - lateinit var mainClass: String - - var mcpVersion = McpVersionPair("", SemanticVersion.release()) - var mcVersion: SemanticVersion = SemanticVersion.release() - - override var type = PlatformType.LITELOADER - - override val preferredBuildSystem = BuildSystemType.GRADLE - - override val javaVersion: JavaVersion - get() = MinecraftVersions.requiredJavaVersion(mcVersion) - - override val compatibleGradleVersions: VersionRange = VersionRange.fixed(Fg2ProjectCreator.FG_WRAPPER_VERSION) - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return LiteLoaderProjectCreator(rootDirectory, module, buildSystem, this) - } - - override fun configureRootGradle( - rootDirectory: Path, - buildSystem: GradleBuildSystem - ) { - buildSystem.gradleVersion = Fg2ProjectCreator.FG_WRAPPER_VERSION - } -} Index: src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectCreator.kt =================================================================== --- src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,60 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.gradle.SimpleGradleSetupStep -import com.demonwav.mcdev.platform.forge.creator.SetupDecompWorkspaceStep -import com.intellij.openapi.module.Module -import java.nio.file.Path - -class LiteLoaderProjectCreator( - private val rootDirectory: Path, - private val rootModule: Module, - private val buildSystem: GradleBuildSystem, - private val config: LiteLoaderProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - private fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - val modName = config.pluginName - LiteLoaderTemplate.applyMainClass(project, packageName, className, modName, buildSystem.version) - } - } - - override fun getSteps(): Iterable { - val buildText = LiteLoaderTemplate.applyBuildGradle(project, buildSystem, config.mcVersion) - val propText = LiteLoaderTemplate.applyGradleProp(project, config) - val settingsText = LiteLoaderTemplate.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - SimpleGradleSetupStep( - project, - rootDirectory, - buildSystem, - files - ), - setupMainClassStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - SetupDecompWorkspaceStep(project, rootDirectory), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - } -} Index: src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,179 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/creator/LiteLoaderProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,253 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.creator - -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.creator.exception.EmptyInputSetupException -import com.demonwav.mcdev.creator.exception.SetupException -import com.demonwav.mcdev.platform.liteloader.version.LiteLoaderVersion -import com.demonwav.mcdev.platform.mcp.version.McpVersion -import com.demonwav.mcdev.platform.mcp.version.McpVersionEntry -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.asyncIO -import com.demonwav.mcdev.util.invokeLater -import com.intellij.openapi.ui.MessageType -import com.intellij.openapi.ui.popup.Balloon -import com.intellij.openapi.ui.popup.JBPopupFactory -import com.intellij.ui.DocumentAdapter -import com.intellij.ui.awt.RelativePoint -import java.awt.event.ActionListener -import java.util.regex.Pattern -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JProgressBar -import javax.swing.JTextField -import javax.swing.event.DocumentEvent -import javax.swing.text.AbstractDocument -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import kotlinx.coroutines.withContext -import org.apache.commons.lang.WordUtils - -class LiteLoaderProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - private lateinit var panel: JPanel - private lateinit var mcpWarning: JLabel - - @ValidatedField(NON_BLANK) - private lateinit var modNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var minecraftVersionBox: JComboBox - private lateinit var mcpVersionBox: JComboBox - private lateinit var loadingBar: JProgressBar - - private var config: LiteLoaderProjectConfig? = null - - private data class LiteLoaderVersions( - val mcpVersion: McpVersion, - val liteloaderVersion: LiteLoaderVersion - ) - - private var versions: LiteLoaderVersions? = null - private var mainClassModified = false - - private var currentJob: Job? = null - - private val mcpBoxActionListener = ActionListener { - mcpWarning.isVisible = (mcpVersionBox.selectedItem as McpVersionEntry).isRed - } - - private val listener = object : DocumentAdapter() { - override fun textChanged(e: DocumentEvent) { - // Make sure they don't try to add spaces or whatever - if (javaClassPattern.matcher(mainClassField.text).find()) { - invokeLater { - mainClassField.document.removeDocumentListener(this) - (e as AbstractDocument.DefaultDocumentEvent).undo() - mainClassField.document.addDocumentListener(this) - } - return - } - - // We just need to make sure they aren't messing up the LiteMod text - val words = mainClassField.text.split(".").dropLastWhile(String::isEmpty).toTypedArray() - if (!words.last().startsWith(LITEMOD)) { - invokeLater { - mainClassField.document.removeDocumentListener(this) - (e as AbstractDocument.DefaultDocumentEvent).undo() - mainClassField.document.addDocumentListener(this) - } - } else { - mainClassModified = true - } - } - } - - init { - mcpWarning.isVisible = false - - minecraftVersionBox.addActionListener { - val mcpVersion = versions?.mcpVersion ?: return@addActionListener - CoroutineScope(Dispatchers.Swing).launch { - val version = minecraftVersionBox.selectedItem as SemanticVersion - val mcpVersions = withContext(Dispatchers.Default) { mcpVersion.getMcpVersionList(version) } - - mcpVersionBox.removeActionListener(mcpBoxActionListener) - mcpVersionBox.removeAllItems() - mcpVersions.forEach { mcpVersionBox.addItem(it) } - mcpVersionBox.addActionListener(mcpBoxActionListener) - mcpBoxActionListener.actionPerformed(null) - } - } - - modNameField.document.addDocumentListener( - object : DocumentAdapter() { - override fun textChanged(e: DocumentEvent) { - if (mainClassModified) { - return - } - - val word = modNameField.text.split(Regex("\\s+")).joinToString("") { WordUtils.capitalize(it) } - - val mainClassWords = mainClassField.text.split('.').toTypedArray() - mainClassWords[mainClassWords.size - 1] = LITEMOD + word - - mainClassField.document.removeDocumentListener(listener) - mainClassField.text = mainClassWords.joinToString(".") - mainClassField.document.addDocumentListener(listener) - } - } - ) - - mainClassField.document.addDocumentListener(listener) - } - - override fun getComponent(): JComponent { - return panel - } - - override fun validate(): Boolean { - try { - if (modNameField.text.isBlank()) { - throw EmptyInputSetupException(modNameField) - } - - if (mainClassField.text.isBlank()) { - throw EmptyInputSetupException(mainClassField) - } - } catch (e: SetupException) { - JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(e.error, MessageType.ERROR, null) - .setFadeoutTime(4000) - .createBalloon() - .show(RelativePoint.getSouthWestOf(e.j), Balloon.Position.below) - return false - } - - return !loadingBar.isVisible - } - - override fun isStepVisible(): Boolean { - return creator.config is LiteLoaderProjectConfig - } - - override fun updateStep() { - config = creator.config as? LiteLoaderProjectConfig - if (config == null) { - return - } - - val buildSystem = creator.buildSystem ?: return - - modNameField.text = WordUtils.capitalizeFully(buildSystem.artifactId.replace('-', ' ')) - - mainClassField.document.removeDocumentListener(listener) - mainClassField.text = generateClassName(buildSystem, modNameField.text) { name -> LITEMOD + name } - mainClassField.document.addDocumentListener(listener) - - if (versions != null || currentJob?.isActive == true) { - return - } - currentJob = updateVersions() - } - - override fun onStepLeaving() { - currentJob?.cancel() - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.modNameField.text - conf.mainClass = this.mainClassField.text - - conf.mcVersion = this.minecraftVersionBox.selectedItem as SemanticVersion - conf.mcpVersion = (this.mcpVersionBox.selectedItem as McpVersionEntry).versionPair - } - - private fun updateVersions() = CoroutineScope(Dispatchers.Swing).launch { - loadingBar.isIndeterminate = true - loadingBar.isVisible = true - - val version = minecraftVersionBox.selectedItem as? SemanticVersion - - val mcpVersionJob = asyncIO { McpVersion.downloadData() } - val liteloaderVersionJob = asyncIO { LiteLoaderVersion.downloadData() } - - val (mcpVersionObj, liteloaderVersionObj) = listOf(mcpVersionJob, liteloaderVersionJob).awaitAll() - val mcpVersion = mcpVersionObj as McpVersion? ?: return@launch - val liteloaderVersion = liteloaderVersionObj as LiteLoaderVersion? ?: return@launch - - val data = withContext(Dispatchers.IO) { - val listVersion = version ?: liteloaderVersion.sortedMcVersions.first() - return@withContext mcpVersion.getMcpVersionList(listVersion) - } - - if (liteloaderVersion.sortedMcVersions.isEmpty()) { - return@launch - } - - minecraftVersionBox.removeAllItems() - - liteloaderVersion.sortedMcVersions.forEach { minecraftVersionBox.addItem(it) } - // Always select most recent - minecraftVersionBox.selectedIndex = 0 - - mcpVersionBox.removeActionListener(mcpBoxActionListener) - mcpVersionBox.removeAllItems() - data.forEach { mcpVersionBox.addItem(it) } - mcpVersionBox.addActionListener(mcpBoxActionListener) - mcpBoxActionListener.actionPerformed(null) - - versions = LiteLoaderVersions(mcpVersion, liteloaderVersion) - - loadingBar.isIndeterminate = false - loadingBar.isVisible = false - - currentJob = null - } - - companion object { - private const val LITEMOD = "LiteMod" - private val javaClassPattern = Pattern.compile("\\s+|-|\\$") - } -} Index: src/main/kotlin/platform/liteloader/creator/LiteLoaderTemplate.kt =================================================================== --- src/main/kotlin/platform/liteloader/creator/LiteLoaderTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/creator/LiteLoaderTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,89 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.forge.ForgeModuleType -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.LITELOADER_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.LITELOADER_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.LITELOADER_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.LITELOADER_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.LITELOADER_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.SemanticVersion -import com.intellij.openapi.project.Project - -object LiteLoaderTemplate : BaseTemplate() { - - fun applyMainClass( - project: Project, - packageName: String, - className: String, - modName: String, - modVersion: String - ): String { - val props = mapOf( - "PACKAGE_NAME" to packageName, - "CLASS_NAME" to className, - "MOD_NAME" to modName, - "MOD_VERSION" to modVersion - ) - - return project.applyTemplate(LITELOADER_MAIN_CLASS_TEMPLATE, props) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem, mcVersion: SemanticVersion): String { - val props = mapOf( - "FORGEGRADLE_VERSION" to fgVersion(mcVersion), - "GROUP_ID" to buildSystem.groupId, - "ARTIFACT_ID" to buildSystem.artifactId, - "VERSION" to buildSystem.version - ) - - return project.applyTemplate(LITELOADER_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project, config: LiteLoaderProjectConfig): String { - val props = mapOf( - "MC_VERSION" to config.mcVersion.toString(), - "MCP_MAPPINGS" to config.mcpVersion.mcpVersion - ) - - return project.applyTemplate(LITELOADER_GRADLE_PROPERTIES_TEMPLATE, props) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(LITELOADER_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem, mcVersion: SemanticVersion): String { - val props = mapOf( - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName, - "FORGEGRADLE_VERSION" to fgVersion(mcVersion), - "ARTIFACT_ID" to buildSystem.artifactId - ) - - return project.applyTemplate(LITELOADER_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } - - private fun fgVersion(mcVersion: SemanticVersion): String { - // Fixes builds for MC1.12+, requires FG 2.3 - return if (mcVersion >= ForgeModuleType.FG23_MC_VERSION) { - "2.3" - } else { - "2.2" - } - } -} Index: src/main/kotlin/platform/liteloader/framework/LiteLoaderLibraryKind.kt =================================================================== --- src/main/kotlin/platform/liteloader/framework/LiteLoaderLibraryKind.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/framework/LiteLoaderLibraryKind.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,16 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.framework - -import com.demonwav.mcdev.util.libraryKind -import com.intellij.openapi.roots.libraries.LibraryKind - -val LITELOADER_LIBRARY_KIND: LibraryKind = libraryKind("liteloader-library") Index: src/main/kotlin/platform/liteloader/framework/LiteLoaderPresentationProvider.kt =================================================================== --- src/main/kotlin/platform/liteloader/framework/LiteLoaderPresentationProvider.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/framework/LiteLoaderPresentationProvider.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,20 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.framework - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.facet.ManifestLibraryPresentationProvider -import com.intellij.framework.library.LibraryVersionProperties - -class LiteLoaderPresentationProvider : - ManifestLibraryPresentationProvider(LITELOADER_LIBRARY_KIND, "LiteLoader", true) { - override fun getIcon(properties: LibraryVersionProperties?) = PlatformAssets.LITELOADER_ICON -} Index: src/main/kotlin/platform/liteloader/util/LiteLoaderConstants.kt =================================================================== --- src/main/kotlin/platform/liteloader/util/LiteLoaderConstants.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/util/LiteLoaderConstants.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.util - -object LiteLoaderConstants { - const val LITEMOD_JSON = "litemod.json" -} Index: src/main/kotlin/platform/liteloader/version/LiteLoaderVersion.kt =================================================================== --- src/main/kotlin/platform/liteloader/version/LiteLoaderVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/liteloader/version/LiteLoaderVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,59 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.liteloader.version - -import com.demonwav.mcdev.creator.selectProxy -import com.demonwav.mcdev.update.PluginUtil -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.fromJson -import com.demonwav.mcdev.util.sortVersions -import com.github.kittinunf.fuel.core.FuelManager -import com.github.kittinunf.fuel.core.requests.suspendable -import com.github.kittinunf.fuel.coroutines.awaitString -import com.google.gson.Gson -import com.intellij.openapi.diagnostic.logger -import java.io.IOException - -class LiteLoaderVersion private constructor(private var map: Map<*, *>) { - - val sortedMcVersions: List by lazy { - val mcVersion = map["versions"] as Map<*, *> - - @Suppress("UNCHECKED_CAST") - val keys = mcVersion.keys as Collection - return@lazy sortVersions(keys) - } - - companion object { - private val LOGGER = logger() - - suspend fun downloadData(): LiteLoaderVersion? { - try { - val url = "https://dl.liteloader.com/versions/versions.json" - val manager = FuelManager() - manager.proxy = selectProxy(url) - - val text = manager.get(url) - .header("User-Agent", PluginUtil.useragent) - .suspendable() - .awaitString() - - val map = Gson().fromJson>(text) - val liteLoaderVersion = LiteLoaderVersion(map) - liteLoaderVersion.sortedMcVersions - return liteLoaderVersion - } catch (e: IOException) { - LOGGER.error("Failed to download LiteLoader version json", e) - } - return null - } - } -} Index: src/main/kotlin/platform/sponge/creator/Sponge8ProjectCreator.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/Sponge8ProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/Sponge8ProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,117 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleSetupStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenGitignoreStep -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import java.nio.file.Path - -sealed class Sponge8ProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: T, - protected val config: SpongeProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - protected fun setupDependencyStep(): SpongeDependenciesSetup { - val spongeApiVersion = config.spongeApiVersion - return SpongeDependenciesSetup(buildSystem, spongeApiVersion, false) - } - - protected fun setupMainClassStep(): BasicJavaClassStep { - return createJavaClassStep(config.mainClass) { packageName, className -> - val pluginId = (buildSystem.parent ?: buildSystem).artifactId - Sponge8Template.applyMainClass(project, pluginId, packageName, className) - } - } -} - -class Sponge8MavenCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: MavenBuildSystem, - config: SpongeProjectConfig -) : Sponge8ProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val mainClassStep = setupMainClassStep() - val pluginsJsonStep = CreatePluginsJsonStep(project, buildSystem, config) - - val pomText = SpongeTemplate.applyPom(project, config) - - return listOf( - setupDependencyStep(), - BasicMavenStep(project, rootDirectory, buildSystem, config, pomText), - mainClassStep, - pluginsJsonStep, - MavenGitignoreStep(project, rootDirectory), - BasicMavenFinalizerStep(rootModule, rootDirectory), - ) - } -} - -class CreatePluginsJsonStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val config: SpongeProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val pluginsJsonPath = buildSystem.dirsOrError.resourceDirectory.resolve("META-INF") - val pluginsJsonText = Sponge8Template.applyPluginsJson(project, buildSystem, config) - CreatorStep.writeTextToFile(project, pluginsJsonPath, "sponge_plugins.json", pluginsJsonText) - } -} - -class Sponge8GradleCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: SpongeProjectConfig -) : Sponge8ProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val mainClassStep = setupMainClassStep() - - val buildText = Sponge8Template.applyBuildGradle( - project, - buildSystem, - config - ) - val propText = Sponge8Template.applyGradleProp(project) - val settingsText = Sponge8Template.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - CreateDirectoriesStep(buildSystem, rootDirectory), - GradleSetupStep(project, rootDirectory, buildSystem, files, true), - mainClassStep, - GradleWrapperStep(project, rootDirectory, buildSystem), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem, "runServer") - ) - } -} Index: src/main/kotlin/platform/sponge/creator/Sponge8Template.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/Sponge8Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/Sponge8Template.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,117 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_PLUGINS_JSON_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE8_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.intellij.openapi.project.Project - -object Sponge8Template : BaseTemplate() { - - fun applyMainClass( - project: Project, - pluginId: String, - packageName: String, - className: String - ): String { - val props = mutableMapOf( - "PLUGIN_ID" to pluginId, - "PACKAGE" to packageName, - "CLASS_NAME" to className - ) - - return project.applyTemplate(SPONGE8_MAIN_CLASS_TEMPLATE, props) - } - - fun applyPluginsJson( - project: Project, - buildSystem: BuildSystem, - config: SpongeProjectConfig - ): String { - val props = mutableMapOf( - "PLUGIN_ID" to buildSystem.artifactId, - "VERSION_PLACEHOLDER" to "\${version}", - "SPONGEAPI_VERSION" to config.spongeApiVersion, - "LICENSE" to config.license, - "PLUGIN_NAME" to config.pluginName, - "MAIN_CLASS" to config.mainClass, - "DESCRIPTION" to config.description, - "WEBSITE" to config.website, - "AUTHORS" to config.authors, - "DEPENDENCIES" to config.dependencies - ) - - return project.applyTemplate(SPONGE8_PLUGINS_JSON_TEMPLATE, props) - } - - fun applyBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: SpongeProjectConfig - ): String { - val props = mutableMapOf( - "JAVA_VERSION" to config.javaVersion.feature, - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_ID" to buildSystem.artifactId, - "PLUGIN_VERSION" to buildSystem.version, - "SPONGEAPI_VERSION" to config.spongeApiVersion, - "LICENSE" to config.license, - "PLUGIN_NAME" to config.pluginName, - "MAIN_CLASS" to config.mainClass, - "DESCRIPTION" to config.description, - "WEBSITE" to config.website, - "AUTHORS" to config.authors, - "DEPENDENCIES" to config.dependencies - ) - - return project.applyTemplate(SPONGE8_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(SPONGE8_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(SPONGE8_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle( - project: Project, - buildSystem: BuildSystem, - config: SpongeProjectConfig - ): String { - val props = mutableMapOf( - "JAVA_VERSION" to config.javaVersion.feature, - "PLUGIN_ID" to buildSystem.parentOrError.artifactId, - "SPONGEAPI_VERSION" to config.spongeApiVersion, - "LICENSE" to config.license, - "PLUGIN_NAME" to config.pluginName, - "MAIN_CLASS" to config.mainClass, - "DESCRIPTION" to config.description, - "WEBSITE" to config.website, - "AUTHORS" to config.authors, - "DEPENDENCIES" to config.dependencies, - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName - ) - - return project.applyTemplate(SPONGE8_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/sponge/creator/SpongeProjectConfig.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/SpongeProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/SpongeProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,96 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.sponge.util.SpongeConstants -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.demonwav.mcdev.util.until -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class SpongeProjectConfig : ProjectConfig(), MavenCreator, GradleCreator { - - lateinit var mainClass: String - - var spongeApiVersion = "" - val apiVersion: SemanticVersion - get() = if (spongeApiVersion.isBlank()) SemanticVersion.release() else SemanticVersion.parse(spongeApiVersion) - - override var type = PlatformType.SPONGE - - init { - type = PlatformType.SPONGE - } - - val dependencies = mutableListOf() - fun hasDependencies() = listContainsAtLeastOne(dependencies) - fun setDependencies(string: String) { - dependencies.clear() - dependencies.addAll(commaSplit(string)) - } - - var license = License.ALL_RIGHTS_RESERVED - - override val preferredBuildSystem = BuildSystemType.GRADLE - - override val javaVersion: JavaVersion - get() = when { - apiVersion >= SpongeConstants.API9 -> JavaVersion.compose(17) - else -> JavaVersion.compose(8) - } - - override fun buildMavenCreator( - rootDirectory: Path, - module: Module, - buildSystem: MavenBuildSystem - ): ProjectCreator { - val apiVersion = SemanticVersion.parse(spongeApiVersion) - return if (apiVersion < SpongeConstants.API8) { - SpongeMavenCreator(rootDirectory, module, buildSystem, this) - } else { - Sponge8MavenCreator(rootDirectory, module, buildSystem, this) - } - } - - override val compatibleGradleVersions: VersionRange - get() = when { - apiVersion >= SpongeConstants.API8 -> SemanticVersion.release(7, 4, 2) until null - else -> SemanticVersion.release(6, 0) until SemanticVersion.release(7) - } - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - val apiVersion = SemanticVersion.parse(spongeApiVersion) - return if (apiVersion < SpongeConstants.API8) { - SpongeGradleCreator(rootDirectory, module, buildSystem, this) - } else { - Sponge8GradleCreator(rootDirectory, module, buildSystem, this) - } - } - - override fun configureRootGradle(rootDirectory: Path, buildSystem: GradleBuildSystem) { - buildSystem.gradleVersion = compatibleGradleVersions.lower - } -} Index: src/main/kotlin/platform/sponge/creator/SpongeProjectCreator.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/SpongeProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/SpongeProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,227 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.LicenseStep -import com.demonwav.mcdev.creator.buildsystem.BuildDependency -import com.demonwav.mcdev.creator.buildsystem.BuildRepository -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.BuildSystemType -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleSetupStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenGitignoreStep -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTaskInSmartMode -import com.demonwav.mcdev.util.virtualFileOrError -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiManager -import com.intellij.psi.codeStyle.CodeStyleManager -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.util.EnumSet -import java.util.Locale - -sealed class SpongeProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: T, - protected val config: SpongeProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - protected fun setupDependencyStep(): SpongeDependenciesSetup { - val spongeApiVersion = config.spongeApiVersion - return SpongeDependenciesSetup(buildSystem, spongeApiVersion, true) - } - - protected fun setupMainClassSteps(): Pair { - val mainClassStep = createJavaClassStep(config.mainClass) { packageName, className -> - SpongeTemplate.applyMainClass(project, packageName, className, config.hasDependencies()) - } - - val (packageName, className) = splitPackage(config.mainClass) - return mainClassStep to SpongeMainClassModifyStep(project, buildSystem, packageName, className, config) - } -} - -class SpongeMavenCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: MavenBuildSystem, - config: SpongeProjectConfig -) : SpongeProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val (mainClassStep, modifyStep) = setupMainClassSteps() - - val pomText = SpongeTemplate.applyPom(project, config) - - return listOf( - setupDependencyStep(), - BasicMavenStep(project, rootDirectory, buildSystem, config, pomText), - mainClassStep, - modifyStep, - MavenGitignoreStep(project, rootDirectory), - LicenseStep(project, rootDirectory, config.license, config.authors.joinToString(", ")), - BasicMavenFinalizerStep(rootModule, rootDirectory) - ) - } -} - -class SpongeGradleCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: SpongeProjectConfig -) : SpongeProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - override fun getSteps(): Iterable { - val (mainClassStep, modifyStep) = setupMainClassSteps() - - val buildText = SpongeTemplate.applyBuildGradle(project, buildSystem) - val propText = SpongeTemplate.applyGradleProp(project) - val settingsText = SpongeTemplate.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - setupDependencyStep(), - CreateDirectoriesStep(buildSystem, rootDirectory), - GradleSetupStep(project, rootDirectory, buildSystem, files), - mainClassStep, - modifyStep, - GradleWrapperStep(project, rootDirectory, buildSystem), - GradleGitignoreStep(project, rootDirectory), - LicenseStep(project, rootDirectory, config.license, config.authors.joinToString(", ")), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - } -} - -class SpongeMainClassModifyStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val packageName: String, - private val className: String, - private val config: SpongeProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val dirs = buildSystem.dirsOrError - - project.runWriteTaskInSmartMode { - val targetDir = dirs.sourceDirectory.resolve(Paths.get(packageName.replace('.', '/'))) - if (!Files.isDirectory(targetDir)) { - throw IllegalStateException("$targetDir is not an existing directory") - } - val javaFile = targetDir.resolve("$className.java") - if (!Files.isRegularFile(javaFile)) { - throw IllegalStateException("$javaFile is not an existing file") - } - - val psiFile = PsiManager.getInstance(project).findFile(javaFile.virtualFileOrError) as? PsiJavaFile - ?: throw IllegalStateException("Failed to resolve PsiJavaFile for $javaFile") - val psiClass = psiFile.classes[0] - - val annotationString = StringBuilder("@Plugin(") - annotationString + "\nid = ${escape(buildSystem.artifactId.lowercase(Locale.ENGLISH))}" - annotationString + ",\nname = ${escape(config.pluginName)}" - if (buildSystem.type != BuildSystemType.GRADLE) { - // SpongeGradle will automatically set the Gradle version as plugin version - annotationString + ",\nversion = ${escape(buildSystem.version)}" - } - - if (config.hasDescription()) { - annotationString + ",\ndescription = ${escape(config.description)}" - } - - if (config.hasWebsite()) { - annotationString + ",\nurl = ${escape(config.website)}" - } - - if (config.hasAuthors()) { - annotationString + ",\nauthors = {\n${config.authors.joinToString(",\n", transform = ::escape)}\n}" - } - - if (config.hasDependencies()) { - val dep = config.dependencies.joinToString(",\n") { "@Dependency(id = ${escape(it)})" } - annotationString + ",\ndependencies = {\n$dep\n}" - } - - annotationString + "\n)" - val factory = JavaPsiFacade.getElementFactory(project) - val annotation = factory.createAnnotationFromText(annotationString.toString(), null) - - psiFile.runWriteAction { - psiClass.modifierList?.let { modifierList -> - modifierList.addBefore(annotation, modifierList.firstChild) - } - CodeStyleManager.getInstance(project).reformat(psiClass) - } - } - } - - private fun escape(text: String?): String { - if (text == null) { - return "\"\"" - } - return "\"" + text.replace("\\", "\\\\").replace("\"", "\\\"") + "\"" - } - - private operator fun StringBuilder.plus(text: String) = this.append(text) -} - -class SpongeDependenciesSetup( - private val buildSystem: BuildSystem, - private val spongeApiVersion: String, - private val addAnnotationProcessor: Boolean -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - buildSystem.repositories.add( - BuildRepository( - "spongepowered-repo", - "https://repo.spongepowered.org/maven/", - buildSystems = EnumSet.of(BuildSystemType.MAVEN) - ) - ) - buildSystem.dependencies.add( - BuildDependency( - "org.spongepowered", - "spongeapi", - spongeApiVersion, - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - if (addAnnotationProcessor) { - buildSystem.dependencies.add( - BuildDependency( - "org.spongepowered", - "spongeapi", - spongeApiVersion, - gradleConfiguration = "annotationProcessor" - ) - ) - } - } -} Index: src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,226 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/SpongeProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,126 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.asset.PlatformAssets -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.platform.sponge.SpongeVersion -import com.demonwav.mcdev.platform.sponge.util.SpongeConstants -import com.demonwav.mcdev.util.License -import com.demonwav.mcdev.util.SemanticVersion -import com.intellij.ui.EnumComboBoxModel -import com.intellij.util.text.nullize -import com.intellij.util.ui.UIUtil -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JTextField -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import kotlinx.coroutines.withContext - -class SpongeProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - @ValidatedField(NON_BLANK) - private lateinit var pluginNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var panel: JPanel - private lateinit var title: JLabel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - - @ValidatedField(LIST) - private lateinit var dependField: JTextField - private lateinit var licenseBox: JComboBox - private lateinit var spongeApiVersionBox: JComboBox - private lateinit var errorLabel: JLabel - - private var config: SpongeProjectConfig? = null - - private var versionsLoaded: Boolean = false - - init { - spongeApiVersionBox.addActionListener { - val stringVersion = spongeApiVersionBox.selectedItem as? String - licenseBox.isEnabled = stringVersion == null || SemanticVersion.parse(stringVersion) >= SpongeConstants.API8 - } - } - - override fun getComponent(): JComponent { - return panel - } - - override fun validate(): Boolean { - return super.validate() && spongeApiVersionBox.selectedItem != null - } - - override fun updateStep() { - config = creator.config as? SpongeProjectConfig - if (config == null) { - return - } - - basicUpdateStep(creator, pluginNameField, mainClassField) - - if (UIUtil.isUnderDarcula()) { - title.icon = PlatformAssets.SPONGE_ICON_2X_DARK - } else { - title.icon = PlatformAssets.SPONGE_ICON_2X - } - - licenseBox.model = EnumComboBoxModel(License::class.java) - licenseBox.selectedItem = License.ALL_RIGHTS_RESERVED - - if (versionsLoaded) { - return - } - - versionsLoaded = true - CoroutineScope(Dispatchers.Swing).launch { - try { - withContext(Dispatchers.IO) { SpongeVersion.downloadData() }?.set(spongeApiVersionBox) - } catch (e: Exception) { - errorLabel.isVisible = true - } - } - } - - override fun isStepVisible(): Boolean { - return creator.config is SpongeProjectConfig - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.pluginNameField.text - conf.mainClass = this.mainClassField.text - conf.description = this.descriptionField.text?.nullize(true) - conf.website = this.websiteField.text?.nullize(true) - conf.spongeApiVersion = this.spongeApiVersionBox.selectedItem as String - - conf.setAuthors(this.authorsField.text) - conf.setDependencies(this.dependField.text) - conf.license = this.licenseBox.selectedItem as License - } -} Index: src/main/kotlin/platform/sponge/creator/SpongeTemplate.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/SpongeTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/sponge/creator/SpongeTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,89 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.sponge.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.SPONGE_SUBMODULE_POM_TEMPLATE -import com.intellij.openapi.project.Project - -object SpongeTemplate : BaseTemplate() { - - fun applyPom(project: Project, config: SpongeProjectConfig): String { - val props = BasicMavenStep.pluginVersions.toMutableMap() - props["JAVA_VERSION"] = config.javaVersion.toString() - - return project.applyTemplate(SPONGE_POM_TEMPLATE, props) - } - - fun applySubPom(project: Project, config: SpongeProjectConfig): String { - val props = BasicMavenStep.pluginVersions.toMutableMap() - props["JAVA_VERSION"] = config.javaVersion.toString() - - return project.applyTemplate(SPONGE_SUBMODULE_POM_TEMPLATE, props) - } - - fun applyMainClass( - project: Project, - packageName: String, - className: String, - hasDependencies: Boolean - ): String { - val props = mutableMapOf( - "PACKAGE" to packageName, - "CLASS_NAME" to className - ) - - if (hasDependencies) { - props["HAS_DEPENDENCIES"] = "true" - } - - return project.applyTemplate(SPONGE_MAIN_CLASS_TEMPLATE, props) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_ID" to buildSystem.artifactId, - "PLUGIN_VERSION" to buildSystem.version - ) - - return project.applyTemplate(SPONGE_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project): String { - return project.applyTemplate(SPONGE_GRADLE_PROPERTIES_TEMPLATE) - } - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf( - "ARTIFACT_ID" to artifactId - ) - - return project.applyTemplate(SPONGE_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName, - "PLUGIN_ID" to buildSystem.artifactId - ) - - return project.applyTemplate(SPONGE_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/sponge/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/sponge/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,56 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.sponge.creator + +import com.demonwav.mcdev.creator.addLicense +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project + +class SpongeProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating project files" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val (packageName, className) = splitPackage(data.getUserData(MainClassStep.KEY) ?: return) + + assets.addTemplateProperties( + "PLUGIN_ID" to buildSystemProps.artifactId, + "PACKAGE" to packageName, + "CLASS_NAME" to className, + ) + val mainClassFile = "src/main/java/${packageName.replace('.', '/')}/$className.java" + assets.addTemplates( + project, + mainClassFile to MinecraftTemplates.SPONGE8_MAIN_CLASS_TEMPLATE, + ) + assets.addLicense(project) + } +} + +class SpongeBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Sponge" +} + +class SpongePostBuildSystemStep( + parent: NewProjectWizardStep +) : AbstractRunBuildSystemStep(parent, SpongeBuildSystemStep::class.java) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/sponge/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/sponge/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,117 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.sponge.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GRADLE_VERSION_KEY +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.ReformatBuildGradleStep +import com.demonwav.mcdev.creator.buildsystem.addGradleWrapperProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ide.starters.local.GeneratorEmptyDirectory +import com.intellij.ide.wizard.NewProjectWizardBaseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +class SpongeGradleSupport : BuildSystemSupport { + override val preferred = true + + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> SpongeGradleFilesStep(parent).chain(::GradleWrapperStep) + BuildSystemSupport.POST_STEP -> SpongeGradleImportStep(parent).chain(::ReformatBuildGradleStep) + else -> EmptyStep(parent) + } + } +} + +class SpongeGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + data.putUserData(GRADLE_VERSION_KEY, SemanticVersion.release(7, 4, 2)) + + val buildSystemProps = findStep>() + val javaVersion = findStep().preferredJdk.ordinal + val spongeVersion = data.getUserData(SpongeApiVersionStep.KEY) ?: return + val license = data.getUserData(LicenseStep.KEY) ?: return + val pluginName = data.getUserData(AbstractModNameStep.KEY) ?: return + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val website = data.getUserData(WebsiteStep.KEY) ?: "" + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val dependencies = data.getUserData(DependStep.KEY) ?: emptyList() + val baseData = data.getUserData(NewProjectWizardBaseData.KEY) ?: return + + assets.addTemplateProperties( + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "PLUGIN_ID" to buildSystemProps.artifactId, + "PLUGIN_VERSION" to buildSystemProps.version, + "JAVA_VERSION" to javaVersion, + "SPONGEAPI_VERSION" to spongeVersion, + "LICENSE" to license.id, + "PLUGIN_NAME" to pluginName, + "MAIN_CLASS" to mainClass, + "AUTHORS" to authors, + "DEPENDENCIES" to dependencies, + "PROJECT_NAME" to baseData.name, + ) + + if (description.isNotBlank()) { + assets.addTemplateProperties("DESCRIPTION" to description) + } + + if (website.isNotBlank()) { + assets.addTemplateProperties("WEBSITE" to website) + } + + assets.addTemplates( + project, + "build.gradle.kts" to MinecraftTemplates.SPONGE8_BUILD_GRADLE_TEMPLATE, + "settings.gradle.kts" to MinecraftTemplates.SPONGE8_SETTINGS_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.SPONGE8_GRADLE_PROPERTIES_TEMPLATE, + ) + + assets.addGradleWrapperProperties(project) + + assets.addAssets( + GeneratorEmptyDirectory("src/main/java"), + GeneratorEmptyDirectory("src/main/resources"), + ) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} + +class SpongeGradleImportStep(parent: NewProjectWizardStep) : GradleImportStep(parent) { + override val additionalRunTasks = listOf("runServer") +} Index: src/main/kotlin/platform/sponge/creator/maven-steps.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/sponge/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,129 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.sponge.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addLicense +import com.demonwav.mcdev.creator.addMavenGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchPomStep +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.BuildSystemType +import com.demonwav.mcdev.creator.buildsystem.MavenImportStep +import com.demonwav.mcdev.creator.buildsystem.ReformatPomStep +import com.demonwav.mcdev.creator.buildsystem.addDefaultMavenProperties +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.psi.xml.XmlTag +import java.util.EnumSet +import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel + +class SpongeMavenSupport : BuildSystemSupport { + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> SpongeMavenFilesStep(parent).chain(::SpongePatchPomStep) + BuildSystemSupport.POST_STEP -> SpongeMavenProjectFilesStep(parent).chain( + ::MavenImportStep, + ::ReformatPomStep + ) + else -> EmptyStep(parent) + } + } +} + +class SpongeMavenFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Maven files" + + override fun setupAssets(project: Project) { + assets.addDefaultMavenProperties() + val javaVersion = findStep().preferredJdk.ordinal + assets.addTemplateProperties("JAVA_VERSION" to javaVersion) + assets.addTemplates(project, "pom.xml" to MinecraftTemplates.SPONGE_POM_TEMPLATE) + if (gitEnabled) { + assets.addMavenGitignore(project) + } + } +} + +class SpongeMavenProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Maven project files" + + override fun setupAssets(project: Project) { + val buildSystemProps = findStep>() + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val spongeApiVersion = data.getUserData(SpongeApiVersionStep.KEY) ?: return + val license = data.getUserData(LicenseStep.KEY) ?: return + val pluginName = data.getUserData(AbstractModNameStep.KEY) ?: return + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val website = data.getUserData(WebsiteStep.KEY) ?: "" + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val dependencies = data.getUserData(DependStep.KEY) ?: emptyList() + + assets.addTemplateProperties( + "PLUGIN_ID" to buildSystemProps.artifactId, + "VERSION_PLACEHOLDER" to "\${version}", + "SPONGEAPI_VERSION" to spongeApiVersion, + "LICENSE" to license.id, + "PLUGIN_NAME" to pluginName, + "MAIN_CLASS" to mainClass, + "DESCRIPTION" to description, + "WEBSITE" to website, + "AUTHORS" to authors, + "DEPENDENCIES" to dependencies, + ) + assets.addTemplates( + project, + "src/main/resources/META-INF/sponge_plugins.json" to MinecraftTemplates.SPONGE8_PLUGINS_JSON_TEMPLATE, + ) + assets.addLicense(project) + } +} + +class SpongePatchPomStep(parent: NewProjectWizardStep) : AbstractPatchPomStep(parent) { + override fun patchPom(model: MavenDomProjectModel, root: XmlTag) { + super.patchPom(model, root) + val spongeApiVersion = data.getUserData(SpongeApiVersionStep.KEY) ?: return + setupDependencies( + model, + listOf( + BuildRepository( + "spongepowered-repo", + "https://repo.spongepowered.org/maven/", + buildSystems = EnumSet.of(BuildSystemType.MAVEN) + ) + ), + listOf( + BuildDependency( + "org.spongepowered", + "spongeapi", + spongeApiVersion.toString(), + mavenScope = "provided" + ) + ) + ) + } +} Index: src/main/kotlin/platform/sponge/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/sponge/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/sponge/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,109 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.sponge.creator + +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.platformtype.PluginPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractSelectVersionStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.LicenseStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.PluginNameStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.sponge.SpongeVersion +import com.demonwav.mcdev.platform.sponge.util.SpongeConstants +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.onShown +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JavaSdkVersion +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel + +private val MIN_SPONGE_VERSION = SpongeConstants.API8 + +class SpongePlatformStep(parent: PluginPlatformStep) : AbstractLatentStep(parent) { + override val description = "download Sponge versions" + + override suspend fun computeData() = SpongeVersion.downloadData() + + override fun createStep(data: SpongeVersion) = SpongeApiVersionStep(this, data).chain( + ::PluginNameStep, + ::MainClassStep, + ::LicenseStep, + ::SpongeOptionalSettingsStep, + ::SpongeBuildSystemStep, + ::SpongeProjectFilesStep, + ::SpongePostBuildSystemStep, + ) + + class Factory : PluginPlatformStep.Factory { + override val name = "Sponge" + + override fun createStep(parent: PluginPlatformStep) = SpongePlatformStep(parent) + } +} + +class SpongeApiVersionStep( + parent: NewProjectWizardStep, + data: SpongeVersion +) : AbstractSelectVersionStep( + parent, + data.versions.keys.mapNotNull(SemanticVersion::tryParse).filter { it >= MIN_SPONGE_VERSION } +) { + override val label = "Sponge API Version:" + + override fun setupUI(builder: Panel) { + super.setupUI(builder) + versionProperty.afterChange { + applyJdkVersion() + } + versionBox.onShown { + applyJdkVersion() + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, SemanticVersion.tryParse(version)) + applyJdkVersion() + } + + private fun applyJdkVersion() { + SemanticVersion.tryParse(version)?.let { version -> + val preferredJdk = when { + version >= SpongeConstants.API9 -> JavaSdkVersion.JDK_17 + else -> JavaSdkVersion.JDK_1_8 + } + findStep().setPreferredJdk(preferredJdk, "Sponge $version") + } + } + + companion object { + val KEY = Key.create("${SpongeApiVersionStep::class.java.name}.version") + } +} + +class SpongeOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::DependStep, + ) +} Index: src/main/kotlin/platform/velocity/creator/VelocityProjectConfig.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/VelocityProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/velocity/creator/VelocityProjectConfig.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,67 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.velocity.creator - -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.ProjectCreator -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleCreator -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenCreator -import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.VersionRange -import com.intellij.openapi.module.Module -import com.intellij.util.lang.JavaVersion -import java.nio.file.Path - -class VelocityProjectConfig : ProjectConfig(), MavenCreator, GradleCreator { - - lateinit var mainClass: String - - var velocityApiVersion = "" - val apiVersion: SemanticVersion - get() = - if (velocityApiVersion.isBlank()) SemanticVersion.release() else SemanticVersion.parse(velocityApiVersion) - - override var type: PlatformType = PlatformType.VELOCITY - - val dependencies = mutableListOf() - fun hasDependencies() = listContainsAtLeastOne(dependencies) - fun setDependencies(string: String) { - dependencies.clear() - dependencies.addAll(commaSplit(string)) - } - - override val javaVersion: JavaVersion - get() = when { - apiVersion >= SemanticVersion.release(3) -> JavaVersion.compose(11) - else -> JavaVersion.compose(8) - } - - override fun buildMavenCreator( - rootDirectory: Path, - module: Module, - buildSystem: MavenBuildSystem - ): ProjectCreator { - return VelocityMavenCreator(rootDirectory, module, buildSystem, this) - } - - override val compatibleGradleVersions: VersionRange? = null - - override fun buildGradleCreator( - rootDirectory: Path, - module: Module, - buildSystem: GradleBuildSystem - ): ProjectCreator { - return VelocityGradleCreator(rootDirectory, module, buildSystem, this) - } -} Index: src/main/kotlin/platform/velocity/creator/VelocityProjectCreator.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/VelocityProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/velocity/creator/VelocityProjectCreator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,232 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.velocity.creator - -import com.demonwav.mcdev.creator.BaseProjectCreator -import com.demonwav.mcdev.creator.BasicJavaClassStep -import com.demonwav.mcdev.creator.CreateDirectoriesStep -import com.demonwav.mcdev.creator.CreatorStep -import com.demonwav.mcdev.creator.buildsystem.BuildDependency -import com.demonwav.mcdev.creator.buildsystem.BuildRepository -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.AddGradlePluginStep -import com.demonwav.mcdev.creator.buildsystem.gradle.BasicGradleFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleBuildSystem -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleFiles -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleGitignoreStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradlePlugin -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleSetupStep -import com.demonwav.mcdev.creator.buildsystem.gradle.GradleWrapperStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenFinalizerStep -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.creator.buildsystem.maven.MavenBuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.MavenGitignoreStep -import com.demonwav.mcdev.platform.velocity.util.VelocityConstants -import com.demonwav.mcdev.util.SemanticVersion -import com.demonwav.mcdev.util.runWriteAction -import com.demonwav.mcdev.util.runWriteTaskInSmartMode -import com.demonwav.mcdev.util.virtualFileOrError -import com.intellij.openapi.module.Module -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.Project -import com.intellij.psi.JavaPsiFacade -import com.intellij.psi.PsiJavaFile -import com.intellij.psi.PsiManager -import com.intellij.psi.codeStyle.CodeStyleManager -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths - -sealed class VelocityProjectCreator( - protected val rootDirectory: Path, - protected val rootModule: Module, - protected val buildSystem: T, - protected val config: VelocityProjectConfig -) : BaseProjectCreator(rootModule, buildSystem) { - - protected fun setupDependencyStep(): VelocityDependenciesSetup { - val velocityApiVersion = config.velocityApiVersion - return VelocityDependenciesSetup(buildSystem, velocityApiVersion) - } - - protected fun setupMainClassSteps(): Pair { - val mainClassStep = createJavaClassStep(config.mainClass) { packageName, className -> - val version = config.apiVersion - VelocityTemplate.applyMainClass(project, packageName, className, config.hasDependencies(), version) - } - - return mainClassStep to VelocityMainClassModifyStep(project, buildSystem, config.mainClass, config) - } -} - -class VelocityMavenCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: MavenBuildSystem, - config: VelocityProjectConfig -) : VelocityProjectCreator(rootDirectory, rootModule, buildSystem, config) { - override fun getSteps(): Iterable { - val (mainClassStep, modifyStep) = setupMainClassSteps() - - val pomText = VelocityTemplate.applyPom(project, config) - - return listOf( - setupDependencyStep(), - BasicMavenStep(project, rootDirectory, buildSystem, config, pomText), - mainClassStep, - modifyStep, - MavenGitignoreStep(project, rootDirectory), - BasicMavenFinalizerStep(rootModule, rootDirectory) - ) - } -} - -class VelocityGradleCreator( - rootDirectory: Path, - rootModule: Module, - buildSystem: GradleBuildSystem, - config: VelocityProjectConfig -) : VelocityProjectCreator(rootDirectory, rootModule, buildSystem, config) { - - private val ideaExtPlugin = GradlePlugin("org.jetbrains.gradle.plugin.idea-ext", "1.0.1") - - override fun getSteps(): Iterable { - val (mainClassStep, modifyStep) = setupMainClassSteps() - - val buildText = VelocityTemplate.applyBuildGradle(project, buildSystem, config) - val propText = VelocityTemplate.applyGradleProp(project, null) - val settingsText = VelocityTemplate.applySettingsGradle(project, buildSystem.artifactId) - val files = GradleFiles(buildText, propText, settingsText) - - return listOf( - setupDependencyStep(), - CreateDirectoriesStep(buildSystem, rootDirectory), - GradleSetupStep(project, rootDirectory, buildSystem, files), - AddGradlePluginStep(project, rootDirectory, listOf(ideaExtPlugin)), - mainClassStep, - modifyStep, - buildConstantsStep(), - GradleWrapperStep(project, rootDirectory, buildSystem), - GradleGitignoreStep(project, rootDirectory), - BasicGradleFinalizerStep(rootModule, rootDirectory, buildSystem) - ) - } - - private fun buildConstantsStep(): BasicJavaClassStep { - return BasicJavaClassStep( - project, - buildSystem, - config.mainClass.replaceAfterLast('.', "BuildConstants"), - VelocityTemplate.applyBuildConstants(project, config.mainClass.substringBeforeLast('.')), - false - ) { it.dirsOrError.sourceDirectory.resolveSibling("templates") } - } -} - -class VelocityMainClassModifyStep( - private val project: Project, - private val buildSystem: BuildSystem, - private val classFullName: String, - private val config: VelocityProjectConfig -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - val dirs = buildSystem.dirsOrError - - project.runWriteTaskInSmartMode { - val classFile = dirs.sourceDirectory.resolve(Paths.get(classFullName.replace('.', '/') + ".java")) - if (!Files.isRegularFile(classFile)) { - throw IllegalStateException("$classFile is not an existing file") - } - - val psiFile = PsiManager.getInstance(project).findFile(classFile.virtualFileOrError) as? PsiJavaFile - ?: throw IllegalStateException("Failed to resolve PsiJavaFile for $classFile") - val psiClass = psiFile.classes[0] - val annotationBuilder = StringBuilder("@Plugin(") - annotationBuilder + "\nid = ${literal(buildSystem.artifactId)}" - annotationBuilder + ",\nname = ${literal(config.pluginName)}" - - if (buildSystem is GradleBuildSystem) { - annotationBuilder + ",\nversion = BuildConstants.VERSION" - } else { - annotationBuilder + ",\nversion = \"${buildSystem.version}\"" - } - - if (config.hasDescription()) { - annotationBuilder + ",\ndescription = ${literal(config.description)}" - } - - if (config.hasWebsite()) { - annotationBuilder + ",\nurl = ${literal(config.website)}" - } - - if (config.hasAuthors()) { - annotationBuilder + ",\nauthors = {${config.authors.joinToString(", ", transform = ::literal)}}" - } - - if (config.hasDependencies()) { - val deps = config.dependencies.joinToString(",\n") { "@Dependency(id = ${literal(it)})" } - annotationBuilder + ",\ndependencies = {\n$deps\n}" - } - - annotationBuilder + "\n)" - val factory = JavaPsiFacade.getElementFactory(project) - val pluginAnnotation = factory.createAnnotationFromText(annotationBuilder.toString(), null) - - psiFile.runWriteAction { - psiClass.modifierList?.let { it.addBefore(pluginAnnotation, it.firstChild) } - CodeStyleManager.getInstance(project).reformat(psiClass) - } - } - } - - private fun literal(text: String?): String { - if (text == null) { - return "\"\"" - } - return '"' + text.replace("\\", "\\\\").replace("\"", "\\\"") + '"' - } - - private operator fun StringBuilder.plus(text: String) = this.append(text) -} - -class VelocityDependenciesSetup( - private val buildSystem: BuildSystem, - private val velocityApiVersion: String -) : CreatorStep { - override fun runStep(indicator: ProgressIndicator) { - buildSystem.repositories.add( - BuildRepository( - "papermc-repo", - "https://repo.papermc.io/repository/maven-public/" - ) - ) - - buildSystem.dependencies.add( - BuildDependency( - "com.velocitypowered", - "velocity-api", - velocityApiVersion, - mavenScope = "provided", - gradleConfiguration = "compileOnly" - ) - ) - val semanticApiVersion = SemanticVersion.parse(velocityApiVersion) - buildSystem.dependencies.add( - BuildDependency( - "com.velocitypowered", - if (semanticApiVersion >= VelocityConstants.API_4) "velocity-annotation-processor" else "velocity-api", - velocityApiVersion, - mavenScope = if (semanticApiVersion >= VelocityConstants.API_4) "provided" else null, - gradleConfiguration = "annotationProcessor" - ) - ) - } -} Index: src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.form =================================================================== --- src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.form (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,212 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Index: src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/velocity/creator/VelocityProjectSettingsWizard.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,102 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.velocity.creator - -import com.demonwav.mcdev.creator.MinecraftModuleWizardStep -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ValidatedField -import com.demonwav.mcdev.creator.ValidatedFieldType.CLASS_NAME -import com.demonwav.mcdev.creator.ValidatedFieldType.LIST -import com.demonwav.mcdev.creator.ValidatedFieldType.NON_BLANK -import com.demonwav.mcdev.creator.getVersionSelector -import javax.swing.JComboBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JTextField -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.swing.Swing -import kotlinx.coroutines.withContext - -class VelocityProjectSettingsWizard(private val creator: MinecraftProjectCreator) : MinecraftModuleWizardStep() { - - @ValidatedField(NON_BLANK) - private lateinit var pluginNameField: JTextField - - @ValidatedField(NON_BLANK, CLASS_NAME) - private lateinit var mainClassField: JTextField - private lateinit var panel: JPanel - private lateinit var title: JLabel - private lateinit var descriptionField: JTextField - - @ValidatedField(LIST) - private lateinit var authorsField: JTextField - private lateinit var websiteField: JTextField - - @ValidatedField(LIST) - private lateinit var dependField: JTextField - private lateinit var velocityApiVersionBox: JComboBox - private lateinit var errorLabel: JLabel - - private var config: VelocityProjectConfig? = null - - private var versionsLoaded: Boolean = false - - override fun getComponent(): JComponent { - return panel - } - - override fun validate(): Boolean { - return super.validate() && velocityApiVersionBox.selectedItem != null - } - - override fun updateStep() { - config = creator.config as? VelocityProjectConfig - if (config == null) { - return - } - val conf = config ?: return - - basicUpdateStep(creator, pluginNameField, mainClassField) - - if (versionsLoaded) { - return - } - - versionsLoaded = true - CoroutineScope(Dispatchers.Swing).launch { - try { - withContext(Dispatchers.IO) { getVersionSelector(conf.type) }.set(velocityApiVersionBox) - } catch (e: Exception) { - errorLabel.isVisible = true - } - } - } - - override fun isStepVisible(): Boolean { - return creator.config is VelocityProjectConfig - } - - override fun updateDataModel() { - val conf = this.config ?: return - - conf.pluginName = this.pluginNameField.text - conf.mainClass = this.mainClassField.text - conf.description = this.descriptionField.text - conf.website = this.websiteField.text - conf.velocityApiVersion = this.velocityApiVersionBox.selectedItem as String - - conf.setAuthors(this.authorsField.text) - conf.setDependencies(this.dependField.text) - } -} Index: src/main/kotlin/platform/velocity/creator/VelocityTemplate.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/VelocityTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/platform/velocity/creator/VelocityTemplate.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,105 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.platform.velocity.creator - -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import com.demonwav.mcdev.creator.buildsystem.maven.BasicMavenStep -import com.demonwav.mcdev.platform.BaseTemplate -import com.demonwav.mcdev.platform.velocity.util.VelocityConstants -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_BUILD_CONSTANTS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_GRADLE_PROPERTIES_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_MAIN_CLASS_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_MAIN_CLASS_V2_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_POM_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_SETTINGS_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_SUBMODULE_BUILD_GRADLE_TEMPLATE -import com.demonwav.mcdev.util.MinecraftTemplates.Companion.VELOCITY_SUBMODULE_POM_TEMPLATE -import com.demonwav.mcdev.util.SemanticVersion -import com.intellij.openapi.project.Project - -object VelocityTemplate : BaseTemplate() { - - fun applyPom(project: Project, config: VelocityProjectConfig): String { - val props = BasicMavenStep.pluginVersions + ("JAVA_VERSION" to config.javaVersion.toFeatureString()) - return project.applyTemplate(VELOCITY_POM_TEMPLATE, props) - } - - fun applySubPom(project: Project, config: VelocityProjectConfig): String { - val props = BasicMavenStep.pluginVersions + ("JAVA_VERSION" to config.javaVersion.toFeatureString()) - return project.applyTemplate(VELOCITY_SUBMODULE_POM_TEMPLATE, props) - } - - fun applyMainClass( - project: Project, - packageName: String, - className: String, - hasDependencies: Boolean, - version: SemanticVersion - ): String { - val props = mutableMapOf( - "PACKAGE" to packageName, - "CLASS_NAME" to className - ) - - if (hasDependencies) { - props["HAS_DEPENDENCIES"] = "true" - } - - val template = if (version < VelocityConstants.API_2 || - (version >= VelocityConstants.API_3 && version < VelocityConstants.API_4) - ) { - VELOCITY_MAIN_CLASS_TEMPLATE // API 1 and 3 - } else { - VELOCITY_MAIN_CLASS_V2_TEMPLATE // API 2 and 4 (4+ maybe ?) - } - - return project.applyTemplate(template, props) - } - - fun applyBuildConstants(project: Project, packageName: String): String { - val props = mapOf( - "PACKAGE" to packageName - ) - - return project.applyTemplate(VELOCITY_BUILD_CONSTANTS_TEMPLATE, props) - } - - fun applyBuildGradle(project: Project, buildSystem: BuildSystem, config: VelocityProjectConfig): String { - val javaVersion = config.javaVersion.feature - val props = mapOf( - "GROUP_ID" to buildSystem.groupId, - "PLUGIN_ID" to buildSystem.artifactId, - "PLUGIN_VERSION" to buildSystem.version, - "JAVA_VERSION" to javaVersion - ) - - return project.applyTemplate(VELOCITY_BUILD_GRADLE_TEMPLATE, props) - } - - fun applyGradleProp(project: Project, javaVersion: Int?): String = - project.applyTemplate(VELOCITY_GRADLE_PROPERTIES_TEMPLATE, mapOf("JAVA_VERSION" to javaVersion)) - - fun applySettingsGradle(project: Project, artifactId: String): String { - val props = mapOf("ARTIFACT_ID" to artifactId) - - return project.applyTemplate(VELOCITY_SETTINGS_GRADLE_TEMPLATE, props) - } - - fun applySubBuildGradle(project: Project, buildSystem: BuildSystem): String { - val props = mapOf( - "COMMON_PROJECT_NAME" to buildSystem.commonModuleName, - "PLUGIN_ID" to buildSystem.artifactId - ) - - return project.applyTemplate(VELOCITY_SUBMODULE_BUILD_GRADLE_TEMPLATE, props) - } -} Index: src/main/kotlin/platform/velocity/creator/asset-steps.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/velocity/creator/asset-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,158 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.velocity.creator + +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.AbstractRunBuildSystemStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.AbstractLongRunningStep +import com.demonwav.mcdev.creator.step.AbstractModNameStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.velocity.util.VelocityConstants +import com.demonwav.mcdev.util.MinecraftTemplates +import com.demonwav.mcdev.util.runWriteAction +import com.demonwav.mcdev.util.runWriteTaskInSmartMode +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiJavaFile +import com.intellij.psi.PsiManager +import com.intellij.psi.codeStyle.CodeStyleManager +import java.nio.file.Path + +class VelocityProjectFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating project files" + + override fun setupAssets(project: Project) { + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val dependencies = data.getUserData(DependStep.KEY) ?: emptyList() + val (packageName, className) = splitPackage(mainClass) + val version = data.getUserData(VelocityVersionStep.KEY) ?: return + + assets.addTemplateProperties( + "PACKAGE" to packageName, + "CLASS_NAME" to className, + ) + + if (dependencies.isNotEmpty()) { + assets.addTemplateProperties( + "HAS_DEPENDENCIES" to "true", + ) + } + + val template = if (version < VelocityConstants.API_2 || + (version >= VelocityConstants.API_3 && version < VelocityConstants.API_4) + ) { + MinecraftTemplates.VELOCITY_MAIN_CLASS_TEMPLATE // API 1 and 3 + } else { + MinecraftTemplates.VELOCITY_MAIN_CLASS_V2_TEMPLATE // API 2 and 4 (4+ maybe ?) + } + + assets.addTemplates( + project, + "src/main/java/${mainClass.replace('.', '/')}.java" to template + ) + } +} + +class VelocityModifyMainClassStep( + parent: NewProjectWizardStep, + private val isGradle: Boolean +) : AbstractLongRunningStep(parent) { + override val description = "Patching main class" + + override fun perform(project: Project) { + val buildSystemProps = findStep>() + val pluginName = data.getUserData(AbstractModNameStep.KEY) ?: return + val mainClassName = data.getUserData(MainClassStep.KEY) ?: return + val mainClassFile = "${context.projectFileDirectory}/src/main/java/${mainClassName.replace('.', '/')}.java" + val description = data.getUserData(DescriptionStep.KEY) ?: "" + val website = data.getUserData(WebsiteStep.KEY) ?: "" + val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList() + val dependencies = data.getUserData(DependStep.KEY) ?: emptyList() + + project.runWriteTaskInSmartMode { + val mainClassVirtualFile = VfsUtil.findFile(Path.of(mainClassFile), true) + ?: return@runWriteTaskInSmartMode + val mainClassPsi = PsiManager.getInstance(project).findFile(mainClassVirtualFile) as? PsiJavaFile + ?: return@runWriteTaskInSmartMode + + val psiClass = mainClassPsi.classes[0] + val annotation = buildString { + append("@Plugin(") + append("\nid = ${literal(buildSystemProps.artifactId)}") + append(",\nname = ${literal(pluginName)}") + + if (isGradle) { + append(",\nversion = BuildConstants.VERSION") + } else { + append(",\nversion = \"${buildSystemProps.version}\"") + } + + if (description.isNotBlank()) { + append(",\ndescription = ${literal(description)}") + } + + if (website.isNotBlank()) { + append(",\nurl = ${literal(website)}") + } + + if (authors.isNotEmpty()) { + append(",\nauthors = {${authors.joinToString(", ", transform = ::literal)}}") + } + + if (dependencies.isNotEmpty()) { + val deps = dependencies.joinToString(",\n") { "@Dependency(id = ${literal(it)})" } + append(",\ndependencies = {\n$deps\n}") + } + + append("\n)") + } + + val factory = JavaPsiFacade.getElementFactory(project) + val pluginAnnotation = factory.createAnnotationFromText(annotation, null) + + mainClassPsi.runWriteAction { + psiClass.modifierList?.let { it.addBefore(pluginAnnotation, it.firstChild) } + CodeStyleManager.getInstance(project).reformat(psiClass) + } + } + } + + private fun literal(text: String?): String { + if (text == null) { + return "\"\"" + } + return '"' + StringUtil.escapeStringCharacters(text) + '"' + } +} + +class VelocityBuildSystemStep(parent: NewProjectWizardStep) : AbstractBuildSystemStep(parent) { + override val platformName = "Velocity" +} + +class VelocityPostBuildSystemStep(parent: NewProjectWizardStep) : AbstractRunBuildSystemStep( + parent, + VelocityBuildSystemStep::class.java +) { + override val step = BuildSystemSupport.POST_STEP +} Index: src/main/kotlin/platform/velocity/creator/gradle-steps.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/velocity/creator/gradle-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,128 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.velocity.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addGradleGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchGradleFilesStep +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.creator.buildsystem.BuildSystemPropertiesStep +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.GradleImportStep +import com.demonwav.mcdev.creator.buildsystem.GradlePlugin +import com.demonwav.mcdev.creator.buildsystem.GradleWrapperStep +import com.demonwav.mcdev.creator.buildsystem.ReformatBuildGradleStep +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.splitPackage +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.platform.velocity.util.VelocityConstants +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardBaseData.Companion.baseData +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project + +class VelocityGradleSupport : BuildSystemSupport { + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> VelocityGradleFilesStep(parent).chain( + ::VelocityPatchGradleFilesStep, + ::GradleWrapperStep + ) + BuildSystemSupport.POST_STEP -> GradleImportStep(parent).chain( + ::ReformatBuildGradleStep, + { VelocityModifyMainClassStep(it, true) } + ) + else -> EmptyStep(parent) + } + } +} + +class VelocityGradleFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Gradle files" + + override fun setupAssets(project: Project) { + val projectName = baseData.name + val buildSystemProps = findStep>() + val javaVersion = findStep().preferredJdk.ordinal + val mainClass = data.getUserData(MainClassStep.KEY) ?: return + val (mainPackage, _) = splitPackage(mainClass) + + assets.addTemplateProperties( + "GROUP_ID" to buildSystemProps.groupId, + "ARTIFACT_ID" to buildSystemProps.artifactId, + "PLUGIN_ID" to buildSystemProps.artifactId, + "PLUGIN_VERSION" to buildSystemProps.version, + "JAVA_VERSION" to javaVersion, + "PROJECT_NAME" to projectName, + "PACKAGE" to mainPackage, + ) + + val buildConstantsJava = "src/main/java/${mainPackage.replace('.', '/')}/BuildConstants.java" + assets.addTemplates( + project, + "build.gradle" to MinecraftTemplates.VELOCITY_BUILD_GRADLE_TEMPLATE, + "gradle.properties" to MinecraftTemplates.VELOCITY_GRADLE_PROPERTIES_TEMPLATE, + "settings.gradle" to MinecraftTemplates.VELOCITY_SETTINGS_GRADLE_TEMPLATE, + buildConstantsJava to MinecraftTemplates.VELOCITY_BUILD_CONSTANTS_TEMPLATE, + ) + + if (gitEnabled) { + assets.addGradleGitignore(project) + } + } +} + +class VelocityPatchGradleFilesStep(parent: NewProjectWizardStep) : AbstractPatchGradleFilesStep(parent) { + override fun patch(project: Project, gradleFiles: GradleFiles) { + val velocityApiVersion = data.getUserData(VelocityVersionStep.KEY) ?: return + + addPlugins( + project, gradleFiles.buildGradle, + listOf( + GradlePlugin("org.jetbrains.gradle.plugin.idea-ext", "1.0.1") + ) + ) + addRepositories( + project, gradleFiles.buildGradle, + listOf( + BuildRepository( + "papermc-repo", + "https://repo.papermc.io/repository/maven-public/" + ) + ) + ) + val annotationArtifactId = + if (velocityApiVersion >= VelocityConstants.API_4) "velocity-annotation-processor" else "velocity-api" + addDependencies( + project, gradleFiles.buildGradle, + listOf( + BuildDependency( + "com.velocitypowered", + "velocity-api", + velocityApiVersion.toString(), + gradleConfiguration = "compileOnly" + ), + BuildDependency( + "com.velocitypowered", + annotationArtifactId, + velocityApiVersion.toString(), + gradleConfiguration = "annotationProcessor" + ), + ) + ) + } +} Index: src/main/kotlin/platform/velocity/creator/maven-steps.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/velocity/creator/maven-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,97 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.velocity.creator + +import com.demonwav.mcdev.creator.EmptyStep +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.addMavenGitignore +import com.demonwav.mcdev.creator.addTemplates +import com.demonwav.mcdev.creator.buildsystem.AbstractPatchPomStep +import com.demonwav.mcdev.creator.buildsystem.BuildDependency +import com.demonwav.mcdev.creator.buildsystem.BuildRepository +import com.demonwav.mcdev.creator.buildsystem.BuildSystemSupport +import com.demonwav.mcdev.creator.buildsystem.MavenImportStep +import com.demonwav.mcdev.creator.buildsystem.ReformatPomStep +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.gitEnabled +import com.demonwav.mcdev.creator.step.AbstractLongRunningAssetsStep +import com.demonwav.mcdev.platform.velocity.util.VelocityConstants +import com.demonwav.mcdev.util.MinecraftTemplates +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.psi.xml.XmlTag +import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel + +class VelocityMavenSupport : BuildSystemSupport { + override fun createStep(step: String, parent: NewProjectWizardStep): NewProjectWizardStep { + return when (step) { + BuildSystemSupport.PRE_STEP -> VelocityMavenFilesStep(parent).chain(::VelocityPatchPomStep) + BuildSystemSupport.POST_STEP -> MavenImportStep(parent).chain( + ::ReformatPomStep, + { VelocityModifyMainClassStep(it, false) } + ) + else -> EmptyStep(parent) + } + } +} + +class VelocityMavenFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) { + override val description = "Creating Maven files" + + override fun setupAssets(project: Project) { + val javaVersion = findStep().preferredJdk.ordinal + assets.addTemplateProperties( + "JAVA_VERSION" to javaVersion, + ) + assets.addTemplates( + project, + "pom.xml" to MinecraftTemplates.VELOCITY_POM_TEMPLATE, + ) + if (gitEnabled) { + assets.addMavenGitignore(project) + } + } +} + +class VelocityPatchPomStep(parent: NewProjectWizardStep) : AbstractPatchPomStep(parent) { + override fun patchPom(model: MavenDomProjectModel, root: XmlTag) { + super.patchPom(model, root) + + val velocityApiVersion = data.getUserData(VelocityVersionStep.KEY) ?: return + + val annotationArtifactId = + if (velocityApiVersion >= VelocityConstants.API_4) "velocity-annotation-processor" else "velocity-api" + setupDependencies( + model, + listOf( + BuildRepository( + "papermc-repo", + "https://repo.papermc.io/repository/maven-public/" + ) + ), + listOf( + BuildDependency( + "com.velocitypowered", + "velocity-api", + velocityApiVersion.toString(), + mavenScope = "provided", + ), + BuildDependency( + "com.velocitypowered", + annotationArtifactId, + velocityApiVersion.toString(), + mavenScope = if (velocityApiVersion >= VelocityConstants.API_4) "provided" else null, + ) + ) + ) + } +} Index: src/main/kotlin/platform/velocity/creator/ui-steps.kt =================================================================== --- src/main/kotlin/platform/velocity/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/platform/velocity/creator/ui-steps.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,112 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.platform.velocity.creator + +import com.demonwav.mcdev.creator.JdkProjectSetupFinalizer +import com.demonwav.mcdev.creator.PlatformVersion +import com.demonwav.mcdev.creator.chain +import com.demonwav.mcdev.creator.findStep +import com.demonwav.mcdev.creator.getVersionSelector +import com.demonwav.mcdev.creator.platformtype.PluginPlatformStep +import com.demonwav.mcdev.creator.step.AbstractCollapsibleStep +import com.demonwav.mcdev.creator.step.AbstractLatentStep +import com.demonwav.mcdev.creator.step.AbstractSelectVersionStep +import com.demonwav.mcdev.creator.step.AuthorsStep +import com.demonwav.mcdev.creator.step.DependStep +import com.demonwav.mcdev.creator.step.DescriptionStep +import com.demonwav.mcdev.creator.step.MainClassStep +import com.demonwav.mcdev.creator.step.PluginNameStep +import com.demonwav.mcdev.creator.step.WebsiteStep +import com.demonwav.mcdev.platform.PlatformType +import com.demonwav.mcdev.util.SemanticVersion +import com.demonwav.mcdev.util.asyncIO +import com.demonwav.mcdev.util.onShown +import com.intellij.ide.wizard.NewProjectWizardStep +import com.intellij.ide.wizard.chain +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JavaSdkVersion +import com.intellij.openapi.util.Key +import com.intellij.ui.dsl.builder.Panel +import kotlinx.coroutines.coroutineScope + +class VelocityPlatformStep(parent: PluginPlatformStep) : AbstractLatentStep(parent) { + override val description = "download Velocity versions" + + override suspend fun computeData() = coroutineScope { + try { + asyncIO { getVersionSelector(PlatformType.VELOCITY) }.await() + } catch (e: Throwable) { + null + } + } + + override fun createStep(data: PlatformVersion) = + VelocityVersionStep(this, data.versions.mapNotNull(SemanticVersion::tryParse)).chain( + ::PluginNameStep, + ::MainClassStep, + ::VelocityOptionalSettingsStep, + ::VelocityBuildSystemStep, + ::VelocityProjectFilesStep, + ::VelocityPostBuildSystemStep, + ) + + class Factory : PluginPlatformStep.Factory { + override val name = "Velocity" + + override fun createStep(parent: PluginPlatformStep) = VelocityPlatformStep(parent) + } +} + +class VelocityVersionStep( + parent: NewProjectWizardStep, + versions: List +) : AbstractSelectVersionStep(parent, versions) { + override val label = "Velocity Version:" + + override fun setupUI(builder: Panel) { + super.setupUI(builder) + versionProperty.afterChange { + applyJdkVersion() + } + versionBox.onShown { + applyJdkVersion() + } + } + + override fun setupProject(project: Project) { + data.putUserData(KEY, SemanticVersion.tryParse(version)) + applyJdkVersion() + } + + private fun applyJdkVersion() { + SemanticVersion.tryParse(version)?.let { version -> + val preferredJdk = when { + version >= SemanticVersion.release(3) -> JavaSdkVersion.JDK_11 + else -> JavaSdkVersion.JDK_1_8 + } + findStep().setPreferredJdk(preferredJdk, "Velocity $version") + } + } + + companion object { + val KEY = Key.create("${VelocityVersionStep::class.java.name}.version") + } +} + +class VelocityOptionalSettingsStep(parent: NewProjectWizardStep) : AbstractCollapsibleStep(parent) { + override val title = "Optional Settings" + + override fun createStep() = DescriptionStep(this).chain( + ::AuthorsStep, + ::WebsiteStep, + ::DependStep, + ) +} Index: src/main/kotlin/util/License.kt =================================================================== --- src/main/kotlin/util/License.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/License.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -25,4 +25,9 @@ ; override fun toString() = displayName + + companion object { + private val byId = values().associateBy { it.id } + fun byId(id: String) = byId[id] -} + } +} Index: src/main/kotlin/util/MinecraftTemplates.kt =================================================================== --- src/main/kotlin/util/MinecraftTemplates.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/MinecraftTemplates.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -26,11 +26,9 @@ bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_MAIN_CLASS_TEMPLATE)) bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_PLUGIN_YML_TEMPLATE)) bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_BUILD_GRADLE_TEMPLATE)) - bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_SUBMODULE_BUILD_GRADLE_TEMPLATE)) bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_GRADLE_PROPERTIES_TEMPLATE)) bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_SETTINGS_GRADLE_TEMPLATE)) bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_POM_TEMPLATE)) - bukkitGroup.addTemplate(FileTemplateDescriptor(BUKKIT_SUBMODULE_POM_TEMPLATE)) } FileTemplateGroupDescriptor("BungeeCord", PlatformAssets.BUNGEECORD_ICON).let { bungeeGroup -> @@ -38,11 +36,9 @@ bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_MAIN_CLASS_TEMPLATE)) bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_PLUGIN_YML_TEMPLATE)) bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_BUILD_GRADLE_TEMPLATE)) - bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_SUBMODULE_BUILD_GRADLE_TEMPLATE)) bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_GRADLE_PROPERTIES_TEMPLATE)) bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_SETTINGS_GRADLE_TEMPLATE)) bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_POM_TEMPLATE)) - bungeeGroup.addTemplate(FileTemplateDescriptor(BUNGEECORD_SUBMODULE_POM_TEMPLATE)) } FileTemplateGroupDescriptor("Velocity", PlatformAssets.VELOCITY_ICON).let { velocityGroup -> @@ -51,41 +47,24 @@ velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_BUILD_CONSTANTS_TEMPLATE)) velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_MAIN_CLASS_V2_TEMPLATE)) velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_BUILD_GRADLE_TEMPLATE)) - velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_SUBMODULE_BUILD_GRADLE_TEMPLATE)) velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_GRADLE_PROPERTIES_TEMPLATE)) velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_SETTINGS_GRADLE_TEMPLATE)) velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_POM_TEMPLATE)) - velocityGroup.addTemplate(FileTemplateDescriptor(VELOCITY_SUBMODULE_POM_TEMPLATE)) } FileTemplateGroupDescriptor("Sponge", PlatformAssets.SPONGE_ICON).let { spongeGroup -> group.addTemplate(spongeGroup) - FileTemplateGroupDescriptor("Legacy", null).let { legacyGroup -> - spongeGroup.addTemplate(legacyGroup) - legacyGroup.addTemplate(template(SPONGE_MAIN_CLASS_TEMPLATE)) - legacyGroup.addTemplate(template(SPONGE_BUILD_GRADLE_TEMPLATE)) - legacyGroup.addTemplate(template(SPONGE_SUBMODULE_BUILD_GRADLE_TEMPLATE)) - legacyGroup.addTemplate(template(SPONGE_GRADLE_PROPERTIES_TEMPLATE)) - legacyGroup.addTemplate(template(SPONGE_SETTINGS_GRADLE_TEMPLATE)) - } fun sponge8Template(fileName: String) = template(fileName, fileName.replace("8+ ", "")) spongeGroup.addTemplate(sponge8Template(SPONGE8_MAIN_CLASS_TEMPLATE)) spongeGroup.addTemplate(sponge8Template(SPONGE8_PLUGINS_JSON_TEMPLATE)) spongeGroup.addTemplate(sponge8Template(SPONGE8_BUILD_GRADLE_TEMPLATE)) - spongeGroup.addTemplate(sponge8Template(SPONGE8_SUBMODULE_BUILD_GRADLE_TEMPLATE)) spongeGroup.addTemplate(sponge8Template(SPONGE8_GRADLE_PROPERTIES_TEMPLATE)) spongeGroup.addTemplate(sponge8Template(SPONGE8_SETTINGS_GRADLE_TEMPLATE)) spongeGroup.addTemplate(template(SPONGE_POM_TEMPLATE)) - spongeGroup.addTemplate(template(SPONGE_SUBMODULE_POM_TEMPLATE)) } FileTemplateGroupDescriptor("Forge", PlatformAssets.FORGE_ICON).let { forgeGroup -> group.addTemplate(forgeGroup) - forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_MAIN_CLASS_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_BUILD_GRADLE_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_SUBMODULE_BUILD_GRADLE_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_GRADLE_PROPERTIES_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_SETTINGS_GRADLE_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FORGE_MIXINS_JSON_TEMPLATE, PlatformAssets.FORGE_ICON)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_MAIN_CLASS_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_1_17_MAIN_CLASS_TEMPLATE)) @@ -93,10 +72,8 @@ forgeGroup.addTemplate(FileTemplateDescriptor(FG3_1_19_MAIN_CLASS_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_1_19_3_MAIN_CLASS_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_BUILD_GRADLE_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(FG3_SUBMODULE_BUILD_GRADLE_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_GRADLE_PROPERTIES_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(FG3_SETTINGS_GRADLE_TEMPLATE)) - forgeGroup.addTemplate(FileTemplateDescriptor(MCMOD_INFO_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(MODS_TOML_TEMPLATE)) forgeGroup.addTemplate(FileTemplateDescriptor(PACK_MCMETA_TEMPLATE)) } @@ -110,19 +87,12 @@ fabricGroup.addTemplate(FileTemplateDescriptor(FABRIC_MIXINS_JSON_TEMPLATE, PlatformAssets.FABRIC_ICON)) fabricGroup.addTemplate(FileTemplateDescriptor(FABRIC_MOD_JSON_TEMPLATE, PlatformAssets.FABRIC_ICON)) fabricGroup.addTemplate(FileTemplateDescriptor(FABRIC_SETTINGS_GRADLE_TEMPLATE, PlatformAssets.FABRIC_ICON)) - fabricGroup.addTemplate( - FileTemplateDescriptor(FABRIC_SUBMODULE_BUILD_GRADLE_TEMPLATE, PlatformAssets.FABRIC_ICON) - ) - fabricGroup.addTemplate( - FileTemplateDescriptor(FABRIC_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE, PlatformAssets.FABRIC_ICON) - ) } FileTemplateGroupDescriptor("LiteLoader", PlatformAssets.LITELOADER_ICON).let { liteGroup -> group.addTemplate(liteGroup) liteGroup.addTemplate(FileTemplateDescriptor(LITELOADER_MAIN_CLASS_TEMPLATE)) liteGroup.addTemplate(FileTemplateDescriptor(LITELOADER_BUILD_GRADLE_TEMPLATE)) - liteGroup.addTemplate(FileTemplateDescriptor(LITELOADER_SUBMODULE_BUILD_GRADLE_TEMPLATE)) liteGroup.addTemplate(FileTemplateDescriptor(LITELOADER_GRADLE_PROPERTIES_TEMPLATE)) liteGroup.addTemplate(FileTemplateDescriptor(LITELOADER_SETTINGS_GRADLE_TEMPLATE)) } @@ -145,6 +115,7 @@ group.addTemplate(commonGroup) commonGroup.addTemplate(FileTemplateDescriptor(GRADLE_GITIGNORE_TEMPLATE)) commonGroup.addTemplate(FileTemplateDescriptor(MAVEN_GITIGNORE_TEMPLATE)) + commonGroup.addTemplate(FileTemplateDescriptor(GRADLE_WRAPPER_PROPERTIES)) } FileTemplateGroupDescriptor("Skeletons", GeneralAssets.MC_TEMPLATE).let { skeletonGroup -> @@ -189,62 +160,41 @@ const val BUKKIT_MAIN_CLASS_TEMPLATE = "Bukkit Main Class.java" const val BUKKIT_PLUGIN_YML_TEMPLATE = "Bukkit plugin.yml" const val BUKKIT_BUILD_GRADLE_TEMPLATE = "Bukkit build.gradle" - const val BUKKIT_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Bukkit Submodule build.gradle" const val BUKKIT_GRADLE_PROPERTIES_TEMPLATE = "Bukkit gradle.properties" const val BUKKIT_SETTINGS_GRADLE_TEMPLATE = "Bukkit settings.gradle" const val BUKKIT_POM_TEMPLATE = "Bukkit pom.xml" - const val BUKKIT_SUBMODULE_POM_TEMPLATE = "Bukkit Submodule pom.xml" const val BUNGEECORD_MAIN_CLASS_TEMPLATE = "BungeeCord Main Class.java" const val BUNGEECORD_PLUGIN_YML_TEMPLATE = "BungeeCord bungee.yml" const val BUNGEECORD_BUILD_GRADLE_TEMPLATE = "BungeeCord build.gradle" - const val BUNGEECORD_SUBMODULE_BUILD_GRADLE_TEMPLATE = "BungeeCord Submodule build.gradle" const val BUNGEECORD_GRADLE_PROPERTIES_TEMPLATE = "BungeeCord gradle.properties" const val BUNGEECORD_SETTINGS_GRADLE_TEMPLATE = "BungeeCord settings.gradle" const val BUNGEECORD_POM_TEMPLATE = "BungeeCord pom.xml" - const val BUNGEECORD_SUBMODULE_POM_TEMPLATE = "BungeeCord Submodule pom.xml" const val VELOCITY_MAIN_CLASS_TEMPLATE = "Velocity Main Class.java" const val VELOCITY_MAIN_CLASS_V2_TEMPLATE = "Velocity Main Class V2.java" const val VELOCITY_BUILD_CONSTANTS_TEMPLATE = "Velocity Build Constants.java" const val VELOCITY_BUILD_GRADLE_TEMPLATE = "Velocity build.gradle" - const val VELOCITY_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Velocity Submodule build.gradle" const val VELOCITY_GRADLE_PROPERTIES_TEMPLATE = "Velocity gradle.properties" const val VELOCITY_SETTINGS_GRADLE_TEMPLATE = "Velocity settings.gradle" const val VELOCITY_POM_TEMPLATE = "Velocity pom.xml" - const val VELOCITY_SUBMODULE_POM_TEMPLATE = "Velocity Submodule pom.xml" - const val SPONGE_MAIN_CLASS_TEMPLATE = "Sponge Main Class.java" - const val SPONGE_BUILD_GRADLE_TEMPLATE = "Sponge build.gradle" - const val SPONGE_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Sponge Submodule build.gradle" - const val SPONGE_GRADLE_PROPERTIES_TEMPLATE = "Sponge gradle.properties" - const val SPONGE_SETTINGS_GRADLE_TEMPLATE = "Sponge settings.gradle" const val SPONGE_POM_TEMPLATE = "Sponge pom.xml" - const val SPONGE_SUBMODULE_POM_TEMPLATE = "Sponge Submodule pom.xml" - const val SPONGE8_MAIN_CLASS_TEMPLATE = "Sponge 8+ Main Class.java" const val SPONGE8_PLUGINS_JSON_TEMPLATE = "Sponge 8+ sponge_plugins.json" const val SPONGE8_BUILD_GRADLE_TEMPLATE = "Sponge 8+ build.gradle.kts" - const val SPONGE8_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Sponge 8+ Submodule build.gradle.kts" const val SPONGE8_GRADLE_PROPERTIES_TEMPLATE = "Sponge 8+ gradle.properties" const val SPONGE8_SETTINGS_GRADLE_TEMPLATE = "Sponge 8+ settings.gradle.kts" - const val FORGE_MAIN_CLASS_TEMPLATE = "Forge Main Class.java" - const val FORGE_BUILD_GRADLE_TEMPLATE = "Forge build.gradle" - const val FORGE_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Forge Submodule build.gradle" - const val FORGE_GRADLE_PROPERTIES_TEMPLATE = "Forge gradle.properties" const val FORGE_MIXINS_JSON_TEMPLATE = "Forge Mixins Config.json" - const val FORGE_SETTINGS_GRADLE_TEMPLATE = "Forge settings.gradle" const val FG3_MAIN_CLASS_TEMPLATE = "Forge (1.13+) Main Class.java" const val FG3_1_17_MAIN_CLASS_TEMPLATE = "Forge (1.17+) Main Class.java" const val FG3_1_18_MAIN_CLASS_TEMPLATE = "Forge (1.18+) Main Class.java" const val FG3_1_19_MAIN_CLASS_TEMPLATE = "Forge (1.19+) Main Class.java" const val FG3_1_19_3_MAIN_CLASS_TEMPLATE = "Forge (1.19.3+) Main Class.java" const val FG3_BUILD_GRADLE_TEMPLATE = "Forge (1.13+) build.gradle" - const val FG3_SUBMODULE_BUILD_GRADLE_TEMPLATE = "Forge (1.13+) Submodule build.gradle" const val FG3_GRADLE_PROPERTIES_TEMPLATE = "Forge (1.13+) gradle.properties" const val FG3_SETTINGS_GRADLE_TEMPLATE = "Forge (1.13+) settings.gradle" - const val MCMOD_INFO_TEMPLATE = "mcmod.info" const val MODS_TOML_TEMPLATE = "mods.toml" const val PACK_MCMETA_TEMPLATE = "pack.mcmeta" @@ -253,13 +203,9 @@ const val FABRIC_MIXINS_JSON_TEMPLATE = "fabric_mixins.json" const val FABRIC_MOD_JSON_TEMPLATE = "fabric_mod.json" const val FABRIC_SETTINGS_GRADLE_TEMPLATE = "fabric_settings.gradle" - const val FABRIC_SUBMODULE_BUILD_GRADLE_TEMPLATE = "fabric_submodule_build.gradle" - const val FABRIC_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE = "fabric_submodule_gradle.properties" const val ARCHITECTURY_BUILD_GRADLE_TEMPLATE = "architectury_build.gradle" const val ARCHITECTURY_GRADLE_PROPERTIES_TEMPLATE = "architectury_gradle.properties" - const val ARCHITECTURY_SUBMODULE_BUILD_GRADLE_TEMPLATE = "architectury_submodule_build.gradle" - const val ARCHITECTURY_SUBMODULE_GRADLE_PROPERTIES_TEMPLATE = "architectury_submodule_gradle.properties" const val ARCHITECTURY_SETTINGS_GRADLE_TEMPLATE = "architectury_settings.gradle" const val ARCHITECTURY_COMMON_BUILD_GRADLE_TEMPLATE = "architectury_common_build.gradle" const val ARCHITECTURY_COMMON_MAIN_CLASS_TEMPLATE = "architectury_common_main_class.java" @@ -277,7 +223,6 @@ const val LITELOADER_MAIN_CLASS_TEMPLATE = "LiteLoader Main Class.java" const val LITELOADER_BUILD_GRADLE_TEMPLATE = "LiteLoader build.gradle" - const val LITELOADER_SUBMODULE_BUILD_GRADLE_TEMPLATE = "LiteLoader Submodule build.gradle" const val LITELOADER_GRADLE_PROPERTIES_TEMPLATE = "LiteLoader gradle.properties" const val LITELOADER_SETTINGS_GRADLE_TEMPLATE = "LiteLoader settings.gradle" @@ -289,6 +234,7 @@ const val MIXIN_OVERWRITE_FALLBACK = "Mixin Overwrite Fallback.java" + const val GRADLE_WRAPPER_PROPERTIES = "MinecraftDev gradle-wrapper.properties" const val GRADLE_GITIGNORE_TEMPLATE = "Gradle.gitignore" const val MAVEN_GITIGNORE_TEMPLATE = "Maven.gitignore" Index: src/main/kotlin/util/MinecraftVersions.kt =================================================================== --- src/main/kotlin/util/MinecraftVersions.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/MinecraftVersions.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -10,20 +10,22 @@ package com.demonwav.mcdev.util -import com.intellij.util.lang.JavaVersion +import com.intellij.openapi.projectRoots.JavaSdkVersion object MinecraftVersions { val MC1_12_2 = SemanticVersion.release(1, 12, 2) val MC1_14_4 = SemanticVersion.release(1, 14, 4) val MC1_16_1 = SemanticVersion.release(1, 16, 1) + val MC1_16_5 = SemanticVersion.release(1, 16, 5) val MC1_17 = SemanticVersion.release(1, 17) + val MC1_17_1 = SemanticVersion.release(1, 17, 1) val MC1_18 = SemanticVersion.release(1, 18) val MC1_19 = SemanticVersion.release(1, 19) val MC1_19_3 = SemanticVersion.release(1, 19, 3) fun requiredJavaVersion(minecraftVersion: SemanticVersion) = when { - minecraftVersion >= MC1_18 -> JavaVersion.compose(17) - minecraftVersion >= MC1_17 -> JavaVersion.compose(16) - else -> JavaVersion.compose(8) + minecraftVersion <= MC1_16_5 -> JavaSdkVersion.JDK_1_8 + minecraftVersion <= MC1_17_1 -> JavaSdkVersion.JDK_16 + else -> JavaSdkVersion.JDK_17 } } Index: src/main/kotlin/util/SemanticVersion.kt =================================================================== --- src/main/kotlin/util/SemanticVersion.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/SemanticVersion.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -86,6 +86,14 @@ */ fun release(vararg parts: Int) = SemanticVersion(parts.map { ReleasePart(it, it.toString()) }) + fun tryParse(value: String): SemanticVersion? { + return try { + parse(value) + } catch (e: IllegalArgumentException) { + null + } + } + /** * Parses a version string into a comparable representation. * @throws IllegalArgumentException if any part of the version string cannot be parsed as integer or split into text parts. Index: src/main/kotlin/util/mod-creator.kt =================================================================== --- src/main/kotlin/util/mod-creator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/mod-creator.kt (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,29 +0,0 @@ -/* - * Minecraft Dev for IntelliJ - * - * https://minecraftdev.org - * - * Copyright (c) 2023 minecraft-dev - * - * MIT License - */ - -package com.demonwav.mcdev.util - -import com.demonwav.mcdev.creator.MinecraftProjectCreator -import com.demonwav.mcdev.creator.ProjectConfig -import com.demonwav.mcdev.creator.buildsystem.BuildSystem -import javax.swing.JTextField -import org.apache.commons.lang.WordUtils - -inline fun modUpdateStep( - creator: MinecraftProjectCreator, - modNameField: JTextField -): Pair? { - val buildSystem = creator.buildSystem ?: return null - - modNameField.text = WordUtils.capitalize(buildSystem.artifactId.replace('-', ' ')) - - val config = creator.config as? T ?: return null - return config to buildSystem -} Index: src/main/kotlin/util/swing-utils.kt =================================================================== --- src/main/kotlin/util/swing-utils.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/kotlin/util/swing-utils.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,41 @@ +/* + * Minecraft Dev for IntelliJ + * + * https://minecraftdev.org + * + * Copyright (c) 2023 minecraft-dev + * + * MIT License + */ + +package com.demonwav.mcdev.util + +import com.intellij.openapi.observable.properties.ObservableProperty +import com.intellij.openapi.observable.util.bindEnabled +import com.intellij.ui.dsl.builder.Cell +import java.awt.Component +import java.awt.event.HierarchyEvent +import javax.swing.JComponent + +fun Component.onShown(func: (HierarchyEvent) -> Unit) { + addHierarchyListener { event -> + if ((event.changeFlags and HierarchyEvent.SHOWING_CHANGED.toLong()) != 0L && isShowing) { + func(event) + } + } +} + +fun Component.onHidden(func: (HierarchyEvent) -> Unit) { + addHierarchyListener { event -> + if ((event.changeFlags and HierarchyEvent.SHOWING_CHANGED.toLong()) != 0L && !isShowing) { + func(event) + } + } +} + +fun Cell.bindEnabled(property: ObservableProperty): Cell { + applyToComponent { + bindEnabled(property) + } + return this +} Index: src/main/kotlin/util/utils.kt =================================================================== --- src/main/kotlin/util/utils.kt (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/kotlin/util/utils.kt (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -30,6 +30,7 @@ import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Condition import com.intellij.openapi.util.Ref +import com.intellij.openapi.util.text.StringUtil import com.intellij.pom.java.LanguageLevel import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiFile @@ -52,31 +53,26 @@ } } -inline fun Project.runWriteTaskInSmartMode(crossinline func: () -> T): T { - if (ApplicationManager.getApplication().isReadAccessAllowed) { - return runWriteTask { func() } - } - +inline fun Project.runWriteTaskInSmartMode(crossinline func: () -> Unit) { val dumbService = DumbService.getInstance(this) - val ref = Ref() - while (true) { - dumbService.waitForSmartMode() - val success = runWriteTask { + lateinit var runnable: Runnable + runnable = Runnable { - if (isDisposed) { - throw ProcessCanceledException() - } + if (isDisposed) { + throw ProcessCanceledException() + } + runWriteTask { + if (isDisposed) { + throw ProcessCanceledException() + } if (dumbService.isDumb) { - return@runWriteTask false + dumbService.runWhenSmart(runnable) + } else { + func() } - ref.set(func()) - return@runWriteTask true } - if (success) { - break - } + } + dumbService.runWhenSmart(runnable) - } +} - return ref.get() -} fun invokeAndWait(func: () -> T): T { val ref = Ref() @@ -306,6 +302,9 @@ .joinToString("") } +fun String.toJavaClassName() = StringUtil.capitalizeWords(this, true) + .replace(" ", "").toJavaIdentifier(allowDollars = false) + fun String.toPackageName(): String { if (this.isEmpty()) { return "_" Index: src/main/resources/META-INF/plugin.xml =================================================================== --- src/main/resources/META-INF/plugin.xml (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/META-INF/plugin.xml (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -13,7 +13,9 @@ com.intellij.modules.java org.jetbrains.idea.maven com.intellij.gradle + org.jetbrains.kotlin org.intellij.groovy + com.intellij.properties ByteCodeViewer org.toml.lang @@ -22,8 +24,7 @@ minecraft-dev messages.MinecraftDevelopment @@ -34,6 +35,18 @@ + + + + + + + + + + + + @@ -44,6 +57,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -82,7 +130,6 @@ * Sponge * Forge * Fabric - * LiteLoader * MCP * Mixin * Velocity @@ -269,14 +316,6 @@ - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,49 +0,0 @@ -plugins { - id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "0.+" apply false -} - -architectury { - minecraft = project.minecraft_version -} - -subprojects { - apply plugin: "dev.architectury.loom" - - loom { - silentMojangMappingsLicense() - } - - dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - // The following line declares the mojmap mappings, you may use other mappings as well - mappings loom.officialMojangMappings() - // The following line declares the yarn mappings you may select this one as well. - // mappings "net.fabricmc:yarn:@YARN_MAPPINGS@:v2" - } -} - -allprojects { - apply plugin: "java" - apply plugin: "architectury-plugin" - apply plugin: "maven-publish" - - archivesBaseName = project.archives_base_name - - repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. - } - - tasks.withType(JavaCompile) { - options.encoding = "UTF-8" - options.release = ${JAVA_VERSION} - } - - java { - withSourcesJar() - } -} Index: src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle file for multi-module Architectury projects.

- - Index: src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,12 +0,0 @@ -org.gradle.jvmargs=-Xmx1G - -minecraft_version=${MC_VERSION} - -archives_base_name=${ARTIFACT_ID} - -architectury_version=${ARCHITECTURY_API_VERSION} - -fabric_loader_version=${FABRIC_LOADER_VERSION} -fabric_api_version=${FABRIC_API_VERSION} - -forge_version=${FORGE_VERSION} Index: src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/architectury/architectury_submodule_gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new gradle.properties file for multi-module Architectury projects.

- - Index: src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,28 +0,0 @@ -plugins { - id 'com.github.johnrengelman.shadow' -} - -repositories { -} - -dependencies { - api project(':${COMMON_PROJECT_NAME}') -} - -processResources { - def props = [version: project.version] - inputs.properties props - expand props - filteringCharset 'UTF-8' - filesMatching('plugin.yml') { - expand props - } -} - -shadowJar { - dependencies { - include(dependency(':${COMMON_PROJECT_NAME}')) - } -} - -tasks.build.dependsOn tasks.shadowJar Index: src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' Bukkit submodule.

- - Index: src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,42 +0,0 @@ - - - 4.0.0 - - - - - - - - - jar - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-shade-plugin - - - - - src/main/resources - true - - - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bukkit/Bukkit Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for the multi-module projects' Bukkit submodule.

- - Index: src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,28 +0,0 @@ -plugins { - id 'com.github.johnrengelman.shadow' -} - -repositories { -} - -dependencies { - api project(':${COMMON_PROJECT_NAME}') -} - -processResources { - def props = [version: project.version] - inputs.properties props - expand props - filteringCharset 'UTF-8' - filesMatching('bungee.yml') { - expand props - } -} - -shadowJar { - dependencies { - include(dependency(':${COMMON_PROJECT_NAME}')) - } -} - -tasks.build.dependsOn tasks.shadowJar Index: src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' BungeeCord submodule.

- - Index: src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,42 +0,0 @@ - - - 4.0.0 - - - - - - - - - jar - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-shade-plugin - - - - - src/main/resources - true - - - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/bungeecord/BungeeCord Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for the multi-module projects' BungeeCord submodule.

- - Index: src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.ft (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.ft (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,1 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-${GRADLE_WRAPPER_VERSION}-bin.zip Index: src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.html (revision 83949ccec33f5900f9afa7453acfd67b84f16454) +++ src/main/resources/fileTemplates/j2ee/common/MinecraftDev gradle-wrapper.properties.html (revision 83949ccec33f5900f9afa7453acfd67b84f16454) @@ -0,0 +1,15 @@ + + + + +

This is a built-in file template used to create a new gradle-wrapper.properties file for Minecraft projects.

+ + Index: src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,80 +0,0 @@ -plugins { - id 'fabric-loom' version '${LOOM_VERSION}' - id 'maven-publish' -} - -repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. -} - -dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - #if (${API_VERSION}) - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - #end -} - -processResources { - inputs.property "version", project.version - filteringCharset "UTF-8" - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -def targetJavaVersion = ${JAVA_VERSION} -tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - it.options.encoding = "UTF-8" - if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { - it.options.release = targetJavaVersion - } -} - -java { - def javaVersion = JavaVersion.toVersion(targetJavaVersion) - if (JavaVersion.current() < javaVersion) { - toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) - } - archivesBaseName = project.archives_base_name - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - withSourcesJar() -} - -jar { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}"} - } -} - -// configure the maven publication -publishing { - publications { - mavenJava(MavenPublication) { - from components.java - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - } -} Index: src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle file for multi-module Fabric projects.

- - Index: src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,17 +0,0 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx1G - -# Fabric Properties - # check these on https://modmuss50.me/fabric.html - minecraft_version=${MC_VERSION} - yarn_mappings=${YARN_MAPPINGS} - loader_version=${LOADER_VERSION} - -# Mod Properties - archives_base_name = ${ARTIFACT_ID} - -#if (${API_VERSION}) -# Dependencies - # check this on https://modmuss50.me/fabric.html - fabric_version=${API_VERSION} -#end Index: src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/fabric/fabric_submodule_gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new gradle.properties file for multi-module Fabric projects.

- - Index: src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,56 +0,0 @@ -buildscript { - repositories { - mavenCentral() - maven { - name = "forge" - url = "https://files.minecraftforge.net/maven" - } - } - dependencies { - classpath "net.minecraftforge.gradle:ForgeGradle:${FORGEGRADLE_VERSION}-SNAPSHOT" - } -} - -apply plugin: "net.minecraftforge.gradle.forge" - -archivesBaseName = '${ARTIFACT_ID}' - -minecraft { - version = project.forgeVersion - runDir = "run" - - // the mappings can be changed at any time, and must be in the following format. - // snapshot_YYYYMMDD snapshot are built nightly. - // stable_# stables are built at the discretion of the MCP team. - // Use non-default mappings at your own risk. they may not always work. - // simply re-run your setup task after changing the mappings to update your workspace. - mappings = project.mcpVersion - // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. -} - -repositories { - mavenCentral() -} - -dependencies { - compile project(":${COMMON_PROJECT_NAME}") -} - -processResources { - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include "mcmod.info" - - // replace version and mcversion - expand "version": project.version, "mcversion": project.minecraft.version - } - - // copy everything else, thats not the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude "mcmod.info" - } -} Index: src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/forge/Forge Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' Forge submodule for 1.12 and below.

- - Index: src/main/resources/fileTemplates/j2ee/forge/mcmod.info.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/forge/mcmod.info.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/forge/mcmod.info.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,28 +0,0 @@ -[ - { - "modid": "${ARTIFACT_ID}", - "name": "${MOD_NAME}", - "description": "${DESCRIPTION}", - "version": "${version}", - "mcversion": "${mcversion}", -#if (${URL}) - "url": "${URL}", -#else - "url": "", -#end -#if (${UPDATE_URL}) - "updateUrl": "${UPDATE_URL}", -#else - "updateUrl": "", -#end -#if (${AUTHOR_LIST}) - "authorList": [${AUTHOR_LIST}], -#else - "authorList": [], -#end - "credits": "", - "logoFile": "", - "screenshots": [], - "dependencies": [] - } -] Index: src/main/resources/fileTemplates/j2ee/forge/mcmod.info.html =================================================================== --- src/main/resources/fileTemplates/j2ee/forge/mcmod.info.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/forge/mcmod.info.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new mcmod.info for Forge projects 1.12 and below.

- - Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,55 +0,0 @@ -package ${PACKAGE_NAME}; - -import com.mumfrey.liteloader.LiteMod; -import java.io.File; - -public class ${CLASS_NAME} implements LiteMod { - - /** - * Default constructor. All LiteMods must have a default constructor. In general you should do very little - * in the mod constructor EXCEPT for initialising any non-game-interfacing components or performing - * sanity checking prior to initialisation - */ - public ${CLASS_NAME}() { - } - - /** - * getName() should be used to return the display name of your mod and MUST NOT return null - * - * @see com.mumfrey.liteloader.LiteMod#getName() - */ - @Override - public String getName() { - return "${MOD_NAME}"; - } - - /** - * getVersion() should return the same version string present in the mod metadata, although this is - * not a strict requirement. - * - * @see com.mumfrey.liteloader.LiteMod#getVersion() - */ - @Override - public String getVersion() { - return "${MOD_VERSION}"; - } - - /** - * init() is called very early in the initialisation cycle, before the game is fully initialised, this - * means that it is important that your mod does not interact with the game in any way at this point. - * - * @see com.mumfrey.liteloader.LiteMod#init(File) - */ - @Override - public void init(File configPath) { - } - - /** - * upgradeSettings is used to notify a mod that its version-specific settings are being migrated - * - * @see com.mumfrey.liteloader.LiteMod#upgradeSettings(String, File, File) - */ - @Override - public void upgradeSettings(String version, File configPath, File oldConfigPath) { - } -} \ No newline at end of file Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.html =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Main Class.java.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new main class for LiteLoader projects.

- - Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,52 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/repositories/snapshots/" - } - maven { - name = "forge" - url = "https://files.minecraftforge.net/maven" - } - maven { - name = 'sponge' - url = 'https://repo.spongepowered.org/maven' - } - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:${FORGEGRADLE_VERSION}-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.4-SNAPSHOT' - } -} - -apply plugin: 'com.github.johnrengelman.shadow' -apply plugin: 'net.minecraftforge.gradle.liteloader' -apply plugin: 'org.spongepowered.mixin' - -archivesBaseName = '${ARTIFACT_ID}' - -minecraft { - version = project.mcVersion - mappings = project.mcpMappings - runDir = "run" -} - -dependencies { - compile project(":${COMMON_PROJECT_NAME}") -} - -mixin { - defaultObfuscationEnv notch -} - -jar { - from litemod.outputs -} - -shadowJar { - dependencies { - include(dependency(":${COMMON_PROJECT_NAME}")) - } -} Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' LiteLoader submodule.

- - Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,43 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/repositories/snapshots/" - } - maven { - name = "forge" - url = "https://files.minecraftforge.net/maven" - } - maven { - name = 'sponge' - url = 'https://repo.spongepowered.org/maven' - } - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:${FORGEGRADLE_VERSION}-SNAPSHOT' - classpath 'org.spongepowered:mixingradle:0.4-SNAPSHOT' - } -} - -apply plugin: 'net.minecraftforge.gradle.liteloader' -apply plugin: 'org.spongepowered.mixin' - -group = '${GROUP_ID}' -version = '${VERSION}' -archivesBaseName = '${ARTIFACT_ID}' - -minecraft { - version = project.mcVersion - mappings = project.mcpMappings - runDir = "run" -} - -mixin { - defaultObfuscationEnv notch -} - -jar { - from litemod.outputs -} Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for LiteLoader projects.

- - Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,2 +0,0 @@ -mcVersion = ${MC_VERSION} -mcpMappings = ${MCP_MAPPINGS} Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new gradle.properties file for LiteLoader projects.

- - Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,1 +0,0 @@ -rootProject.name = '${PROJECT_NAME}' Index: src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/liteloader/LiteLoader settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new settings.gradle for LiteLoader projects.

- - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,34 +0,0 @@ -plugins { - id "com.github.johnrengelman.shadow" version "7.0.0" apply false -} - -group = '${GROUP_ID}' -version = '${PLUGIN_VERSION}' - -subprojects { - apply plugin: 'java-library' - apply plugin: 'maven-publish' - - group = parent.group - version = parent.version - - def targetJavaVersion = property('javaVersion') as int - java { - def javaVersion = JavaVersion.toVersion(targetJavaVersion) - sourceCompatibility = javaVersion - targetCompatibility = javaVersion - if (JavaVersion.current() < javaVersion) { - toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) - } - } - - tasks.withType(JavaCompile).configureEach { - if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { - options.release = targetJavaVersion - } - } - - repositories { - mavenCentral() - } -} Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for multi-module Minecraft projects.

- - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,1 +0,0 @@ -javaVersion=8 Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new gradle.properties file for Minecraft projects.

- - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,51 +0,0 @@ - - - 4.0.0 - - - - - pom - - - 1.8 - UTF-8 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - ${maven-compiler-plugin-version} - - ${java.version} - ${java.version} - - - - org.apache.maven.plugins - maven-shade-plugin - ${maven-shade-plugin-version} - - - package - - shade - - - false - - - - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for multi-module Minecraft projects.

- - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,3 +0,0 @@ -rootProject.name = '${ARTIFACT_ID}' - -include ${INCLUDES} Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Base settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new settings.gradle for multi-module Minecraft projects.

- - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,34 +0,0 @@ - - - 4.0.0 - - - - - - - - - jar - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-shade-plugin - - - - - src/main/resources - true - - - - Index: src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/multi/Multi-Module Common pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for the common module in multi-module Minecraft projects.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,94 +0,0 @@ -import org.spongepowered.gradle.plugin.config.PluginLoaders -import org.spongepowered.plugin.metadata.model.PluginDependency - -plugins { - `java-library` - id("com.github.johnrengelman.shadow") - id("org.spongepowered.gradle.plugin") version "2.0.2" -} - -repositories { - mavenCentral() -} - -dependencies { - implementation(project(":${COMMON_PROJECT_NAME}")) -} - -sponge { - apiVersion("${SPONGEAPI_VERSION}") - license("${LICENSE}") - loader { - name(PluginLoaders.JAVA_PLAIN) - version("1.0") - } - plugin("${PLUGIN_ID}") { - displayName("${PLUGIN_NAME}") - entrypoint("${MAIN_CLASS}") - #if (${DESCRIPTION}) - description("${DESCRIPTION}") - #else - description("My plugin description") - #end - links { - #if (${WEBSITE}) - homepage("${WEBSITE}") - #else - // homepage("https://spongepowered.org") - #end - // source("https://spongepowered.org/source") - // issues("https://spongepowered.org/issues") - } - #foreach (${AUTHOR} in ${AUTHORS}) - contributor("${AUTHOR}") { - description("Author") - } - #end - dependency("spongeapi") { - loadOrder(PluginDependency.LoadOrder.AFTER) - optional(false) - } - #foreach (${DEPENDENCY} in ${DEPENDENCIES}) - dependency("${DEPEDENCY}") { - loadOrder(PluginDependency.LoadOrder.AFTER) - optional(false) - } - #end - } -} - -val javaTarget = ${JAVA_VERSION} // Sponge targets a minimum of Java ${JAVA_VERSION} -java { - sourceCompatibility = JavaVersion.toVersion(javaTarget) - targetCompatibility = JavaVersion.toVersion(javaTarget) - if (JavaVersion.current() < JavaVersion.toVersion(javaTarget)) { - toolchain.languageVersion.set(JavaLanguageVersion.of(javaTarget)) - } -} - -tasks.withType(JavaCompile::class).configureEach { - options.apply { - encoding = "utf-8" // Consistent source file encoding - if (JavaVersion.current().isJava10Compatible) { - release.set(javaTarget) - } - } -} - -// Make sure all tasks which produce archives (jar, sources jar, javadoc jar, etc) produce more consistent output -tasks.withType(AbstractArchiveTask::class).configureEach { - isReproducibleFileOrder = true - isPreserveFileTimestamps = false -} - -tasks { - shadowJar { - dependencies { - include(dependency(":${COMMON_PROJECT_NAME}")) - } - } - - build { - dependsOn(shadowJar) - } -} Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge 8+ Submodule build.gradle.kts.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' SpongeAPI 8 submodule.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,19 +0,0 @@ -package ${PACKAGE}; - -import com.google.inject.Inject; -import org.slf4j.Logger; -import org.spongepowered.api.event.game.state.GameStartedServerEvent; -import org.spongepowered.api.event.Listener; -#if(${HAS_DEPENDENCIES}) -import org.spongepowered.api.plugin.Dependency; -#end -import org.spongepowered.api.plugin.Plugin; - -public class ${CLASS_NAME} { - - @Inject private Logger logger; - - @Listener - public void onServerStart(GameStartedServerEvent event) { - } -} Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Main Class.java.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new main class for legacy Sponge (API 7).

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,23 +0,0 @@ -plugins { - id 'org.spongepowered.plugin' version '0.9.0' - id 'com.github.johnrengelman.shadow' -} - -java { - targetCompatibility = null - sourceCompatibility = null -} - -dependencies { - compile project(':${COMMON_PROJECT_NAME}') -} - -sponge.plugin.id = '${PLUGIN_ID}' - -shadowJar { - dependencies { - include(dependency(':${COMMON_PROJECT_NAME}')) - } -} - -tasks.build.dependsOn tasks.shadowJar Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' legacy Sponge (API 7) submodule.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,149 +0,0 @@ - - - 4.0.0 - - - - - - - - - jar - - - - - ${JAVA_VERSION} - UTF-8 - - - - - release - - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin-version} - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin-version} - - - sign-artifacts - verify - - sign - - - - - - - - src/main/resources - true - - - - - - - - - - ${project.basedir}/src/main/resources - true - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.codehaus.mojo - templating-maven-plugin - ${templating-maven-plugin-version} - - - filter-src - - filter-sources - - - - - - org.apache.maven.plugins - maven-site-plugin - ${maven-site-plugin-version} - - - net.trajano.wagon - wagon-git - ${wagon-git-version} - - - org.apache.maven.doxia - doxia-module-markdown - ${doxia-module-markdown-version} - - - - - org.apache.maven.plugins - maven-release-plugin - ${maven-release-plugin-version} - - true - @{project.version} - [RELEASE] - install deploy site-deploy - release - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for the multi-module projects' Sponge submodule.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,27 +0,0 @@ -plugins { - id 'org.spongepowered.plugin' version '0.9.0' -} - -group = '${GROUP_ID}' -version = '${PLUGIN_VERSION}' - -dependencies { -} - -sponge.plugin.id = '${PLUGIN_ID}' - -def targetJavaVersion = 8 -java { - def javaVersion = JavaVersion.toVersion(targetJavaVersion) - sourceCompatibility = javaVersion - targetCompatibility = javaVersion - if (JavaVersion.current() < javaVersion) { - toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) - } -} - -tasks.withType(JavaCompile).configureEach { - if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { - options.release = targetJavaVersion - } -} Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for legacy Sponge (API 7) projects.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,0 +0,0 @@ Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge gradle.properties.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new gradle.properties file for legacy Sponge (API 7) projects.

- - Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,1 +0,0 @@ -rootProject.name = '${PROJECT_NAME}' Index: src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/sponge/Sponge settings.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new settings.gradle for legacy Sponge (API 7) projects.

- - Index: src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,39 +0,0 @@ -plugins { - id 'java' - id 'eclipse' - id 'com.github.johnrengelman.shadow' -} - -repositories { - mavenCentral() -} - -dependencies { - api project(':${COMMON_PROJECT_NAME}') -} - -def templateSource = file('src/main/templates') -def templateDest = layout.buildDirectory.dir('generated/sources/templates') -def generateTemplates = tasks.register('generateTemplates', Copy) { task -> - def props = [ - 'version': project.version - ] - task.inputs.properties props - - task.from templateSource - task.into templateDest - task.expand props -} - -sourceSets.main.java.srcDir(generateTemplates.map { it.outputs }) - -rootProject.idea.project.settings.taskTriggers.afterSync generateTemplates -project.eclipse.synchronizationTasks(generateTemplates) - -shadowJar { - dependencies { - include(dependency(':${COMMON_PROJECT_NAME}')) - } -} - -tasks.build.dependsOn tasks.shadowJar Index: src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.html =================================================================== --- src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule build.gradle.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new build.gradle for the multi-module projects' Velocity submodule.

- - Index: src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.ft =================================================================== --- src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.ft (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,149 +0,0 @@ - - - 4.0.0 - - - - - - - - - jar - - - - - ${JAVA_VERSION} - UTF-8 - - - - - release - - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin-version} - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - ${maven-gpg-plugin-version} - - - sign-artifacts - verify - - sign - - - - - - - - src/main/resources - true - - - - - - - - - - ${project.basedir}/src/main/resources - true - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.codehaus.mojo - templating-maven-plugin - ${templating-maven-plugin-version} - - - filter-src - - filter-sources - - - - - - org.apache.maven.plugins - maven-site-plugin - ${maven-site-plugin-version} - - - net.trajano.wagon - wagon-git - ${wagon-git-version} - - - org.apache.maven.doxia - doxia-module-markdown - ${doxia-module-markdown-version} - - - - - org.apache.maven.plugins - maven-release-plugin - ${maven-release-plugin-version} - - true - @{project.version} - [RELEASE] - install deploy site-deploy - release - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven-javadoc-plugin-version} - - - - - - - - Index: src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.html =================================================================== --- src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) +++ src/main/resources/fileTemplates/j2ee/velocity/Velocity Submodule pom.xml.html (revision 4041be848225d64c78051c358da2fe10a425b575) @@ -1,15 +0,0 @@ - - - - -

This is a built-in file template used to create a new pom.xml for the multi-module projects' Velocity submodule.

- -