Bump as 3.0, migrate to archtiectury runtime transformer

This commit is contained in:
shedaniel
2021-02-14 21:57:26 +08:00
parent 21d2a47623
commit c9abaea8ae
16 changed files with 252 additions and 1030 deletions

View File

@@ -26,10 +26,9 @@ logger.lifecycle(":building architectury plugin v${version}")
sourceCompatibility = targetCompatibility = 1.8
repositories {
jcenter()
maven { url "https://maven.fabricmc.net/" }
maven { url "https://files.minecraftforge.net/maven/" }
maven { url "https://dl.bintray.com/shedaniel/cloth/" }
maven { url "https://maven.shedaniel.me/" }
gradlePluginPortal()
}
@@ -44,6 +43,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72"
implementation "org.jetbrains.kotlin:kotlin-reflect:1.3.72"
implementation "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:0.10"
implementation "me.shedaniel:architectury-transformer:$transformer_version"
implementation "me.shedaniel:forgified-fabric-loom:$loom_version"
runtime "me.shedaniel:forgified-fabric-loom:$loom_version"
implementation "net.fabricmc:tiny-remapper:0.3.0.70"

View File

@@ -1,3 +1,4 @@
kotlin.code.style=official
loom_version=0.6.54
base_version=2.0
loom_version=0.6.67
transformer_version=2.0.7
base_version=3.0

View File

@@ -1,6 +1,8 @@
package me.shedaniel.architect.plugin
import me.shedaniel.architect.plugin.transformers.*
import me.shedaniel.architect.plugin.transformers.AddRefmapName
import me.shedaniel.architect.plugin.transformers.RemapMixinVariables
import me.shedaniel.architectury.transformer.transformers.*
import net.fabricmc.loom.util.LoggerFilter
import org.gradle.api.Plugin
import org.gradle.api.Project
@@ -43,49 +45,32 @@ class ArchitectPlugin : Plugin<Project> {
project.extensions.create("architectury", ArchitectPluginExtension::class.java, project)
project.configurations.create("transformFabric")
project.configurations.create("transformForge")
project.tasks.register("transformProductionFabric", TransformingTask::class.java) {
it.group = "Architectury"
it(RemapMixinVariables)
it(TransformExpectPlatform)
it(TransformInjectables)
it(AddRefmapName)
}
project.tasks.register("transformDevelopmentFabric", TransformingTask::class.java) {
it.group = "Architectury"
it(GenerateFakeFabricModJson)
it(TransformExpectPlatform)
it(TransformInjectables)
it += RemapMixinVariables(project)
it += TransformExpectPlatform()
it += RemapInjectables()
it += AddRefmapName(project)
}
project.tasks.register("transformProductionForge", TransformingTask::class.java) {
it.group = "Architectury"
it(RemapMixinVariables)
it(TransformExpectPlatform)
it(TransformInjectables)
it(AddRefmapName)
it += RemapMixinVariables(project)
it += TransformExpectPlatform()
it += RemapInjectables()
it += AddRefmapName(project)
it(TransformForgeBytecode)
it(RemoveFabricModJson)
it(TransformForgeEnvironment)
it(FixForgeMixin)
}
project.tasks.register("transformDevelopmentForge", TransformingTask::class.java) {
it.group = "Architectury"
it(TransformExpectPlatform)
it(TransformInjectables)
it(TransformForgeBytecode)
it(RemoveFabricModJson)
it(TransformForgeEnvironment)
it(GenerateFakeForgeMod)
it(FixForgeMixin)
it += TransformForgeAnnotations()
it += TransformForgeEnvironment()
it += FixForgeMixin()
}
project.repositories.apply {
mavenCentral()
maven { it.url = URI("https://dl.bintray.com/shedaniel/cloth") }
maven { it.url = URI("https://maven.shedaniel.me/") }
}
}
}

View File

