Skip to content

Commit a9f6a9b

Browse files
authored
Merge pull request #1470 from ZalithLauncher/main
merge main
2 parents 8bdc6f2 + a64aca7 commit a9f6a9b

14 files changed

Lines changed: 112 additions & 86 deletions

File tree

ZalithLauncher/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ default_store_password=vh#nn%N(#eNjwfA78-77s6&f-cdd(@-7eana-e%!nhj%))!@c
1515
default_key_password=sfv72ghSSNQaadf99-Q69!2
1616

1717
# launcher version
18-
launcher_version_code=200029
19-
launcher_version_name=2.4.7
18+
launcher_version_code=200031
19+
launcher_version_name=2.4.9

ZalithLauncher/src/main/assets/game/versions.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,23 @@
914914
26.1
915915
26.1.1-rc-1
916916
26.1.1
917+
26w14a
917918
26.1.2-rc-1
918919
26.1.2
919-
26w14a
920+
26.2-snapshot-1
921+
26.2-snapshot-2
922+
26.2-snapshot-3
923+
26.2-snapshot-4
924+
26.2-snapshot-5
925+
26.2-snapshot-6
926+
26.2-snapshot-7
927+
26.2-snapshot-8
928+
26.2-pre-1
929+
26.2-pre-2
930+
26.2-pre-3
931+
26.2-pre-4
932+
26.2-pre-5
933+
26.2-pre-6
934+
26.2-rc-1
935+
26.2-rc-2
936+
26.2

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/game/download/assets/platform/_PlatformSearch.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ private val mirrorModrinthSearcher = ModrinthSearcher(
5353
private val curseForgeSearcher = CurseForgeSearcher()
5454
private val mirrorCurseForgeSearcher = CurseForgeSearcher(
5555
api = MCIM_CURSEFORGE_API,
56-
apiKey = null, //不向镜像源提供 api key
5756
source = "MCIM CurseForge"
5857
)
5958

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/game/download/assets/platform/curseforge/CurseForgeSearcher.kt

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
package com.movtery.zalithlauncher.game.download.assets.platform.curseforge
2020

21-
import com.movtery.zalithlauncher.BuildKeys
2221
import com.movtery.zalithlauncher.game.download.assets.platform.AbstractPlatformSearcher
2322
import com.movtery.zalithlauncher.game.download.assets.platform.Platform
2423
import com.movtery.zalithlauncher.game.download.assets.platform.PlatformClasses
@@ -42,7 +41,6 @@ import java.io.File
4241

4342
class CurseForgeSearcher(
4443
val api: String = CURSEFORGE_API,
45-
val apiKey: String? = BuildKeys.CURSEFORGE_API,
4644
source: String = "Official CurseForge"
4745
): AbstractPlatformSearcher(
4846
platform = Platform.CURSEFORGE,
@@ -55,7 +53,6 @@ class CurseForgeSearcher(
5553
): CurseForgeSearchResult {
5654
return httpGetJson(
5755
url = "$api/mods/search",
58-
headers = listOf("x-api-key" to apiKey),
5956
parameters = searchFilter.toCurseForgeRequest(
6057
query = query,
6158
platformClasses = platformClasses
@@ -65,8 +62,7 @@ class CurseForgeSearcher(
6562

6663
override suspend fun getProject(projectID: String): CurseForgeProject {
6764
val project = httpGetJson<CurseForgeProject>(
68-
url = "$api/mods/$projectID",
69-
headers = listOf("x-api-key" to apiKey)
65+
url = "$api/mods/$projectID"
7066
)
7167
if (!project.isApproved()) throw NotFoundException("The project {$projectID} is not in a publicly available state.")
7268
return project
@@ -80,8 +76,7 @@ class CurseForgeSearcher(
8076
fileID: String,
8177
): CurseForgeVersion {
8278
return httpGetJson(
83-
url = "$api/mods/$projectID/files/$fileID",
84-
headers = listOf("x-api-key" to apiKey)
79+
url = "$api/mods/$projectID/files/$fileID"
8580
)
8681
}
8782

@@ -96,7 +91,6 @@ class CurseForgeSearcher(
9691
pageSize: Int = 100
9792
): CurseForgeVersions = httpGetJson(
9893
url = "$api/mods/$projectID/files",
99-
headers = listOf("x-api-key" to apiKey),
10094
parameters = Parameters.build {
10195
append("index", index.toString())
10296
append("pageSize", pageSize.toString())
@@ -136,7 +130,6 @@ class CurseForgeSearcher(
136130
val hash = MurmurHash2Incremental.computeHash(file, byteToSkip = listOf(0x9, 0xa, 0xd, 0x20))
137131
return httpPostJson<CurseForgeFingerprintsMatches>(
138132
url = "$api/fingerprints",
139-
headers = listOf("x-api-key" to apiKey),
140133
body = mapOf("fingerprints" to listOf(hash))
141134
).data.exactMatches
142135
?.takeIf { it.isNotEmpty() }

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/game/launch/Launcher.kt

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import com.movtery.zalithlauncher.utils.device.Architecture
4343
import com.movtery.zalithlauncher.utils.device.Architecture.ARCH_X86
4444
import com.movtery.zalithlauncher.utils.device.Architecture.is64BitsDevice
4545
import com.movtery.zalithlauncher.utils.logging.Logger
46+
import com.movtery.zalithlauncher.utils.string.splitPreservingQuotes
4647
import com.oracle.dalvik.VMLauncher
4748
import org.apache.commons.io.FileUtils
4849
import java.io.File
@@ -153,7 +154,7 @@ abstract class Launcher(
153154
screenSize: IntSize,
154155
useLocalLanguage: Boolean
155156
): List<String> {
156-
val userArguments = parseJavaArguments(userArgumentsString).toMutableList()
157+
val userArguments = userArgumentsString.splitPreservingQuotes().toMutableList()
157158
val resolvFile = ensureDNSConfig()
158159

159160
val overridableArguments = mutableMapOf<String, String>().apply {
@@ -448,45 +449,6 @@ abstract class Launcher(
448449
}
449450
}
450451

451-
/**
452-
* [Modified from PojavLauncher](https://github.com/PojavLauncherTeam/PojavLauncher/blob/98947f2/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java#L411-L456)
453-
*/
454-
fun parseJavaArguments(args: String): List<String> {
455-
val parsedArguments = mutableListOf<String>()
456-
var cleanedArgs = args.trim().replace(" ", "")
457-
val separators = listOf("-XX:-", "-XX:+", "-XX:", "--", "-D", "-X", "-javaagent:", "-verbose")
458-
459-
for (prefix in separators) {
460-
while (true) {
461-
val start = cleanedArgs.indexOf(prefix)
462-
if (start == -1) break
463-
464-
val end = separators
465-
.mapNotNull { sep ->
466-
val i = cleanedArgs.indexOf(sep, start + prefix.length)
467-
if (i != -1) i else null
468-
}
469-
.minOrNull() ?: cleanedArgs.length
470-
471-
val parsedSubstring = cleanedArgs.substring(start, end)
472-
cleanedArgs = cleanedArgs.replace(parsedSubstring, "")
473-
474-
if (parsedSubstring.indexOf('=') == parsedSubstring.lastIndexOf('=')) {
475-
val last = parsedArguments.lastOrNull()
476-
if (last != null && (last.endsWith(',') || parsedSubstring.contains(','))) {
477-
parsedArguments[parsedArguments.lastIndex] = last + parsedSubstring
478-
} else {
479-
parsedArguments.add(parsedSubstring)
480-
}
481-
} else {
482-
Logger.warning(TAG, "Removed improper arguments: $parsedSubstring")
483-
}
484-
}
485-
}
486-
487-
return parsedArguments
488-
}
489-
490452
fun getCacioJavaArgs(
491453
screenSize: IntSize,
492454
isJava8: Boolean

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/game/support/touch_controller/VibrationHandler.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.annotation.SuppressLint
2222
import android.os.Build
2323
import android.os.VibrationEffect
2424
import android.os.Vibrator
25+
import com.google.gson.annotations.SerializedName
2526
import com.movtery.zalithlauncher.utils.logging.Logger
2627
import top.fifthlight.touchcontroller.proxy.client.LauncherProxyClient
2728
import top.fifthlight.touchcontroller.proxy.message.VibrateMessage
@@ -34,10 +35,15 @@ class VibrationHandler(
3435
private val vibrateKind: VibrateKind?,
3536
) : LauncherProxyClient.VibrationHandler {
3637
enum class VibrateKind {
38+
@SerializedName("ONE_SHOT")
3739
ONE_SHOT,
40+
@SerializedName("CLICK")
3841
CLICK,
42+
@SerializedName("DOUBLE_CLICK")
3943
DOUBLE_CLICK,
44+
@SerializedName("HEAVY_CLICK")
4045
HEAVY_CLICK,
46+
@SerializedName("TICK")
4147
TICK;
4248

4349
companion object {

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/game/version/installed/VersionConfig.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,11 @@ class VersionConfig(
291291
}
292292

293293
enum class SettingState(val textRes: Int) {
294+
@SerializedName("FOLLOW_GLOBAL")
294295
FOLLOW_GLOBAL(R.string.generic_follow_global),
296+
@SerializedName("ENABLE")
295297
ENABLE(R.string.generic_enable),
298+
@SerializedName("DISABLE")
296299
DISABLE(R.string.generic_disable)
297300
}
298301

@@ -301,12 +304,16 @@ enum class GraphicsApi(
301304
val option: String
302305
) {
303306
/** 默认使用游戏设定 */
307+
@SerializedName("DEFAULT")
304308
DEFAULT("", "\"default\""),
305309
/** 强制切换到OpenGL,覆盖游戏原有设定 */
310+
@SerializedName("OPENGL")
306311
OPENGL("OpenGL", "\"opengl\""),
307312
/** 默认切换到OpenGL,如果游戏有设定过则不覆盖 */
313+
@SerializedName("DEFAULT_OPENGL")
308314
DEFAULT_OPENGL(OPENGL.displayName, OPENGL.option),
309315
/** 强制切换到Vulkan,覆盖游戏原有设定 */
316+
@SerializedName("VULKAN")
310317
VULKAN("Vulkan", "\"vulkan\"")
311318
}
312319

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/path/UrlManager.kt

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,23 @@ import io.ktor.client.engine.cio.CIO
2525
import io.ktor.client.plugins.HttpTimeout
2626
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
2727
import io.ktor.client.plugins.defaultRequest
28+
import io.ktor.client.request.HttpRequestPipeline
29+
import io.ktor.client.request.header
2830
import io.ktor.http.HttpHeaders
2931
import io.ktor.serialization.kotlinx.json.json
3032
import kotlinx.serialization.json.Json
33+
import okhttp3.Interceptor
3134
import okhttp3.OkHttpClient
3235
import okhttp3.Request
3336
import okhttp3.RequestBody
3437
import java.util.concurrent.TimeUnit
3538

3639
val URL_USER_AGENT: String = "${BuildKeys.LAUNCHER_SHORT_NAME}/Android_${BuildConfig.VERSION_NAME}"
3740
val TIME_OUT = TimeUnit.SECONDS.toMillis(30L)
41+
42+
const val HOST_CURSEFORGE_API = "api.curseforge.com"
43+
const val HOST_CURSEFORGE_EDGE = "edge.forgecdn.net"
44+
3845
const val URL_MCMOD: String = "https://www.mcmod.cn/"
3946
const val URL_MINECRAFT_VERSION_REPOS: String = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"
4047
const val URL_MINECRAFT_ASSETS_INDEX: String = "https://launchermeta.mojang.com/v1/packages"
@@ -70,10 +77,41 @@ val GLOBAL_CLIENT = HttpClient(CIO) {
7077
expectSuccess = true
7178

7279
defaultRequest {
73-
headers {
74-
append(HttpHeaders.UserAgent, URL_USER_AGENT)
80+
header(HttpHeaders.UserAgent, URL_USER_AGENT)
81+
}
82+
}.apply {
83+
requestPipeline.intercept(HttpRequestPipeline.State) {
84+
// 检查 host 是否为 CurseForge
85+
// 自动添加 CurseForge 的 api 密钥
86+
val host = context.url.host
87+
if (host == HOST_CURSEFORGE_API || host == HOST_CURSEFORGE_EDGE) {
88+
val apiKey = BuildKeys.CURSEFORGE_API
89+
if (apiKey.isNotBlank()) {
90+
context.header("x-api-key", apiKey)
91+
}
92+
}
93+
}
94+
}
95+
96+
/**
97+
* An [Interceptor] for CurseForge API requests.
98+
*
99+
* It automatically injects the `x-api-key` header when the request host matches
100+
* [HOST_CURSEFORGE_API] or [HOST_CURSEFORGE_EDGE], provided the API key is not blank.
101+
*/
102+
private val CURSEFORGE_INTERCEPTOR = Interceptor { chain ->
103+
val request = chain.request()
104+
val host = request.url.host
105+
if (host == HOST_CURSEFORGE_API || host == HOST_CURSEFORGE_EDGE) {
106+
val apiKey = BuildKeys.CURSEFORGE_API
107+
if (apiKey.isNotBlank()) {
108+
val newRequest = request.newBuilder()
109+
.header("x-api-key", apiKey)
110+
.build()
111+
return@Interceptor chain.proceed(newRequest)
75112
}
76113
}
114+
chain.proceed(request)
77115
}
78116

79117
fun createRequestBuilder(url: String): Request.Builder {
@@ -94,6 +132,7 @@ fun createOkHttpClient(): OkHttpClient = createOkHttpClientBuilder().build()
94132
fun createOkHttpClientBuilder(action: (OkHttpClient.Builder) -> Unit = { }): OkHttpClient.Builder {
95133
return OkHttpClient.Builder()
96134
.callTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
135+
.addInterceptor(CURSEFORGE_INTERCEPTOR)
97136
.apply(action)
98137
}
99138

@@ -112,6 +151,7 @@ val DOWNLOAD_OKHTTP_CLIENT: OkHttpClient by lazy {
112151
.readTimeout(30, TimeUnit.SECONDS)
113152
.writeTimeout(30, TimeUnit.SECONDS)
114153
.retryOnConnectionFailure(true)
154+
.addInterceptor(CURSEFORGE_INTERCEPTOR)
115155
.build()
116156
// 注意:不设置 callTimeout,因为文件大小差异极大
117157
// 协程层的 withTimeout 提供整体兜底保护

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/setting/SettingsInitializer.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
package com.movtery.zalithlauncher.setting
2020

2121
import android.content.Context
22-
import com.movtery.zalithlauncher.game.launch.parseJavaArguments
2322
import com.movtery.zalithlauncher.utils.device.Architecture
2423
import com.movtery.zalithlauncher.utils.platform.bytesToMB
2524
import com.movtery.zalithlauncher.utils.platform.getTotalMemory
25+
import com.movtery.zalithlauncher.utils.string.splitPreservingQuotes
2626

2727
private const val LWJGL_LIB_NAME_ARG = "-Dorg.lwjgl.opengl.libname="
2828

@@ -37,7 +37,7 @@ fun loadAllSettings(context: Context, reloadAll: Boolean = false) {
3737
AllSettings.ramAllocation.save(ram)
3838
}
3939
val jvmArgs = AllSettings.jvmArgs.getValue()
40-
parseJavaArguments(jvmArgs).find { it.startsWith(LWJGL_LIB_NAME_ARG) }?.let { arg ->
40+
jvmArgs.splitPreservingQuotes().find { it.startsWith(LWJGL_LIB_NAME_ARG) }?.let { arg ->
4141
AllSettings.jvmArgs.save(jvmArgs.replace(arg, ""))
4242
}
4343
}

ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/elements/LauncherElements.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,13 +319,13 @@ fun Background(
319319
modifier: Modifier = Modifier,
320320
allowVideo: Boolean = true
321321
) {
322-
if (viewModel.isValid) {
323-
Box(
324-
modifier = modifier.backgroundBlur(
325-
blur = AllSettings.backgroundBlur.state,
326-
hazeState = viewModel.hazeState,
327-
)
328-
) {
322+
Box(
323+
modifier = modifier.backgroundBlur(
324+
blur = AllSettings.backgroundBlur.state,
325+
hazeState = viewModel.hazeState,
326+
)
327+
) {
328+
if (viewModel.isValid) {
329329
when {
330330
viewModel.isVideo && allowVideo -> {
331331
VideoPlayer(

0 commit comments

Comments
 (0)