Skip to main content

launcher/utils/
storage.rs

1use crate::constants::SSBZ_API_BASE_URL;
2use std::path::PathBuf;
3use supreme_fs::GameStorage;
4
5/// Get the game path
6#[must_use]
7pub fn get_game_path() -> PathBuf {
8    let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
9    let has_game_dll = std::fs::read_dir(&cwd)
10        .into_iter()
11        .flatten()
12        .filter_map(Result::ok)
13        .any(|entry| entry.file_name().eq_ignore_ascii_case("supreme_game.dll"));
14    if has_game_dll {
15        cwd
16    } else {
17        std::env::current_exe()
18            .ok()
19            .and_then(|exe| exe.parent().map(std::path::Path::to_path_buf))
20            .unwrap_or_else(|| PathBuf::from("."))
21    }
22}
23
24/// Create a GameStorage instance for operations
25#[must_use]
26pub fn create_storage() -> GameStorage {
27    let game_path = get_game_path();
28    let mut storage = GameStorage::with_online(&game_path, SSBZ_API_BASE_URL);
29    refresh_hook_resolver(&mut storage);
30    storage
31}
32
33/// Rebuilds `storage`'s hook resolver from whatever is currently on disk
34/// under `.supreme/mods/`, the active redirection rules a fresh
35/// `create_storage()` call would produce, without needing to throw away
36/// and rebuild the rest of `storage` (its online configuration, etc.).
37///
38/// Call this any time the active mod configuration changes after startup
39/// (a mod enabled/disabled, reordered, or one of its parameters edited),
40/// `HookResolver` is loaded once and then cached for the lifetime of the
41/// `GameStorage` it's attached to, so nothing picks up a change on disk
42/// until this (or a fresh `create_storage()`) runs again. The Mods page
43/// itself already knows the moment it persists such a change (its
44/// `mods_page`/`render_mod_list`/`render_mod_details` functions return
45/// whether they did), so callers should invoke this right after that
46/// signal fires rather than polling.
47pub fn refresh_hook_resolver(storage: &mut GameStorage) {
48    let game_path = storage.game_path().clone();
49    let mods_dir = game_path.join(supreme_hook_config::DEFAULT_MODS_DIR_NAME);
50    let (refreshed, skipped) = storage
51        .clone()
52        .with_hook_resolver(&mods_dir, game_path.join(".supreme/tmp"));
53    for (mod_name, error) in skipped {
54        eprintln!("Skipped mod '{mod_name}' while reloading hook config: {error}");
55    }
56    *storage = refreshed;
57}