Skip to content
33 changes: 24 additions & 9 deletions src/main/kotlin/insight/generation/MinecraftClassCreateAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import com.intellij.psi.PsiNameHelper
import com.intellij.psi.util.PsiTypesUtil
import com.intellij.psi.util.PsiUtil
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes
import com.intellij.openapi.diagnostic.Logger

class MinecraftClassCreateAction :
CreateTemplateInPackageAction<PsiClass>(
Expand All @@ -69,9 +70,13 @@ class MinecraftClassCreateAction :
val isForge = MinecraftFacet.getInstance(module, ForgeModuleType) != null
val isNeoForge = MinecraftFacet.getInstance(module, NeoForgeModuleType) != null
val isFabric = MinecraftFacet.getInstance(module, FabricModuleType) != null
val mcVersion = MinecraftFacet.getInstance(module, McpModuleType)?.getSettings()
?.minecraftVersion?.let(SemanticVersion::parse)

val mcVersion = MinecraftFacet.getInstance(module, NeoForgeModuleType)?.computeVersion()?:
MinecraftFacet.getInstance(module, McpModuleType)?.getSettings()
?.minecraftVersion?.let(SemanticVersion::parse) ?:
MinecraftFacet.getInstance(module, FabricModuleType)?.computeVersion()

// LOG.info("VERSIONI: $neomcVersion, $mcVersion, $fabricMcVersion")
if (isForge && mcVersion != null) {
val icon = PlatformAssets.FORGE_ICON

Expand All @@ -88,29 +93,39 @@ class MinecraftClassCreateAction :
builder.addKind("Packet", icon, MinecraftTemplates.FORGE_1_17_PACKET_TEMPLATE)
} else {
builder.addKind("Block", icon, MinecraftTemplates.FORGE_1_17_BLOCK_TEMPLATE)
builder.addKind("Enchantment", icon, MinecraftTemplates.FORGE_1_17_ENCHANTMENT_TEMPLATE)
builder.addKind("Item", icon, MinecraftTemplates.FORGE_1_17_ITEM_TEMPLATE)
builder.addKind("Mob effect", icon, MinecraftTemplates.FORGE_1_17_MOB_EFFECT_TEMPLATE)
builder.addKind("Packet", icon, MinecraftTemplates.FORGE_1_18_PACKET_TEMPLATE)
}
if (mcVersion < MinecraftVersions.MC1_21) {
builder.addKind("Enchantment", icon, MinecraftTemplates.FORGE_1_17_ENCHANTMENT_TEMPLATE)
}
}

if (isNeoForge) {
val icon = PlatformAssets.NEOFORGE_ICON
builder.addKind("Block", icon, MinecraftTemplates.NEOFORGE_BLOCK_TEMPLATE)
builder.addKind("Enchantment", icon, MinecraftTemplates.NEOFORGE_ENCHANTMENT_TEMPLATE)
builder.addKind("Item", icon, MinecraftTemplates.NEOFORGE_ITEM_TEMPLATE)
builder.addKind("Mob effect", icon, MinecraftTemplates.NEOFORGE_MOB_EFFECT_TEMPLATE)
builder.addKind("Packet", icon, MinecraftTemplates.NEOFORGE_PACKET_TEMPLATE)
if (mcVersion == null || mcVersion < MinecraftVersions.MC1_21)
builder.addKind("Enchantment", icon, MinecraftTemplates.NEOFORGE_ENCHANTMENT_TEMPLATE)
}

