Skip to content

Commit 1a1fc03

Browse files
committed
Don't hardcode namespaces for CT files; don't assume LoomExtension has a mappingsFile property
1 parent 76e69e4 commit 1a1fc03

File tree

10 files changed

+129
-38
lines changed

10 files changed

+129
-38
lines changed

src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelBuilderImpl.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class FabricLoomModelBuilderImpl extends AbstractModelBuilderService {
6161

6262
FabricLoomModel build(Project project, Object loomExtension) {
6363
def minecraftVersion = loomExtension.minecraftProvider.minecraftVersion()
64-
def tinyMappings = loomExtension.mappingsFile
64+
def tinyMappings = loomExtension.hasProperty("mappingsFile") ? loomExtension.mappingsFile : null
6565
def splitMinecraftJar = loomExtension.areEnvironmentSourceSetsSplit()
6666

6767
def decompilers = [:]

src/gradle-tooling-extension/groovy/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModelImpl.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
package com.demonwav.mcdev.platform.mcp.gradle.tooling.fabricloom
2222

2323
import groovy.transform.Immutable
24+
import org.jetbrains.annotations.Nullable
2425

2526
@Immutable(knownImmutableClasses = [File])
2627
class FabricLoomModelImpl implements FabricLoomModel, Serializable {
2728
String minecraftVersion
29+
@Nullable
2830
File tinyMappings
2931
Map<String, List<DecompilerModel>> decompilers
3032
boolean splitMinecraftJar

src/gradle-tooling-extension/java/com/demonwav/mcdev/platform/mcp/gradle/tooling/fabricloom/FabricLoomModel.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
package com.demonwav.mcdev.platform.mcp.gradle.tooling.fabricloom;
2222

23+
import org.jetbrains.annotations.Nullable;
24+
2325
import java.io.File;
2426
import java.util.List;
2527
import java.util.Map;
@@ -28,6 +30,7 @@ public interface FabricLoomModel {
2830

2931
String getMinecraftVersion();
3032

33+
@Nullable
3134
File getTinyMappings();
3235

3336
Map<String, List<DecompilerModel>> getDecompilers();

src/main/grammars/CtLexer.flex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import static com.intellij.psi.TokenType.*;
5252

5353
HEADER_NAME=accessWidener|classTweaker
5454
HEADER_VERSION_ELEMENT=v\d+
55-
HEADER_NAMESPACE_ELEMENT=named|intermediary
55+
HEADER_NAMESPACE_ELEMENT=\w+
5656
PRIMITIVE=[ZBCSIFDJV]
5757
CLASS_VALUE=L[^;\n]+;
5858
SIGNATURE_CLASS_VALUE_START=L[^;<\n]+

src/main/grammars/CtParser.bnf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ private end_line ::= crlf | <<eof>>
4343
header ::= HEADER_NAME HEADER_VERSION_ELEMENT HEADER_NAMESPACE_ELEMENT {
4444
mixin="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.impl.CtHeaderImplMixin"
4545
implements="com.demonwav.mcdev.platform.mcp.ct.psi.mixins.CtHeaderMixin"
46+
methods=[
47+
namespaceElement="HEADER_NAMESPACE_ELEMENT"
48+
]
4649
pin = 1
4750
}
4851

src/main/kotlin/platform/fabric/FabricModule.kt

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
5656
override val namedToMojangManager: MappingsManager?
5757
get() = namedToMojangManagerField
5858

59+
private var mappingNamespacesField = emptyList<String>()
60+
val mappingNamespaces: List<String>
61+
get() = mappingNamespacesField
62+
5963
override val moduleType = FabricModuleType
6064
override val type = PlatformType.FABRIC
6165
override val icon = PlatformAssets.FABRIC_ICON
@@ -79,60 +83,74 @@ class FabricModule internal constructor(facet: MinecraftFacet) : AbstractModule(
7983
}
8084

8185
override fun refresh() {
82-
namedToMojangManagerField = if (detectYarn()) {
86+
val mappingDetection = detectMappings()
87+
88+
namedToMojangManagerField = if (mappingDetection.yarnDetected) {
8389
MappingsManager.Immediate(HardcodedYarnToMojmap.createMappings())
8490
} else {
8591
null
8692
}
93+
94+
mappingNamespacesField = mappingDetection.namespaces
8795
}
8896

89-
private fun detectYarn(): Boolean {
90-
val gradleData = GradleUtil.findGradleModuleData(facet.module) ?: return false
91-
val loomData =
92-
gradleData.children.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData ?: return false
93-
val mappingsFile = loomData.tinyMappings ?: return false
97+
private fun detectMappings(): MappingDetectionResult {
98+
val gradleData = GradleUtil.findGradleModuleData(facet.module) ?: return MappingDetectionResult.DEFAULT
99+
val loomData = gradleData.children.find { it.key == FabricLoomData.KEY }?.data as? FabricLoomData
100+
?: return MappingDetectionResult.DEFAULT
101+
val mappingsFile = loomData.tinyMappings ?: return MappingDetectionResult.DEFAULT
94102

95-
var yarnDetected = false
96-
val visitor = object : MappingVisitor {
97-
private var namedIndex = -1
103+
val result = MappingDetectionResult()
98104

99-
override fun visitNamespaces(srcNamespace: String?, dstNamespaces: List<String>) {
100-
namedIndex = dstNamespaces.indexOf("named")
101-
}
105+
try {
106+
MappingReader.read(mappingsFile.toPath(), result)
107+
} catch (_: IOException) {
108+
return MappingDetectionResult.DEFAULT
109+
}
102110

103-
override fun visitContent() = namedIndex >= 0
111+
return result
112+
}
104113

105-
override fun visitClass(srcName: String) = true
114+
override fun dispose() {
115+
super.dispose()
116+
fabricJson = null
117+
}
106118

107-
override fun visitField(srcName: String?, srcDesc: String?) = false
119+
private class MappingDetectionResult : MappingVisitor {
120+
var yarnDetected = false
121+
var namespaces = emptyList<String>()
122+
private var namedIndex = -1
108123

109-
override fun visitMethod(srcName: String?, srcDesc: String?) = false
124+
override fun visitNamespaces(srcNamespace: String?, dstNamespaces: List<String>) {
125+
namedIndex = dstNamespaces.indexOf("named")
126+
namespaces = listOfNotNull(srcNamespace) + dstNamespaces
127+
}
110128

111-
override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?) = false
129+
override fun visitContent() = namedIndex >= 0
112130

113-
override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String?) = false
131+
override fun visitClass(srcName: String) = true
114132

115-
override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String) {
116-
if (namespace == namedIndex && name == "net/minecraft/client/MinecraftClient") {
117-
yarnDetected = true
118-
}
119-
}
133+
override fun visitField(srcName: String?, srcDesc: String?) = false
134+
135+
override fun visitMethod(srcName: String?, srcDesc: String?) = false
136+
137+
override fun visitMethodArg(argPosition: Int, lvIndex: Int, srcName: String?) = false
138+
139+
override fun visitMethodVar(lvtRowIndex: Int, lvIndex: Int, startOpIdx: Int, srcName: String?) = false
120140

121-
override fun visitComment(targetKind: MappedElementKind?, comment: String?) {
141+
override fun visitDstName(targetKind: MappedElementKind?, namespace: Int, name: String) {
142+
if (namespace == namedIndex && name == "net/minecraft/client/MinecraftClient") {
143+
yarnDetected = true
122144
}
123145
}
124146

125-
try {
126-
MappingReader.read(mappingsFile.toPath(), visitor)
127-
} catch (e: IOException) {
128-
return false
147+
override fun visitComment(targetKind: MappedElementKind?, comment: String?) {
129148
}
130149

131-
return yarnDetected
132-
}
133-
134-
override fun dispose() {
135-
super.dispose()
136-
fabricJson = null
150+
companion object {
151+
val DEFAULT = MappingDetectionResult().apply {
152+
namespaces = listOf("official")
153+
}
154+
}
137155
}
138156
}

src/main/kotlin/platform/mcp/ct/CtCompletionContributor.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020

2121
package com.demonwav.mcdev.platform.mcp.ct
2222

23+
import com.demonwav.mcdev.facet.MinecraftFacet
24+
import com.demonwav.mcdev.platform.fabric.FabricModuleType
2325
import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtTypes
26+
import com.demonwav.mcdev.util.findModule
2427
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase
2528
import com.intellij.codeInsight.completion.CompletionContributor
2629
import com.intellij.codeInsight.completion.CompletionParameters
@@ -86,7 +89,11 @@ object CtNamespaceCompletionProvider : CompletionProvider<CompletionParameters>(
8689
parameters: CompletionParameters,
8790
context: ProcessingContext,
8891
result: CompletionResultSet,
89-
) = result.addAllElements(listOf("named", "intermediary").map(LookupElementBuilder::create))
92+
) {
93+
val module = parameters.originalFile.findModule() ?: return
94+
val fabricModule = MinecraftFacet.getInstance(module, FabricModuleType) ?: return
95+
result.addAllElements(fabricModule.mappingNamespaces.map(LookupElementBuilder::create))
96+
}
9097
}
9198

9299
object CtEntryStartCompletionProvider : CompletionProvider<CompletionParameters>() {

src/main/kotlin/platform/mcp/ct/CtSyntaxHighlighter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class CtSyntaxHighlighter : SyntaxHighlighterBase() {
5555
val HEADER_NAME =
5656
TextAttributesKey.createTextAttributesKey("CT_HEADER_NAME", DefaultLanguageHighlighterColors.KEYWORD)
5757
val HEADER_NAMESPACE =
58-
TextAttributesKey.createTextAttributesKey("CT_HEADER_NAMESPACE", DefaultLanguageHighlighterColors.KEYWORD)
58+
TextAttributesKey.createTextAttributesKey("CT_HEADER_NAMESPACE", DefaultLanguageHighlighterColors.CLASS_REFERENCE)
5959
val ACCESS =
6060
TextAttributesKey.createTextAttributesKey("CT_ACCESS", DefaultLanguageHighlighterColors.KEYWORD)
6161
val INJECT_INTERFACE =
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Minecraft Development for IntelliJ
3+
*
4+
* https://mcdev.io/
5+
*
6+
* Copyright (C) 2025 minecraft-dev
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published
10+
* by the Free Software Foundation, version 3.0 only.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
package com.demonwav.mcdev.platform.mcp.ct.inspections
22+
23+
import com.demonwav.mcdev.facet.MinecraftFacet
24+
import com.demonwav.mcdev.platform.fabric.FabricModuleType
25+
import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtHeader
26+
import com.demonwav.mcdev.platform.mcp.ct.gen.psi.CtVisitor
27+
import com.demonwav.mcdev.platform.mcp.ct.psi.mixins.CtHeaderMixin
28+
import com.demonwav.mcdev.util.findModule
29+
import com.intellij.codeInspection.LocalInspectionTool
30+
import com.intellij.codeInspection.ProblemsHolder
31+
32+
class UnknownCtNamespaceInspection : LocalInspectionTool() {
33+
override fun getDisplayName() = "Unknown CT namespace"
34+
override fun getStaticDescription() = "Reports an unknown namespace in a ClassTweaker header"
35+
36+
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = object : CtVisitor() {
37+
override fun visitHeaderMixin(header: CtHeaderMixin) {
38+
val namespace = header.namespaceString ?: return
39+
40+
val module = header.findModule() ?: return
41+
val fabricModule = MinecraftFacet.getInstance(module, FabricModuleType) ?: return
42+
43+
if (namespace !in fabricModule.mappingNamespaces) {
44+
holder.registerProblem(
45+
(header as CtHeader).namespaceElement ?: header,
46+
"Unrecognized namespace"
47+
)
48+
}
49+
}
50+
}
51+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,13 @@
10271027
level="WARNING"
10281028
hasStaticDescription="true"
10291029
implementationClass="com.demonwav.mcdev.platform.mcp.ct.inspections.DuplicateAwEntryInspection"/>
1030+
<localInspection displayName="Unknown CT namespace"
1031+
groupName="MCP"
1032+
language="Class Tweaker"
1033+
enabledByDefault="true"
1034+
level="WARNING"
1035+
hasStaticDescription="true"
1036+
implementationClass="com.demonwav.mcdev.platform.mcp.ct.inspections.UnknownCtNamespaceInspection"/>
10301037
<!--endregion-->
10311038

10321039
<!--region MIXIN INSPECTIONS-->

0 commit comments

Comments
 (0)