@@ -2,41 +2,177 @@
package me.shedaniel.architect.plugin
import me.shedaniel.architectury.transformer.Transformer
import me.shedaniel.architectury.transformer.transformers.*
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.task.RemapJarTask
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import java.io.File
import java.lang.IllegalStateException
import java.nio.file.Path
import java.util.*
import java.util.function.Consumer
import java.util.jar.JarOutputStream
import java.util.jar.Manifest
open class ArchitectPluginExtension(val project: Project) {
var transformerVersion = "2.0.7"
var minecraft = ""
var injectInjectables = true
private val transforms = mutableMapOf<String, Transform>()
private var transformedLoom = false
private val agentFile by lazy {
project.gradle.rootProject.file(".gradle/architectury/architectury-transformer-agent.jar").also {
it.parentFile.mkdirs()
}
}
private val mainClassTransformerFile by lazy {
project.file(".gradle/architectury/.main_class").also {
it.parentFile.mkdirs()
}
}
private val runtimeTransformerFile by lazy {
project.file(".gradle/architectury/.transforms").also {
it.parentFile.mkdirs()
}
}
private val propertiesTransformerFile by lazy {
project.file(".gradle/architectury/.properties").also {
it.parentFile.mkdirs()
}
}
init {
project.afterEvaluate {
if (transforms.isNotEmpty()) {
val transformPaths = mutableMapOf<Path, List<Class<Transformer>>>()
for (transform in transforms.values) {
project.configurations.getByName(transform.configName).forEach {
transformPaths[it.toPath()] = transform.transformers
}
}
transformPaths.asSequence().flatMap { it.value.asSequence().map { c -> it.key to c } }
.joinToString(File.pathSeparator) { "${it.first}|${it.second.name}" }
.also {
runtimeTransformerFile.writeText(it)
}
}
val properties = Properties()
properties().forEach { (key, value) ->
System.setProperty(key, value)
properties.setProperty(key, value)
}
propertiesTransformerFile.writer().use {
properties.store(it, "Architectury Runtime Transformer Properties")
}
}
}
private fun properties(): Map<String, String> {
val loom = project.extensions.findByType(LoomGradleExtension::class.java) ?: return mapOf()
return mutableMapOf(
BuiltinProperties.MIXIN_MAPPINGS to loom.allMixinMappings.joinToString(File.pathSeparator),
BuiltinProperties.INJECT_INJECTABLES to injectInjectables.toString(),
BuiltinProperties.UNIQUE_IDENTIFIER to project.projectUniqueIdentifier(),
BuiltinProperties.COMPILE_CLASSPATH to project.configurations.getByName("compileClasspath")
.joinToString(File.pathSeparator),
BuiltinProperties.MAPPINGS_WITH_SRG to loom.mappingsProvider.tinyMappingsWithSrg.toString(),
BuiltinProperties.REFMAP_NAME to loom.refmapName,
BuiltinProperties.MCMETA_VERSION to "4"
)
}
fun transform(name: String, action: Action<Transform>) {
transforms.getOrPut(name) {
Transform("development" + name.capitalize()).also { transform ->
project.configurations.create(transform.configName)
if (!transformedLoom) {
val architecturyJavaAgents = project.configurations.create("architecturyJavaAgents") {
project.configurations.getByName("runtimeOnly").extendsFrom(it)
}
transformedLoom = true
with(project.dependencies) {
add("runtimeOnly", "me.shedaniel:architectury-transformer:$transformerVersion:runtime")
add("architecturyJavaAgents", "me.shedaniel:architectury-transformer:$transformerVersion:agent")
}
val loom = project.extensions.getByType(LoomGradleExtension::class.java)
loom.settingsPostEdit.add(Consumer { config ->
val s = config.mainClass
config.mainClass = "me.shedaniel.architectury.transformer.TransformerRuntime"
mainClassTransformerFile.writeText(s)
config.vmArgs += " -Darchitectury.main.class=$mainClassTransformerFile"
config.vmArgs += " -Darchitectury.runtime.transformer=$runtimeTransformerFile"
config.vmArgs += " -Darchitectury.properties=$propertiesTransformerFile"
config.vmArgs += " -Djdk.attach.allowAttachSelf=true"
if (architecturyJavaAgents.toList().size == 1) {
architecturyJavaAgents.first().copyTo(agentFile, overwrite = true)
config.vmArgs += " -javaagent:${agentFile.absolutePath}"
} else {
throw IllegalStateException("Illegal Count of Architectury Java Agents! " + architecturyJavaAgents.toList().joinToString(", "))
}
})
}
}
}.also {
action.execute(it)
}
}
fun fabric() {
transform("fabric", Action {
it.setupFabricTransforms()
})
}
fun forge() {
transform("forge", Action {
it.setupForgeTransforms()
})
}
fun common() {
common(true)
common {}
}
data class CommonSettings(
var forgeEnabled: Boolean = true
)
fun platformSetupLoomIde() {
val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
loomExtension.autoGenIDERuns = true
loomExtension.runConfigs.forEach { it.isIdeConfigGenerated = true }
loomExtension.runConfigs.whenObjectAdded { it.isIdeConfigGenerated = true }
loomExtension.addTaskBeforeRun("\$PROJECT_DIR\$/${project.name}:classes")
}
fun common(forgeEnabled: Boolean) {
common {
this.forgeEnabled = forgeEnabled
}
}
fun common(action: CommonSettings.() -> Unit) {
common(Action { it.action() })
}
fun common(action: Action<CommonSettings>) {
val settings = CommonSettings().also { action.execute(it) }
if (injectInjectables) {
with(project.dependencies) {
add("compileOnly", "me.shedaniel:architectury-injectables:1.0.4")
}
}
if (forgeEnabled) {
if (settings.forgeEnabled) {
project.configurations.create("transformProductionForge")
project.configurations.create("transformDevelopmentForge")
}
project.configurations.create("transformProductionFabric")
project.configurations.create("transformDevelopmentFabric")
val buildTask = project.tasks.getByName("build")
val jarTask = project.tasks.getByName("jar") {
@@ -55,19 +191,6 @@ open class ArchitectPluginExtension(val project: Project) {
buildTask.dependsOn(it)
it.outputs.upToDateWhen { false }
} as TransformingTask
val transformDevelopmentFabricTask = project.tasks.getByName("transformDevelopmentFabric") {
it as TransformingTask
it.archiveClassifier.set("transformDevelopmentFabric")
it.input.set(jarTask.archiveFile.get())
project.artifacts.add("transformDevelopmentFabric", it)
it.dependsOn(jarTask)
buildTask.dependsOn(it)
it.outputs.upToDateWhen { false }
} as TransformingTask
transformProductionFabricTask.dependsOn(transformDevelopmentFabricTask)
val remapJarTask = project.tasks.getByName("remapJar") {
it as RemapJarTask
@@ -78,7 +201,7 @@ open class ArchitectPluginExtension(val project: Project) {
it.mustRunAfter(transformProductionFabricTask)
} as RemapJarTask
if (forgeEnabled) {
if (settings.forgeEnabled) {
val transformProductionForgeTask = project.tasks.getByName("transformProductionForge") {
it as TransformingTask
@@ -91,30 +214,12 @@ open class ArchitectPluginExtension(val project: Project) {
it.outputs.upToDateWhen { false }
} as TransformingTask
val transformDevelopmentForgeTask = project.tasks.getByName("transformDevelopmentForge") {
it as TransformingTask
it.input.set(jarTask.archiveFile.get())
it.archiveClassifier.set("transformDevelopmentForge")
project.artifacts.add("transformDevelopmentForge", it) { artifact ->
artifact.builtBy(it)
}
it.dependsOn(jarTask)
buildTask.dependsOn(it)
it.outputs.upToDateWhen { false }
} as TransformingTask
transformProductionForgeTask.dependsOn(transformDevelopmentForgeTask)
transformProductionForgeTask.archiveFile.get().asFile.takeUnless { it.exists() }?.createEmptyJar()
transformDevelopmentForgeTask.archiveFile.get().asFile.takeUnless { it.exists() }?.createEmptyJar()
project.extensions.getByType(LoomGradleExtension::class.java).generateSrgTiny = true
}
transformProductionFabricTask.archiveFile.get().asFile.takeUnless { it.exists() }?.createEmptyJar()
transformDevelopmentFabricTask.archiveFile.get().asFile.takeUnless { it.exists() }?.createEmptyJar()
}
}
@@ -122,3 +227,27 @@ private fun File.createEmptyJar() {
parentFile.mkdirs()
JarOutputStream(outputStream(), Manifest()).close()
}
data class Transform(val configName: String, val transformers: MutableList<Class<Transformer>> = mutableListOf()) {
fun setupFabricTransforms() {
this += GenerateFakeFabricMod::class.java
this += TransformExpectPlatform::class.java
this += RemapInjectables::class.java
}
fun setupForgeTransforms() {
this += TransformExpectPlatform::class.java
this += RemapInjectables::class.java
this += TransformForgeAnnotations::class.java
this += TransformForgeEnvironment::class.java
this += GenerateFakeForgeMod::class.java
this += FixForgeMixin::class.java
}
operator fun <T : Transformer> plusAssign(transformer: Class<T>) {
transformers.add(transformer as Class<Transformer>)
}
fun <T : Transformer> add(transformer: Class<T>) = plusAssign(transformer as Class<Transformer>)
}

View File

@@ -1,97 +1,43 @@
package me.shedaniel.architect.plugin
import me.shedaniel.architect.plugin.utils.GradleSupport
import me.shedaniel.architectury.transformer.Transform
import me.shedaniel.architectury.transformer.Transformer
import org.gradle.api.Project
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
import org.gradle.jvm.tasks.Jar
import java.io.File
import java.io.ObjectOutputStream
import java.io.Serializable
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.util.*
import kotlin.properties.Delegates
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
import kotlin.time.nanoseconds
open class TransformingTask : Jar() {
@InputFile
val input: RegularFileProperty = GradleSupport.getFileProperty(project)
@Input
@Internal
val transformers = mutableListOf<Transformer>()
@ExperimentalTime
@TaskAction
fun doTask() {
val input: Path = this.input.asFile.get().toPath()
val taskOutputs = transformers.mapIndexed { index, _ ->
project.file("build")
.resolve("architectury-plugin/" + input.toFile().nameWithoutExtension + "-intermediate-${index}.jar")
.toPath()
}
val output: Path = this.archiveFile.get().asFile.toPath()
transformers.forEachIndexed { index, transformer ->
val i = if (index == 0) input else taskOutputs[index - 1]
val o = taskOutputs[index]
Files.deleteIfExists(o)
Files.createDirectories(o.parent)
runCatching {
var skipped = false
measureTime {
try {
transformer(project, i, o)
} catch (ignored: TransformerStepSkipped) {
skipped = true
}
if (index != 0) {
Files.deleteIfExists(i)
}
}.let { duration ->
if (skipped) {
project.logger.lifecycle(":skipped transforming step ${index + 1}/${transformers.size} [${transformer::class.simpleName}] in $duration")
} else {
project.logger.lifecycle(":finished transforming step ${index + 1}/${transformers.size} [${transformer::class.simpleName}] in $duration")
}
}
}.onFailure {
throw RuntimeException(
"Failed transformer step ${index + 1}/${transformers.size} [${transformer::class.simpleName}]",
it
)
}
runCatching {
o.toFile().also { it.renameTo(it) }
}.onFailure {
throw RuntimeException(
"Transformer step ${index + 1}/${transformers.size} [${transformer::class.simpleName}] did not properly close the output file!",
it
)
}
}
Files.move(taskOutputs.last(), output, StandardCopyOption.REPLACE_EXISTING)
Transform.runTransformers(input, output, transformers)
}
operator fun invoke(transformer: Transformer) {
transformers.add(transformer)
}
}
@ExperimentalTime
private inline fun measureTime(block: () -> Unit): Duration {
val current = System.nanoTime()
block()
val finished = System.nanoTime()
return (finished - current).nanoseconds
operator fun plusAssign(transformer: Transformer) {
transformers.add(transformer)
}
}
fun Project.projectUniqueIdentifier(): String {
@@ -109,13 +55,3 @@ fun Project.projectUniqueIdentifier(): String {
if (project.rootProject != project) name = project.rootProject.name + "_" + name
return "architectury_inject_${name}_$id".filter { Character.isJavaIdentifierPart(it) }
}
interface Transformer : Serializable {
operator fun invoke(project: Project, input: Path, output: Path)
@JvmDefault
fun writeObject(s: ObjectOutputStream) {
}
}
object TransformerStepSkipped : Throwable()

View File

@@ -1,44 +1,57 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import com.google.gson.JsonObject
import me.shedaniel.architectury.transformer.Transformer
import me.shedaniel.architectury.transformer.TransformerStepSkipped
import me.shedaniel.architectury.transformer.transformers.base.AssetEditTransformer
import me.shedaniel.architectury.transformer.transformers.base.edit.AssetEditSink
import me.shedaniel.architectury.transformer.transformers.base.edit.TransformerContext
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.LoomGradlePlugin
import org.gradle.api.Project
import java.io.ByteArrayInputStream
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
object AddRefmapName : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
Files.copy(input, output)
class AddRefmapName(private val project: Project) : AssetEditTransformer {
override fun doEdit(context: TransformerContext, sink: AssetEditSink) {
val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
var refmapHelperClass: Class<*>? = null
runCatching {
refmapHelperClass = Class.forName("net.fabricmc.loom.util.MixinRefmapHelper")
}.onFailure {
runCatching {
refmapHelperClass = Class.forName("net.fabricmc.loom.build.MixinRefmapHelper")
}.onFailure {
throw ClassNotFoundException("Failed to find MixinRefmapHelper!")
val mixins = mutableSetOf<String>()
sink.handle { path, bytes ->
// Check JSON file in root directory
if (path.endsWith(".json") && !path.contains("/") && !path.contains("\\")) {
try {
val json =
LoomGradlePlugin.GSON.fromJson(ByteArrayInputStream(bytes).reader(), JsonObject::class.java)
if (json != null) {
val hasMixins = json.has("mixins") && json["mixins"].isJsonArray
val hasClient = json.has("client") && json["client"].isJsonArray
val hasServer = json.has("server") && json["server"].isJsonArray
if (json.has("package") && (hasMixins || hasClient || hasServer)) {
if (!json.has("refmap") || !json.has("minVersion")) {
mixins.add(path)
}
}
}
} catch (_: Exception) {
}
}
}
mixins.forEach { path ->
sink.transformFile(path) {
val json: JsonObject = LoomGradlePlugin.GSON.fromJson<JsonObject>(
ByteArrayInputStream(it).reader(),
JsonObject::class.java
)
val method = refmapHelperClass!!.getDeclaredMethod(
"addRefmapName",
String::class.java,
String::class.java,
Path::class.java
)
if (
method.invoke(
null,
loomExtension.getRefmapName(),
loomExtension.mixinJsonVersion,
output
) as Boolean
) {
project.logger.debug("Transformed mixin reference maps in output JAR!")
} else {
throw TransformerStepSkipped
if (!json.has("refmap")) {
json.addProperty("refmap", loomExtension.getRefmapName())
}
LoomGradlePlugin.GSON.toJson(json).toByteArray()
}
}
}
}

View File

@@ -1,220 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import net.fabricmc.loom.LoomGradleExtension
import org.gradle.api.Project
import org.zeroturnaround.zip.ZipUtil
import java.io.File
import java.io.IOException
import java.io.InputStreamReader
import java.io.StringReader
import java.nio.file.Files
import java.nio.file.Path
import java.util.jar.Manifest
import java.util.zip.ZipEntry
object FixForgeMixin : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
Files.copy(input, output)
fixMixins(project, output.toFile())
}
private fun fixMixins(project: Project, output: File) {
val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
val gson = GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create()
val mixinConfigs = mutableListOf<String>()
val refmap = loomExtension.getRefmapName()
ZipUtil.iterate(output) { stream, entry ->
if (!entry.isDirectory && entry.name.endsWith(".json") &&
!entry.name.contains("/") && !entry.name.contains("\\")
) {
try {
InputStreamReader(stream).use { reader ->
val json: JsonObject? = gson.fromJson<JsonObject>(reader, JsonObject::class.java)
if (json != null) {
val hasMixins = json.has("mixins") && json["mixins"].isJsonArray
val hasClient = json.has("client") && json["client"].isJsonArray
val hasServer = json.has("server") && json["server"].isJsonArray
if (json.has("package") && (hasMixins || hasClient || hasServer)) {
mixinConfigs.add(entry.name)
}
}
}
} catch (ignored: Exception) {
}
}
}
if (mixinConfigs.isNotEmpty()) {
if (ZipUtil.containsEntry(output, "META-INF/MANIFEST.MF")) {
ZipUtil.transformEntry(output, "META-INF/MANIFEST.MF") { input, zipEntry, out ->
val manifest = Manifest(input)
manifest.mainAttributes.putValue("MixinConfigs", mixinConfigs.joinToString(","))
out.putNextEntry(ZipEntry(zipEntry.name))
manifest.write(out)
out.closeEntry()
}
}
}
if (ZipUtil.containsEntry(output, refmap)) {
ZipUtil.transformEntry(output, refmap) { input, zipEntry, out ->
val refmapElement: JsonObject = JsonParser().parse(InputStreamReader(input)).asJsonObject.deepCopy()
if (refmapElement.has("mappings")) {
refmapElement["mappings"].asJsonObject.entrySet().forEach { (_, value) ->
remapRefmap(project, value.asJsonObject)
}
}
if (refmapElement.has("data")) {
val data = refmapElement["data"].asJsonObject
if (data.has("named:intermediary")) {
data.add("searge", data["named:intermediary"].deepCopy().also {
it.asJsonObject.entrySet().forEach { (_, value) ->
remapRefmap(project, value.asJsonObject)
}
})
data.remove("named:intermediary")
}
}
out.putNextEntry(ZipEntry(zipEntry.name))
out.write(gson.toJson(refmapElement).toByteArray())
out.closeEntry()
}
} else {
project.logger.info("Failed to locate refmap: $refmap")
if (mixinConfigs.isEmpty()) {
throw TransformerStepSkipped
}
}
}
private fun remapRefmap(project: Project, obj: JsonObject) {
val srg = project.extensions.getByType(LoomGradleExtension::class.java).mappingsProvider.mappingsWithSrg
val methodPattern = "L(.*);(.*)(\\(.*)".toRegex()
val methodPatternWithoutClass = "(.*)(\\(.*)".toRegex()
val fieldPattern = "L(.*);(.*):(.*)".toRegex()
val fieldPatternWithoutClass = "(.*):(.*)".toRegex()
obj.keySet().forEach { key ->
val originalRef = obj[key].asString
val methodMatch = methodPattern.matchEntire(originalRef)
val fieldMatch = fieldPattern.matchEntire(originalRef)
val fieldMatchWithoutClass = fieldPatternWithoutClass.matchEntire(originalRef)
val methodMatchWithoutClass = methodPatternWithoutClass.matchEntire(originalRef)
val classMatch = srg.classes.firstOrNull { it.getName("intermediary") == originalRef }
when {
methodMatch != null -> {
val matchedClass =
srg.classes.firstOrNull { it.getName("intermediary") == methodMatch.groups[1]!!.value }
val replacementName: String = srg.classes.asSequence()
.flatMap { it.methods.asSequence() }
.filter { it.getName("intermediary") == methodMatch.groups[2]!!.value }
.firstOrNull { it.getDescriptor("intermediary") == methodMatch.groups[3]!!.value }
?.getName("srg") ?: methodMatch.groups[2]!!.value
obj.addProperty(
key, originalRef
.replaceFirst(
methodMatch.groups[1]!!.value,
matchedClass?.getName("srg") ?: methodMatch.groups[1]!!.value
)
.replaceFirst(methodMatch.groups[2]!!.value, replacementName)
.replaceFirst(methodMatch.groups[3]!!.value, methodMatch.groups[3]!!.value.remapDescriptor {
srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg")
?: it
})
)
}
fieldMatch != null -> {
val matchedClass =
srg.classes.firstOrNull { it.getName("intermediary") == fieldMatch.groups[1]!!.value }
val replacementName: String = srg.classes.asSequence()
.flatMap { it.fields.asSequence() }
.filter { it.getName("intermediary") == fieldMatch.groups[2]!!.value }
.firstOrNull { it.getDescriptor("intermediary") == fieldMatch.groups[3]!!.value }
?.getName("srg") ?: fieldMatch.groups[2]!!.value
obj.addProperty(
key, originalRef
.replaceFirst(
fieldMatch.groups[1]!!.value,
matchedClass?.getName("srg") ?: fieldMatch.groups[1]!!.value
)
.replaceFirst(fieldMatch.groups[2]!!.value, replacementName)
.replaceFirst(fieldMatch.groups[3]!!.value, fieldMatch.groups[3]!!.value.remapDescriptor {
srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg")
?: it
})
)
}
fieldMatchWithoutClass != null -> {
val replacementName: String = srg.classes.asSequence()
.flatMap { it.fields.asSequence() }
.filter { it.getName("intermediary") == fieldMatchWithoutClass.groups[1]!!.value }
.firstOrNull { it.getDescriptor("intermediary") == fieldMatchWithoutClass.groups[2]!!.value }
?.getName("srg") ?: fieldMatchWithoutClass.groups[1]!!.value
obj.addProperty(
key, originalRef
.replaceFirst(fieldMatchWithoutClass.groups[1]!!.value, replacementName)
.replaceFirst(fieldMatchWithoutClass.groups[2]!!.value, fieldMatchWithoutClass.groups[2]!!.value.remapDescriptor {
srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg")
?: it
})
)
}
methodMatchWithoutClass != null -> {
val replacementName: String = srg.classes.asSequence()
.flatMap { it.methods.asSequence() }
.filter { it.getName("intermediary") == methodMatchWithoutClass.groups[1]!!.value }
.firstOrNull { it.getDescriptor("intermediary") == methodMatchWithoutClass.groups[2]!!.value }
?.getName("srg") ?: methodMatchWithoutClass.groups[1]!!.value
obj.addProperty(
key, originalRef
.replaceFirst(methodMatchWithoutClass.groups[1]!!.value, replacementName)
.replaceFirst(
methodMatchWithoutClass.groups[2]!!.value,
methodMatchWithoutClass.groups[2]!!.value.remapDescriptor {
srg.classes.firstOrNull { def -> def.getName("intermediary") == it }?.getName("srg")
?: it
})
)
}
classMatch != null -> obj.addProperty(key, classMatch.getName("srg"))
else -> project.logger.warn("Failed to remap refmap value: $originalRef")
}
}
}
private fun String.remapDescriptor(classMappings: (String) -> String): String {
return try {
val reader = StringReader(this)
val result = StringBuilder()
var insideClassName = false
val className = StringBuilder()
while (true) {
val c: Int = reader.read()
if (c == -1) {
break
}
if (c == ';'.toInt()) {
insideClassName = false
result.append(classMappings(className.toString()))
}
if (insideClassName) {
className.append(c.toChar())
} else {
result.append(c.toChar())
}
if (!insideClassName && c == 'L'.toInt()) {
insideClassName = true
className.setLength(0)
}
}
result.toString()
} catch (e: IOException) {
throw AssertionError(e)
}
}
}

View File

@@ -1,31 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import org.gradle.api.Project
import org.zeroturnaround.zip.ByteSource
import org.zeroturnaround.zip.ZipUtil
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
object GenerateFakeFabricModJson : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
Files.copy(input, output)
val fakeModId = "generated_" + UUID.randomUUID().toString().filterNot { it == '-' }.take(7)
ZipUtil.addOrReplaceEntries(
output.toFile(), arrayOf(
ByteSource(
"fabric.mod.json", """{
"schemaVersion": 1,
"id": "$fakeModId",
"name": "Generated Mod (Please Ignore)",
"version": "1.0.0",
"custom": {
"fabric-loom:generated": true
}
}""".toByteArray()
)
)
)
}
}

View File

@@ -1,52 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import org.gradle.api.Project
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import org.zeroturnaround.zip.ByteSource
import org.zeroturnaround.zip.ZipUtil
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
object GenerateFakeForgeMod : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
val fakeModId = "generated_" + UUID.randomUUID().toString().filterNot { it == '-' }.take(7)
Files.copy(input, output)
ZipUtil.addEntries(
output.toFile(), arrayOf(
ByteSource(
"META-INF/mods.toml",
"""modLoader = "javafml"
loaderVersion = "[33,)"
license = "Generated"
[[mods]]
modId = "$fakeModId"""".toByteArray()
),
ByteSource(
"pack.mcmeta",
"""{"pack":{"description":"Generated","pack_format":4}}""".toByteArray()
),
ByteSource(
"generated/$fakeModId.class",
ClassWriter(0).let { classWriter ->
classWriter.visit(52, Opcodes.ACC_PUBLIC, "generated/$fakeModId", null, "java/lang/Object", null)
val modAnnotation = classWriter.visitAnnotation("Lnet/minecraftforge/fml/common/Mod;", false)
modAnnotation.visit("value", fakeModId)
modAnnotation.visitEnd()
classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, arrayOf()).also {
it.visitVarInsn(Opcodes.ALOAD, 0)
it.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
it.visitInsn(Opcodes.RETURN)
it.visitMaxs(1, 1)
it.visitEnd()
}
classWriter.visitEnd()
classWriter.toByteArray()
}
)
)
)
}
}

View File

@@ -1,65 +1,21 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import me.shedaniel.architect.plugin.utils.validateJarFs
import me.shedaniel.architectury.transformer.shadowed.impl.net.fabricmc.tinyremapper.IMappingProvider
import me.shedaniel.architectury.transformer.shadowed.impl.net.fabricmc.tinyremapper.TinyUtils
import me.shedaniel.architectury.transformer.transformers.base.TinyRemapperTransformer
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.util.LoggerFilter
import net.fabricmc.tinyremapper.OutputConsumerPath
import net.fabricmc.tinyremapper.TinyRemapper
import net.fabricmc.tinyremapper.TinyUtils
import org.gradle.api.Project
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
object RemapMixinVariables : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
class RemapMixinVariables(private val project: Project) : TinyRemapperTransformer {
override fun collectMappings(): MutableList<IMappingProvider> {
val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
var remapperBuilder = TinyRemapper.newRemapper()
var requiresRemap = false
for (mixinMapFile in loomExtension.allMixinMappings) {
if (mixinMapFile.exists()) {
if (!requiresRemap) {
requiresRemap = Files.readAllLines(mixinMapFile.toPath()).count { it.isNotBlank() } > 1
}
remapperBuilder = remapperBuilder.withMappings(
TinyUtils.createTinyMappingProvider(
mixinMapFile.toPath(),
"named",
"intermediary"
)
)
}
}
if (!requiresRemap) {
Files.copy(input, output)
throw TransformerStepSkipped
}
val remapper = remapperBuilder.build()
val classpathFiles: Set<File> = LinkedHashSet(
project.configurations.getByName("compileClasspath").files
)
val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() }.filter { p: Path ->
input != p && Files.exists(p)
}.toList().toTypedArray()
LoggerFilter.replaceSystemOut()
try {
project.validateJarFs(output)
OutputConsumerPath.Builder(output).build().use { outputConsumer ->
outputConsumer.addNonClassFiles(input)
remapper.readClassPath(*classpath)
remapper.readInputs(input)
remapper.apply(outputConsumer)
}
} catch (e: Exception) {
throw RuntimeException("Failed to remap $input to $output", e)
} finally {
remapper.finish()
}
return loomExtension.allMixinMappings.asSequence().filter(File::exists).map {
TinyUtils.createTinyMappingProvider(
it.toPath(),
"named",
"intermediary"
)
}.toMutableList()
}
}

View File

@@ -1,19 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import org.gradle.api.Project
import org.zeroturnaround.zip.ZipUtil
import java.nio.file.Files
import java.nio.file.Path
object RemoveFabricModJson : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
Files.copy(input, output)
if (ZipUtil.containsEntry(output.toFile(), "fabric.mod.json")) {
ZipUtil.removeEntry(output.toFile(), "fabric.mod.json")
} else {
throw TransformerStepSkipped
}
}
}

