Skip to content

Commit b8f9dc8

Browse files
committed
add small enigma plugin to suggest name automatically
1 parent de98504 commit b8f9dc8

File tree

9 files changed

+193
-13
lines changed

9 files changed

+193
-13
lines changed

build.gradle.kts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.parchmentmc.validation.MethodStandardsValidatorV2
1111

1212
plugins {
1313
java
14+
`kotlin-dsl`
1415
`maven-publish`
1516
id("org.parchmentmc.compass")
1617
}
@@ -36,7 +37,11 @@ repositories {
3637
}
3738
}
3839

39-
val enigma by configurations.registering
40+
val enigmaPlugin by sourceSets.creating
41+
42+
val enigma by configurations.registering {
43+
extendsFrom(configurations.getByName(enigmaPlugin.implementationConfigurationName))
44+
}
4045
val remapper by configurations.registering
4146
val minecraft by configurations.registering
4247

@@ -62,6 +67,11 @@ dependencies {
6267
enigma("cuchaz:enigma-swing:2.5.2")
6368
enigma("org.vineflower:vineflower:1.11.1") // sync with mache
6469

70+
enigma(enigmaPlugin.output)
71+
72+
enigmaPlugin.implementationConfigurationName(gradleKotlinDsl())
73+
enigmaPlugin.implementationConfigurationName("cuchaz:enigma:2.5.2")
74+
6575
// ParchmentJAM, JAMMER integration for migrating mapping data
6676
jammer("org.parchmentmc.jam:jam-parchment:0.1.0")
6777

@@ -118,6 +128,7 @@ tasks.register<EnigmaRunner>("enigma") {
118128
mainClass = "cuchaz.enigma.gui.Main"
119129
inputJar = remapJar.flatMap { it.outputJar }
120130
mappings = project.compass.productionData
131+
profile = project.layout.projectDirectory.file("enigma_profile.json")
121132
}
122133

123134
tasks.withType<ValidateData>().configureEach {

buildSrc/src/main/kotlin/org/parchmentmc/BlackstonePlugin.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ class BlackstonePlugin : Plugin<Project> {
3030
dependencies.add(target.dependencyFactory.create(cfc))
3131
}
3232
// Fix faulty task wiring
33-
target.tasks.withType(SanitizeData::class.java).configureEach {
33+
target.tasks.withType<SanitizeData>().configureEach {
3434
inputs.files(blackstoneConfig)
3535
}
36-
target.tasks.withType(ValidateData::class.java).configureEach {
36+
target.tasks.withType<ValidateData>().configureEach {
3737
inputs.files(blackstoneConfig)
3838
}
39-
target.tasks.withType(GenerateExport::class.java).configureEach {
39+
target.tasks.withType<GenerateExport>().configureEach {
4040
inputs.files(blackstoneConfig)
4141
}
4242

@@ -64,7 +64,7 @@ class BlackstonePlugin : Plugin<Project> {
6464
val downloadVersionMeta by target.tasks.registering(DownloadVersionMetadata::class) {
6565
group = PLUGIN_TASK_GROUP
6666
input = downloadLauncherMeta.flatMap { it.output }
67-
output = target.layout.buildDirectory.file(name + ".json") // Remove subdir to fix caching
67+
output = target.layout.buildDirectory.file("$name.json") // Remove subdir to fix caching
6868
outputs.cacheIf { true }
6969
}
7070

buildSrc/src/main/kotlin/org/parchmentmc/tasks/EnigmaRunner.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@ abstract class EnigmaArgumentProvider : CommandLineArgumentProvider {
2020
@get:InputDirectory
2121
abstract val mappings: DirectoryProperty
2222

23+
@get:InputFile
24+
abstract val profile: RegularFileProperty
25+
2326
override fun asArguments(): Iterable<String> {
2427
val args = mutableListOf("--no-edit-all", "--edit-parameters", "--edit-javadocs", "--single-class-tree")
2528

2629
args.add("--jar=${inputJar.get().asFile.absolutePath}")
2730
args.add("--mappings=${mappings.get().asFile.absolutePath}")
31+
args.add("--profile=${profile.get().asFile.absolutePath}")
2832

2933
return args.toList()
3034
}
@@ -41,10 +45,14 @@ abstract class EnigmaRunner @Inject constructor(
4145
@get:InputDirectory
4246
abstract val mappings: DirectoryProperty
4347

48+
@get:InputFile
49+
abstract val profile: RegularFileProperty
50+
4451
init {
4552
val provider = objects.newInstance<EnigmaArgumentProvider>()
4653
provider.inputJar.set(inputJar)
4754
provider.mappings.set(mappings)
55+
provider.profile.set(profile)
4856
argumentProviders.add(provider)
4957

5058
// Enigma runs on Java 17. If the Gradle JVM supports Java 17, then we are fine

buildSrc/src/main/kotlin/org/parchmentmc/validation/MemberExistenceValidatorV2.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class MemberExistenceValidatorV2 : MemberExistenceValidator() {
1414
super.visitField(classData, fieldData, classMetadata, fieldMetadata)
1515
if (fieldMetadata != null) {
1616
if (fieldMetadata.descriptor.mojangName.orElseThrow() != fieldData.descriptor) {
17-
error("Field descriptor does not match according to metadata");
17+
error("Field descriptor does not match according to metadata.")
1818
}
1919
} else {
2020
// Fields existence are already checked in MemberExistenceValidator

buildSrc/src/main/kotlin/org/parchmentmc/validation/MethodStandardsValidatorV2.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import org.parchmentmc.feather.metadata.MethodMetadata
77

88
class MethodStandardsValidatorV2 : MethodStandardsValidator() {
99

10+
data class ParamInfo(val lvtIndex: Byte, val name: String)
11+
1012
private val standardMethods: Map<String, Array<ParamInfo>> = mapOf(
1113
"equals (Ljava/lang/Object;)Z" to arrayOf(
1214
ParamInfo(1, "other")
1315
),
14-
"compareTo (<owner>)I" to arrayOf(
16+
"compareTo (<owner>)I" to arrayOf( // doesn't work well for FriendlyByteBuf and LinkFSPath
1517
ParamInfo(1, "other")
1618
)
1719
)
@@ -22,18 +24,14 @@ class MethodStandardsValidatorV2 : MethodStandardsValidator() {
2224
): Boolean {
2325
val standardParams = standardMethods[methodData.name + " " + methodData.descriptor.replace("L${classData.name};", "<owner>")]
2426
if (standardParams != null) {
25-
methodData.parameters.forEachIndexed { index, paramData ->
26-
val standardParam = standardParams[index]
27+
methodData.parameters.zip(standardParams) { paramData, standardParam ->
2728
if (paramData.index == standardParam.lvtIndex && paramData.name != standardParam.name) {
28-
error("Parameter #${paramData.index} doesn't match the expected name: ${standardParam.name}")
29+
error("Parameter #${paramData.index} doesn't match the expected name: ${standardParam.name}.")
2930
return false
3031
}
3132
}
32-
3333
}
3434

3535
return super.visitMethod(classData, methodData, classMetadata, methodMetadata)
3636
}
37-
38-
data class ParamInfo(val lvtIndex: Byte, val name: String)
3937
}

enigma_profile.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"services": {
3+
"name_proposal": {
4+
"id": "paper:name_proposal"
5+
},
6+
"jar_indexer": {
7+
"id": "paper:jar_indexer"
8+
}
9+
}
10+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package org.parchmentmc.enigma
2+
3+
import cuchaz.enigma.analysis.index.JarIndex
4+
import cuchaz.enigma.api.service.JarIndexerService
5+
import cuchaz.enigma.api.service.NameProposalService
6+
import cuchaz.enigma.classprovider.ClassProvider
7+
import cuchaz.enigma.translation.mapping.EntryRemapper
8+
import cuchaz.enigma.translation.representation.MethodDescriptor
9+
import cuchaz.enigma.translation.representation.entry.ClassEntry
10+
import cuchaz.enigma.translation.representation.entry.Entry
11+
import cuchaz.enigma.translation.representation.entry.LocalVariableEntry
12+
import cuchaz.enigma.translation.representation.entry.MethodEntry
13+
import java.util.*
14+
import javax.lang.model.SourceVersion
15+
16+
class EnigmaNameProposalService() : JarIndexerService, NameProposalService {
17+
18+
lateinit var indexer: JarIndex
19+
20+
val suggestions = mapOf(
21+
// client
22+
"Lcom/mojang/blaze3d/vertex/VertexConsumer;" to "consumer",
23+
"Lnet/minecraft/client/renderer/MultiBufferSource;" to "bufferSource",
24+
"Lnet/minecraft/client/renderer/SubmitNodeCollector;" to "nodeCollector",
25+
"Lnet/minecraft/client/renderer/SubmitNodeCollection;" to "nodeCollection",
26+
"Lnet/minecraft/client/renderer/SubmitNodeStorage;" to "nodeStorage",
27+
"Lnet/minecraft/client/gui/ActiveTextCollector;" to "textCollector",
28+
// server
29+
"Lcom/mojang/authlib/GameProfile;" to "profile",
30+
31+
"Lnet/minecraft/world/item/ItemStack;" to "stack",
32+
"Lnet/minecraft/world/level/ItemLike;" to "item",
33+
"Lnet/minecraft/world/level/block/state/BlockState;" to "state",
34+
"Lnet/minecraft/core/BlockPos;" to "pos",
35+
$$"Lnet/minecraft/core/BlockPos$MutableBlockPos;" to "pos",
36+
"Lnet/minecraft/resources/ResourceLocation;" to "location",
37+
38+
"Lnet/minecraft/server/level/WorldGenRegion;" to "region",
39+
"Lnet/minecraft/server/level/ServerLevel;" to "level",
40+
"Lnet/minecraft/world/level/LevelReader;" to "level",
41+
"Lnet/minecraft/world/level/LevelHeightAccessor;" to "level",
42+
"Lnet/minecraft/world/level/BlockGetter;" to "level",
43+
// "Lnet/minecraft/world/level/CollisionGetter;" to "level",
44+
45+
"Lnet/minecraft/server/level/ServerPlayer;" to "player",
46+
"Lnet/minecraft/world/entity/animal/nautilus/AbstractNautilus;" to "nautilus",
47+
"Lnet/minecraft/world/entity/projectile/AbstractArrow;" to "arrow",
48+
"Lnet/minecraft/world/entity/monster/AbstractSkeleton;" to "skeleton",
49+
"Lnet/minecraft/world/entity/animal/horse/AbstractHorse;" to "horse",
50+
"Lnet/minecraft/world/entity/HumanoidArm;" to "arm",
51+
"Lnet/minecraft/util/debug/DebugValueAccess;" to "valueAccess",
52+
)
53+
54+
override fun acceptJar(scope: Set<String>, classProvider: ClassProvider, jarIndex: JarIndex) {
55+
indexer = jarIndex
56+
}
57+
58+
private fun paramCanConflict(startIndex: Int, methodDesc: MethodDescriptor, entry: ClassEntry): Boolean {
59+
var alreadyFound = false
60+
for (index in startIndex..methodDesc.argumentDescs.lastIndex) {
61+
val desc = methodDesc.argumentDescs[index]
62+
if (desc.containsType() && desc.typeEntry.equals(entry)) {
63+
if (alreadyFound) {
64+
return true
65+
}
66+
alreadyFound = true
67+
}
68+
}
69+
return false
70+
}
71+
72+
private fun isEnumConstructor(method: MethodEntry): Boolean {
73+
if (!method.isConstructor) {
74+
return false
75+
}
76+
77+
return indexer.entryIndex.getClassAccess(method.parent)?.isEnum ?: false
78+
}
79+
80+
override fun proposeName(obfEntry: Entry<*>, remapper: EntryRemapper): Optional<String> {
81+
if (obfEntry is LocalVariableEntry && obfEntry.isArgument) {
82+
val parent = obfEntry.parent
83+
if (parent != null && !parent.name.startsWith("lambda$")) { // todo handle lambda
84+
val isStatic = indexer.entryIndex.getMethodAccess(parent)?.isStatic ?: false
85+
86+
var offsetLvtIndex = 0
87+
if (!isStatic) {
88+
offsetLvtIndex++ // (this, ...)
89+
}
90+
var descStartIndex = 0 // ignore implicit argument in descriptors for conflict check
91+
if (isEnumConstructor(parent)) {
92+
descStartIndex += 2 // (name, ordinal, ...)
93+
}
94+
95+
val paramIndex = fromLvtToParamIndex(obfEntry.index, parent, offsetLvtIndex)
96+
val desc = parent.desc.argumentDescs[paramIndex]
97+
if (desc.isPrimitive) {
98+
return Optional.empty()
99+
}
100+
101+
val strDesc = desc.toString()
102+
var name = suggestions[strDesc] ?: strDesc.substringAfterLast('/').substringAfterLast('$').dropLast(1).replaceFirstChar { it.lowercase() } // relevant type
103+
if (paramCanConflict(descStartIndex, parent.desc, desc.typeEntry)) {
104+
name += (paramIndex + 1)
105+
}
106+
if (SourceVersion.isKeyword(name)) {
107+
name += '_'
108+
}
109+
110+
return Optional.of(name)
111+
}
112+
}
113+
return Optional.empty()
114+
}
115+
116+
/*
117+
* Transform the given LVT index into a parameter index.
118+
*/
119+
fun fromLvtToParamIndex(lvtIndex: Int, method: MethodEntry, offsetLvtIndex: Int): Int {
120+
var currentParamIndex = 0
121+
var currentLvtIndex = offsetLvtIndex
122+
123+
for (param in method.desc.argumentDescs) {
124+
if (currentLvtIndex == lvtIndex) {
125+
return currentParamIndex
126+
}
127+
128+
currentParamIndex++
129+
currentLvtIndex++
130+
131+
if (param.toString() == "J" || param.toString() == "D") { // long / double take two slots
132+
currentLvtIndex++
133+
}
134+
}
135+
return -1
136+
}
137+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.parchmentmc.enigma
2+
3+
import cuchaz.enigma.api.EnigmaPlugin
4+
import cuchaz.enigma.api.EnigmaPluginContext
5+
import cuchaz.enigma.api.service.JarIndexerService
6+
import cuchaz.enigma.api.service.NameProposalService
7+
8+
class NameProposalServiceEnigmaPlugin : EnigmaPlugin {
9+
10+
override fun init(ctx: EnigmaPluginContext) {
11+
val service = EnigmaNameProposalService()
12+
ctx.registerService("paper:name_proposal", NameProposalService.TYPE) { _ -> service }
13+
ctx.registerService("paper:jar_indexer", JarIndexerService.TYPE) { _ -> service }
14+
}
15+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.parchmentmc.enigma.NameProposalServiceEnigmaPlugin

0 commit comments

Comments
 (0)