Skip to content

Commit

Permalink
hell^2
Browse files Browse the repository at this point in the history
  • Loading branch information
IThundxr committed Jun 8, 2024
1 parent 1ba6028 commit cb27355
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 133 deletions.
135 changes: 2 additions & 133 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import dev.ithundxr.numismaticsgradle.asm.NumismaticsGradleASM
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import net.fabricmc.loom.api.LoomGradleExtensionAPI
Expand Down Expand Up @@ -246,7 +247,7 @@ fun transformJar(projectPath: String, jar: File) {
if (name.endsWith(".json") || name.endsWith(".mcmeta")) {
data = (JsonOutput.toJson(JsonSlurper().parse(data)).toByteArray())
} else if (name.endsWith(".class")) {
data = transformClass(projectPath, data)
data = NumismaticsGradleASM().transformClass(projectPath, data)
}

out.putNextEntry(JarEntry(name))
Expand All @@ -258,138 +259,6 @@ fun transformJar(projectPath: String, jar: File) {
}
}

@Suppress("LocalVariableName")
fun transformClass(projectPath: String, bytes: ByteArray): ByteArray {
val node = ClassNode()
ClassReader(bytes).accept(node, 0)

if (node.invisibleAnnotations != null ) {
// Cache the field, so we don't CME the list during the remove
val annotationNodes = node.invisibleAnnotations.toList()
for (annotationNode in annotationNodes) {
if (annotationNode.desc.equals("Ldev/ithundxr/createnumismatics/annotation/asm/CCForgeImpl;")) {
// Remove
node.invisibleAnnotations.remove(annotationNode)

if (projectPath == ":forge") {
// Add the interface that's needed
node.interfaces.add("net/minecraftforge/common/capabilities/ICapabilityProvider")

// getCapability method
run {
val mv = node.visitMethod(
Opcodes.ACC_PUBLIC,
"getCapability",
"(Lnet/minecraftforge/common/capabilities/Capability;Lnet/minecraft/core/Direction;)Lnet/minecraftforge/common/util/LazyOptional;",
null,
null
)
mv.visitCode()

val L1 = Label()

// L0
mv.visitLabel(Label())
mv.visitVarInsn(Opcodes.ALOAD, 0)
mv.visitFieldInsn(
Opcodes.GETFIELD,
node.name,
"computerBehaviour",
"Lcom/simibubi/create/compat/computercraft/AbstractComputerBehaviour;"
)
mv.visitVarInsn(Opcodes.ALOAD, 1)
mv.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"com/simibubi/create/compat/computercraft/AbstractComputerBehaviour",
"isPeripheralCap",
"(Lnet/minecraftforge/common/capabilities/Capability;)Z",
false
)
mv.visitJumpInsn(Opcodes.IFEQ, L1)

// L2
mv.visitLabel(Label())
mv.visitVarInsn(Opcodes.ALOAD, 0)
mv.visitFieldInsn(
Opcodes.GETFIELD,
node.name,
"computerBehaviour",
"Lcom/simibubi/create/compat/computercraft/AbstractComputerBehaviour;"
)
mv.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"com/simibubi/create/compat/computercraft/AbstractComputerBehaviour",
"getPeripheralCapability",
"()Lnet/minecraftforge/common/util/LazyOptional;",
false
)
mv.visitInsn(Opcodes.ARETURN)

// L1
mv.visitLabel(L1)
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null)
mv.visitVarInsn(Opcodes.ALOAD, 0)
mv.visitVarInsn(Opcodes.ALOAD, 1)
mv.visitVarInsn(Opcodes.ALOAD, 2)
mv.visitMethodInsn(
Opcodes.INVOKESPECIAL,
node.name,
"getCapability",
"(Lnet/minecraftforge/common/capabilities/Capability;Lnet/minecraft/core/Direction;)Lnet/minecraftforge/common/util/LazyOptional;",
false
)
mv.visitInsn(Opcodes.ARETURN)

mv.visitEnd()
}

// invalidateCaps method
run {
val mv = node.visitMethod(Opcodes.ACC_PUBLIC, "invalidateCaps", "()V", null, null)
mv.visitCode()

// L0
val L0 = Label()
mv.visitLabel(L0)
mv.visitVarInsn(Opcodes.ALOAD, 0)
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, node.name, "invalidateCaps", "()V", false)

// L1
mv.visitLabel(Label())
mv.visitVarInsn(Opcodes.ALOAD, 0)
mv.visitFieldInsn(
Opcodes.GETFIELD,
node.name,
"computerBehaviour",
"Lcom/simibubi/create/compat/computercraft/AbstractComputerBehaviour;"
)
mv.visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"com/simibubi/create/compat/computercraft/AbstractComputerBehaviour",
"removePeripheral",
"()V",
false
)

// L2
mv.visitLabel(Label())
mv.visitInsn(Opcodes.RETURN)

mv.visitEnd()
}
}
}
}
}

val byteArray = ClassWriter(0).also { node.accept(it) }.toByteArray()

// Verify the bytecode is valid
ClassReader(byteArray).accept(CheckClassAdapter(null), 0)

return byteArray
}

fun calculateGitHash(): String {
val stdout = ByteArrayOutputStream()
exec {
Expand Down
41 changes: 41 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Numismatics
* Copyright (c) 2024 The Railways Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

plugins {
id("java-gradle-plugin")
kotlin("jvm") version "1.9.23"
`kotlin-dsl`
}

repositories {
gradlePluginPortal()
mavenCentral()
}

dependencies {
implementation("org.ow2.asm:asm:${"asm_version"()}")
//implementation("org.ow2.asm:asm-analysis:${"asm_version"()}")
//implementation("org.ow2.asm:asm-commons:${"asm_version"()}")
implementation("org.ow2.asm:asm-tree:${"asm_version"()}")
implementation("org.ow2.asm:asm-util:${"asm_version"()}")
}

operator fun String.invoke(): String {
return rootProject.ext[this] as? String
?: throw IllegalStateException("Property $this is not defined")
}
19 changes: 19 additions & 0 deletions buildSrc/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Numismatics
# Copyright (c) 2024 The Railways Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#

asm_version = 9.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Numismatics
* Copyright (c) 2024 The Railways Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package dev.ithundxr.numismaticsgradle.asm

import dev.ithundxr.numismaticsgradle.asm.internal.SubprojectType
import dev.ithundxr.numismaticsgradle.asm.transformers.CCCapabilitiesASM
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.util.CheckClassAdapter

class NumismaticsGradleASM {
fun transformClass(projectPath: String, bytes: ByteArray): ByteArray {
// Get project type
val project = SubprojectType.getProjectType(projectPath)

var node = ClassNode()
ClassReader(bytes).accept(node, 0)

// Transformers
node = CCCapabilitiesASM().transform(project, node)

// Verify the bytecode is valid
val byteArray = ClassWriter(0).also { node.accept(it) }.toByteArray()
ClassReader(byteArray).accept(CheckClassAdapter(null), 0)
return byteArray
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Numismatics
* Copyright (c) 2024 The Railways Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package dev.ithundxr.numismaticsgradle.asm.internal

enum class SubprojectType {
COMMON, FABRIC, FORGE;

companion object {
fun getProjectType(projectPath: String): SubprojectType {
return when (projectPath) {
":common" -> COMMON
":fabric" -> FABRIC
":forge" -> FORGE
else -> throw IllegalStateException("Invalid Project Type")
}
}
}
}
Loading

0 comments on commit cb27355

Please sign in to comment.