View File

@@ -1,206 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.ArchitectPluginExtension
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.projectUniqueIdentifier
import me.shedaniel.architect.plugin.utils.ClassTransformer
import me.shedaniel.architect.plugin.utils.Transform
import org.gradle.api.Project
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Handle
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.ClassRemapper
import org.objectweb.asm.commons.Remapper
import org.objectweb.asm.tree.*
import org.zeroturnaround.zip.ZipUtil
import java.io.InputStream
import java.lang.invoke.CallSite
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
import java.nio.file.Path
import java.util.zip.ZipEntry
object TransformExpectPlatform : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
Transform.transform(input, output, transformExpectPlatform(project))
}
fun transformExpectPlatform(project: Project): ClassTransformer {
val projectUniqueIdentifier by lazy { project.projectUniqueIdentifier() }
var injectedClass = !project.extensions.getByType(ArchitectPluginExtension::class.java).injectInjectables
return { clazz, classAdder ->
if (!injectedClass) {
injectedClass = true
Transform::class.java.getResourceAsStream("/annotations-inject/injection.jar").use { stream ->
ZipUtil.iterate(stream) { input: InputStream, entry: ZipEntry ->
if (entry.name.endsWith(".class")) {
val newName = "$projectUniqueIdentifier/${
entry.name.substringBeforeLast(".class").substringAfterLast('/')
}"
classAdder(newName, input.readBytes().let {
val node = ClassNode(Opcodes.ASM8)
ClassReader(it).accept(node, ClassReader.EXPAND_FRAMES)
val writer = ClassWriter(ClassWriter.COMPUTE_MAXS)
val remapper = ClassRemapper(writer, object : Remapper() {
override fun map(internalName: String?): String {
if (internalName?.startsWith("me/shedaniel/architect/plugin/callsite") == true) {
return internalName.replace(
"me/shedaniel/architect/plugin/callsite",
projectUniqueIdentifier
)
}
return super.map(internalName)
}
})
node.apply {
name = newName
}.accept(remapper)
writer.toByteArray()
})
}
}
}
}
clazz.methods.mapNotNull { method ->
when {
method?.visibleAnnotations?.any { it.desc == TransformInjectables.expectPlatform } == true -> method to "me/shedaniel/architectury/PlatformMethods"
method?.invisibleAnnotations?.any { it.desc == TransformInjectables.expectPlatformNew } == true -> {
method to "$projectUniqueIdentifier/PlatformMethods"
}
else -> null
}
}.forEach { (method, platformMethodsClass) ->
if (method.access and Opcodes.ACC_STATIC == 0) {
System.err.println("@ExpectPlatform can only apply to static methods!")
} else {
method.instructions.clear()
val endOfDesc = method.desc.lastIndexOf(')')
val returnValue = method.desc.substring(endOfDesc + 1)
val args = method.desc.substring(1, endOfDesc)
var cursor = 0
var inClass = false
var index = 0
while (cursor < args.length) {
val char = args[cursor]
if (inClass) {
if (char == ';') {
method.instructions.addLoad(char, index++)
inClass = false
}
} else when (char) {
'[' -> Unit
'L' -> inClass = true
else -> method.instructions.addLoad(char, when (char) {
'J', 'D' -> index.also { index += 2 }
else -> index++
})
}
cursor++
}
val methodType = MethodType.methodType(
CallSite::class.java,
MethodHandles.Lookup::class.java,
String::class.java,
MethodType::class.java
)
val handle = Handle(
Opcodes.H_INVOKESTATIC,
platformMethodsClass,
"platform",
methodType.toMethodDescriptorString(),
false
)
method.instructions.add(
InvokeDynamicInsnNode(
method.name,
method.desc,
handle
)
)
method.instructions.addReturn(returnValue.first { it != '[' })
method.maxStack = -1
}
}
clazz
}
}
private fun InsnList.addLoad(type: Char, index: Int) {
when (type) {
';' -> add(
VarInsnNode(
Opcodes.ALOAD,
index
)
)
'I', 'S', 'B', 'C', 'Z' -> add(
VarInsnNode(
Opcodes.ILOAD,
index
)
)
'F' -> add(
VarInsnNode(
Opcodes.FLOAD,
index
)
)
'J' -> add(
VarInsnNode(
Opcodes.LLOAD,
index
)
)
'D' -> add(
VarInsnNode(
Opcodes.DLOAD,
index
)
)
else -> throw IllegalStateException("Invalid Type: $type")
}
}
private fun InsnList.addReturn(type: Char) {
when (type) {
'L' -> add(
InsnNode(
Opcodes.ARETURN
)
)
'I', 'S', 'B', 'C', 'Z' -> add(
InsnNode(
Opcodes.IRETURN
)
)
'F' -> add(
InsnNode(
Opcodes.FRETURN
)
)
'J' -> add(
InsnNode(
Opcodes.LRETURN
)
)
'D' -> add(
InsnNode(
Opcodes.DRETURN
)
)
'V' -> add(
InsnNode(
Opcodes.RETURN
)
)
}
}
}

