From ee4a80639426f208390a79fa82449ed6b1326eb9 Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 24 Sep 2023 17:11:25 +0100 Subject: [PATCH] Placeholder mappings API --- src/main/kotlin/facet/MinecraftFacet.kt | 1 + src/main/kotlin/platform/AbstractModule.kt | 1 + .../kotlin/platform/fabric/FabricModule.kt | 68 ++++++++- .../reference/ReflectedFieldReference.kt | 6 +- .../ReflectedMemberReferenceBasePoly.kt | 6 +- .../reference/ReflectedMethodReference.kt | 6 +- src/main/kotlin/platform/mcp/McpModule.kt | 14 +- .../platform/mcp/actions/CopyAtAction.kt | 14 +- .../mcp/actions/CopyCoremodTargetAction.kt | 14 +- .../mcp/actions/FindSrgMappingAction.kt | 10 +- .../platform/mcp/actions/GotoAtEntryAction.kt | 12 +- .../platform/mcp/actions/SrgActionBase.kt | 6 +- .../kotlin/platform/mcp/at/AtAnnotator.kt | 6 +- .../mcp/at/AtGotoDeclarationHandler.kt | 10 +- .../platform/mcp/at/AtUsageInspection.kt | 6 +- .../at/completion/AtCompletionContributor.kt | 6 +- .../mcp/inspections/StackEmptyInspection.kt | 44 +++--- .../mcp/mappings/HardcodedYarnToMojmap.kt | 40 ++++++ .../mcp/mappings/HasCustomNamedMappings.kt | 25 ++++ .../kotlin/platform/mcp/mappings/Mappings.kt | 134 ++++++++++++++++++ .../MappingsManager.kt} | 77 ++++++---- .../SrgMemberChooseByNameContributor.kt | 6 +- src/main/kotlin/platform/mcp/srg/McpSrgMap.kt | 61 -------- .../kotlin/platform/mcp/srg/McpUnscrambler.kt | 5 +- src/main/kotlin/platform/mcp/srg/SrgParser.kt | 3 +- .../platform/mcp/srg/StandardSrgParser.kt | 5 +- .../kotlin/platform/mcp/srg/TinySrgParser.kt | 6 +- src/main/kotlin/util/MemberReference.kt | 9 +- 28 files changed, 411 insertions(+), 190 deletions(-) create mode 100644 src/main/kotlin/platform/mcp/mappings/HardcodedYarnToMojmap.kt create mode 100644 src/main/kotlin/platform/mcp/mappings/HasCustomNamedMappings.kt create mode 100644 src/main/kotlin/platform/mcp/mappings/Mappings.kt rename src/main/kotlin/platform/mcp/{srg/SrgManager.kt => mappings/MappingsManager.kt} (52%) delete mode 100644 src/main/kotlin/platform/mcp/srg/McpSrgMap.kt diff --git a/src/main/kotlin/facet/MinecraftFacet.kt b/src/main/kotlin/facet/MinecraftFacet.kt index 6c38fd206..5be0acd96 100644 --- a/src/main/kotlin/facet/MinecraftFacet.kt +++ b/src/main/kotlin/facet/MinecraftFacet.kt @@ -114,6 +114,7 @@ class MinecraftFacet( } newlyEnabled.forEach(AbstractModule::init) + modules.forEach(AbstractModule::refresh) ProjectView.getInstance(module.project).refresh() } diff --git a/src/main/kotlin/platform/AbstractModule.kt b/src/main/kotlin/platform/AbstractModule.kt index f4ffe5eec..fdc77c22f 100644 --- a/src/main/kotlin/platform/AbstractModule.kt +++ b/src/main/kotlin/platform/AbstractModule.kt @@ -93,4 +93,5 @@ abstract class AbstractModule(protected val facet: MinecraftFacet) { open fun init() {} open fun dispose() {} + open fun refresh() {} } diff --git a/src/main/kotlin/platform/fabric/FabricModule.kt b/src/main/kotlin/platform/fabric/FabricModule.kt index 6d02073a8..8ec555e48 100644 --- a/src/main/kotlin/platform/fabric/FabricModule.kt +++ b/src/main/kotlin/platform/fabric/FabricModule.kt @@ -26,6 +26,10 @@ import com.demonwav.mcdev.platform.AbstractModule import com.demonwav.mcdev.platform.PlatformType import com.demonwav.mcdev.platform.fabric.reference.EntryPointReference import com.demonwav.mcdev.platform.fabric.util.FabricConstants +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.SourceType import com.demonwav.mcdev.util.nullable import com.demonwav.mcdev.util.runCatchingKtIdeaExceptions @@ -33,16 +37,25 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.search.searches.ReferencesSearch +import java.io.IOException +import net.fabricmc.mappingio.MappedElementKind +import net.fabricmc.mappingio.MappingReader +import net.fabricmc.mappingio.MappingVisitor +import org.jetbrains.plugins.gradle.util.GradleUtil import org.jetbrains.uast.UClass import org.jetbrains.uast.UIdentifier import org.jetbrains.uast.UMethod import org.jetbrains.uast.toUElementOfType -class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet) { +class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(facet), HasCustomNamedMappings { var fabricJson by nullable { facet.findFile(FabricConstants.FABRIC_MOD_JSON, SourceType.RESOURCE) } private set + private var namedToMojangManagerField: MappingsManager? = null + override val namedToMojangManager: MappingsManager? + get() = namedToMojangManagerField + override val moduleType = FabricModuleType override val type = PlatformType.FABRIC override val icon = PlatformAssets.FABRIC_ICON @@ -65,6 +78,59 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule( return ReferencesSearch.search(psiParent).anyMatch { EntryPointReference.isEntryPointReference(it) } } + override fun refresh() { + namedToMojangManagerField = if (detectYarn()) { + MappingsManager.Immediate(HardcodedYarnToMojmap.createMappings()) + } else { + null + } + } + + private fun detectYarn(): Boolean { + val gradleData = GradleUtil.findGradleModuleData(facet.module) ?: return false + val loomData = + gradleData.children.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData ?: return false + val mappingsFile = loomData.tinyMappings ?: return false + + var yarnDetected = false + val visitor = object : MappingVisitor { + private var namedIndex = -1 + + override fun visitNamespaces(srcNamespace: String?, dstNamespaces: List) { + namedIndex = dstNamespaces.indexOf("named") + } + + override fun visitContent() = namedIndex >= 0 + + override fun visitClass(srcName: String) = true + + override fun visitField(srcName: String?, srcDesc: String?) = false + + override fun visitMethod(srcName: String?, srcDesc: String?) = false + + override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?) = false + + override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String?) = false + + override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String) { + if (namespace == namedIndex && name == "net/minecraft/client/MinecraftClient") { + yarnDetected = true + } + } + + override fun visitComment(targetKind: MappedElementKind?, comment: String?) { + } + } + + try { + MappingReader.read(mappingsFile.toPath(), visitor) + } catch (e: IOException) { + return false + } + + return yarnDetected + } + override fun dispose() { super.dispose() fabricJson = null diff --git a/src/main/kotlin/platform/forge/reflection/reference/ReflectedFieldReference.kt b/src/main/kotlin/platform/forge/reflection/reference/ReflectedFieldReference.kt index 90eb2f117..ffce39644 100644 --- a/src/main/kotlin/platform/forge/reflection/reference/ReflectedFieldReference.kt +++ b/src/main/kotlin/platform/forge/reflection/reference/ReflectedFieldReference.kt @@ -67,9 +67,9 @@ object ReflectedFieldReference : PsiReferenceProvider() { ?: return@withInsertHandler val srgManager = literal.findModule()?.let { MinecraftFacet.getInstance(it) } - ?.getModuleOfType(McpModuleType)?.srgManager - val srgMap = srgManager?.srgMapNow - val srgField = srgMap?.getSrgField(field.simpleQualifiedMemberReference) + ?.getModuleOfType(McpModuleType)?.mappingsManager + val srgMap = srgManager?.mappingsNow + val srgField = srgMap?.getIntermediaryField(field.simpleQualifiedMemberReference) ?: return@withInsertHandler context.setLaterRunnable { diff --git a/src/main/kotlin/platform/forge/reflection/reference/ReflectedMemberReferenceBasePoly.kt b/src/main/kotlin/platform/forge/reflection/reference/ReflectedMemberReferenceBasePoly.kt index e5709deca..84e57bf06 100644 --- a/src/main/kotlin/platform/forge/reflection/reference/ReflectedMemberReferenceBasePoly.kt +++ b/src/main/kotlin/platform/forge/reflection/reference/ReflectedMemberReferenceBasePoly.kt @@ -49,9 +49,9 @@ abstract class ReflectedMemberReferenceBasePoly(element: PsiLiteral) : PsiRefere val name = memberName val srgManager = element.findModule()?.let { MinecraftFacet.getInstance(it) } - ?.getModuleOfType(McpModuleType)?.srgManager - val srgMap = srgManager?.srgMapNow - val mcpName = srgMap?.mapMcpToSrgName(name) ?: name + ?.getModuleOfType(McpModuleType)?.mappingsManager + val srgMap = srgManager?.mappingsNow + val mcpName = srgMap?.mapIntermediaryToMapped(name) ?: name return typeClass.allFields.asSequence() .filter { it.name == mcpName } diff --git a/src/main/kotlin/platform/forge/reflection/reference/ReflectedMethodReference.kt b/src/main/kotlin/platform/forge/reflection/reference/ReflectedMethodReference.kt index e4e4a2ce9..cad7c8f94 100644 --- a/src/main/kotlin/platform/forge/reflection/reference/ReflectedMethodReference.kt +++ b/src/main/kotlin/platform/forge/reflection/reference/ReflectedMethodReference.kt @@ -74,8 +74,8 @@ object ReflectedMethodReference : PsiReferenceProvider() { ?: return@withInsertHandler val params = literal.parent as? PsiExpressionList ?: return@withInsertHandler val srgManager = literal.findModule()?.let { MinecraftFacet.getInstance(it) } - ?.getModuleOfType(McpModuleType)?.srgManager - val srgMap = srgManager?.srgMapNow + ?.getModuleOfType(McpModuleType)?.mappingsManager + val srgMap = srgManager?.mappingsNow val signature = method.getSignature(PsiSubstitutor.EMPTY) val returnType = method.returnType?.let { TypeConversionUtil.erasure(it).canonicalText } @@ -84,7 +84,7 @@ object ReflectedMethodReference : PsiReferenceProvider() { .map { it.canonicalText } val memberRef = method.qualifiedMemberReference - val srgMethod = srgMap?.getSrgMethod(memberRef) ?: memberRef + val srgMethod = srgMap?.getIntermediaryMethod(memberRef) ?: memberRef context.setLaterRunnable { // Commit changes made by code completion diff --git a/src/main/kotlin/platform/mcp/McpModule.kt b/src/main/kotlin/platform/mcp/McpModule.kt index e0816ff44..dcb1a7845 100644 --- a/src/main/kotlin/platform/mcp/McpModule.kt +++ b/src/main/kotlin/platform/mcp/McpModule.kt @@ -23,7 +23,7 @@ package com.demonwav.mcdev.platform.mcp import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.AbstractModule import com.demonwav.mcdev.platform.PlatformType -import com.demonwav.mcdev.platform.mcp.srg.SrgManager +import com.demonwav.mcdev.platform.mcp.mappings.MappingsManager import com.demonwav.mcdev.platform.mcp.util.McpConstants import com.demonwav.mcdev.translations.TranslationFileListener import com.demonwav.mcdev.util.runWriteTaskLater @@ -43,7 +43,7 @@ class McpModule(facet: MinecraftFacet) : AbstractModule(facet) { private val settings: McpModuleSettings = McpModuleSettings.getInstance(module) val accessTransformers = mutableSetOf() - var srgManager: SrgManager? = null + var mappingsManager: MappingsManager? = null private set override fun init() { @@ -61,8 +61,8 @@ class McpModule(facet: MinecraftFacet) : AbstractModule(facet) { val file = settings.mappingFile ?: return val srgType = settings.srgType ?: return - srgManager = SrgManager.getInstance(file, srgType) - srgManager?.parse() + mappingsManager = MappingsManager.getInstance(file, srgType) + mappingsManager?.parse() } override val moduleType = McpModuleType @@ -78,8 +78,8 @@ class McpModule(facet: MinecraftFacet) : AbstractModule(facet) { val mappingFile = data.mappingFile ?: return val srgType = data.srgType ?: return - srgManager = SrgManager.getInstance(mappingFile, srgType) - srgManager?.parse() + mappingsManager = MappingsManager.getInstance(mappingFile, srgType) + mappingsManager?.parse() } fun addAccessTransformerFile(file: VirtualFile) { @@ -91,6 +91,6 @@ class McpModule(facet: MinecraftFacet) : AbstractModule(facet) { connection.disconnect() accessTransformers.clear() - srgManager = null + mappingsManager = null } } diff --git a/src/main/kotlin/platform/mcp/actions/CopyAtAction.kt b/src/main/kotlin/platform/mcp/actions/CopyAtAction.kt index aa8bb7f9e..219ddbe02 100644 --- a/src/main/kotlin/platform/mcp/actions/CopyAtAction.kt +++ b/src/main/kotlin/platform/mcp/actions/CopyAtAction.kt @@ -20,7 +20,7 @@ package com.demonwav.mcdev.platform.mcp.actions -import com.demonwav.mcdev.platform.mcp.srg.McpSrgMap +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.ActionData import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.editor.Editor @@ -32,12 +32,12 @@ import java.awt.Toolkit import java.awt.datatransfer.StringSelection class CopyAtAction : SrgActionBase() { - override fun withSrgTarget(parent: PsiElement, srgMap: McpSrgMap, e: AnActionEvent, data: ActionData) { + override fun withSrgTarget(parent: PsiElement, srgMap: Mappings, e: AnActionEvent, data: ActionData) { when (parent) { is PsiField -> { val containing = parent.containingClass ?: return showBalloon("No SRG name found", e) - val classSrg = srgMap.getSrgClass(containing) ?: return showBalloon("No SRG name found", e) - val srg = srgMap.getSrgField(parent) ?: return showBalloon("No SRG name found", e) + val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryField(parent) ?: return showBalloon("No SRG name found", e) copyToClipboard( data.editor, data.element, @@ -46,8 +46,8 @@ class CopyAtAction : SrgActionBase() { } is PsiMethod -> { val containing = parent.containingClass ?: return showBalloon("No SRG name found", e) - val classSrg = srgMap.getSrgClass(containing) ?: return showBalloon("No SRG name found", e) - val srg = srgMap.getSrgMethod(parent) ?: return showBalloon("No SRG name found", e) + val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryMethod(parent) ?: return showBalloon("No SRG name found", e) copyToClipboard( data.editor, data.element, @@ -55,7 +55,7 @@ class CopyAtAction : SrgActionBase() { ) } is PsiClass -> { - val classMcpToSrg = srgMap.getSrgClass(parent) ?: return showBalloon("No SRG name found", e) + val classMcpToSrg = srgMap.getIntermediaryClass(parent) ?: return showBalloon("No SRG name found", e) copyToClipboard(data.editor, data.element, classMcpToSrg) } else -> showBalloon("Not a valid element", e) diff --git a/src/main/kotlin/platform/mcp/actions/CopyCoremodTargetAction.kt b/src/main/kotlin/platform/mcp/actions/CopyCoremodTargetAction.kt index 3c398cb4e..c51bf138f 100644 --- a/src/main/kotlin/platform/mcp/actions/CopyCoremodTargetAction.kt +++ b/src/main/kotlin/platform/mcp/actions/CopyCoremodTargetAction.kt @@ -20,7 +20,7 @@ package com.demonwav.mcdev.platform.mcp.actions -import com.demonwav.mcdev.platform.mcp.srg.McpSrgMap +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.ActionData import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.editor.Editor @@ -34,12 +34,12 @@ import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive class CopyCoremodTargetAction : SrgActionBase() { - override fun withSrgTarget(parent: PsiElement, srgMap: McpSrgMap, e: AnActionEvent, data: ActionData) { + override fun withSrgTarget(parent: PsiElement, srgMap: Mappings, e: AnActionEvent, data: ActionData) { when (parent) { is PsiField -> { val containing = parent.containingClass ?: return showBalloon("No SRG name found", e) - val classSrg = srgMap.getSrgClass(containing) ?: return showBalloon("No SRG name found", e) - val srg = srgMap.getSrgField(parent) ?: return showBalloon("No SRG name found", e) + val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryField(parent) ?: return showBalloon("No SRG name found", e) copyToClipboard( data.editor, data.element, @@ -50,8 +50,8 @@ class CopyCoremodTargetAction : SrgActionBase() { } is PsiMethod -> { val containing = parent.containingClass ?: return showBalloon("No SRG name found", e) - val classSrg = srgMap.getSrgClass(containing) ?: return showBalloon("No SRG name found", e) - val srg = srgMap.getSrgMethod(parent) ?: return showBalloon("No SRG name found", e) + val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryMethod(parent) ?: return showBalloon("No SRG name found", e) val srgDescriptor = srg.descriptor ?: return showBalloon("No SRG name found", e) copyToClipboard( data.editor, @@ -63,7 +63,7 @@ class CopyCoremodTargetAction : SrgActionBase() { ) } is PsiClass -> { - val classSrg = srgMap.getSrgClass(parent) ?: return showBalloon("No SRG name found", e) + val classSrg = srgMap.getIntermediaryClass(parent) ?: return showBalloon("No SRG name found", e) copyToClipboard( data.editor, data.element, diff --git a/src/main/kotlin/platform/mcp/actions/FindSrgMappingAction.kt b/src/main/kotlin/platform/mcp/actions/FindSrgMappingAction.kt index b0b17f42b..e9ad627e8 100644 --- a/src/main/kotlin/platform/mcp/actions/FindSrgMappingAction.kt +++ b/src/main/kotlin/platform/mcp/actions/FindSrgMappingAction.kt @@ -20,7 +20,7 @@ package com.demonwav.mcdev.platform.mcp.actions -import com.demonwav.mcdev.platform.mcp.srg.McpSrgMap +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.ActionData import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.psi.PsiClass @@ -30,18 +30,18 @@ import com.intellij.psi.PsiMethod class FindSrgMappingAction : SrgActionBase() { - override fun withSrgTarget(parent: PsiElement, srgMap: McpSrgMap, e: AnActionEvent, data: ActionData) { + override fun withSrgTarget(parent: PsiElement, srgMap: Mappings, e: AnActionEvent, data: ActionData) { when (parent) { is PsiField -> { - val srg = srgMap.getSrgField(parent) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryField(parent) ?: return showBalloon("No SRG name found", e) showSuccessBalloon(data.editor, data.element, "SRG name: " + srg.name) } is PsiMethod -> { - val srg = srgMap.getSrgMethod(parent) ?: return showBalloon("No SRG name found", e) + val srg = srgMap.getIntermediaryMethod(parent) ?: return showBalloon("No SRG name found", e) showSuccessBalloon(data.editor, data.element, "SRG name: " + srg.name + srg.descriptor) } is PsiClass -> { - val classMcpToSrg = srgMap.getSrgClass(parent) ?: return showBalloon("No SRG name found", e) + val classMcpToSrg = srgMap.getIntermediaryClass(parent) ?: return showBalloon("No SRG name found", e) showSuccessBalloon(data.editor, data.element, "SRG name: $classMcpToSrg") } else -> showBalloon("Not a valid element", e) diff --git a/src/main/kotlin/platform/mcp/actions/GotoAtEntryAction.kt b/src/main/kotlin/platform/mcp/actions/GotoAtEntryAction.kt index cd7193613..967617fd9 100644 --- a/src/main/kotlin/platform/mcp/actions/GotoAtEntryAction.kt +++ b/src/main/kotlin/platform/mcp/actions/GotoAtEntryAction.kt @@ -22,7 +22,7 @@ package com.demonwav.mcdev.platform.mcp.actions import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.mcp.McpModuleType -import com.demonwav.mcdev.platform.mcp.srg.SrgManager +import com.demonwav.mcdev.platform.mcp.mappings.MappingsManager import com.demonwav.mcdev.platform.mixin.handlers.ShadowHandler import com.demonwav.mcdev.util.ActionData import com.demonwav.mcdev.util.getDataFromActionEvent @@ -56,12 +56,12 @@ class GotoAtEntryAction : AnAction() { return } - val srgManager = data.instance.getModuleOfType(McpModuleType)?.srgManager + val mappingsManager = data.instance.getModuleOfType(McpModuleType)?.mappingsManager // Not all ATs are in MCP modules, fallback to this if possible // TODO try to find SRG references for all modules if current module isn't found? - ?: SrgManager.findAnyInstance(data.project) ?: return showBalloon(e) + ?: MappingsManager.findAnyInstance(data.project) ?: return showBalloon(e) - srgManager.srgMap.onSuccess { srgMap -> + mappingsManager.mappings.onSuccess { srgMap -> var parent = data.element.parent if (parent is PsiMember) { @@ -73,11 +73,11 @@ class GotoAtEntryAction : AnAction() { when (parent) { is PsiField -> { - val reference = srgMap.getSrgField(parent) ?: parent.simpleQualifiedMemberReference + val reference = srgMap.getIntermediaryField(parent) ?: parent.simpleQualifiedMemberReference searchForText(e, data, reference.name) } is PsiMethod -> { - val reference = srgMap.getSrgMethod(parent) ?: parent.qualifiedMemberReference + val reference = srgMap.getIntermediaryMethod(parent) ?: parent.qualifiedMemberReference searchForText(e, data, reference.name + reference.descriptor) } else -> diff --git a/src/main/kotlin/platform/mcp/actions/SrgActionBase.kt b/src/main/kotlin/platform/mcp/actions/SrgActionBase.kt index 3e6de0f41..8b94807c8 100644 --- a/src/main/kotlin/platform/mcp/actions/SrgActionBase.kt +++ b/src/main/kotlin/platform/mcp/actions/SrgActionBase.kt @@ -21,7 +21,7 @@ package com.demonwav.mcdev.platform.mcp.actions import com.demonwav.mcdev.platform.mcp.McpModuleType -import com.demonwav.mcdev.platform.mcp.srg.McpSrgMap +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.platform.mixin.handlers.ShadowHandler import com.demonwav.mcdev.util.ActionData import com.demonwav.mcdev.util.getDataFromActionEvent @@ -53,7 +53,7 @@ abstract class SrgActionBase : AnAction() { val mcpModule = data.instance.getModuleOfType(McpModuleType) ?: return showBalloon("No mappings found", e) - mcpModule.srgManager?.srgMap?.onSuccess { srgMap -> + mcpModule.mappingsManager?.mappings?.onSuccess { srgMap -> var parent = data.element.parent ?: return@onSuccess showBalloon("Not a valid element", e) if (parent is PsiMember) { @@ -73,7 +73,7 @@ abstract class SrgActionBase : AnAction() { } ?: showBalloon("No mappings found", e) } - abstract fun withSrgTarget(parent: PsiElement, srgMap: McpSrgMap, e: AnActionEvent, data: ActionData) + abstract fun withSrgTarget(parent: PsiElement, srgMap: Mappings, e: AnActionEvent, data: ActionData) companion object { fun showBalloon(message: String, e: AnActionEvent) { diff --git a/src/main/kotlin/platform/mcp/at/AtAnnotator.kt b/src/main/kotlin/platform/mcp/at/AtAnnotator.kt index f303f7363..300380d69 100644 --- a/src/main/kotlin/platform/mcp/at/AtAnnotator.kt +++ b/src/main/kotlin/platform/mcp/at/AtAnnotator.kt @@ -47,7 +47,7 @@ class AtAnnotator : Annotator { val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return val facet = MinecraftFacet.getInstance(module) ?: return val mcpModule = facet.getModuleOfType(McpModuleType) ?: return - val srgMap = mcpModule.srgManager?.srgMapNow ?: return + val srgMap = mcpModule.mappingsManager?.mappingsNow ?: return val reference = AtMemberReference.get(element, member) ?: return @@ -64,11 +64,11 @@ class AtAnnotator : Annotator { // We need to check the srg map, or it can't be resolved (and no underline) when (member) { is AtFieldName -> { - srgMap.getMcpField(reference)?.resolveMember(element.project) ?: return + srgMap.tryGetMappedField(reference)?.resolveMember(element.project) ?: return underline(member, holder) } is AtFunction -> { - srgMap.getMcpMethod(reference)?.resolveMember(element.project) ?: return + srgMap.tryGetMappedMethod(reference)?.resolveMember(element.project) ?: return underline(member.funcName, holder) } } diff --git a/src/main/kotlin/platform/mcp/at/AtGotoDeclarationHandler.kt b/src/main/kotlin/platform/mcp/at/AtGotoDeclarationHandler.kt index 32255457d..f53729b5b 100644 --- a/src/main/kotlin/platform/mcp/at/AtGotoDeclarationHandler.kt +++ b/src/main/kotlin/platform/mcp/at/AtGotoDeclarationHandler.kt @@ -55,12 +55,12 @@ class AtGotoDeclarationHandler : GotoDeclarationHandler { val mcpModule = instance.getModuleOfType(McpModuleType) ?: return null - val srgMap = mcpModule.srgManager?.srgMapNow ?: return null + val srgMap = mcpModule.mappingsManager?.mappingsNow ?: return null return when { sourceElement.node.treeParent.elementType === AtTypes.CLASS_NAME -> { val className = sourceElement.parent as AtClassName - val classSrgToMcp = srgMap.mapToMcpClass(className.classNameText) + val classSrgToMcp = srgMap.getMappedClass(className.classNameText) val psiClass = findQualifiedClass(sourceElement.project, classSrgToMcp) ?: return null arrayOf(psiClass) } @@ -69,7 +69,7 @@ class AtGotoDeclarationHandler : GotoDeclarationHandler { val function = funcName.parent as AtFunction val entry = function.parent as AtEntry - val reference = srgMap.mapToMcpMethod(AtMemberReference.get(entry, function) ?: return null) + val reference = srgMap.getMappedMethod(AtMemberReference.get(entry, function) ?: return null) val member = reference.resolveMember(sourceElement.project) ?: return null arrayOf(member) } @@ -77,12 +77,12 @@ class AtGotoDeclarationHandler : GotoDeclarationHandler { val fieldName = sourceElement.parent as AtFieldName val entry = fieldName.parent as AtEntry - val reference = srgMap.mapToMcpField(AtMemberReference.get(entry, fieldName) ?: return null) + val reference = srgMap.getMappedField(AtMemberReference.get(entry, fieldName) ?: return null) val member = reference.resolveMember(sourceElement.project) ?: return null arrayOf(member) } sourceElement.node.elementType === AtTypes.CLASS_VALUE -> { - val className = srgMap.mapToMcpClass(parseClassDescriptor(sourceElement.text)) + val className = srgMap.getMappedClass(parseClassDescriptor(sourceElement.text)) val psiClass = findQualifiedClass(sourceElement.project, className) ?: return null arrayOf(psiClass) } diff --git a/src/main/kotlin/platform/mcp/at/AtUsageInspection.kt b/src/main/kotlin/platform/mcp/at/AtUsageInspection.kt index 6a25c54bb..cdef1bffe 100644 --- a/src/main/kotlin/platform/mcp/at/AtUsageInspection.kt +++ b/src/main/kotlin/platform/mcp/at/AtUsageInspection.kt @@ -50,19 +50,19 @@ class AtUsageInspection : LocalInspectionTool() { val module = ModuleUtilCore.findModuleForPsiElement(element) ?: return val instance = MinecraftFacet.getInstance(module) ?: return val mcpModule = instance.getModuleOfType(McpModuleType) ?: return - val srgMap = mcpModule.srgManager?.srgMapNow ?: return + val srgMap = mcpModule.mappingsManager?.mappingsNow ?: return val member = element.function ?: element.fieldName ?: return val reference = AtMemberReference.get(element, member) ?: return val psi = when (member) { is AtFunction -> - reference.resolveMember(element.project) ?: srgMap.getMcpMethod(reference)?.resolveMember( + reference.resolveMember(element.project) ?: srgMap.tryGetMappedMethod(reference)?.resolveMember( element.project, ) ?: return is AtFieldName -> reference.resolveMember(element.project) - ?: srgMap.getMcpField(reference)?.resolveMember(element.project) ?: return + ?: srgMap.tryGetMappedField(reference)?.resolveMember(element.project) ?: return else -> return } diff --git a/src/main/kotlin/platform/mcp/at/completion/AtCompletionContributor.kt b/src/main/kotlin/platform/mcp/at/completion/AtCompletionContributor.kt index d3d1b0605..ff323285b 100644 --- a/src/main/kotlin/platform/mcp/at/completion/AtCompletionContributor.kt +++ b/src/main/kotlin/platform/mcp/at/completion/AtCompletionContributor.kt @@ -221,7 +221,7 @@ class AtCompletionContributor : CompletionContributor() { val mcpModule = MinecraftFacet.getInstance(module)?.getModuleOfType(McpModuleType) ?: return - val srgMap = mcpModule.srgManager?.srgMapNow ?: return + val srgMap = mcpModule.mappingsManager?.mappingsNow ?: return val srgResult = result.withPrefixMatcher(SrgPrefixMatcher(text)) @@ -230,7 +230,7 @@ class AtCompletionContributor : CompletionContributor() { continue } - val memberReference = srgMap.getSrgField(field) ?: field.simpleQualifiedMemberReference + val memberReference = srgMap.getIntermediaryField(field) ?: field.simpleQualifiedMemberReference srgResult.addElement( PrioritizedLookupElement.withPriority( LookupElementBuilder @@ -263,7 +263,7 @@ class AtCompletionContributor : CompletionContributor() { continue } - val memberReference = srgMap.getSrgMethod(method) ?: method.qualifiedMemberReference + val memberReference = srgMap.getIntermediaryMethod(method) ?: method.qualifiedMemberReference srgResult.addElement( PrioritizedLookupElement.withPriority( LookupElementBuilder.create(method.nameAndParameterTypes) diff --git a/src/main/kotlin/platform/mcp/inspections/StackEmptyInspection.kt b/src/main/kotlin/platform/mcp/inspections/StackEmptyInspection.kt index 22693193d..0ed73a5fa 100644 --- a/src/main/kotlin/platform/mcp/inspections/StackEmptyInspection.kt +++ b/src/main/kotlin/platform/mcp/inspections/StackEmptyInspection.kt @@ -20,10 +20,9 @@ package com.demonwav.mcdev.platform.mcp.inspections -import com.demonwav.mcdev.facet.MinecraftFacet -import com.demonwav.mcdev.platform.mcp.McpModuleType -import com.demonwav.mcdev.platform.mcp.srg.SrgMemberReference -import com.demonwav.mcdev.util.MemberReference +import com.demonwav.mcdev.platform.mcp.mappings.getMappedClass +import com.demonwav.mcdev.platform.mcp.mappings.getMappedField +import com.demonwav.mcdev.platform.mcp.mappings.getMappedMethod import com.demonwav.mcdev.util.findModule import com.demonwav.mcdev.util.fullQualifiedName import com.intellij.codeInspection.ProblemDescriptor @@ -35,18 +34,15 @@ import com.intellij.psi.PsiBinaryExpression import com.intellij.psi.PsiExpression import com.intellij.psi.PsiField import com.intellij.psi.PsiReferenceExpression +import com.intellij.psi.util.createSmartPointer import com.siyeh.ig.BaseInspection import com.siyeh.ig.BaseInspectionVisitor import com.siyeh.ig.InspectionGadgetsFix import org.jetbrains.annotations.Nls -import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer class StackEmptyInspection : BaseInspection() { companion object { - const val STACK_FQ_NAME = "net.minecraft.item.ItemStack" - val STACK_JVM_NAME = STACK_FQ_NAME.replace('.', '/') - val EMPTY_SRG = SrgMemberReference.parse("$STACK_JVM_NAME/field_190927_a") - val IS_EMPTY_SRG = SrgMemberReference.parse("$STACK_JVM_NAME/func_190926_b") + const val STACK_FQ_NAME = "net.minecraft.world.item.ItemStack" } @Nls @@ -74,7 +70,7 @@ class StackEmptyInspection : BaseInspection() { val compareExpression = compareExpressionPointer.element ?: return val binaryExpression = binaryExpressionPointer.element ?: return - val mappedIsEmpty = compareExpression.findModule()?.getMappedMethod(IS_EMPTY_SRG)?.name ?: "isEmpty" + val mappedIsEmpty = compareExpression.findModule()?.getMappedMethod(STACK_FQ_NAME, "isEmpty", "()Z") var expressionText = "${compareExpression.text}.$mappedIsEmpty()" @@ -100,9 +96,10 @@ class StackEmptyInspection : BaseInspection() { val rightExpression = expression.rOperand // Check if both operands evaluate to an ItemStack - if (isExpressionStack(leftExpression) && isExpressionStack(rightExpression)) { - val leftEmpty = isExpressionEmptyConstant(leftExpression) - val rightEmpty = isExpressionEmptyConstant(rightExpression) + val module = expression.findModule() ?: return + if (isExpressionStack(module, leftExpression) && isExpressionStack(module, rightExpression)) { + val leftEmpty = isExpressionEmptyConstant(module, leftExpression) + val rightEmpty = isExpressionEmptyConstant(module, rightExpression) // Check that only one of the references are ItemStack.EMPTY if (leftEmpty xor rightEmpty) { @@ -116,26 +113,17 @@ class StackEmptyInspection : BaseInspection() { } } - private fun isExpressionStack(expression: PsiExpression?): Boolean { - return expression?.type?.equalsToText(STACK_FQ_NAME) == true + private fun isExpressionStack(module: Module, expression: PsiExpression?): Boolean { + return expression?.type?.equalsToText(module.getMappedClass(STACK_FQ_NAME)) == true } - private fun isExpressionEmptyConstant(expression: PsiExpression?): Boolean { + private fun isExpressionEmptyConstant(module: Module, expression: PsiExpression?): Boolean { val reference = expression as? PsiReferenceExpression ?: return false val field = reference.resolve() as? PsiField ?: return false - val mappedEmpty = field.findModule()?.getMappedField(EMPTY_SRG)?.name ?: "EMPTY" - return field.name == mappedEmpty && field.containingClass?.fullQualifiedName == STACK_FQ_NAME + val mappedEmpty = module.getMappedField(STACK_FQ_NAME, "EMPTY") + return field.name == mappedEmpty && + field.containingClass?.fullQualifiedName == module.getMappedClass(STACK_FQ_NAME) } } } - - private fun Module.getMappedMethod(reference: MemberReference): MemberReference? { - val srgManager = MinecraftFacet.getInstance(this, McpModuleType)?.srgManager - return srgManager?.srgMapNow?.mapToMcpMethod(reference) - } - - private fun Module.getMappedField(reference: MemberReference): MemberReference? { - val srgManager = MinecraftFacet.getInstance(this, McpModuleType)?.srgManager - return srgManager?.srgMapNow?.mapToMcpField(reference) - } } diff --git a/src/main/kotlin/platform/mcp/mappings/HardcodedYarnToMojmap.kt b/src/main/kotlin/platform/mcp/mappings/HardcodedYarnToMojmap.kt new file mode 100644 index 000000000..4e17692d7 --- /dev/null +++ b/src/main/kotlin/platform/mcp/mappings/HardcodedYarnToMojmap.kt @@ -0,0 +1,40 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2023 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mcp.mappings + +import com.google.common.collect.ImmutableBiMap + +/** + * A temporary solution until we get something more dynamic sorted + */ +object HardcodedYarnToMojmap { + fun createMappings() = Mappings( + ImmutableBiMap.ofEntries( + "net.minecraft.item.ItemStack" mapTo "net.minecraft.world.item.ItemStack" + ), + ImmutableBiMap.ofEntries(), + ImmutableBiMap.ofEntries(), + hashMapOf(), + false, + ) + + private infix fun T.mapTo(value: T) = java.util.AbstractMap.SimpleEntry(this, value) +} diff --git a/src/main/kotlin/platform/mcp/mappings/HasCustomNamedMappings.kt b/src/main/kotlin/platform/mcp/mappings/HasCustomNamedMappings.kt new file mode 100644 index 000000000..f950859f5 --- /dev/null +++ b/src/main/kotlin/platform/mcp/mappings/HasCustomNamedMappings.kt @@ -0,0 +1,25 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2023 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mcp.mappings + +interface HasCustomNamedMappings { + val namedToMojangManager: MappingsManager? +} diff --git a/src/main/kotlin/platform/mcp/mappings/Mappings.kt b/src/main/kotlin/platform/mcp/mappings/Mappings.kt new file mode 100644 index 000000000..f7240c79c --- /dev/null +++ b/src/main/kotlin/platform/mcp/mappings/Mappings.kt @@ -0,0 +1,134 @@ +/* + * Minecraft Development for IntelliJ + * + * https://mcdev.io/ + * + * Copyright (C) 2023 minecraft-dev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, version 3.0 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.demonwav.mcdev.platform.mcp.mappings + +import com.demonwav.mcdev.facet.MinecraftFacet +import com.demonwav.mcdev.util.MemberReference +import com.demonwav.mcdev.util.descriptor +import com.demonwav.mcdev.util.fullQualifiedName +import com.demonwav.mcdev.util.mapFirstNotNull +import com.demonwav.mcdev.util.qualifiedMemberReference +import com.demonwav.mcdev.util.simpleQualifiedMemberReference +import com.google.common.collect.ImmutableBiMap +import com.intellij.openapi.module.Module +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod + +class Mappings( + val classMap: ImmutableBiMap, + val fieldMap: ImmutableBiMap, + val methodMap: ImmutableBiMap, + private val intermediaryNames: HashMap, + val containsFieldDescriptors: Boolean, +) { + fun getIntermediaryClass(fullQualifiedName: String) = classMap[fullQualifiedName] + fun getIntermediaryClass(psiClass: PsiClass): String? { + return getIntermediaryClass(psiClass.fullQualifiedName ?: return null) + } + + fun getIntermediaryField(reference: MemberReference) = fieldMap[reference] + fun getIntermediaryField(field: PsiField) = getIntermediaryField( + if (containsFieldDescriptors) { + field.qualifiedMemberReference + } else { + field.simpleQualifiedMemberReference + } + ) + + fun getIntermediaryMethod(reference: MemberReference) = methodMap[reference] + fun getIntermediaryMethod(method: PsiMethod) = getIntermediaryMethod(method.qualifiedMemberReference) + + fun tryGetMappedClass(fullQualifiedName: String) = classMap.inverse()[fullQualifiedName] + fun getMappedClass(fullQualifiedName: String) = tryGetMappedClass(fullQualifiedName) ?: fullQualifiedName + + fun tryGetMappedField(reference: MemberReference) = fieldMap.inverse()[reference] + fun getMappedField(reference: MemberReference) = tryGetMappedField(reference) ?: reference + fun tryGetMappedField(field: PsiField) = tryGetMappedField(field.qualifiedMemberReference) + + fun tryGetMappedMethod(reference: MemberReference) = methodMap.inverse()[reference] + fun getMappedMethod(reference: MemberReference) = tryGetMappedMethod(reference) ?: reference + fun tryGetMappedMethod(method: PsiMethod) = tryGetMappedMethod(method.qualifiedMemberReference) + + fun mapIntermediaryToMapped(name: String) = intermediaryNames[name] +} + +private val Module.namedToMojang: Mappings? get() { + val mcFacet = MinecraftFacet.getInstance(this) ?: return null + val manager = mcFacet.modules.filterIsInstance().mapFirstNotNull { it.namedToMojangManager } + ?: return null + return manager.mappingsNow?.takeUnless { it.containsFieldDescriptors } +} + +fun Module.getMappedClass(mojangName: String): String { + return namedToMojang?.getMappedClass(mojangName) ?: mojangName +} + +fun Module.getMojangClass(mappedName: String): String { + return namedToMojang?.getIntermediaryClass(mappedName) ?: mappedName +} + +fun Module.getMojangClass(clazz: PsiClass): String? { + return getMojangClass(clazz.fullQualifiedName ?: return null) +} + +fun Module.getMappedField(mojangField: MemberReference): String { + return namedToMojang?.tryGetMappedField(mojangField.withoutDescriptor)?.name ?: mojangField.name +} + +fun Module.getMappedField(mojangClass: String, mojangField: String): String { + return getMappedField(MemberReference(mojangField, null, mojangClass)) +} + +fun Module.getMojangField(mappedField: MemberReference): String { + return namedToMojang?.getIntermediaryField(mappedField.withoutDescriptor)?.name ?: mappedField.name +} + +fun Module.getMojangField(mappedClass: String, mappedField: String): String { + return getMojangField(MemberReference(mappedField, null, mappedClass)) +} + +fun Module.getMojangField(field: PsiField): String? { + val clazz = field.containingClass?.fullQualifiedName ?: return null + return getMojangField(clazz, field.name) +} + +fun Module.getMappedMethod(mojangMethod: MemberReference): String { + return namedToMojang?.tryGetMappedMethod(mojangMethod)?.name ?: return mojangMethod.name +} + +fun Module.getMappedMethod(mojangClass: String, mojangMethod: String, mojangDescriptor: String): String { + return getMappedMethod(MemberReference(mojangMethod, mojangDescriptor, mojangClass)) +} + +fun Module.getMojangMethod(mappedMethod: MemberReference): String { + return namedToMojang?.getIntermediaryMethod(mappedMethod)?.name ?: return mappedMethod.name +} + +fun Module.getMojangMethod(mappedClass: String, mappedMethod: String, mappedDescriptor: String): String { + return getMojangMethod(MemberReference(mappedMethod, mappedDescriptor, mappedClass)) +} + +fun Module.getMojangMethod(method: PsiMethod): String? { + val clazz = method.containingClass?.fullQualifiedName ?: return null + val descriptor = method.descriptor ?: return null + return getMojangMethod(clazz, method.name, descriptor) +} diff --git a/src/main/kotlin/platform/mcp/srg/SrgManager.kt b/src/main/kotlin/platform/mcp/mappings/MappingsManager.kt similarity index 52% rename from src/main/kotlin/platform/mcp/srg/SrgManager.kt rename to src/main/kotlin/platform/mcp/mappings/MappingsManager.kt index cf58d9f38..5f51fb41f 100644 --- a/src/main/kotlin/platform/mcp/srg/SrgManager.kt +++ b/src/main/kotlin/platform/mcp/mappings/MappingsManager.kt @@ -18,10 +18,11 @@ * along with this program. If not, see . */ -package com.demonwav.mcdev.platform.mcp.srg +package com.demonwav.mcdev.platform.mcp.mappings import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.mcp.McpModuleType +import com.demonwav.mcdev.platform.mcp.srg.SrgType import com.demonwav.mcdev.util.mapFirstNotNull import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project @@ -33,53 +34,67 @@ import java.util.concurrent.TimeoutException import kotlin.io.path.absolutePathString import org.jetbrains.concurrency.Promise import org.jetbrains.concurrency.rejectedPromise +import org.jetbrains.concurrency.resolvedPromise import org.jetbrains.concurrency.runAsync -class SrgManager(val file: String, val srgType: SrgType) { - - var srgMap: Promise = rejectedPromise("SRG map not loaded") +abstract class MappingsManager { + var mappings: Promise = rejectedPromise("Mappings not loaded") @Synchronized get - private set + protected set - val srgMapNow: McpSrgMap? + val mappingsNow: Mappings? @Synchronized get() = try { - srgMap.blockingGet(1, TimeUnit.NANOSECONDS) + mappings.blockingGet(1, TimeUnit.NANOSECONDS) } catch (e: ExecutionException) { null } catch (e: TimeoutException) { null } - @Synchronized - fun parse() { - if (srgMap.state == Promise.State.PENDING) { - return - } - - srgMap = if (file.isNotBlank()) { - val path = Paths.get(file) - if (Files.notExists(path)) { - rejectedPromise("No mapping data available at " + path.absolutePathString()) - } else { - runAsync { - // Load SRG map from files - srgType.srgParser.parseSrg(Paths.get(file)) - } - } - } else { - // Path to SRG files is unknown - rejectedPromise("No mapping data available: file path is blank") - } - } + abstract fun parse() companion object { - private val map = HashMap() + private val map = HashMap() - fun getInstance(file: String, srgType: SrgType) = map.computeIfAbsent(file) { SrgManager(it, srgType) } + @Deprecated("This needs replacing with something that doesn't cause memory leaks") + fun getInstance(file: String, srgType: SrgType) = map.computeIfAbsent(file) { SrgMappingsManager(it, srgType) } fun findAnyInstance(project: Project) = ModuleManager.getInstance(project).modules.mapFirstNotNull { - MinecraftFacet.getInstance(it, McpModuleType)?.srgManager + MinecraftFacet.getInstance(it, McpModuleType)?.mappingsManager } } + + class Immediate(mappings: Mappings) : MappingsManager() { + init { + this.mappings = resolvedPromise(mappings) + } + + override fun parse() { + } + } + + private class SrgMappingsManager(val file: String, val srgType: SrgType) : MappingsManager() { + @Synchronized + override fun parse() { + if (mappings.state == Promise.State.PENDING) { + return + } + + mappings = if (file.isNotBlank()) { + val path = Paths.get(file) + if (Files.notExists(path)) { + rejectedPromise("No mapping data available at " + path.absolutePathString()) + } else { + runAsync { + // Load SRG map from files + srgType.srgParser.parseSrg(Paths.get(file)) + } + } + } else { + // Path to SRG files is unknown + rejectedPromise("No mapping data available: file path is blank") + } + } + } } diff --git a/src/main/kotlin/platform/mcp/navigation/SrgMemberChooseByNameContributor.kt b/src/main/kotlin/platform/mcp/navigation/SrgMemberChooseByNameContributor.kt index d63060425..eeab68949 100644 --- a/src/main/kotlin/platform/mcp/navigation/SrgMemberChooseByNameContributor.kt +++ b/src/main/kotlin/platform/mcp/navigation/SrgMemberChooseByNameContributor.kt @@ -22,7 +22,7 @@ package com.demonwav.mcdev.platform.mcp.navigation import com.demonwav.mcdev.facet.MinecraftFacet import com.demonwav.mcdev.platform.mcp.McpModuleType -import com.demonwav.mcdev.platform.mcp.srg.McpSrgMap +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.MemberReference import com.intellij.navigation.ChooseByNameContributor import com.intellij.navigation.NavigationItem @@ -34,7 +34,7 @@ import com.intellij.psi.search.GlobalSearchScope class SrgMemberChooseByNameContributor : ChooseByNameContributor { // Cached between uses - var srgMap: McpSrgMap? = null + var srgMap: Mappings? = null var module: Module? = null override fun getNames(project: Project, includeNonProjectItems: Boolean): Array { @@ -47,7 +47,7 @@ class SrgMemberChooseByNameContributor : ChooseByNameContributor { val modules = ModuleManager.getInstance(project).modules for (module in modules) { val mcpModule = MinecraftFacet.getInstance(module, McpModuleType) ?: continue - srgMap = mcpModule.srgManager?.srgMapNow ?: continue + srgMap = mcpModule.mappingsManager?.mappingsNow ?: continue this.module = module break // for speed's sake, only use the first one found } diff --git a/src/main/kotlin/platform/mcp/srg/McpSrgMap.kt b/src/main/kotlin/platform/mcp/srg/McpSrgMap.kt deleted file mode 100644 index 1641a8310..000000000 --- a/src/main/kotlin/platform/mcp/srg/McpSrgMap.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Minecraft Development for IntelliJ - * - * https://mcdev.io/ - * - * Copyright (C) 2023 minecraft-dev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation, version 3.0 only. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.demonwav.mcdev.platform.mcp.srg - -import com.demonwav.mcdev.util.MemberReference -import com.demonwav.mcdev.util.fullQualifiedName -import com.demonwav.mcdev.util.qualifiedMemberReference -import com.demonwav.mcdev.util.simpleQualifiedMemberReference -import com.google.common.collect.ImmutableBiMap -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiField -import com.intellij.psi.PsiMethod - -class McpSrgMap( - val classMap: ImmutableBiMap, - val fieldMap: ImmutableBiMap, - val methodMap: ImmutableBiMap, - private val srgNames: HashMap, -) { - fun getSrgClass(fullQualifiedName: String) = classMap[fullQualifiedName] - fun getSrgClass(psiClass: PsiClass): String? { - return getSrgClass(psiClass.fullQualifiedName ?: return null) - } - - fun getSrgField(reference: MemberReference) = fieldMap[reference] - fun getSrgField(field: PsiField) = getSrgField(field.simpleQualifiedMemberReference) - - fun getSrgMethod(reference: MemberReference) = methodMap[reference] - fun getSrgMethod(method: PsiMethod) = getSrgMethod(method.qualifiedMemberReference) - - fun getMcpClass(fullQualifiedName: String) = classMap.inverse()[fullQualifiedName] - fun mapToMcpClass(fullQualifiedName: String) = getMcpClass(fullQualifiedName) ?: fullQualifiedName - - fun getMcpField(reference: MemberReference) = fieldMap.inverse()[reference] - fun mapToMcpField(reference: MemberReference) = getMcpField(reference) ?: reference - fun findMcpField(field: PsiField) = getMcpField(field.qualifiedMemberReference) - - fun getMcpMethod(reference: MemberReference) = methodMap.inverse()[reference] - fun mapToMcpMethod(reference: MemberReference) = getMcpMethod(reference) ?: reference - fun findMcpMethod(method: PsiMethod) = getMcpMethod(method.qualifiedMemberReference) - - fun mapMcpToSrgName(name: String) = srgNames[name] -} diff --git a/src/main/kotlin/platform/mcp/srg/McpUnscrambler.kt b/src/main/kotlin/platform/mcp/srg/McpUnscrambler.kt index 8492e7d53..1ccb6e95b 100644 --- a/src/main/kotlin/platform/mcp/srg/McpUnscrambler.kt +++ b/src/main/kotlin/platform/mcp/srg/McpUnscrambler.kt @@ -20,6 +20,7 @@ package com.demonwav.mcdev.platform.mcp.srg +import com.demonwav.mcdev.platform.mcp.mappings.MappingsManager import com.intellij.openapi.project.Project import com.intellij.unscramble.UnscrambleSupport import javax.swing.JComponent @@ -31,7 +32,7 @@ class McpUnscrambler : UnscrambleSupport { override fun getPresentableName() = "Remap SRG names" override fun unscramble(project: Project, text: String, logName: String, settings: JComponent?): String? { - val srgMap = SrgManager.findAnyInstance(project)?.srgMapNow ?: return null - return srgPattern.replace(text) { srgMap.mapMcpToSrgName(it.value) ?: it.value } + val srgMap = MappingsManager.findAnyInstance(project)?.mappingsNow ?: return null + return srgPattern.replace(text) { srgMap.mapIntermediaryToMapped(it.value) ?: it.value } } } diff --git a/src/main/kotlin/platform/mcp/srg/SrgParser.kt b/src/main/kotlin/platform/mcp/srg/SrgParser.kt index 01de09af7..d7ea8d1b8 100644 --- a/src/main/kotlin/platform/mcp/srg/SrgParser.kt +++ b/src/main/kotlin/platform/mcp/srg/SrgParser.kt @@ -20,8 +20,9 @@ package com.demonwav.mcdev.platform.mcp.srg +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import java.nio.file.Path interface SrgParser { - fun parseSrg(path: Path): McpSrgMap + fun parseSrg(path: Path): Mappings } diff --git a/src/main/kotlin/platform/mcp/srg/StandardSrgParser.kt b/src/main/kotlin/platform/mcp/srg/StandardSrgParser.kt index 7d3da40de..766a9a4a8 100644 --- a/src/main/kotlin/platform/mcp/srg/StandardSrgParser.kt +++ b/src/main/kotlin/platform/mcp/srg/StandardSrgParser.kt @@ -20,13 +20,14 @@ package com.demonwav.mcdev.platform.mcp.srg +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.MemberReference import com.google.common.collect.ImmutableBiMap import java.nio.file.Files import java.nio.file.Path object StandardSrgParser : SrgParser { - override fun parseSrg(path: Path): McpSrgMap { + override fun parseSrg(path: Path): Mappings { val classMapBuilder = ImmutableBiMap.builder() val fieldMapBuilder = ImmutableBiMap.builder() val methodMapBuilder = ImmutableBiMap.builder() @@ -55,6 +56,6 @@ object StandardSrgParser : SrgParser { } } - return McpSrgMap(classMapBuilder.build(), fieldMapBuilder.build(), methodMapBuilder.build(), srgNames) + return Mappings(classMapBuilder.build(), fieldMapBuilder.build(), methodMapBuilder.build(), srgNames, false) } } diff --git a/src/main/kotlin/platform/mcp/srg/TinySrgParser.kt b/src/main/kotlin/platform/mcp/srg/TinySrgParser.kt index 139799cc9..2d5bc64be 100644 --- a/src/main/kotlin/platform/mcp/srg/TinySrgParser.kt +++ b/src/main/kotlin/platform/mcp/srg/TinySrgParser.kt @@ -20,6 +20,7 @@ package com.demonwav.mcdev.platform.mcp.srg +import com.demonwav.mcdev.platform.mcp.mappings.Mappings import com.demonwav.mcdev.util.MemberReference import com.google.common.collect.ImmutableBiMap import com.intellij.openapi.util.registry.Registry @@ -32,7 +33,7 @@ import net.fabricmc.mappingio.MappingVisitor object TinySrgParser : SrgParser { private val commentRegex = Regex("#.+") - override fun parseSrg(path: Path): McpSrgMap { + override fun parseSrg(path: Path): Mappings { val classMapBuilder = ImmutableBiMap.builder() val fieldMapBuilder = ImmutableBiMap.builder() val methodMapBuilder = ImmutableBiMap.builder() @@ -44,11 +45,12 @@ object TinySrgParser : SrgParser { oldParser(path, classMapBuilder, fieldMapBuilder, methodMapBuilder, srgNames) } - return McpSrgMap( + return Mappings( classMapBuilder.build(), fieldMapBuilder.build(), methodMapBuilder.build(), srgNames, + false, ) } diff --git a/src/main/kotlin/util/MemberReference.kt b/src/main/kotlin/util/MemberReference.kt index bbc5ab857..bc07c01eb 100644 --- a/src/main/kotlin/util/MemberReference.kt +++ b/src/main/kotlin/util/MemberReference.kt @@ -47,11 +47,18 @@ data class MemberReference( assert(owner?.contains('/') != true) } + val withoutDescriptor + get() = if (this.descriptor == null) { + this + } else { + copy(descriptor = null) + } + val withoutOwner get() = if (this.owner == null) { this } else { - MemberReference(this.name, this.descriptor, null, this.matchAllNames, this.matchAllDescs) + copy(owner = null) } override val methodDescriptor = descriptor?.takeIf { it.contains("(") }