remap transitive AWs if necessary and AW remapping/validation

This commit is contained in:
moehreag 2024-08-03 15:22:21 +02:00
parent 7a2f8aefb0
commit e54543b2b7
4 changed files with 72 additions and 72 deletions

View file

@ -7,7 +7,7 @@ plugins {
} }
group = "dev.frogmc" group = "dev.frogmc"
version = "0.0.1-alpha.15" version = "0.0.1-alpha.16"
repositories { repositories {
maven { maven {
@ -24,7 +24,7 @@ repositories {
} }
dependencies { dependencies {
implementation("dev.frogmc:thyroxine:0.0.1-alpha.9") implementation("dev.frogmc:thyroxine:0.0.1-alpha.10")
implementation("org.ow2.asm:asm:9.7") implementation("org.ow2.asm:asm:9.7")
implementation("org.ow2.asm:asm-commons:9.7") implementation("org.ow2.asm:asm-commons:9.7")
implementation("org.ow2.asm:asm-tree:9.7") implementation("org.ow2.asm:asm-tree:9.7")

View file

@ -22,6 +22,7 @@ import dev.frogmc.thyroxine.RemappingStep
import dev.frogmc.thyroxine.Thyroxine import dev.frogmc.thyroxine.Thyroxine
import dev.frogmc.thyroxine.api.Mapper import dev.frogmc.thyroxine.api.Mapper
import dev.frogmc.thyroxine.api.data.MappingBundle import dev.frogmc.thyroxine.api.data.MappingBundle
import dev.frogmc.thyroxine.api.data.MappingData
import dev.frogmc.thyroxine.provider.MojmapProvider import dev.frogmc.thyroxine.provider.MojmapProvider
import dev.frogmc.thyroxine.writer.tiny.TinyV2Writer import dev.frogmc.thyroxine.writer.tiny.TinyV2Writer
import net.fabricmc.fernflower.api.IFabricJavadocProvider import net.fabricmc.fernflower.api.IFabricJavadocProvider
@ -225,40 +226,7 @@ class PhytotelmaPlugin : Plugin<Project> {
.get<String>("frog.extensions.accesswidener")?.let { name -> .get<String>("frog.extensions.accesswidener")?.let { name ->
val aw = metadata.resolveSibling(name) val aw = metadata.resolveSibling(name)
AccessWidener.checkAW(aw, ProjectStorage.get(project).remappedGameJarPath!!) AccessWidener.checkAW(aw, ProjectStorage.get(project).remappedGameJarPath!!)
val mapper = Mapper(mappings) { listOf() } remapAccesswidener(mappings, aw)
val buffer = buildString {
aw.forEachLine {
if (it.contains("\\t") && !it.startsWith("#")) {
val parts = it.split("[\\t #]+".toRegex()).toMutableList()
if (parts.size > 2) {
val type = parts[1]
when (type) {
"class" -> {
parts[2] = mapper.map(parts[2])
}
"fields" -> {
parts[3] = mapper.mapFieldName(parts[2], parts[3], parts[4])
parts[4] = mapper.mapDesc(parts[4])
parts[3] = mapper.map(parts[2])
}
"methods" -> {
parts[3] = mapper.mapMethodName(parts[2], parts[3], parts[4])
parts[4] = mapper.mapMethodDesc(parts[4])
parts[2] = mapper.map(parts[2])
}
}
appendLine(parts.joinToString("\\t"))
return@forEachLine
}
}
appendLine(it)
}
}
aw.writeText(buffer)
} }
} }
Thyroxine.remap( Thyroxine.remap(
@ -328,13 +296,11 @@ class PhytotelmaPlugin : Plugin<Project> {
TinyV2Writer.write(storage.mappings!!, TinyV2Writer.write(storage.mappings!!,
project.projectDir.resolve("storageMappings.tiny").writer()) project.projectDir.resolve("storageMappings.tiny").writer())
val officialStore = storage.mappings!!.forNamespaces(storage.targetNamespace!!, "official").reverse() val officialStore = storage.mappings!!.forNamespaces(storage.targetNamespace!!, "official").reverse()
TinyV2Writer.write(MappingBundle(officialStore), project.projectDir.resolve("officialStore.tiny").toPath().writer())
val mojOfficial = MojmapProvider.get( val mojOfficial = MojmapProvider.get(
storage.minecraftVersion!!, storage.minecraftVersion!!,
globalCacheDir.resolve("net/minecraft/client/${storage.minecraftVersion}/client-${storage.minecraftVersion}.txt") globalCacheDir.resolve("net/minecraft/client/${storage.minecraftVersion}/client-${storage.minecraftVersion}.txt")
).orElseThrow().reverse().renameDstNamespace(Constants.MOJMAP_NAMESPACE).also { ).orElseThrow().reverse().renameDstNamespace(Constants.MOJMAP_NAMESPACE).data[0].reverse()
TinyV2Writer.write(it,
project.projectDir.resolve("mojmap.tiny").writer())
}.data[0].reverse()
val targetPath = project.layout.buildDirectory.asFile.get().toPath().resolve("remappedMods") val targetPath = project.layout.buildDirectory.asFile.get().toPath().resolve("remappedMods")
.resolve("dev/frogmc/phytotelma/remapped_mods") .resolve("dev/frogmc/phytotelma/remapped_mods")
val remappedPaths = mutableListOf<Path>() val remappedPaths = mutableListOf<Path>()
@ -366,16 +332,28 @@ class PhytotelmaPlugin : Plugin<Project> {
Thyroxine.remap( Thyroxine.remap(
mojOfficial, artifact.file.toPath(), temp, false, defaultRemappingSteps( mojOfficial, artifact.file.toPath(), temp, false, defaultRemappingSteps(
mojmapGameJar mojmapGameJar
) ), mojmapGameJar
) )
Thyroxine.remap( Thyroxine.remap(
officialStore, temp, remappedPath, false, defaultRemappingSteps( officialStore, temp, remappedPath, false, defaultRemappingSteps(
officialJar officialJar
) ), officialJar
) )
Files.deleteIfExists(temp) Files.deleteIfExists(temp)
NestStripper.stripJij(remappedPath) NestStripper.stripJij(remappedPath)
FileSystems.newFileSystem(remappedPath).use { fs ->
val metadata = fs.getPath(Constants.MOD_METADATA_FILE)
tomlParser.parse(metadata, FileNotFoundAction.READ_NOTHING)
.get<String>("frog.extensions.accesswidener")?.let { name ->
val aw = metadata.resolveSibling(name)
remapAccesswidener(mojOfficial, aw)
remapAccesswidener(officialStore, aw)
AccessWidener.checkAW(aw, ProjectStorage.get(project).remappedGameJarPath!!)
}
}
project.dependencies.add( project.dependencies.add(
target.name, target.name,
"dev.frogmc.phytotelma.remapped_mods:$groupname:$artifactVersion" + (classifier?.let { ":$it" } ?: "") "dev.frogmc.phytotelma.remapped_mods:$groupname:$artifactVersion" + (classifier?.let { ":$it" } ?: "")
@ -386,6 +364,43 @@ class PhytotelmaPlugin : Plugin<Project> {
System.setOut(out) System.setOut(out)
} }
private fun remapAccesswidener(mappings: MappingData, aw: Path) {
val mapper = Mapper(mappings) { listOf() }
val buffer = buildString {
aw.forEachLine {
if ((it.contains("\t") || it.contains(" ")) && !it.startsWith("#")) {
val parts = it.split("[\\t #]+".toRegex()).toMutableList()
if (parts.size > 2) {
val type = parts[1]
when (type) {
"class" -> {
parts[2] = mapper.map(parts[2])
}
"field" -> {
parts[3] = mapper.mapFieldName(parts[2], parts[3], parts[4])
parts[4] = mapper.mapDesc(parts[4])
parts[2] = mapper.map(parts[2])
}
"method" -> {
parts[3] = mapper.mapMethodName(parts[2], parts[3], parts[4])
parts[4] = mapper.mapMethodDesc(parts[4])
parts[2] = mapper.map(parts[2])
}
}
appendLine(parts.joinToString(" "))
return@forEachLine
}
}
appendLine(it)
}
}
aw.writeText(buffer)
}
companion object { companion object {
lateinit var globalCacheDir: Path lateinit var globalCacheDir: Path
val tomlParser = TomlParser() val tomlParser = TomlParser()

View file

@ -81,7 +81,7 @@ object AccessWidener {
} }
FileSystems.newFileSystem(gamePath).use { fs -> FileSystems.newFileSystem(gamePath).use { fs ->
reader.lines().toList().forEachIndexed { index, line -> reader.lines().toList().forEachIndexed { index, line ->
val checkString = line.substring(0, line.indexOf("#")) val checkString = if (line.contains("#")) line.substring(0, line.indexOf("#")) else line
if (checkString.isNotEmpty()) { if (checkString.isNotEmpty()) {
val parts = checkString.split(SEPARATOR) val parts = checkString.split(SEPARATOR)
@ -90,9 +90,10 @@ object AccessWidener {
} }
if (parts[1] == "class") { if (parts[1] == "class") {
val target = parts[2] val target = parts[2]
if (fs.getPath(target).notExists()) { if (fs.getPath("/$target.class").notExists()) {
error("AccessWidener validation failed in line ${index + 2}: $line (Invalid target)") error("AccessWidener validation failed in line ${index + 2}: $line (Invalid target)")
} }
return@forEachIndexed
} }
if (parts.size < 5) { if (parts.size < 5) {
error("AccessWidener validation failed in line ${index + 2}: $line (Declaration missing)") error("AccessWidener validation failed in line ${index + 2}: $line (Declaration missing)")
@ -102,16 +103,17 @@ object AccessWidener {
val desc = parts[4] val desc = parts[4]
when (parts[1]) { when (parts[1]) {
"method" -> { "method" -> {
val classReader = ClassReader(fs.getPath(owner).readBytes()) val classReader = ClassReader(fs.getPath("/$owner.class").readBytes())
val node = ClassNode() val node = ClassNode()
classReader.accept(node, 0) classReader.accept(node, 0)
if (node.methods.none { it.name.equals(name) && it.desc.equals(desc) }) { if (node.methods.none { it.name.equals(name) && it.desc.equals(desc) }) {
error("AccessWidener validation failed in line ${index + 2}: $line (Could not find target method)") val similar = "\nSimilar methods:\n ${node.methods.filter { it.name.equals(name) || it.desc.equals(desc) }.joinToString("\n") { it.name+" ${it.desc}" }}"
error("AccessWidener validation failed in line ${index + 2}: $line (Could not find target method)"+ if (node.methods.any { it.name.equals(name) || it.desc.equals(desc) }) similar else "")
} }
} }
"field" -> { "field" -> {
val classReader = ClassReader(fs.getPath(owner).readBytes()) val classReader = ClassReader(fs.getPath("/$owner.class").readBytes())
val node = ClassNode() val node = ClassNode()
classReader.accept(node, 0) classReader.accept(node, 0)
if (node.fields.none { it.name.equals(name) && it.desc.equals(desc) }) { if (node.fields.none { it.name.equals(name) && it.desc.equals(desc) }) {
@ -136,7 +138,8 @@ object AccessWidener {
private fun readTransitiveAW(path: Path): List<String> { private fun readTransitiveAW(path: Path): List<String> {
return path.bufferedReader(StandardCharsets.UTF_8).takeIf { HEADER.test(it.readLine() ?: "") }?.lines() return path.bufferedReader(StandardCharsets.UTF_8).takeIf { HEADER.test(it.readLine() ?: "") }?.lines()
?.filter { it.startsWith("transitive-") }?.toList() ?: emptyList() ?.filter { it.startsWith("transitive-") }
?.map { it.replace("transitive-", "") }?.toList() ?: emptyList()
} }
private fun readAllAWs(project: Project): Stream<Entry> { private fun readAllAWs(project: Project): Stream<Entry> {

View file

@ -22,21 +22,6 @@ class MixinAnnotationRemapper(
private var target: String? = null private var target: String? = null
private var targetNode: ClassNode? = null private var targetNode: ClassNode? = null
override fun visit(
version: Int,
access: Int,
name: String,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
super.visit(version, access, name, signature, superName, interfaces)
}
override fun visitInnerClass(name: String?, outerName: String?, innerName: String?, access: Int) {
super.visitInnerClass(name, outerName, innerName, access)
}
override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? { override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
if (descriptor == null || descriptor != "Lorg/spongepowered/asm/mixin/Mixin;") { if (descriptor == null || descriptor != "Lorg/spongepowered/asm/mixin/Mixin;") {
return super.visitAnnotation(descriptor, visible) return super.visitAnnotation(descriptor, visible)
@ -157,29 +142,26 @@ class MixinAnnotationRemapper(
if (desc == null) { if (desc == null) {
val method = owner.methods.find { it.name == methodName } val method = owner.methods.find { it.name == methodName }
if (method != null) { if (method != null) {
newVal = mapper.mapMethodName( val newName = mapper.mapMethodName(
owner.name, owner.name,
methodName, methodName,
method.desc method.desc
) + mapper.mapMethodDesc(method.desc) )
println("Mapped mixin target (method) to new name: $newVal from $methodName (with found ${method.desc})") newVal = newName + mapper.mapMethodDesc(method.desc)
} }
} else { } else {
newVal = mapper.mapMethodName( val newName = mapper.mapMethodName(
owner.name, owner.name,
methodName, methodName,
desc desc
) + mapper.mapMethodDesc(desc) )
newVal = newName + mapper.mapMethodDesc(desc)
} }
} else if (name == "target") { } else if (name == "target") {
newVal = remapMemberInfo(value, mapper) newVal = remapMemberInfo(value, mapper)
println("target remap: $value to $newVal")
} }
} }
if (newVal != value) {
println("new annotation value: $newVal instead of $value")
}
super.visit(name, newVal) super.visit(name, newVal)
} }