Skip to content

Commit 95d6211

Browse files
committed
Merge branch '2025.2' into 2025.3
2 parents 5c6174c + e1796ea commit 95d6211

File tree

54 files changed

+1385
-382
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1385
-382
lines changed

changelog.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,76 @@
11
# Minecraft Development for IntelliJ
22

3+
## [1.8.7]
4+
5+
### Added
6+
7+
- Translations inside `deprecated.json` are now properly handled.
8+
- Usages of removed or renamed translations will be reported as a warning.
9+
- Translations will now properly be redirected to the correct entry in the translation file if they have been renamed.
10+
- New error if a local class is used in a mixin.
11+
- Access wideners have been renamed to class tweakers, which are a new beta Fabric feature, backwards compatible with
12+
access wideners. Both the new class tweaker format and the legacy access widener format are supported.
13+
- Added warnings related to `@At.opcode`:
14+
- A warning if it is used on any injection point other than `FIELD` (it would be ignored).
15+
- A warning if it is *not* used on `FIELD`.
16+
- A warning if an unsupported opcode is used.
17+
- Added an inspection for when an injector targets an unsupported instruction. This includes:
18+
- `@Redirect` and `@WrapOperation` targeting any instruction except those that can be targeted according to their docs.
19+
- `@ModifyArg` and `@ModifyArgs` targeting any instruction except method invocations.
20+
- `@ModifyConstant` targeting any instruction that doesn't push a constant.
21+
- `@ModifyExpressionValue` targeting instructions that don't return a value (e.g. void method invocations).
22+
- `@ModifyReceiver` targeting any instruction except non-static method invocations and field references.
23+
- `@ModifyReturnValue` targeting any instruction except `xRETURN`.
24+
- `@WrapWithCondition` targeting any instruction except void method invocations and field assignments.
25+
- Added an inspection for when `@Share` is used on a parameter that isn't from the `LocalRef` family.
26+
- Added an inspection for when two `@Share` annotations pointing to the same variable have a different type.
27+
- Added support for target code which has named variables in the LVT. This is enabled by default on all code except in
28+
the packages `net.minecraft` and `com.mojang.blaze3d`. It can be enabled for these packages too by enabling the
29+
`mcdev.unobfuscated.minecraft` registry value in the registry menu (access via ctrl+shift+A in the IDE and search for
30+
"Registry"). Plugins can add further unobfuscated packages by registering to the
31+
`com.demonwav.minecraft-dev.missingLVTChecker` extension point.
32+
- `@Local` and `@ModifyVariable` will generate warnings if the target class has named variables in the LVT, but are
33+
being targeted with `ordinal`, `index`, or in implicit mode.
34+
- This is currently disabled for parameter locals (those that can have `argsOnly = true`, due to a
35+
[Mixin issue](https://github.com/FabricMC/Mixin/issues/189)).
36+
- There is a quick fix to convert the annotation to use `name`.
37+
- MixinExtras expressions will now auto-complete to use named `@Local` targets where possible.
38+
- The `@Inject` local capture migration quick fix now also uses named `@Local` targets where possible.
39+
40+
### Changed
41+
42+
- Simplified translation identification code and made interpolation inlining less aggressive. When folding translations,
43+
MinecraftDev will no longer attempt to inline the values of variables in the substitution.
44+
- Removed the check for injecting before a `super()` call. This was never a correct thing to check for.
45+
- Switched from using entry points to implicit usage providers in mixins. This allows MixinExtras sugar parameters to be
46+
reported as unused by IntelliJ if they are unused, while maintaining an implicit usage on the whole method to avoid an
47+
unused warning there.
48+
- Changed `@Local` and `@ModifyVariable` can be `argsOnly = true` inspection to also work if the local is specified by
49+
name.
50+
51+
### Fixed
52+
53+
- Error reporting now works again and uses Sentry. If you have had problems reporting errors to MinecraftDev, it may be
54+
worth trying again after this update.
55+
- Fixed auto-completion for `NEW` and `FIELD` targets so they now read from the bytecode rather than the source code,
56+
improving accuracy.
57+
- Injection point specifiers and ordinals no longer prevent completion of `@At` targets.
58+
- `@Local` no longer always reports as able to be `argsOnly = true` if there are other annotations on the method, which
59+
was particularly noticeable when using `@Expression`.
60+
- Fixed `@ModifyConstant`'s expected method signature for class types. It now correctly expects two arguments, an
61+
`Object` instance and a `Class<?>` type, and may return a `Class<?>` or a `boolean`.
62+
- MinecraftDev no longer uses the internal `loom.mods[...].modSourceSets` property when importing a Fabric project.
63+
- Double nested anonymous class resolving now works, so mixins targeting `Foo$1$1` should now work correctly.
64+
- Fixed navigation to constructors from mixins, which was broken in the previous release.
65+
- Class tweaker (access widener) files no longer treat unrecognized namespaces as a syntax error.
66+
- A warning will be generated if the namespace is not in the current mapping file (pulled from Loom). If the current
67+
mapping file does not exist, only `official` will be recognized as a valid namespace.
68+
- Fixed the "copy AT entry" action for unobfuscated environments.
69+
- Fixed an `ArrayIndexOutOfBoundsException` in `LocalVariables.guessAllLocalVariablesUncached`.
70+
- Override `getLanguage` in `NbttCodeStyleSettingsProvider`, preventing an IDE error.
71+
- Weaken the assertions in `TranslationFiles`, showing a balloon to the user instead. This prevents an IDE error from
72+
occurring.
73+
374
## [1.8.6]
475

576
### Added

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Minecraft Development for IntelliJ
3131
</tr>
3232
</table>
3333

34-
Info and Documentation [![Current Release](https://img.shields.io/badge/release-1.8.6-orange.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/8327)
34+
Info and Documentation [![Current Release](https://img.shields.io/badge/release-1.8.7-orange.svg?style=flat-square)](https://plugins.jetbrains.com/plugin/8327)
3535
----------------------
3636

3737
<a href="https://discord.gg/j6UNcfr"><img src="https://i.imgur.com/JXu9C1G.png" height="48px"></img></a>

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/nbt/lang/format/NbttCodeStyleSettingsProvider.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class NbttCodeStyleSettingsProvider : CodeStyleSettingsProvider() {
3434
override fun getHelpTopic(): String? = null
3535
}
3636

37+
override fun getLanguage() = NbttLanguage
38+
3739
override fun getConfigurableDisplayName() = MCDevBundle("nbt.lang.display_name")
3840

3941
override fun createCustomSettings(settings: CodeStyleSettings) = NbttCodeStyleSettings(settings)

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/actions/CopyAtAction.kt

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ package com.demonwav.mcdev.platform.mcp.actions
2222

2323
import com.demonwav.mcdev.platform.mcp.mappings.Mappings
2424
import com.demonwav.mcdev.util.ActionData
25+
import com.demonwav.mcdev.util.descriptor
26+
import com.demonwav.mcdev.util.fullQualifiedName
27+
import com.demonwav.mcdev.util.showBalloon
28+
import com.demonwav.mcdev.util.showSuccessBalloon
2529
import com.intellij.openapi.actionSystem.AnActionEvent
2630
import com.intellij.openapi.editor.Editor
2731
import com.intellij.psi.PsiClass
@@ -32,33 +36,72 @@ import java.awt.Toolkit
3236
import java.awt.datatransfer.StringSelection
3337

3438
class CopyAtAction : SrgActionBase() {
35-
override fun withSrgTarget(parent: PsiElement, srgMap: Mappings, e: AnActionEvent, data: ActionData) {
36-
when (parent) {
37-
is PsiField -> {
38-
val containing = parent.containingClass ?: return showBalloon("No SRG name found", e)
39-
val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e)
40-
val srg = srgMap.getIntermediaryField(parent) ?: return showBalloon("No SRG name found", e)
41-
copyToClipboard(
42-
data.editor,
43-
data.element,
44-
classSrg + " " + srg.name + " # " + parent.name,
45-
)
39+
override fun withSrgTarget(parent: PsiElement, srgMap: Mappings?, e: AnActionEvent, data: ActionData) {
40+
if (srgMap == null) {
41+
when (parent) {
42+
is PsiField -> {
43+
val className = parent.containingClass?.fullQualifiedName ?: return showBalloon(
44+
e,
45+
"No containing class found"
46+
)
47+
copyToClipboard(
48+
data.editor,
49+
data.element,
50+
className + " " + parent.name,
51+
)
52+
}
53+
is PsiMethod -> {
54+
val className = parent.containingClass?.fullQualifiedName ?: return showBalloon(
55+
e,
56+
"No containing class found"
57+
)
58+
copyToClipboard(
59+
data.editor,
60+
data.element,
61+
className + " " + parent.name + parent.descriptor,
62+
)
63+
}
64+
is PsiClass -> {
65+
val className = parent.fullQualifiedName ?: return showBalloon(e, "Could not get FQN")
66+
copyToClipboard(
67+
data.editor,
68+
data.element,
69+
className,
70+
)
71+
}
4672
}
47-
is PsiMethod -> {
48-
val containing = parent.containingClass ?: return showBalloon("No SRG name found", e)
49-
val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon("No SRG name found", e)
50-
val srg = srgMap.getIntermediaryMethod(parent) ?: return showBalloon("No SRG name found", e)
51-
copyToClipboard(
52-
data.editor,
53-
data.element,
54-
classSrg + " " + srg.name + srg.descriptor + " # " + parent.name,
55-
)
56-
}
57-
is PsiClass -> {
58-
val classMcpToSrg = srgMap.getIntermediaryClass(parent) ?: return showBalloon("No SRG name found", e)
59-
copyToClipboard(data.editor, data.element, classMcpToSrg)
73+
} else {
74+
when (parent) {
75+
is PsiField -> {
76+
val containing = parent.containingClass ?: return showBalloon(e, "No SRG name found")
77+
val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon(e, "No SRG name found")
78+
val srg = srgMap.getIntermediaryField(parent) ?: return showBalloon(e, "No SRG name found")
79+
copyToClipboard(
80+
data.editor,
81+
data.element,
82+
classSrg + " " + srg.name + " # " + parent.name,
83+
)
84+
}
85+
86+
is PsiMethod -> {
87+
val containing = parent.containingClass ?: return showBalloon(e, "No SRG name found")
88+
val classSrg = srgMap.getIntermediaryClass(containing) ?: return showBalloon(e, "No SRG name found")
89+
val srg = srgMap.getIntermediaryMethod(parent) ?: return showBalloon(e, "No SRG name found")
90+
copyToClipboard(
91+
data.editor,
92+
data.element,
93+
classSrg + " " + srg.name + srg.descriptor + " # " + parent.name,
94+
)
95+
}
96+
97+
is PsiClass -> {
98+
val classMcpToSrg =
99+
srgMap.getIntermediaryClass(parent) ?: return showBalloon(e, "No SRG name found")
100+
copyToClipboard(data.editor, data.element, classMcpToSrg)
101+
}
102+
103+
else -> showBalloon(e, "Not a valid element")
60104
}
61-
else -> showBalloon("Not a valid element", e)
62105
}
63106
}
64107

0 commit comments

Comments
 (0)