Files
Starlight_Lancher_animation_up/README.md

381 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div align="center">
<img src="./apps/app/icons/128x128.png" width="128" height="128" alt="Starlight Launcher Logo" />
<h1>Starlight Launcher</h1>
<p><strong>次世代 Minecraft 桌面客户端,全能、美观、全平台覆盖。</strong></p>
<p>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/actions">
<img src="https://img.shields.io/badge/Repo-git.starlight.cool-blue?style=for-the-badge&logo=git" alt="Repository" />
</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/releases">
<img src="https://img.shields.io/badge/Releases-Download-green?style=for-the-badge&logo=github" alt="Releases" />
</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/stargazers">
<img src="https://img.shields.io/badge/Stars-★-ffb800?style=for-the-badge&logo=github" alt="Stars" />
</a>
<a href="COPYING.md">
<img src="https://img.shields.io/badge/License-GPL_3.0-blue.svg?style=for-the-badge" alt="License" />
</a>
</p>
<p>
<a href="https://skin.starlight.cool/">官方网站</a>
<a href="https://git.starlight.cool/AxTps/Starlight_Lancher/releases/latest">下载最新版</a>
<a href="CONTRIBUTING.md">参与贡献</a>
<a href="CODE_OF_CONDUCT.md">行为准则</a>
</p>
</div>
<details open>
<summary><strong>关于 The Land of StarLight (TLSL)</strong></summary>
**The Land Of StarLight**(中文全称**星光领域**,英文简称 **TLSL**)成立于 2014 年,是一个主营 Minecraft 相关内容的综合性平台。平台主要负责人为 **Disy**(因名称常被抢注,在多数平台以 **Disy920** 出现)。
TLSL 的前身可追溯至 2012 年初建立的凋灵服务器TWS。经过多次重组与模式调整于 2014 年 10 月定名为**星光服务器StarLight-Server简称 SLS**。2020 年初随着运营模式改变与业务扩展TLSL 正式成立SLS 成为其主营子项目。
如今 TLSL 旗下拥有 Minecraft 服务器 **StarLight-ServerSLS**、面向 Fabric 端的领地模组 **Enclosure** 等项目,致力于打造一个完善的 Minecraft 交流与开发平台。
**Starlight Launcher** 即是面向 **SLS星光服务器** 打造的 Minecraft 桌面启动器。
</details>
---
**Starlight Launcher星光启动器** 是一款免费、开源、跨平台的 Minecraft Java 版第三方启动器,支持在一个客户端中搜索、安装和更新来自 Modrinth 与 CurseForge 的模组、整合包、资源包和光影,并提供实例管理、多种账户认证与个性化外观。
本项目基于 [Modrinth App](https://github.com/modrinth/code) 构建,并在其基础上由 [Axolotl 启动器](https://github.com/Mystic-Stars/Axolotl) 修改而来,移除了不适用于本项目的商业化模块,专注于提供纯净、无广告的桌面启动体验。
_(注:本项目是调用 Modrinth 公开 API 的独立客户端,与 Rinth, Inc. 无任何关联。)_
## 核心优势
- **真跨平台体验**:告别繁琐的环境配置,原生支持 Windows、macOS完美兼容 Intel 与 Apple Silicon及各类主流 Linux 发行版。
- **现代化内容生态**:集成 Modrinth 和 CurseForge可在启动器中一键浏览。游戏实例、整合包、模组、资源包及光影均可一键安装与升级彻底告别手动管理依赖的痛苦。
- **高度定制化**:无论是主题色调、背景图片,还是离线皮肤,核心功能与视觉展现均由你自由支配。
- **All in one 全新体验**:启动器内置 “实验室” 功能,囊括种子地图、投影工坊等海量使用工具,带来全新原生轮椅体验。
## 下载与安装
请前往 [Releases](https://git.starlight.cool/AxTps/Starlight_Lancher/releases/latest) 下载适合你操作系统的最新安装包。
已安装的用户每次均可通过内置的 Tauri 签名校验机制,自动在后台完成更新,无需手动下载安装更新。
| 系统平台 | 推荐下载文件 |
| ----------------------- | ----------------------------------------- |
| **Windows** (10/11 x64) | 下载 `.exe` (NSIS) 安装程序 |
| **macOS** | 下载 `通用 .dmg` 镜像文件 |
| **Linux** (x64) | 提供 `.AppImage``.deb``.rpm` 多种格式 |
## 参与项目开发
Starlight Launcher 的进步离不开社区的反馈与贡献。
如果遇到 Bug 或有新的功能点子,欢迎提交 Issue。如需搭建本地开发环境或查阅打包发布规范请阅读详细的 [贡献指南 (CONTRIBUTING.md)](CONTRIBUTING.md)。
参与社区和贡献代码前,也请先阅读[行为准则 (CODE_OF_CONDUCT.md)](CODE_OF_CONDUCT.md)。
---
# 🌟 启动过渡动画(本次改动)
> 本节记录「游戏启动时窗口平滑过渡」功能的完整实现,供后续维护、移植与继续开发使用。
> **生效平台:仅 Windows**(其他平台为空实现,行为与改动前一致)。
## 一、功能目标
消除「点击启动 → MC 游戏窗口突然弹出 → 把启动器挤走」的割裂感,用一套完整的窗口动画把这段过渡变得顺滑。
启动一个实例后,会经历以下动画序列:
```
点击「启动实例」
① 纯色遮罩出现(启动器主题色,无图)—— 立刻盖住后续所有抖动
② 启动器放大到全屏0.4s 动画,全程置顶 + 聚焦)
③ 全屏后,遮罩上渐显 Mojang SVG logo0.5s
④ 等待 MC 游戏窗口出现(最多 60 秒,期间遮罩一直盖着)
⑤ 缩小前:遮罩背景色 → Mojang 红 (#db1f29) + 渐隐 logo0.5s
⑥ 启动器缩放到 MC 窗口的位置和大小0.4s
⑦ 等待 1 秒(让游戏稳定,遮罩仍在)
⑧ 整体淡出透明0.5s)→ 聚焦游戏窗口 → 启动器最小化
进入轻量模式(隐藏到系统托盘)
```
**设计要点**
- **遮罩提前**:纯色遮罩在放大**之前**就出现,所以放大和缩小时的窗口抖动都被盖住,用户看不到。
- **缩放与淡出串行**:先缩放完成,再淡出,不再同步进行(早期版本两者同步,观感差)。
- **动画放慢**:缩放 0.4s(早期 0.2s 太快),淡出 0.5s。
- **修复重开透明**:最小化后重置窗口透明度,并且恢复时用轻量模式**重建全新窗口**,彻底杜绝「重新打开启动器一片透明、需要点击/拖动才恢复」的问题。
- **轻量模式接管**:过渡动画结束后,统一进入轻量模式(隐藏到托盘),不再分别判断用户的「轻量模式 / 启动后隐藏」设置,避免冲突。
## 二、改动文件总览
| 文件 | 改动类型 | 说明 |
|---|---|---|
| `apps/app/src/mc_transition.rs` | **新建** | 核心模块(约 470 行),负责窗口查找、四段动画、遮罩/淡出协调 |
| `apps/app/src/main.rs` | 修改 | 声明模块 + 注册 4 个 Tauri 命令 |
| `apps/app/src/lightweight_mode.rs` | 修改 | `launched` 分支接入过渡,并统一进轻量模式 |
| `apps/app/Cargo.toml` | 修改 | windows crate 增加 `Win32_Graphics_Gdi` feature |
| `apps/app-frontend/src/App.vue` | 修改 | 遮罩三阶段、淡出、透明度重置等前端逻辑 |
| `apps/app-frontend/public/mojang-logo.svg` | 新建 | 过渡遮罩上显示的 Mojang logo |
| `packages/app-lib/.env` | 新建 | 从 `.env.prod` 复制,提供编译期环境变量(非功能改动) |
## 三、各文件详细说明
### 1. `apps/app/src/mc_transition.rs`(新建 · 核心)
> 搜索定位关键词:`mc_transition`
**关键常量**
| 常量 | 值 | 含义 |
|---|---|---|
| `FIND_RETRIES` | 120 | 等待 MC 窗口的最大轮询次数 |
| `FIND_INTERVAL_MS` | 500 | 每次轮询间隔120 × 500ms = 60 秒) |
| `ANIM_DURATION_MS` | 400 | 放大/缩小动画时长0.4s |
| `ANIM_STEPS` | 50 | 动画帧数400ms / 50 = 8ms 一帧) |
| `FADE_TIMEOUT_MS` | 700 | 等待前端淡出的超时兜底 |
**静态变量(跨 await 传信号)**
- `FADE_DONE` — 等前端淡出完成
- `COVER_DONE` — 等纯色遮罩出现
- `LOGO_IN_DONE` — 等 logo 渐显完成
- `LOGO_OUT_DONE` — 等 logo 渐隐 + 变红完成
**关键函数**
| 函数 | 关键词 | 作用 |
|---|---|---|
| `pub async fn run(app, pid, maximize)` | `run() invoked` | 主入口,串联全部 8 步 |
| `async fn animate_resize(...)` | `animate_resize` | 分帧移动 + 缩放窗口 |
| `fn ease_in_out(t)` | `ease_in_out` | 缓入缓出曲线 |
| `win_impl::find_window(pid)` | `find_cb` / `FOUND_HWND` | 按 pid 枚举顶层窗口 |
| `win_impl::covers_monitor(raw)` | `covers_monitor` | 判断窗口是否铺满显示器 |
| `win_impl::get_rect(raw)` | `get_rect` | 取窗口矩形 |
| `win_impl::focus(raw)` | `SetForegroundWindow` | 把焦点交给游戏 |
| `win_impl::dump_pid_windows(pid)` | `dump_pid_windows` | **调试用**:列出 pid 下所有窗口 |
| `#[tauri::command] mc_transition_fade_done` | — | 前端淡出完成回调 |
| `#[tauri::command] mc_transition_cover_ready` | — | 遮罩出现完成回调 |
| `#[tauri::command] mc_transition_logo_in_done` | — | logo 渐显完成回调 |
| `#[tauri::command] mc_transition_logo_out_done` | — | logo 渐隐完成回调 |
**⚠️ 三个关键设计约束(改代码前必读)**
1. **HWND 不能跨 await 持有**
`HWND` 是裸指针,非 `Send`,一旦跨 `await` 持有async 块就不是 `Send`,无法被 `tauri::async_runtime::spawn`
→ 因此全程用 `usize` 保存窗口句柄(变量 `mc_raw`),只在同步的 win32 调用里通过 `to_hwnd()` 临时转回。
搜索关键词:`to_hwnd``FOUND_HWND`
2. **`BOOL` 的导入路径**。
`windows` crate 0.61 中,`BOOL` 位于 `windows::core::BOOL`**不在** `Win32::Foundation`
搜索关键词:`use windows::core::BOOL`
3. **窗口尺寸过滤阈值**
`find_cb` 里只认宽高都 > 50 的可见窗口,用来排除工具窗口 / 0 尺寸窗口。
**⚠️ 调试代码仍在(上线前需清理)**
- `fn dbg(msg)` —— 把日志直接写入 `%USERPROFILE%\mc_transition_debug.log`,绕过 tracing 配置
- 全文件多处 `dbg(...)` 调用
- 等待窗口期间每 2 秒调用一次 `dump_pid_windows`
- 搜索关键词:`fn dbg(``mc_transition_debug.log``dump_pid_windows`
### 2. `apps/app/src/main.rs`
- 第 25 行附近:`mod mc_transition;`
- `invoke_handler``generate_handler!` 宏内注册 4 个命令:
```rust
mc_transition::mc_transition_fade_done,
mc_transition::mc_transition_cover_ready,
mc_transition::mc_transition_logo_in_done,
mc_transition::mc_transition_logo_out_done,
```
- 搜索关键词:`mod mc_transition``mc_transition_fade_done`
### 3. `apps/app/src/lightweight_mode.rs`
`process_event``None if payload.event == "launched"` 分支(约 250 行起):
- 新增调用:`crate::mc_transition::run(&app, payload.pid, payload.maximize_window).await;`
- 过渡完成后**统一**进入轻量模式:`state.enter(&app)`
- **删除**了原来分别判断 `settings.enter_lightweight_mode_on_game_launch``settings.hide_on_process_start` 的逻辑
- 搜索关键词:`crate::mc_transition::run``launched``enter lightweight mode after transition`
**执行顺序**
```
maximize_minecraft_window若用户勾选最大化
→ mc_transition::run完整过渡动画
→ state.enter()(隐藏到托盘)
```
### 4. `apps/app/Cargo.toml`
`[target."cfg(windows)".dependencies.windows]` 的 features 中新增:
```toml
"Win32_Graphics_Gdi",
```
> 原因:`GetMonitorInfoW` / `MonitorFromWindow` / `MONITORINFO` 属于 GDI 模块,不加会编译失败。
- 搜索关键词:`Win32_Graphics_Gdi`
### 5. `apps/app-frontend/src/App.vue`
**变量声明**(约 376~381 行):
```ts
let unlistenMcTransitionFadeout: (() => void) | undefined
let unlistenMcTransitionFocus: (() => void) | undefined
let unlistenMcTransitionCover: (() => void) | undefined
let unlistenMcTransitionLogoIn: (() => void) | undefined
let unlistenMcTransitionLogoOut: (() => void) | undefined
let unlistenMcTransitionReset: (() => void) | undefined
```
**`onMounted` 内注册的监听**(约 500 行起):
| 监听事件 | 作用 |
|---|---|
| `mc-transition-fadeout` | `#app``opacity: 0` + 500ms 过渡510ms 后回调 `mc_transition_fade_done` |
| `mc-transition-cover-show` | 动态创建遮罩 div主题色背景 + 隐藏的 logo渐显后回调 `mc_transition_cover_ready` |
| `mc-transition-logo-in` | logo 渐显opacity 0→1520ms 后回调 `mc_transition_logo_in_done` |
| `mc-transition-logo-out` | 遮罩背景 → `#db1f29` + logo 渐隐520ms 后回调 `mc_transition_logo_out_done` |
| `mc-transition-reset-opacity` | 重置 `#app` 透明度 + 移除遮罩 |
**透明度重置(修复重开透明)**——三重兜底:
- `window``focus` 事件
- `document``visibilitychange` 事件
- Tauri 的 `getCurrentWindow().onFocusChanged`
任一触发即调用 `resetLauncherOpacity()`,把 `#app` 的 opacity 清空。
**`onUnmounted` 内清理**(约 674 行起6 个 `unlistenMcTransition*.?.()`
- 搜索关键词:`unlistenMcTransitionFadeout``mc-transition-fadeout``mc_transition_fade_done``mcCoverEl``resetLauncherOpacity`
**遮罩实现细节**
遮罩是**运行时动态创建**的 DOM不是 Vue template避免改动庞大的 template 结构:
```ts
mcCoverEl = document.createElement('div') // 固定定位、铺满、主题色背景、最高 z-index
mcCoverImg = document.createElement('img') // /mojang-logo.svg初始 opacity 0
```
- 遮罩 id`mc-transition-cover`
- 背景色:`var(--color-brand, #db1f29)`(跟随启动器主题色)
- logo 宽度42%,最大 640px
### 6. `apps/app-frontend/public/mojang-logo.svg`(新建)
过渡遮罩上显示的 Mojang 官方 logo矢量图
## 四、实测记录
调试日志 `%USERPROFILE%\mc_transition_debug.log` 中的一次完整流程实录:
```
run() invoked pid=3088 maximize=false
try#0 ... try#38 candidates: [] <- MC 窗口约 20 秒后才出现
FOUND hwnd=0x3b03da try#40 covers=false
...
```
**关键发现**
- **MC 窗口需要约 20 秒才出现**(带 mod 的实例更慢),所以等待轮询必须足够长(当前 60s
- 早期版本只等 5 秒,导致「启动器毫无变化」的假象——实际是超时静默放弃了。
## 五、编译与运行Windows
### 前置准备
```bat
:: 1. 子模块(本项目不是 git 仓库,需手动 clone
git clone https://github.com/Cubitect/cubiomes.git apps/app/vendor/cubiomes
git clone https://github.com/Axolotl-Launcher/blockbench-skin-standalone.git third-party/blockbench
:: 2. 环境变量(或把 .env.prod 复制为 packages/app-lib/.env
set "PATH=%USERPROFILE%\.cargo\bin;%PATH%"
set "MODRINTH_URL=https://modrinth.com/"
set "MODRINTH_API_BASE_URL=https://api.modrinth.com/"
set "MODRINTH_ARCHON_BASE_URL=https://archon.modrinth.com/"
set "MODRINTH_API_URL=https://api.modrinth.com/v2/"
set "MODRINTH_API_URL_V3=https://api.modrinth.com/v3/"
set "MODRINTH_SOCKET_URL=wss://api.modrinth.com/"
set "MODRINTH_LAUNCHER_META_URL=https://launcher-meta.modrinth.com/"
```
### 构建
```bat
:: 前端
pnpm install
pnpm --filter @modrinth/app-frontend run build
:: 后端 debug产物 target/debug/theseus_gui.exe约 155 MB
cargo build -p theseus_gui
:: 后端 release产物 target/release/theseus_gui.exe约 75 MB
cargo build -p theseus_gui --release
```
### 已知坑
| 坑 | 现象 | 解决 |
|---|---|---|
| 子模块缺失 | `build.rs` panic`Blockbench skin editor submodule is missing` | 手动 clone 两个子模块 |
| 资源路径校验 | `resource path resources\blockbench-skin doesn't exist` | 构建会自动生成;若报错手动建空目录 |
| 环境变量缺失 | `environment variable MODRINTH_API_URL not defined` | 见上方环境变量,或复制 `.env` |
| 数据库迁移冲突 | `migration ... was previously applied but is missing` | 删除 `%APPDATA%\cool.starlight.launcher\release\app.db` 后重启 |
| exe 被占用 | `failed to remove file ...theseus_gui.exe`(拒绝访问) | `taskkill /F /IM theseus_gui.exe` 后重编 |
| `pnpm app:build` 失败 | 找不到 cargo | 那会走完整 `tauri build` 打包;只构建前端请用 `--filter @modrinth/app-frontend` |
## 六、待办 / TODO
| # | 事项 | 优先级 | 关键词 |
|---|---|---|---|
| 1 | **清理调试代码**:删 `fn dbg` + 所有 `dbg(...)` + `dump_pid_windows` 调用 | 高 | `fn dbg(``mc_transition_debug.log` |
| 2 | 等待窗口超时60s可做成可配置 / 事件驱动 | 中 | `FIND_RETRIES` |
| 3 | 多显示器场景未充分测试(已按窗口所在屏取显示器) | 中 | `monitor_rect` |
| 4 | 前端淡出若卡顿靠 700ms 兜底 | 低 | `FADE_TIMEOUT_MS` |
| 5 | `SetForegroundWindow` 可能被系统拒绝,未做失败重试 | 低 | `focus` |
| 6 | 未来若做 macOS / Linux 支持:需 `CGWindowListCopyWindowInfo` / X11Wayland 基本不可行) | 低 | `#[cfg(target_os]` |
## 七、快速搜索索引
| 想找什么 | 搜这个关键词 |
|---|---|
| 核心模块 | `mc_transition` |
| 过渡主流程 | `pub async fn run(app` |
| 八步流程标记 | `step 1` ~ `step 8` |
| 找 MC 窗口 | `find_window``find_cb` |
| 全屏判定 | `covers_monitor` |
| 缩放动画 | `animate_resize``ANIM_DURATION_MS` |
| 缓动曲线 | `ease_in_out` |
| 纯色遮罩事件 | `mc-transition-cover-show` |
| logo 渐显事件 | `mc-transition-logo-in` |
| logo 渐隐/变红事件 | `mc-transition-logo-out` |
| 淡出事件 | `mc-transition-fadeout` |
| 透明度重置事件 | `mc-transition-reset-opacity` |
| 前端回调命令 | `mc_transition_cover_ready``mc_transition_logo_in_done``mc_transition_logo_out_done``mc_transition_fade_done` |
| 接入点 | `crate::mc_transition::run` |
| 透明度重置函数 | `resetLauncherOpacity` |
| 遮罩 DOM | `mc-transition-cover``mcCoverEl` |
| 调试日志(待删) | `fn dbg(``mc_transition_debug.log` |
| 调试日志文件 | `%USERPROFILE%\mc_transition_debug.log` |
| windows feature | `Win32_Graphics_Gdi` |
| 数据库冲突 | `previously applied but is missing` |
---
_文档结束。功能已跑通上线前记得清理调试代码喵。_