if (isFabric) {
val icon = PlatformAssets.FABRIC_ICON
if (mcVersion != null && mcVersion >= MinecraftVersions.MC26_1) {
builder.addKind("Block", icon, MinecraftTemplates.FABRIC_26_1_BLOCK_TEMPLATE)
builder.addKind("Item", icon, MinecraftTemplates.FABRIC_26_1_ITEM_TEMPLATE)
builder.addKind("Mob effect", icon, MinecraftTemplates.FABRIC_26_1_MOB_EFFECT_TEMPLATE)

builder.addKind("Block", icon, MinecraftTemplates.FABRIC_BLOCK_TEMPLATE)
builder.addKind("Enchantment", icon, MinecraftTemplates.FABRIC_ENCHANTMENT_TEMPLATE)
builder.addKind("Item", icon, MinecraftTemplates.FABRIC_ITEM_TEMPLATE)
builder.addKind("Status effect", icon, MinecraftTemplates.FABRIC_STATUS_EFFECT_TEMPLATE)
} else {
builder.addKind("Block", icon, MinecraftTemplates.FABRIC_1_21_11_BLOCK_TEMPLATE)
builder.addKind("Item", icon, MinecraftTemplates.FABRIC_1_21_11_ITEM_TEMPLATE)
builder.addKind("Status effect", icon, MinecraftTemplates.FABRIC_1_21_11_STATUS_EFFECT_TEMPLATE)
}
if (mcVersion != null && mcVersion < MinecraftVersions.MC1_21)
builder.addKind("Enchantment", icon, MinecraftTemplates.FABRIC_1_21_11_ENCHANTMENT_TEMPLATE)
}
}

Expand Down Expand Up @@ -140,7 +155,7 @@ class MinecraftClassCreateAction :
return JavaDirectoryService.getInstance().createClass(dir, className, templateName, false)
}