View File

@@ -1,72 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.utils.Transform
import org.gradle.api.Project
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.AnnotationNode
import org.objectweb.asm.tree.MethodInsnNode
import java.nio.file.Path
object TransformForgeBytecode : Transformer {
val forgeEvent = "Lme/shedaniel/architectury/ForgeEvent;"
val forgeEventCancellable = "Lme/shedaniel/architectury/ForgeEventCancellable;"
val cancellable = "Lnet/minecraftforge/eventbus/api/Cancelable;"
private val environmentClass = "net/fabricmc/api/Environment"
override fun invoke(project: Project, input: Path, output: Path) {
Transform.transform(input, output) { node, classAdder ->
if (node.access and Opcodes.ACC_INTERFACE == 0) {
if (node.visibleAnnotations?.any { it.desc == forgeEvent || it.desc == forgeEventCancellable } == true) {
node.superName = "net/minecraftforge/eventbus/api/Event"
node.methods.forEach {
if (it.name == "<init>") {
for (insnNode in it.instructions) {
if (insnNode.opcode == Opcodes.INVOKESPECIAL) {
insnNode as MethodInsnNode
if (insnNode.name == "<init>" && insnNode.owner == "java/lang/Object") {
insnNode.owner = "net/minecraftforge/eventbus/api/Event"
break
}
}
}
}
}
node.signature?.let {
node.signature = it.substringBeforeLast('L') + "Lnet/minecraftforge/eventbus/api/Event;"
}
// if @ForgeEventCancellable, add the cancellable annotation from forge
node.visibleAnnotations.apply {
if (any { it.desc == forgeEventCancellable }) {
add(AnnotationNode(cancellable))
}
}
}
}
node.visibleAnnotations = (node.visibleAnnotations ?: mutableListOf()).apply {
val invisibleEnvironments =
node.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList()
node.invisibleAnnotations?.removeAll(invisibleEnvironments)
addAll(invisibleEnvironments)
}
node.fields.forEach { field ->
field.visibleAnnotations = (field.visibleAnnotations ?: mutableListOf()).apply {
val invisibleEnvironments =
field.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList()
field.invisibleAnnotations?.removeAll(invisibleEnvironments)
addAll(invisibleEnvironments)
}
}
node.methods.forEach { method ->
method.visibleAnnotations = (method.visibleAnnotations ?: mutableListOf()).apply {
val invisibleEnvironments =
method.invisibleAnnotations?.filter { it.desc == "L${environmentClass};" } ?: emptyList()
method.invisibleAnnotations?.removeAll(invisibleEnvironments)
addAll(invisibleEnvironments)
}
}
node
}
}
}

