用户诉求是 PCL 差距四项里的「存档截图 / 导入」,M230 审计确认三层全缺。塔裁决 U3
把这一版钉成「只读列表 + 打开文件夹」,不做缩略图墙(缩略图要引图片解码依赖,而
AGENTS §2 只允许 palette-extract 引 image 类依赖;截图/导入产物形态也没定型)。
core
- `game::saves`(新):只读列 `<run_dir>/saves`(世界目录)与 `<run_dir>/screenshots`
(图片文件)。只调 symlink_metadata / read_dir / metadata,不建目录、不写文件、不读
文件内容(`icon.png` 只判存在)。目录不存在 ⇒ 空列表不是错误;存在但不可用(符号
链接 / 不是目录 / 读不了)⇒ 具名错误。条目级异常逐条登记原因,不静默丢。
- `platform::opener`(新):`open_dir` 是**目录**打开器的唯一收敛点(explorer / open /
xdg-open),内部复用 `child::quiet`,cfg 分支只此一处。塔明确要求按 AGENTS §6 放
platform 而不是业务模块,并要一条可执行判据防退化
(`the_launcher_literals_live_here_only` 扫 `crates/core/src`:除本文件外不许出现
`"explorer"` / `"xdg-open"` 字面量)。
presenter
- `dto::saves`:SavesCommand(List / OpenFolder)、SavesListView、SavesFailureView
(结构 + OS 原文,不拼中文)、`SavesListView` 的计数助手。
- `host::saves`:走 `job::spawn`,UI 只收快照;运行目录仍是
`isolation::derive_game_dir` 的同一个答案(与启动 / mod 列表同源,**不写盘**)。
「打开文件夹」打开哪个目录由 host 定:`saves/` → `screenshots/` → 运行目录。
失败分三类(InstanceUnavailable / DirUnusable / OpenFailed),可重试。
- `state::saves`:快照整体替换、迟到结果丢弃、失败保留绑定(重试才有意义)。
- 接线:CoreEvent::Saves / AppCommand::Saves / HostTask::Saves。
app-iced
- `pages::instances::saves`:详情页 SAVES 卡片(MODS 之后、启动参数之前;**不套第二层
滚动条**,整列那一条是唯一入口)。世界行带 UTC 时间与「有图标」,截图行带大小与时间;
第一行固定画「这一版只读」(U3 边界让用户看得见)。读盘失败画一条红字 + 「重试」;
打开文件夹失败**不画**重试(那个动作的重试就是再点一次按钮)。
- 接线:Message::{ReloadSaves, OpenSavesFolder}、`sync_saves`(与 `sync_mods` 同一判据)、
Model::saves、`saves_shot` 出图夹具(ULL_SAVES_FIXTURE=1)。
i18n
- `InstancesSaves*` 20 条中英成对,catalog 与金表在**同一条锚点**后追加、逐字节一致。
证据
- core 只读判据:`game::saves::tests` 在真盘建世界/截图,调用前后各拍一次
(相对路径, 是否目录, 字节数, mtime)指纹并逐条比对;另有用例钉「目录缺失不建目录」。
- presenter:`host::saves::tests` 真盘端到端(custom 档位派生运行目录 → 快照)。
- GUI:`--software-renderer` 1180×760 浅/深各一张 + 1180×1280 两张「整块卡片可见」
(1180×760 下 SAVES 卡片位于折叠线附近,只能看到卡头;第二对用 ULL_WINDOW_SIZE
把窗口拉高,口径与 M98 的矩阵一致),落 `DevDocs/artifacts/M235/`。
没做的(U3 边界内,见 handoff):缩略图墙、导入、删除/重命名、`level.dat` 的
LevelName 解析(世界名暂时就是目录名)。
92 lines
4.5 KiB
Rust
92 lines
4.5 KiB
Rust
//! 版本与实例仓库:不可变快照 + 单写者草稿、版本 JSON 继承解析、实例目录布局。
|
||
//!
|
||
//! 设计定稿:`DevDocs/PlanDoc/04-data-and-config.md` §4(实例模型)、
|
||
//! `DevDocs/PlanDoc/01-tech-stack-and-architecture.md` §3(Snapshot/Draft 纪律),
|
||
//! 源证据 `DevDocs/analyse/01-architecture-overview.md` §3.3。
|
||
//!
|
||
//! 与其它模块的契约:快照(Snapshot)类型与继承解析结果要与 launch 对齐
|
||
//! (`DevDocs/SubAgentsTalk/README.md` 的对齐点;详细约定见 `SubAgentsTalk/game-接口约定.md`)。
|
||
//!
|
||
//! 公共面(M14):
|
||
//! - 版本清单:[`VersionList`] / [`RemoteVersion`] / [`ReleaseType`] / [`VersionCategory`],
|
||
//! 外加内嵌补充清单 [`unlisted`];
|
||
//! - 版本 JSON 与继承:[`VersionJson`]、[`resolve`]、[`merge`]、[`apply_patches`];
|
||
//! - 参数与库:[`Arguments`] / [`Environment`] / [`Rule`]、[`Library`] / [`MavenCoordinate`];
|
||
//! - 版本 id → 加载器:[`loader`]([`InstanceLoader::parse`],全仓唯一解析入口);
|
||
//! - 能力位:[`capability`](版本 JSON 库表 → `has_vulkan_backend`);
|
||
//! - 实例:目录布局 [`GameLayout`]、档案 [`ProfileList`] / [`InstanceProfile`] / [`ProfileId`];
|
||
//! - 发布:快照仓库 [`Store`] / [`Snapshot`] / [`Draft`]。
|
||
//!
|
||
//! 安装层(M27,[`install`]):版本链 → 下载计划 → 分区落盘 → 实例登记。
|
||
//! 它把上面这些"模型"串成可执行的流程,但**自己不碰 UI、不拼镜像 URL**:
|
||
//! 下载全部交给 `core::download` 的引擎(镜像/健康度/续传/校验都在那边)。
|
||
//!
|
||
//! Java 管理(M33,[`java`]):托管 JDK 的查询/下载/解压/探测(`.ULL/data/java-managed/`)
|
||
//! 与 MC↔Java 映射表。同样只借 `core::download` 的引擎做下载,自己不拼镜像 URL。
|
||
//!
|
||
//! 已铺在盘上的版本接入(M221,[`adopt`]):扫描/检查 `versions/` 里**别人装的**版本 → 只登记
|
||
//! (`profiles.json` + 实例设置),不搬文件、不写游戏根。缺省运行目录落 ULL 数据区,
|
||
//! 共用/写进对方的 `.minecraft` 必须显式选择(见 [`adopt::AdoptTarget`])。
|
||
//!
|
||
//! 存档与截图(M235,[`saves`]):**只读**列 `<run_dir>/saves`(世界目录)与
|
||
//! `<run_dir>/screenshots`(图片),不建目录、不写盘;「打开文件夹」走
|
||
//! [`crate::platform::opener::open_dir`](平台差异不在这里)。缩略图墙与导入不在这一版(塔裁决 U3)。
|
||
//!
|
||
//! 模块分工按"数据形状 / 纯计算 / 状态"切开,任何模块都不碰网络与 UI:
|
||
//! 下载归 `core::download`、进程归 `core::launch`、配置落盘归 `core::setting`。
|
||
|
||
pub mod adopt;
|
||
pub mod arguments;
|
||
pub mod capability;
|
||
pub mod error;
|
||
pub mod inherit;
|
||
pub mod install;
|
||
pub mod isolation;
|
||
pub mod java;
|
||
pub mod launch_overrides;
|
||
pub mod layout;
|
||
pub mod library;
|
||
pub mod loader;
|
||
pub mod manifest;
|
||
pub mod profiles;
|
||
pub mod saves;
|
||
pub mod snapshot;
|
||
pub mod unlisted;
|
||
pub mod version;
|
||
|
||
pub use adopt::{
|
||
AdoptCandidate, AdoptError, AdoptOutcome, AdoptPlan, AdoptProblem, AdoptRequest, AdoptScan,
|
||
AdoptTarget, RegisteredInstance,
|
||
};
|
||
pub use arguments::{rules_allow, Arguments, Environment, ExpandedArguments, Rule, RuleAction};
|
||
pub use capability::{
|
||
is_vulkan_library, library_names_have_vulkan, VersionCapabilities, VULKAN_LIBRARY_ARTIFACT,
|
||
VULKAN_LIBRARY_GROUP,
|
||
};
|
||
pub use error::GameError;
|
||
pub use inherit::{apply_patches, merge, resolve, sorted_patches, VersionSource};
|
||
pub use isolation::{
|
||
derive_game_dir, observe_mode, probe_both_sides, probe_side, Derivation, IsolationMode,
|
||
IsolationSource, ModeChange, ModeChangeProbe, ModeChangeWarning, SideContent,
|
||
PROBED_CONTENT_DIRS, SHARED_LAYERS,
|
||
};
|
||
pub use launch_overrides::{
|
||
resolve as resolve_launch_overrides, valid_memory, GlobalLaunchDefaults, GraphicsBackend,
|
||
LaunchOverrides, LaunchOverridesPatch, ResolvedLaunch, DEFAULT_MAX_MEMORY_MB,
|
||
MAX_MAX_MEMORY_MB, MIN_MAX_MEMORY_MB,
|
||
};
|
||
pub use layout::GameLayout;
|
||
pub use library::{Library, MavenCoordinate};
|
||
pub use loader::{InstanceLoader, LoaderKind};
|
||
pub use manifest::{AssetIndexRef, DownloadInfo, Downloads, JavaVersion, Logging, VersionJson};
|
||
pub use profiles::{InstanceProfile, ProfileId, ProfileList, PROFILE_SCHEMA_VERSION};
|
||
pub use saves::{
|
||
Area, SavesError, SavesScan, SavesSkip, ScreenshotEntry, SkipKind, WorldEntry,
|
||
IMAGE_EXTENSIONS, SAVES_DIR, SCREENSHOTS_DIR, WORLD_ICON,
|
||
};
|
||
pub use snapshot::{Draft, Snapshot, Store};
|
||
pub use version::{
|
||
LatestVersions, ReleaseType, RemoteVersion, VersionCategory, VersionList,
|
||
VERSION_MANIFEST_V2_URL,
|
||
};
|