Skip to content

Commit

Permalink
Move second fabric files setup step to after Gradle import
Browse files Browse the repository at this point in the history
Attempts to resolve #2054
  • Loading branch information
RedNesto committed Aug 13, 2023
1 parent a48d691 commit 9a0afac
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 206 deletions.
245 changes: 44 additions & 201 deletions src/main/kotlin/platform/fabric/creator/asset-steps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

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
Expand All @@ -43,69 +42,20 @@ 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.fileEditor.impl.NonProjectFileWritingAccessProvider
import com.intellij.openapi.application.WriteAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.LocalFileSystem
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<BuildSystemPropertiesStep<*>>()
val modId = data.getUserData(AbstractModIdStep.KEY) ?: return
val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false
val javaVersion = findStep<JdkProjectSetupFinalizer>().preferredJdk.ordinal
const val MAGIC_DEFERRED_INIT_FILE = ".hello_fabric_from_mcdev"

if (useMixins) {
val packageName =
"${buildSystemProps.groupId.toPackageName()}.${modId.toPackageName()}.mixin"
assets.addTemplateProperties(
"PACKAGE_NAME" to packageName,
"JAVA_VERSION" to javaVersion,
)
val mixinsJsonFile = "src/main/resources/$modId.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<EntryPoint>
class FabricBaseFilesStep(parent: NewProjectWizardStep) : AbstractLongRunningAssetsStep(parent) {
override val description = "Adding Fabric project files (phase 1)"

override fun setupAssets(project: Project) {
val buildSystemProps = findStep<BuildSystemPropertiesStep<*>>()
Expand All @@ -124,14 +74,6 @@ class FabricSmartModeFilesStep(parent: NewProjectWizardStep) : AbstractLongRunni
val apiVersion = data.getUserData(FabricVersionChainStep.API_VERSION_KEY)
val useMixins = data.getUserData(UseMixinsStep.KEY) ?: false

val packageName = "${buildSystemProps.groupId.toPackageName()}.${modId.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_ID" to modId,
Expand All @@ -149,153 +91,54 @@ class FabricSmartModeFilesStep(parent: NewProjectWizardStep) : AbstractLongRunni
}

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)

NonProjectFileWritingAccessProvider.allowWriting(listOf(fabricModJsonFile))
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<Pair<String, String>>()
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<JsonArray>("[]")
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()
val packageName =
"${buildSystemProps.groupId.toPackageName()}.${modId.toPackageName()}.mixin"
assets.addTemplateProperties(
"MIXINS" to "true",
"MIXIN_PACKAGE_NAME" to packageName,
)
val mixinsJsonFile = "src/main/resources/$modId.mixins.json"
assets.addTemplates(project, mixinsJsonFile to FABRIC_MIXINS_JSON_TEMPLATE)
}
}

private fun createEntryPoints(project: Project) {
val root = VfsUtil.findFile(Path.of(context.projectFileDirectory), true) ?: return
val psiManager = PsiManager.getInstance(project)

val generatedClasses = mutableSetOf<PsiClass>()

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('.')
assets.addLicense(project)

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
assets.addAssets(
GeneratorEmptyDirectory("src/main/java"),
GeneratorEmptyDirectory("src/main/resources"),
)

clazz.containingFile.runWriteAction {
clazz.addImplements(entryPoint.interfaceName)
assets.addTemplates(project, "src/main/resources/fabric.mod.json" to FABRIC_MOD_JSON_TEMPLATE)

val methodsToImplement = OverrideImplementUtil.getMethodsToOverrideImplement(clazz, true)
val methods = OverrideImplementUtil.overrideOrImplementMethodCandidates(clazz, methodsToImplement, true)
for (method in methods) {
clazz.addMethod(method)
}
}
WriteAction.runAndWait<Throwable> {
val dir = VfsUtil.createDirectoryIfMissing(
LocalFileSystem.getInstance(),
"${assets.outputDirectory}/.gradle",
)
?: throw IllegalStateException("Unable to create .gradle directory")
val file = dir.findOrCreateChildData(this, MAGIC_DEFERRED_INIT_FILE)

generatedClasses += clazz
}
val authors = data.getUserData(AuthorsStep.KEY) ?: emptyList()
val website = data.getUserData(WebsiteStep.KEY)
val repo = data.getUserData(RepositoryStep.KEY)

for (clazz in generatedClasses) {
ReformatCodeProcessor(project, clazz.containingFile, null, false).run()
EditorHelper.openInEditor(clazz)
}
}
val packageName = "${buildSystemProps.groupId.toPackageName()}.${modId.toPackageName()}"
val mainClassName = "$packageName.${modName.toJavaClassName()}"
val clientClassName = "$packageName.client.${modName.toJavaClassName()}Client"

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()
}
}
val entrypoints = listOf(
"main,${EntryPoint.Type.CLASS.name},$mainClassName,${FabricConstants.MOD_INITIALIZER}",
"client,${EntryPoint.Type.CLASS.name},$clientClassName,${FabricConstants.CLIENT_MOD_INITIALIZER}",
)
val fileContents = """
${authors.joinToString(",")}
$website
$repo
${entrypoints.joinToString(";")}
""".trimIndent() // TODO: un-hardcode?

VfsUtil.saveText(file, fileContents)
}
latch.await()
}
}

Expand Down
5 changes: 1 addition & 4 deletions src/main/kotlin/platform/fabric/creator/ui-steps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import com.demonwav.mcdev.creator.step.NewProjectWizardChainStep.Companion.nextS
import com.demonwav.mcdev.creator.step.RepositoryStep
import com.demonwav.mcdev.creator.step.UseMixinsStep
import com.demonwav.mcdev.creator.step.VersionChainComboBox
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
Expand Down Expand Up @@ -80,10 +79,8 @@ class FabricPlatformStep(
.nextStep(::LicenseStep)
.nextStep(::FabricOptionalSettingsStep)
.nextStep(::FabricBuildSystemStep)
.nextStep(::FabricDumbModeFilesStep)
.nextStep(::FabricBaseFilesStep)
.nextStep(::FabricPostBuildSystemStep)
.nextStep(::WaitForSmartModeStep)
.nextStep(::FabricSmartModeFilesStep)
}

class Factory : ModPlatformStep.Factory {
Expand Down
Loading

0 comments on commit 9a0afac

Please sign in to comment.