2021-12-03 08:35:29 -05:00
|
|
|
archivesBaseName = "fabric-data-generation-api-v1"
|
|
|
|
version = getSubprojectVersion(project)
|
|
|
|
|
|
|
|
moduleDependencies(project, [
|
|
|
|
'fabric-api-base',
|
|
|
|
'fabric-registry-sync-v0',
|
2022-01-14 10:08:18 -05:00
|
|
|
'fabric-networking-api-v1',
|
2022-09-25 09:44:35 -04:00
|
|
|
'fabric-resource-conditions-api-v1',
|
2023-01-05 07:49:19 -05:00
|
|
|
'fabric-item-group-api-v1',
|
|
|
|
'fabric-recipe-api-v1',
|
2021-12-03 08:35:29 -05:00
|
|
|
])
|
|
|
|
|
2021-12-22 13:25:57 -05:00
|
|
|
dependencies {
|
|
|
|
}
|
|
|
|
|
2021-12-03 08:35:29 -05:00
|
|
|
sourceSets {
|
|
|
|
testmod {
|
|
|
|
resources {
|
|
|
|
srcDirs += [
|
|
|
|
'src/testmod/generated'
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
loom {
|
|
|
|
accessWidenerPath = file("src/main/resources/fabric-data-generation-api-v1.accesswidener")
|
|
|
|
|
|
|
|
runs {
|
|
|
|
datagen {
|
|
|
|
inherit testmodServer
|
|
|
|
name "Data Generation"
|
|
|
|
vmArg "-Dfabric-api.datagen"
|
|
|
|
vmArg "-Dfabric-api.datagen.output-dir=${file("src/testmod/generated")}"
|
|
|
|
vmArg "-Dfabric-api.datagen.strict-validation"
|
|
|
|
|
|
|
|
ideConfigGenerated = true
|
|
|
|
runDir "build/datagen"
|
|
|
|
}
|
|
|
|
datagenClient {
|
|
|
|
client()
|
|
|
|
name "Data Generation"
|
|
|
|
vmArg "-Dfabric-api.datagen"
|
|
|
|
vmArg "-Dfabric-api.datagen.output-dir=${file("src/testmod/generated")}"
|
|
|
|
vmArg "-Dfabric-api.datagen.strict-validation"
|
|
|
|
|
|
|
|
ideConfigGenerated = true
|
|
|
|
runDir "build/datagen"
|
|
|
|
source sourceSets.testmod
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-22 12:22:58 -05:00
|
|
|
test.dependsOn runDatagen
|
2021-12-03 08:35:29 -05:00
|
|
|
|
2023-01-05 07:50:01 -05:00
|
|
|
task datapackZip(type: Zip, dependsOn: runDatagen) {
|
|
|
|
archiveFileName = "${archivesBaseName}-${project.version}-test-datapack.zip"
|
|
|
|
destinationDirectory = layout.buildDirectory.dir('libs')
|
|
|
|
|
|
|
|
from file("src/testmod/generated")
|
|
|
|
from file("pack.mcmeta")
|
|
|
|
}
|
|
|
|
|
|
|
|
build.dependsOn datapackZip
|
|
|
|
|
2021-12-03 08:35:29 -05:00
|
|
|
import org.objectweb.asm.ClassReader
|
|
|
|
import org.objectweb.asm.Opcodes
|
|
|
|
import org.objectweb.asm.tree.ClassNode
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
import java.lang.reflect.Modifier
|
|
|
|
import java.util.zip.ZipEntry
|
2021-12-03 08:35:29 -05:00
|
|
|
import java.util.zip.ZipFile
|
|
|
|
|
|
|
|
task generateAccessWidener() {
|
|
|
|
doLast {
|
2023-02-01 11:35:59 -05:00
|
|
|
File inputJar = loom.namedMinecraftProvider.parentMinecraftProvider.commonJar.path.toFile()
|
2022-12-23 10:23:14 -05:00
|
|
|
String accessWidener = "accessWidener\tv2\tnamed\n"
|
|
|
|
accessWidener += "\n"
|
|
|
|
accessWidener += "# DO NOT EDIT BY HAND! This file is generated automatically.\n"
|
|
|
|
accessWidener += "# Edit \"template.accesswidener\" instead then run \"gradlew generateAccessWidener\".\n"
|
|
|
|
accessWidener += "\n"
|
|
|
|
accessWidener += file("template.accesswidener").text + "\n"
|
2021-12-03 08:35:29 -05:00
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
def classes = getClasses(inputJar)
|
|
|
|
|
|
|
|
visitMethods(classes["net/minecraft/data/server/recipe/RecipeProvider"]) { name, desc, owner ->
|
2021-12-03 08:35:29 -05:00
|
|
|
if (it.name == "generate")
|
|
|
|
return
|
|
|
|
|
|
|
|
accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n"
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
visitMethods(classes["net/minecraft/data/client/BlockStateModelGenerator"]) { name, desc, owner ->
|
2021-12-03 08:35:29 -05:00
|
|
|
if (desc == "()V")
|
|
|
|
// Skip over methods that dont take any arguments, as they are specific to minecraft.
|
|
|
|
return
|
|
|
|
|
|
|
|
accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n"
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
visitMethods(classes["net/minecraft/data/server/loottable/BlockLootTableGenerator"]) { name, desc, owner ->
|
2021-12-03 08:35:29 -05:00
|
|
|
accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n"
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
visitMethods(classes["net/minecraft/data/client/ItemModelGenerator"]) { name, desc, owner ->
|
2022-06-19 14:17:44 -04:00
|
|
|
accessWidener += "transitive-accessible\tmethod\t${owner}\t${name}\t${desc}\n"
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
classes.values().forEach { classNode ->
|
|
|
|
visitFinalMethods(classNode) { name, desc, owner ->
|
|
|
|
if (name != "getName" || desc != "()Ljava/lang/String;") {
|
|
|
|
// Not the method we are after
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasAncestor(classNode, classes, "net/minecraft/data/DataProvider")) {
|
|
|
|
// Not a descendant of DataProvider
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
accessWidener += "transitive-extendable\tmethod\t${owner}\t${name}\t${desc}\n"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-03 08:35:29 -05:00
|
|
|
file("src/main/resources/fabric-data-generation-api-v1.accesswidener").text = accessWidener
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
def visitMethods(ClassNode classNode, closure) {
|
|
|
|
classNode.methods.forEach {
|
2021-12-03 08:35:29 -05:00
|
|
|
if ((it.access & Opcodes.ACC_SYNTHETIC) != 0 || (it.access & Opcodes.ACC_PUBLIC) != 0)
|
|
|
|
return
|
|
|
|
|
|
|
|
if (it.name.startsWith("<"))
|
|
|
|
return
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
closure(it.name, it.desc, classNode.name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def visitFinalMethods(ClassNode classNode, closure) {
|
|
|
|
classNode.methods.forEach {
|
|
|
|
if (!Modifier.isFinal(it.access))
|
|
|
|
return
|
|
|
|
|
|
|
|
if (it.name.startsWith("<"))
|
|
|
|
return
|
|
|
|
|
|
|
|
closure(it.name, it.desc, classNode.name)
|
2021-12-03 08:35:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
// Return a map of all class names to classNodes
|
|
|
|
def getClasses(File input) {
|
2022-12-23 08:09:13 -05:00
|
|
|
Map<String, ClassNode> classes = new TreeMap<>()
|
2022-12-11 08:50:46 -05:00
|
|
|
|
2022-02-11 12:02:44 -05:00
|
|
|
new ZipFile(input).withCloseable { ZipFile zip ->
|
2022-12-11 08:50:46 -05:00
|
|
|
zip.entries().toList().forEach { ZipEntry entry ->
|
|
|
|
if (!entry.name.endsWith(".class")) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
zip.getInputStream(entry).withCloseable { is ->
|
|
|
|
ClassReader reader = new ClassReader(is)
|
|
|
|
ClassNode classNode = new ClassNode()
|
|
|
|
reader.accept(classNode, ClassReader.SKIP_CODE)
|
|
|
|
|
|
|
|
classes.put(classNode.name, classNode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return classes
|
|
|
|
}
|
|
|
|
|
|
|
|
def hasAncestor(ClassNode classNode, Map<String, ClassNode> classes, String ancestorName) {
|
|
|
|
if (classNode.superName == ancestorName) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recuse through the super classes
|
|
|
|
def superClass = classes.get(classNode.superName)
|
|
|
|
if (superClass != null && hasAncestor(superClass, classes, ancestorName)) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
for (def interfaceName : classNode.interfaces) {
|
|
|
|
if (interfaceName == ancestorName) {
|
|
|
|
return true
|
|
|
|
}
|
2021-12-03 08:35:29 -05:00
|
|
|
|
2022-12-11 08:50:46 -05:00
|
|
|
def ifaceClass = classes.get(interfaceName)
|
|
|
|
if (ifaceClass != null && hasAncestor(ifaceClass, classes, ancestorName)) {
|
|
|
|
return true
|
2021-12-03 08:35:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-17 14:23:48 -04:00
|
|
|
|
|
|
|
generateResources.dependsOn generateAccessWidener
|