Skip to main content

siglus_scene_vm/runtime/
game_display_info.rs

1//! Game display information shared by bundle/mobile platform UI code.
2//!
3//! This module intentionally keeps cover discovery outside the VM semantics.
4//! Game scripts do not observe this data. Platform launchers and bundle UIs can
5//! call it to decide whether to show a cover image or a text title.
6
7use std::path::{Path, PathBuf};
8
9use super::game_title;
10
11const COVER_CANDIDATES: &[(&str, &str)] = &[
12    ("cover.png", "image/png"),
13    ("cover.jpg", "image/jpeg"),
14    ("cover.jpeg", "image/jpeg"),
15    ("thumbnail.png", "image/png"),
16    ("icon.png", "image/png"),
17];
18
19#[derive(Clone, Debug)]
20pub struct GameDisplayInfo {
21    /// Display name for platform UI. This is the Gameexe `GAMENAME` when
22    /// available, otherwise the game directory name, otherwise `Siglus`.
23    pub name: String,
24    /// Compatibility alias for existing callers that still use title wording.
25    pub title: String,
26    /// Optional cover discovered from the game directory.
27    pub cover: Option<GameCover>,
28}
29
30#[derive(Clone, Debug)]
31pub struct GameCover {
32    pub bytes: Vec<u8>,
33    pub mime: String,
34    pub source_path: PathBuf,
35}
36
37/// Return the display name for a game directory.
38///
39/// This is a naming alias for `resolve_game_title_from_project_dir` so bundle
40/// and mobile UI code can use game-name terminology without duplicating title
41/// parsing logic.
42pub fn resolve_game_name_from_project_dir(project_dir: impl AsRef<Path>) -> String {
43    game_title::resolve_game_title_from_project_dir(project_dir)
44}
45
46/// Return display metadata for bundle/mobile UI.
47///
48/// Cover lookup is intentionally simple and explicit. If the game directory has
49/// one of the conventional files below, the first existing file is returned:
50///
51/// - `cover.png`
52/// - `cover.jpg`
53/// - `cover.jpeg`
54/// - `thumbnail.png`
55/// - `icon.png`
56///
57/// If no cover file exists or the file cannot be read, `cover` is `None` and UI
58/// callers should display `name` instead.
59pub fn resolve_game_display_info_from_project_dir(
60    project_dir: impl AsRef<Path>,
61) -> GameDisplayInfo {
62    let project_dir = project_dir.as_ref();
63    let name = resolve_game_name_from_project_dir(project_dir);
64    let cover = resolve_game_cover_from_project_dir(project_dir);
65    GameDisplayInfo {
66        title: name.clone(),
67        name,
68        cover,
69    }
70}
71
72pub fn resolve_game_cover_from_project_dir(project_dir: impl AsRef<Path>) -> Option<GameCover> {
73    let project_dir = project_dir.as_ref();
74    for (file_name, mime) in COVER_CANDIDATES {
75        let path = project_dir.join(file_name);
76        if !path.is_file() {
77            continue;
78        }
79        let Ok(bytes) = std::fs::read(&path) else {
80            continue;
81        };
82        return Some(GameCover {
83            bytes,
84            mime: (*mime).to_string(),
85            source_path: path,
86        });
87    }
88    None
89}