Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# JavaAntLauncher — repository notes

Android launcher for Minecraft: Java Edition. Fork of Zalith Launcher 2, which itself
descends from PojavLauncher. Repo root is the Gradle root; the Android app module is
`ZalithLauncher/`.

## Build

* `./gradlew :ZalithLauncher:assembleDebug` (needs a JDK and an Android SDK).
* A dev container may have neither installed — check before promising a compile or a run.
* `ZalithLauncher/gradle.properties` holds `oauth_client_id`; a git-ignored
`ZalithLauncher/.oauth_client_id.txt` overrides it locally. CI passes `OAUTH_CLIENT_ID`.
* Microsoft sign-in needs a real Azure app registration (public client flows enabled).
Without one, only offline/local accounts work.

## Architecture worth knowing

* Launch pipeline: `LaunchGameOperation.TryLaunch` (UI gate) →
`LaunchGameViewModel.start()` → `GameLaunchFlow.buildLaunchPhases()` (account check +
file verification) → `runGame()` → `GameLauncher.launch()`.
* `LaunchGameOperation` is a sealed interface in
`ui/screens/content/elements/LauncherElements.kt`. Adding a case means handling it in the
`when` in that same file — it is exhaustive, so the compiler enforces it.
* `Version` is `Parcelize`d and passed through Intents. `getVersionInfo()` returns
`VersionInfo?`; it is **null** whenever the version's `<name>.json` is missing or fails to
parse, while the version can still exist on disk. `version.isValid()` is exactly
"versionInfo parsed successfully".
* `version.offlineAccountLogin` decides whether `GameLauncher` swaps in a LOCAL copy of the
account (`usingAccount`). Microsoft accounts with no entitlement are constructed as offline
identities (locally derived UUID, no official profile), so they *must* keep this flag or
the client fails session validation after launch.
* `OfflineYggdrasilServer` is only started for LOCAL accounts that have a local skin file;
it is what lets offline accounts resolve skins.

## Conventions

* UI strings live in `values/`, `values-zh-rCN/`, `values-zh-rTW/`. Add all three.
* Comments in this codebase are written in Chinese; match the surrounding file.
* `!!` on `getVersionInfo()` is a latent crash. Use `?.` and surface a launch error instead.

## Gotchas

* No JDK/Android SDK in the default dev container: verify Kotlin changes by reading, not by
compiling, unless you install a toolchain.
* `MCOptions` watches `options.txt` with a `FileObserver`; it stops watching around its own
atomic write to avoid re-entrant reloads.
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,16 @@ class GameHandler(
// set("options.narrator", "0")
// set("narrator", "0")

if (version.getVersionInfo()!!.minecraftVersion.isLowerVer("1.13")) {
//fix: 牢版本按键事件
//shift + w -> 87 错误的触发了F11,切换全屏
set("key_key.fullscreen", "0")
//输入字符@ -> 64 错误的触发了F6,触发“开始/停止直播”
set("key_key.streamStartStop", "0")
set("key_key.streamPauseUnpause", "0")
//版本信息缺失时无法判断版本号,跳过这些兼容性修正而不是中断启动
version.getVersionInfo()?.minecraftVersion?.let { minecraftVersion ->
if (minecraftVersion.isLowerVer("1.13")) {
//fix: 牢版本按键事件
//shift + w -> 87 错误的触发了F11,切换全屏
set("key_key.fullscreen", "0")
//输入字符@ -> 64 错误的触发了F6,触发“开始/停止直播”
set("key_key.streamStartStop", "0")
set("key_key.streamPauseUnpause", "0")
}
}

set("overrideWidth", screenSize.width.toString())
Expand All @@ -126,7 +129,9 @@ class GameHandler(
else -> set(graphicsOption, graphicsApi.option)
}

loadLanguage(version.getVersionInfo()!!.minecraftVersion)
version.getVersionInfo()?.minecraftVersion?.let { minecraftVersion ->
loadLanguage(minecraftVersion)
}
save()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ sealed interface LaunchGameOperation {
data object NoVersion : LaunchGameOperation
/** 版本名称非法时 */
data class InvalidVersionName(val th: InvalidFilenameException) : LaunchGameOperation
/** 选中的版本无法读取版本信息(缺少或损坏的 json),无法启动 */
data class InvalidVersion(val version: Version) : LaunchGameOperation
/** 没有可用账号 */
data object NoAccount : LaunchGameOperation

Expand Down Expand Up @@ -228,6 +230,13 @@ fun LaunchGameOperation(
launchGameViewModel.updateOperation(LaunchGameOperation.None)
}
}
is LaunchGameOperation.InvalidVersion -> {
LaunchedEffect(Unit) {
eventViewModel.sendToast(androidText(R.string.game_launch_invalid_version))
toVersionManageScreen()
launchGameViewModel.updateOperation(LaunchGameOperation.None)
}
}
is LaunchGameOperation.RendererNoStoragePermission -> {
LaunchedEffect(Unit) {
val renderer = operation.renderer
Expand Down Expand Up @@ -303,7 +312,13 @@ fun LaunchGameOperation(
Renderers.setCurrentRenderer(version.getRenderer())
val currentRenderer = Renderers.getCurrentRenderer()

val mcVer = version.getVersionInfo()!!.minecraftVersion
//缺少或损坏的版本 json 会导致版本信息为 null,后续所有取用都会失败
//这里提前拦截,避免启动过程中直接崩溃
val versionInfo = version.getVersionInfo() ?: run {
launchGameViewModel.updateOperation(LaunchGameOperation.InvalidVersion(version))
return@LaunchedEffect
}
val mcVer = versionInfo.minecraftVersion

// 设备完全支持 Vulkan 时跳过渲染器的版本支持检查
if (!version.hasVulkanBackend() || !ensureVulkanSupported(version)) {
Expand Down
1 change: 1 addition & 0 deletions ZalithLauncher/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@
<!-- 启动游戏 -->
<string name="game_launch_no_version">未选择游戏版本!</string>
<string name="game_launch_no_account">未登录游戏账号!</string>
<string name="game_launch_invalid_version">该版本无法启动:版本文件缺失或已损坏。请重新安装该版本后再试。</string>
<string name="game_auto_pick_runtime_failed">未找到合适的运行环境,已设置为当前版本选择的运行环境。</string>
<string name="game_button_input">输入法</string>
<string name="game_button_force_close">强制关闭</string>
Expand Down
1 change: 1 addition & 0 deletions ZalithLauncher/src/main/res/values-zh-rTW/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@
<!-- 啟動遊戲 -->
<string name="game_launch_no_version">未選擇遊戲版本!</string>
<string name="game_launch_no_account">未登入遊戲帳號!</string>
<string name="game_launch_invalid_version">該版本無法啟動:版本檔案缺失或已損毀。請重新安裝該版本後再試。</string>
<string name="game_auto_pick_runtime_failed">找不到合適的執行環境,已設定為目前版本選擇的執行環境。</string>
<string name="game_button_input">輸入法</string>
<string name="game_button_force_close">強制關閉</string>
Expand Down
1 change: 1 addition & 0 deletions ZalithLauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@
<!-- Game Launch -->
<string name="game_launch_no_version">No game version selected!</string>
<string name="game_launch_no_account">No account logged in!</string>
<string name="game_launch_invalid_version">This version cannot be launched: its version file is missing or damaged. Reinstall the version and try again.</string>
<string name="game_auto_pick_runtime_failed">No compatible runtime found. Using selected version\'s runtime.</string>
<string name="game_button_input">Input Method</string>
<string name="game_button_force_close">Force Close</string>
Expand Down
Loading