View File

@@ -1,104 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import me.shedaniel.architect.plugin.utils.validateJarFs
import net.fabricmc.loom.LoomGradleExtension
import net.fabricmc.loom.util.LoggerFilter
import net.fabricmc.tinyremapper.*
import org.gradle.api.Project
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
object TransformForgeEnvironment : Transformer {
override fun invoke(project: Project, input: Path, output: Path) {
val remapperBuilder: TinyRemapper.Builder = TinyRemapper.newRemapper()
.withMappings(remapEnvironment())
.skipLocalVariableMapping(true)
mapMixin(project, remapperBuilder)
val classpathFiles: Set<File> = LinkedHashSet(
project.configurations.getByName("compileClasspath").files
)
val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() }
.filter { p: Path -> input != p && Files.exists(p) }.toList().toTypedArray()
val remapper = remapperBuilder.build()
LoggerFilter.replaceSystemOut()
try {
project.validateJarFs(output)
OutputConsumerPath.Builder(output).build().use { outputConsumer ->
outputConsumer.addNonClassFiles(input, NonClassCopyMode.FIX_META_INF, null)
remapper.readClassPath(*classpath)
remapper.readInputs(input)
remapper.apply(outputConsumer)
}
} catch (e: Exception) {
throw RuntimeException("Failed to remap $input to $output", e)
} finally {
remapper.finish()
}
}
private fun remapEnvironment(): IMappingProvider = IMappingProvider { out ->
out.acceptClass("net/fabricmc/api/Environment", "net/minecraftforge/api/distmarker/OnlyIn")
out.acceptClass("net/fabricmc/api/EnvType", "net/minecraftforge/api/distmarker/Dist")
out.acceptField(
IMappingProvider.Member("net/fabricmc/api/EnvType", "SERVER", "Lnet/fabricmc/api/EnvType;"),
"DEDICATED_SERVER"
)
}
private fun mapMixin(project: Project, remapperBuilder: TinyRemapper.Builder) {
val loomExtension = project.extensions.getByType(LoomGradleExtension::class.java)
val srg = project.extensions.getByType(LoomGradleExtension::class.java).mappingsProvider.mappingsWithSrg
for (mixinMapFile in loomExtension.allMixinMappings) {
if (mixinMapFile.exists()) {
remapperBuilder.withMappings { sink ->
TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), "named", "intermediary").load(object :
IMappingProvider.MappingAcceptor {
override fun acceptClass(srcName: String, dstName: String) {
sink.acceptClass(dstName, srg.classes
.firstOrNull { it.getName("intermediary") == dstName }
?.getName("srg") ?: dstName
)
}
override fun acceptMethod(method: IMappingProvider.Member, dstName: String) {
sink.acceptMethod(
IMappingProvider.Member(method.owner, dstName, method.desc),
srg.classes
.flatMap { it.methods }
.firstOrNull { it.getName("intermediary") == dstName }
?.getName("srg") ?: dstName)
}
override fun acceptField(field: IMappingProvider.Member, dstName: String) {
sink.acceptField(
IMappingProvider.Member(field.owner, dstName, field.desc),
srg.classes
.flatMap { it.fields }
.firstOrNull { it.getName("intermediary") == dstName }
?.getName("srg") ?: dstName)
}
override fun acceptMethodArg(method: IMappingProvider.Member, lvIndex: Int, dstName: String) {}
override fun acceptMethodVar(
method: IMappingProvider.Member,
lvIndex: Int,
startOpIdx: Int,
asmIndex: Int,
dstName: String
) {
}
})
}
}
}
}
}

