forked from Sinytra/ForgifiedFabricAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.gradle
142 lines (117 loc) · 5.09 KB
/
build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
version = getSubprojectVersion(project)
loom {
accessWidenerPath = file('src/main/resources/fabric-transitive-access-wideners-v1.accesswidener')
}
testDependencies(project, [
':fabric-rendering-v1',
':fabric-object-builder-api-v1'
])
import org.objectweb.asm.ClassReader
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.ClassNode
import java.nio.file.FileSystem
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.stream.Collectors
task generateAccessWidener {
doLast {
List<String> lines = new ArrayList<>();
lines.add("accessWidener v2 named")
lines.add("")
lines.add("# DO NOT EDIT BY HAND! This file is generated automatically.")
lines.add("# Edit \"template.accesswidener\" instead then run \"gradlew generateAccessWidener\".")
lines.add("")
lines.addAll(file("template.accesswidener").text.lines().toList())
Path commonJar = loom.namedMinecraftProvider.parentMinecraftProvider.commonJar.path
FileSystems.newFileSystem(URI.create("jar:${commonJar.toUri()}"), [create: false]).withCloseable { fs ->
generateBlockConstructors(lines, fs)
lines.add("")
generateItemConstructors(lines, fs)
lines.add("")
}
Path clientJar = loom.namedMinecraftProvider.parentMinecraftProvider.clientOnlyJar.path
FileSystems.newFileSystem(URI.create("jar:${clientJar.toUri()}"), [create: false]).withCloseable { fs ->
generateRenderPhaseFields(lines, fs)
}
file('src/main/resources/fabric-transitive-access-wideners-v1.accesswidener').text = String.join('\n', lines) + '\n'
validateAccessWidener(lines)
}
}
def generateBlockConstructors(List<String> lines, FileSystem fs) {
lines.add("# Constructors of non-abstract block classes")
Files.list(fs.getPath("net/minecraft/block"))
.filter { Files.isRegularFile(it) && it.toString().endsWith(".class") }
.map { loadClass(it) }
.sorted(Comparator.comparing { it.name })
.filter { (it.access & Opcodes.ACC_ABSTRACT) == 0 }
.forEach { node ->
for (def method : node.methods) {
// Checklist for finding block constructors as of 1.19.3:
// - class directly in net.minecraft.block (excluding subpackages)
// - method name == <init> (by definition)
// - contains an AbstractBlock$Settings parameter
// - only taking into account non-abstract classes and non-public constructors
// Block constructor...
if (method.name == "<init>" && Type.getArgumentTypes(method.desc).any { it.internalName == 'net/minecraft/block/AbstractBlock$Settings' }) {
// ...and non-public
if ((method.access & Opcodes.ACC_PUBLIC) == 0) {
lines.add("transitive-accessible method $node.name <init> $method.desc")
}
}
}
}
}
def generateItemConstructors(List<String> lines, FileSystem fs) {
lines.add("# Constructors of non-abstract item classes")
Files.list(fs.getPath("net/minecraft/item"))
.filter { Files.isRegularFile(it) && it.toString().endsWith(".class") }
.map { loadClass(it) }
.sorted(Comparator.comparing { it.name })
.filter { (it.access & Opcodes.ACC_ABSTRACT) == 0 }
.forEach { node ->
for (def method : node.methods) {
// Checklist for finding item constructors as of 1.19.3:
// - class directly in net.minecraft.item (excluding subpackages)
// - method name == <init> (by definition)
// - contains an Item$Settings parameter
// - only taking into account non-abstract classes and non-public constructors
// Item constructor...
if (method.name == "<init>" && Type.getArgumentTypes(method.desc).any { it.internalName == 'net/minecraft/item/Item$Settings' }) {
// ...and non-public
if ((method.access & Opcodes.ACC_PUBLIC) == 0) {
lines.add("transitive-accessible method $node.name <init> $method.desc")
}
}
}
}
}
def generateRenderPhaseFields(List<String> lines, FileSystem fs) {
lines.add("# Protected static fields of RenderPhase")
for (def field : loadClass(fs.getPath("net/minecraft/client/render/RenderPhase.class")).fields) {
// All protected static fields of RenderPhase
if ((field.access & Opcodes.ACC_PROTECTED) != 0 && (field.access & Opcodes.ACC_STATIC) != 0) {
lines.add("transitive-accessible field net/minecraft/client/render/RenderPhase ${field.name} ${field.desc}")
}
}
}
ClassNode loadClass(Path path) {
def node = new ClassNode()
Files.newInputStream(path).withCloseable { is ->
new ClassReader(is).accept(node, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES)
}
return node
}
def validateAccessWidener(List<String> lines) {
List<String> exceptions = new ArrayList<>()
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i)
if (line.isBlank() || line.startsWith("#") || line.startsWith("transitive-") || line.startsWith("accessWidener")) continue
exceptions.add(String.valueOf(i + 1))
}
if (exceptions.size() > 0) {
throw new InvalidUserDataException("\"fabric-transitive-access-wideners-v1.accesswidener\" contains non-transitive access modifiers at lines: [" + String.join(", ", exceptions) + "]")
}
}
generateResources.dependsOn generateAccessWidener