Repository navigation
Expand file tree
/
Copy pathbuild.gradle
More file actions
198 lines (170 loc) · 8.1 KB
/
Copy pathbuild.gradle
File metadata and controls
198 lines (170 loc) · 8.1 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
apply plugin: "java"
import java.util.zip.ZipFile
version = '1.0'
sourceSets.main.java.srcDirs = ["src"]
repositories {
maven { setUrl("https://www.jitpack.io") }
maven { setUrl("https://raw.githubusercontent.com/Zelaux/MindustryRepo/master/repository") }
mavenCentral()
ivy {
url = 'https://github.com/'
patternLayout { artifact '/[organisation]/[module]/releases/download/[revision]/Mindustry.jar' }
metadataSources { artifact() }
}
ivy {
url = 'https://github.com/'
patternLayout { artifact '/[organisation]/[module]/releases/download/[revision]/dependencies.jar' }
metadataSources { artifact() }
}
//For depending on the absolute newest commit for Mindustry
// ivy {
// url = 'https://github.com/'
// patternLayout { artifact '/[organisation]/[module]/releases/download/master/[revision].jar' }
// metadataSources { artifact() }
// }
// If the version is set to 'latest', downloads the latest Mindustry *release* as a dependency
ivy {
url = 'https://github.com/'
patternLayout { artifact '/[organisation]/[module]/releases/[revision]/download/dependencies.jar' }
metadataSources { artifact() }
}
}
java {
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_17
}
tasks.withType(JavaCompile).configureEach {
options.encoding = "UTF-8"
}
ext{
// Mindustry version to depend on.
// Valid values:
// - latest: depend on the latest release of mindustry
// - be: depend on the very latest commit of mindustry
// - v<number>: depend on a specific commit
mindustryVersion = "v160.5"
isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
sdkRoot = System.getenv("ANDROID_HOME") ?: System.getenv("ANDROID_SDK_ROOT")
// Parse mod version from mod.hjson for artifact naming
def hjsonText = file("mod.hjson").text
def versionLine = hjsonText.readLines().find { it.trim().startsWith("version:") }
modVersion = versionLine ? versionLine.split(":", 2)[1].trim() : "unknown"
gameVersion = mindustryVersion
}
dependencies{
compileOnly mindustryVersion == "be" ? "Anuken:MindustryBuilds:latest" : "Anuken:Mindustry:$mindustryVersion"
// compileOnly "com.github.Anuken.Arc:arc-core:$mindustryVersion"
// compileOnly "com.github.Anuken.Mindustry:core:$mindustryVersion"
}
tasks.register('jarAndroid') {
dependsOn "jar"
def projectName = project.name
doLast {
if (!sdkRoot || !new File(sdkRoot).exists()) throw new GradleException("No valid Android SDK found. Ensure that ANDROID_HOME is set to your Android SDK directory.")
def platformRoot = new File("$sdkRoot/platforms/").listFiles().sort().reverse().find { f -> new File(f, "android.jar").exists() }
if (!platformRoot) throw new GradleException("No android.jar found. Ensure that you have an Android platform installed.")
//collect dependencies needed for desugaring
// Use ProcessBuilder with an argument list instead of string concatenation so that
// paths containing spaces (e.g. ANDROID_HOME with "Program Files" on Windows) are
// not split into multiple arguments.
def classpathDeps = configurations.compileClasspath.asList() + configurations.runtimeClasspath.asList()
// dex 化改用独立 R8 8.3.37,不再用 build-tools 34.0.0 的 d8(R8 8.2.2-dev)。
// 背景:旧 d8 开启 desugaring 时会在 classpath 含 java.lang.Record 的情况下
// 崩溃(NPE),当年为绕开而加 --no-desugaring;结果模组自身的 invoke-dynamic
// (字符串拼接/lambda/switch 等)未被脱糖,被编译成 $$ExternalSyntheticThrowRTE0
// 占位方法,安卓真机加载即抛 "Instruction is unrepresentable in DEX V35:
// invoke-dynamic"。R8 8.3.37 可安全处理 classpath 中的 record,恢复默认脱糖。
// 需 JDK 17+(CI 与本地均用 JDK 17)。
def r8Dir = new File(project.projectDir, "gradle/r8")
def r8File = new File(r8Dir, "r8-8.3.37.jar")
if (!r8File.exists()) {
r8Dir.mkdirs()
def tmp = new File(r8Dir, "r8-8.3.37.jar.part")
println "Downloading R8 8.3.37 (~16.6MB) for desugaring..."
new URL("https://dl.google.com/dl/android/maven2/com/android/tools/r8/8.3.37/r8-8.3.37.jar").withInputStream { ins ->
tmp.withOutputStream { outs -> outs << ins }
}
if (!tmp.renameTo(r8File)) throw new GradleException("Failed to move R8 jar into place: ${r8File.path}")
}
def javaBin = new File(System.getProperty("java.home"), "bin" + File.separator + (isWindows ? "java.exe" : "java"))
if (!javaBin.exists()) throw new GradleException("java not found at ${javaBin.path}")
def cmd = new ArrayList<String>()
cmd.add(javaBin.path)
cmd.add("-cp"); cmd.add(r8File.absolutePath)
cmd.add("com.android.tools.r8.D8")
classpathDeps.each { dep -> cmd.add("--classpath"); cmd.add(dep.path) }
cmd.add("--lib"); cmd.add(new File(platformRoot, "android.jar").path)
cmd.add("--min-api"); cmd.add("21")
// 默认脱糖开启(不再 --no-desugaring),确保 invoke-dynamic 全部转成 dex 表示
cmd.add("--output"); cmd.add(projectName + "Android.jar")
cmd.add(projectName + "Desktop.jar")
def process = new ProcessBuilder(cmd)
.directory(new File(project.projectDir, "build/libs"))
.redirectErrorStream(true)
.start()
process.consumeProcessOutput(System.out, System.err)
process.waitFor()
if (process.exitValue() != 0) {
throw new GradleException("d8 dexing failed with exit code ${process.exitValue()}")
}
// 产物自检:classes.dex 不得残留 $$ExternalSyntheticThrowRTE* 占位方法,
// 否则模块必在安卓真机加载时抛 "Instruction is unrepresentable in DEX"。
def androidJar = new File(project.projectDir, "build/libs/${projectName}Android.jar")
def zf = new ZipFile(androidJar)
try {
def entry = zf.getEntry("classes.dex")
if (entry == null) throw new GradleException("classes.dex missing in ${androidJar.path}")
def dex = new byte[(int) entry.size]
def ins = zf.getInputStream(entry)
try {
int off = 0
while (off < dex.length) {
int r = ins.read(dex, off, dex.length - off)
if (r < 0) break
off += r
}
} finally { ins.close() }
def marker = "ExternalSyntheticThrowRTE".getBytes("ISO-8859-1")
boolean found = false
int i = 0
while (!found && i <= dex.length - marker.length) {
boolean match = true
for (int j = 0; j < marker.length; j++) {
if (dex[i + j] != marker[j]) { match = false; break }
}
if (match) found = true
i++
}
if (found) {
throw new GradleException("classes.dex contains ExternalSyntheticThrowRTE placeholders (" +
"un-desugared invoke-dynamic). Desugaring must stay enabled — do not re-add --no-desugaring.")
}
} finally { zf.close() }
}
}
jar{
archiveFileName = "${project.name}Desktop.jar"
from{
configurations.runtimeClasspath.collect{ it.isDirectory() ? it : zipTree(it) }
}
from(projectDir){
include "mod.hjson"
include "pinyin.txt"
}
from("assets/"){
include "**"
}
}
tasks.register('deploy', Jar) {
def projectName = project.name
dependsOn jarAndroid
dependsOn jar
archiveFileName = "${projectName}-${modVersion}-${gameVersion}.jar"
destinationDirectory = file("build/libs")
from { [zipTree("build/libs/${projectName}Desktop.jar"), zipTree("build/libs/${projectName}Android.jar")] }
doLast {
delete {
delete "build/libs/${projectName}Android.jar"
}
}
}