View File

@@ -1,69 +0,0 @@
package me.shedaniel.architect.plugin.transformers
import me.shedaniel.architect.plugin.ArchitectPluginExtension
import me.shedaniel.architect.plugin.Transformer
import me.shedaniel.architect.plugin.TransformerStepSkipped
import me.shedaniel.architect.plugin.projectUniqueIdentifier
import me.shedaniel.architect.plugin.utils.validateJarFs
import net.fabricmc.loom.util.LoggerFilter
import net.fabricmc.tinyremapper.IMappingProvider
import net.fabricmc.tinyremapper.NonClassCopyMode
import net.fabricmc.tinyremapper.OutputConsumerPath
import net.fabricmc.tinyremapper.TinyRemapper
import org.gradle.api.Project
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
object TransformInjectables : Transformer {
const val expectPlatform = "Lme/shedaniel/architectury/ExpectPlatform;"
const val expectPlatformNew = "Lme/shedaniel/architectury/annotations/ExpectPlatform;"
override fun invoke(project: Project, input: Path, output: Path) {
if (project.extensions.getByType(ArchitectPluginExtension::class.java).injectInjectables) {
transformArchitecturyInjectables(project, input, output)
} else {
Files.copy(input, output)
throw TransformerStepSkipped
}
}
private fun transformArchitecturyInjectables(project: Project, input: Path, output: Path) {
val remapper = TinyRemapper.newRemapper()
.withMappings { sink ->
sink.acceptClass(
"me/shedaniel/architectury/targets/ArchitecturyTarget",
project.projectUniqueIdentifier() + "/PlatformMethods"
)
sink.acceptMethod(
IMappingProvider.Member(
"me/shedaniel/architectury/targets/ArchitecturyTarget",
"getCurrentTarget",
"()Ljava/lang/String;"
), "getModLoader"
)
}
.build()
val classpathFiles: Set<File> = LinkedHashSet(
project.configurations.getByName("compileClasspath").files
)
val classpath = classpathFiles.asSequence().map { obj: File -> obj.toPath() }
.filter { p: Path -> Files.exists(p) }.toList().toTypedArray()
LoggerFilter.replaceSystemOut()
try {
project.validateJarFs(output)
OutputConsumerPath.Builder(output).build().use { outputConsumer ->
outputConsumer.addNonClassFiles(input, NonClassCopyMode.UNCHANGED, null)
remapper.readClassPath(*classpath)
remapper.readInputs(input)
remapper.apply(outputConsumer)
}
} catch (e: Exception) {
throw RuntimeException("Failed to remap $input to $output", e)
} finally {
remapper.finish()
}
}
}

View File

@@ -1,25 +0,0 @@
package me.shedaniel.architect.plugin.utils
import org.gradle.api.Project
import java.net.URI
import java.nio.file.FileSystemNotFoundException
import java.nio.file.Path
import java.nio.file.ProviderNotFoundException
import java.nio.file.spi.FileSystemProvider
fun Project.validateJarFs(path: Path) {
val uri = URI("jar:" + path.toUri().toString())
val provider = FileSystemProvider.installedProviders().firstOrNull { it.scheme == uri.scheme }
?: throw ProviderNotFoundException("Provider \"${uri.scheme}\" not found")
try {
val fs = provider.getFileSystem(uri)
val cl = fs.javaClass.classLoader
if (fs.isOpen) {
logger.error("Detected open FS on $path! Forcefully closing the FS! The FS is created on $cl!")
fs.close()
}
} catch (ignored: FileSystemNotFoundException) {
} catch (e: Exception) {
e.printStackTrace()
}
}