private class ClassInputValidator(
class ClassInputValidator(
private val project: Project,
private val directory: PsiDirectory,
) : InputValidatorEx {
Expand Down
108 changes: 108 additions & 0 deletions src/main/kotlin/insight/generation/MinecraftResourceCreateAction.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.demonwav.mcdev.insight.generation

import com.demonwav.mcdev.asset.GeneralAssets
import com.demonwav.mcdev.asset.MCDevBundle
import com.demonwav.mcdev.asset.PlatformAssets
import com.demonwav.mcdev.facet.MinecraftFacet
import com.demonwav.mcdev.insight.generation.MinecraftClassCreateAction.ClassInputValidator
import com.demonwav.mcdev.platform.fabric.FabricModuleType
import com.demonwav.mcdev.platform.forge.ForgeModuleType
import com.demonwav.mcdev.platform.mcp.McpModuleType
import com.demonwav.mcdev.platform.neoforge.NeoForgeModuleType
import com.demonwav.mcdev.util.MinecraftTemplates
import com.demonwav.mcdev.util.MinecraftVersions
import com.demonwav.mcdev.util.SemanticVersion
import com.demonwav.mcdev.util.findModule
import com.intellij.ide.actions.CreateFileFromTemplateAction
import com.intellij.ide.actions.CreateFileFromTemplateDialog
import com.intellij.ide.fileTemplates.FileTemplateManager
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.util.NlsContexts
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiFile
import java.util.*
import org.jetbrains.annotations.NonNls
import org.jetbrains.jps.model.java.JavaResourceRootType


class MinecraftResourceCreateAction : CreateFileFromTemplateAction(
Const.CAPTION,
MCDevBundle("generate.class.description"),
GeneralAssets.MC_TEMPLATE
) {
override fun isAvailable(context: DataContext): Boolean {
val psi = context.getData(CommonDataKeys.PSI_ELEMENT)
val module = psi?.findModule() ?: return false
val dir: PsiDirectory?
if (psi is PsiFile) {
dir = psi.containingDirectory
} else if(psi is PsiDirectory){
dir = psi
}else{
return false
}

val project = context.getData(CommonDataKeys.PROJECT) ?: return false
val underSourceRootOfType = ProjectRootManager.getInstance(project).fileIndex.isUnderSourceRootOfType(
dir.virtualFile,
setOf(JavaResourceRootType.RESOURCE)
)
val mcVersion = MinecraftFacet.getInstance(module, McpModuleType)?.getSettings()
?.minecraftVersion?.let(SemanticVersion::parse) ?: MinecraftFacet.getInstance(module, FabricModuleType)
?.computeVersion() ?: MinecraftFacet.getInstance(module, NeoForgeModuleType)?.computeVersion()

return underSourceRootOfType && findModid(dir, module) != null && mcVersion != null && mcVersion >= MinecraftVersions.MC1_21
}

private fun findModid(dir: PsiDirectory, module: Module): String? {
val modids = MinecraftFacet.getInstance(module, ForgeModuleType)?.modIds ?: MinecraftFacet.getInstance(
module,
FabricModuleType
)?.modIds ?: MinecraftFacet.getInstance(module, NeoForgeModuleType)?.modIds ?: return null

return modids.firstOrNull { dir.virtualFile.path.split("/").contains(it) }
}

override fun buildDialog(
project: Project,
directory: PsiDirectory,
builder: CreateFileFromTemplateDialog.Builder
) {
builder.setTitle(Const.CAPTION)
builder.setValidator(ClassInputValidator(project, directory))
val icon = PlatformAssets.MINECRAFT_ICON
builder.addKind("Enchantment", icon, MinecraftTemplates.JSON_ENCHANTMENT_TEMPLATE)
}

override fun getActionName(
directory: PsiDirectory?,
newName: @NonNls String,
templateName: @NonNls String?
): @NlsContexts.Command String = Const.CAPTION

override fun createFile(name: String?, templateName: String?, dir: PsiDirectory?): PsiFile? {
val module = dir?.findModule() ?: return null
val modid = findModid(dir, module) ?: return null

val template = FileTemplateManager.getInstance(dir.project)
.getInternalTemplate(templateName ?: return null)
return createFileFromTemplate(
name,
template,
dir,
defaultTemplateProperty,
true,
Collections.emptyMap(),
mapOf(Pair("MODID", modid))
)
}

private object Const {
val CAPTION
get() = MCDevBundle("generate.json.caption")
}
}
21 changes: 21 additions & 0 deletions src/main/kotlin/platform/AbstractModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import com.demonwav.mcdev.facet.MinecraftFacet
import com.demonwav.mcdev.insight.generation.EventListenerGenerationSupport
import com.demonwav.mcdev.inspection.IsCancelled
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiExpression
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiMethodCallExpression
import com.intellij.psi.PsiReferenceExpression
Expand All @@ -36,6 +38,8 @@ import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import javax.swing.Icon
import com.intellij.lang.properties.psi.PropertiesFile


abstract class AbstractModule(protected val facet: MinecraftFacet) {

Expand Down Expand Up @@ -107,4 +111,21 @@ abstract class AbstractModule(protected val facet: MinecraftFacet) {
open fun init() {}
open fun dispose() {}
open fun refresh() {}

fun detectMinecraftVersionInProps(keyname: String): String? {
val contentRoots = ModuleRootManager.getInstance(module).contentRoots
var dir = contentRoots.firstOrNull() ?: return null

val projectBase = project.basePath
while (true) {
val found = dir.findChild("gradle.properties")
if (found != null) {
val propsFile = PsiManager.getInstance(project).findFile(found) as? PropertiesFile ?: return null
return propsFile.findPropertyByKey(keyname)?.value
}
val parent = dir.parent ?: return null
if (dir.path == projectBase) return null
dir = parent
}
}
}
57 changes: 55 additions & 2 deletions src/main/kotlin/platform/fabric/FabricModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package com.demonwav.mcdev.platform.fabric

import com.demonwav.mcdev.asset.PlatformAssets
import com.demonwav.mcdev.facet.MinecraftFacet
import com.demonwav.mcdev.insight.generation.MinecraftClassCreateAction
import com.demonwav.mcdev.platform.AbstractModule
import com.demonwav.mcdev.platform.PlatformType
import com.demonwav.mcdev.platform.fabric.reference.EntryPointReference
Expand All @@ -30,11 +31,14 @@ import com.demonwav.mcdev.platform.mcp.fabricloom.FabricLoomData
import com.demonwav.mcdev.platform.mcp.mappings.HardcodedYarnToMojmap
import com.demonwav.mcdev.platform.mcp.mappings.HasCustomNamedMappings
import com.demonwav.mcdev.platform.mcp.mappings.MappingsManager
import com.demonwav.mcdev.util.SemanticVersion
import com.demonwav.mcdev.util.SourceType
import com.demonwav.mcdev.util.nullable
import com.demonwav.mcdev.util.runCatchingKtIdeaExceptions
import com.intellij.json.JsonUtil
import com.intellij.json.psi.JsonArray
import com.intellij.json.psi.JsonFile
import com.intellij.json.psi.JsonObject
import com.intellij.json.psi.JsonStringLiteral
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
Expand Down Expand Up @@ -67,6 +71,7 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
override val moduleType = FabricModuleType
override val type = PlatformType.FABRIC
override val icon = PlatformAssets.FABRIC_ICON
var fabricMinecraftVersion: SemanticVersion? = null;

override fun computeModIds(): List<String> {
val jsonFile = PsiManager.getInstance(project).findFile(fabricJson ?: return emptyList()) as? JsonFile
Expand All @@ -75,6 +80,51 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
return listOfNotNull((jsonObj.findProperty("id")?.value as? JsonStringLiteral)?.value)
}

fun computeVersion(): SemanticVersion? {
val jsonFile = PsiManager.getInstance(project).findFile(fabricJson ?: return null) as? JsonFile
?: return null
val jsonObj = JsonUtil.getTopLevelObject(jsonFile) ?: return null;
val depends = jsonObj.findProperty("depends")?.value as? JsonObject
val range = depends?.findProperty("minecraft")
var value = (range?.value as? JsonStringLiteral)?.value;
val arrayValue = (range?.value as? JsonArray)
if (value != null) {
if (value.contains("\${")) {
val varName = value.substring(value.indexOf("\${") + 2, value.lastIndexOf("}"))
value = value.replace("\${${varName}}", detectMinecraftVersionInProps(varName) ?: return null)
}
val end = value.trimStart { !it.isDigit() }
val parse = try {
SemanticVersion.parse(end)
} catch (_: NumberFormatException) {
null
}
fabricMinecraftVersion = parse
return parse
} else if (arrayValue != null) {
var majorVersion: SemanticVersion? = null;
for (child in arrayValue.valueList) {
var string = (child as? JsonStringLiteral)?.value.toString()
if (string.contains("\${")) {
val varName = string.substring(string.indexOf("\${") + 2, string.lastIndexOf("}"))
string = string.replace("\${${varName}}", detectMinecraftVersionInProps(varName) ?: return null)
}
val end = string.trimStart { !it.isDigit() }
val value = try {
SemanticVersion.parse(end)
} catch (_: NumberFormatException) {
null
}
if (value != null) {
if (majorVersion == null || value > majorVersion) majorVersion = value
};
}
fabricMinecraftVersion = majorVersion
return majorVersion
}
return null
}

override fun isEventClassValid(eventClass: PsiClass, method: PsiMethod?) = true

override fun writeErrorMessageForEventParameter(eventClass: PsiClass, method: PsiMethod) = ""
Expand Down Expand Up @@ -105,8 +155,10 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
mappingNamespacesField = mappingDetection.namespaces
}

private fun detectMappings(): MappingDetectionResult {
private fun
detectMappings(): MappingDetectionResult {
val gradleData = GradleUtil.findGradleModuleData(facet.module) ?: return MappingDetectionResult.DEFAULT

val loomData = gradleData.children.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData
?: return MappingDetectionResult.DEFAULT
val mappingsFile = loomData.tinyMappings ?: return MappingDetectionResult.DEFAULT
Expand Down Expand Up @@ -147,7 +199,8 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(

override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?) = false

override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, endOpIdx: Int, srcName: String?) = false
override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, endOpIdx: Int, srcName: String?) =
false

override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String) {
if (namespace == namedIndex && name == "net/minecraft/client/MinecraftClient") {
Expand Down
Loading
Loading