create-pixi-vn 2.0.11 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template-react-vite-muijoy/.vscode/tasks.json +18 -15
- package/template-react-vite-muijoy-ink/.vscode/extensions.json +2 -1
- package/template-react-vite-muijoy-ink/.vscode/settings.json +6 -1
- package/template-react-vite-muijoy-ink/.vscode/tasks.json +18 -15
- package/template-react-vite-muijoy-ink/_gitignore +1 -0
- package/template-react-vite-muijoy-ink/ink/second_part.ink +571 -0
- package/template-react-vite-muijoy-ink/ink/start.ink +214 -0
- package/template-react-vite-muijoy-ink/package-lock.json +230 -4
- package/template-react-vite-muijoy-ink/package.json +3 -1
- package/template-react-vite-muijoy-ink/src/App.tsx +25 -25
- package/template-react-vite-muijoy-ink/src/assets/index.ts +2 -4
- package/template-react-vite-muijoy-ink/src/assets/ink-manifest.gen.json +4 -1
- package/template-react-vite-muijoy-ink/src/content/ink/hashtag-commands.ts +38 -0
- package/template-react-vite-muijoy-ink/src/content/ink/text-replaces.ts +19 -0
- package/template-react-vite-muijoy-ink/src/lib/hooks/ink-hooks.tsx +12 -0
- package/template-react-vite-muijoy-ink/src/lib/i18n.ts +22 -1
- package/template-react-vite-muijoy-ink/src/pixi-vn-keys.gen.d.ts +2 -0
- package/template-react-vite-muijoy-ink/src/routes/__root.tsx +4 -0
- package/template-react-vite-muijoy-ink/vite.config.ts +6 -0
- package/template-react-vite-muijoy-ink-tauri/.assetpack.ts +9 -0
- package/template-react-vite-muijoy-ink-tauri/.vscode/extensions.json +5 -1
- package/template-react-vite-muijoy-ink-tauri/.vscode/launch.json +11 -0
- package/template-react-vite-muijoy-ink-tauri/.vscode/settings.json +6 -1
- package/template-react-vite-muijoy-ink-tauri/.vscode/tasks.json +61 -11
- package/template-react-vite-muijoy-ink-tauri/README.md +3 -3
- package/template-react-vite-muijoy-ink-tauri/_github/workflows/desktop.yml +188 -0
- package/template-react-vite-muijoy-ink-tauri/_github/workflows/mobile.yml +270 -0
- package/template-react-vite-muijoy-ink-tauri/_gitignore +11 -0
- package/template-react-vite-muijoy-ink-tauri/ink/second_part.ink +571 -0
- package/template-react-vite-muijoy-ink-tauri/ink/start.ink +214 -0
- package/template-react-vite-muijoy-ink-tauri/package-lock.json +480 -4
- package/template-react-vite-muijoy-ink-tauri/package.json +13 -2
- package/template-react-vite-muijoy-ink-tauri/src/App.tsx +25 -25
- package/template-react-vite-muijoy-ink-tauri/src/assets/index.ts +2 -4
- package/template-react-vite-muijoy-ink-tauri/src/assets/ink-manifest.gen.json +4 -1
- package/template-react-vite-muijoy-ink-tauri/src/components/menus/main-menu.tsx +16 -1
- package/template-react-vite-muijoy-ink-tauri/src/components/menus/settings/quick-menus.tsx +17 -1
- package/template-react-vite-muijoy-ink-tauri/src/components/menus/settings/system-controls.tsx +11 -1
- package/template-react-vite-muijoy-ink-tauri/src/content/ink/hashtag-commands.ts +55 -0
- package/template-react-vite-muijoy-ink-tauri/src/content/ink/text-replaces.ts +19 -0
- package/template-react-vite-muijoy-ink-tauri/src/lib/hooks/ink-hooks.tsx +12 -0
- package/template-react-vite-muijoy-ink-tauri/src/lib/hooks/quit-hooks.ts +24 -0
- package/template-react-vite-muijoy-ink-tauri/src/lib/i18n.ts +22 -1
- package/template-react-vite-muijoy-ink-tauri/src/lib/query/settings-query.ts +7 -1
- package/template-react-vite-muijoy-ink-tauri/src/lib/steam.ts +143 -0
- package/template-react-vite-muijoy-ink-tauri/src/pixi-vn-keys.gen.d.ts +2 -0
- package/template-react-vite-muijoy-ink-tauri/src/routes/__root.tsx +4 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/Cargo.toml +50 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/build.rs +46 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/capabilities/default.json +21 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/128x128.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/128x128@2x.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/32x32.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square107x107Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square142x142Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square150x150Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square284x284Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square30x30Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square310x310Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square44x44Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square71x71Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/Square89x89Logo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/StoreLogo.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.icns +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.ico +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/icons/icon.png +0 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/src/lib.rs +64 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/src/main.rs +6 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/src/steam.rs +238 -0
- package/template-react-vite-muijoy-ink-tauri/src-tauri/tauri.conf.json +50 -0
- package/template-react-vite-muijoy-ink-tauri/vite.config.ts +30 -0
- package/template-react-vite-muijoy-tauri/.assetpack.ts +9 -0
- package/template-react-vite-muijoy-tauri/.vscode/extensions.json +4 -1
- package/template-react-vite-muijoy-tauri/.vscode/launch.json +11 -0
- package/template-react-vite-muijoy-tauri/.vscode/tasks.json +61 -11
- package/template-react-vite-muijoy-tauri/README.md +3 -3
- package/template-react-vite-muijoy-tauri/_github/workflows/desktop.yml +188 -0
- package/template-react-vite-muijoy-tauri/_github/workflows/mobile.yml +270 -0
- package/template-react-vite-muijoy-tauri/_gitignore +10 -0
- package/template-react-vite-muijoy-tauri/package-lock.json +250 -0
- package/template-react-vite-muijoy-tauri/package.json +10 -1
- package/template-react-vite-muijoy-tauri/src/components/menus/main-menu.tsx +16 -1
- package/template-react-vite-muijoy-tauri/src/components/menus/settings/quick-menus.tsx +17 -1
- package/template-react-vite-muijoy-tauri/src/components/menus/settings/system-controls.tsx +11 -1
- package/template-react-vite-muijoy-tauri/src/lib/hooks/quit-hooks.ts +24 -0
- package/template-react-vite-muijoy-tauri/src/lib/query/settings-query.ts +7 -1
- package/template-react-vite-muijoy-tauri/src/lib/steam.ts +143 -0
- package/template-react-vite-muijoy-tauri/src-tauri/Cargo.toml +50 -0
- package/template-react-vite-muijoy-tauri/src-tauri/build.rs +46 -0
- package/template-react-vite-muijoy-tauri/src-tauri/capabilities/default.json +21 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/128x128.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/128x128@2x.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/32x32.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square107x107Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square142x142Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square150x150Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square284x284Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square30x30Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square310x310Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square44x44Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square71x71Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/Square89x89Logo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/StoreLogo.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.icns +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.ico +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/icons/icon.png +0 -0
- package/template-react-vite-muijoy-tauri/src-tauri/src/lib.rs +64 -0
- package/template-react-vite-muijoy-tauri/src-tauri/src/main.rs +6 -0
- package/template-react-vite-muijoy-tauri/src-tauri/src/steam.rs +238 -0
- package/template-react-vite-muijoy-tauri/src-tauri/tauri.conf.json +50 -0
- package/template-react-vite-muijoy-tauri/vite.config.ts +24 -0
- package/template-react-vite-muijoy-ink/src/content/labels/second.label.ts +0 -1207
- package/template-react-vite-muijoy-ink/src/content/labels/start.label.ts +0 -566
- package/template-react-vite-muijoy-ink-tauri/src/content/labels/second.label.ts +0 -1207
- package/template-react-vite-muijoy-ink-tauri/src/content/labels/start.label.ts +0 -566
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
use std::{env, fs, path::PathBuf};
|
|
2
|
+
|
|
3
|
+
fn main() {
|
|
4
|
+
if env::var("CARGO_FEATURE_STEAM").is_ok() {
|
|
5
|
+
copy_steam_lib();
|
|
6
|
+
}
|
|
7
|
+
tauri_build::build()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Copies the Steamworks redistributable library from steamworks-sys's OUT_DIR
|
|
11
|
+
// into src-tauri/ so that Tauri's bundler can pick it up as a resource.
|
|
12
|
+
fn copy_steam_lib() {
|
|
13
|
+
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
14
|
+
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
15
|
+
|
|
16
|
+
let lib_name = match env::var("CARGO_CFG_TARGET_OS").as_deref() {
|
|
17
|
+
Ok("windows") => "steam_api64.dll",
|
|
18
|
+
Ok("macos") => "libsteam_api.dylib",
|
|
19
|
+
_ => "libsteam_api.so",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// OUT_DIR layout: .../target/[profile]/build/[pkg-hash]/out
|
|
23
|
+
// nth(2) walks up to .../target/[profile]/build/
|
|
24
|
+
let build_dir = out_dir
|
|
25
|
+
.ancestors()
|
|
26
|
+
.nth(2)
|
|
27
|
+
.expect("unexpected OUT_DIR layout");
|
|
28
|
+
|
|
29
|
+
if let Ok(entries) = fs::read_dir(build_dir) {
|
|
30
|
+
for entry in entries.flatten() {
|
|
31
|
+
let candidate = entry.path().join("out").join(lib_name);
|
|
32
|
+
if candidate.exists() {
|
|
33
|
+
let dest = manifest_dir.join(lib_name);
|
|
34
|
+
fs::copy(&candidate, &dest)
|
|
35
|
+
.unwrap_or_else(|e| panic!("failed to copy {lib_name}: {e}"));
|
|
36
|
+
println!("cargo:warning=Steam: copied {lib_name} → src-tauri/");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
panic!(
|
|
43
|
+
"Steam: could not find `{lib_name}` in build artifacts. \
|
|
44
|
+
Ensure `--features steam` is active and the crate compiled successfully."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../gen/schemas/desktop-schema.json",
|
|
3
|
+
"identifier": "default",
|
|
4
|
+
"description": "Capability for the main window",
|
|
5
|
+
"windows": ["main"],
|
|
6
|
+
"permissions": [
|
|
7
|
+
"core:default",
|
|
8
|
+
"core:window:allow-close",
|
|
9
|
+
"core:window:allow-is-fullscreen",
|
|
10
|
+
"core:window:allow-set-fullscreen",
|
|
11
|
+
"core:window:allow-minimize",
|
|
12
|
+
"core:window:allow-maximize",
|
|
13
|
+
"core:window:allow-unminimize",
|
|
14
|
+
"core:window:allow-set-title",
|
|
15
|
+
"opener:default",
|
|
16
|
+
"process:default",
|
|
17
|
+
"window-state:allow-filename",
|
|
18
|
+
"window-state:allow-restore-state",
|
|
19
|
+
"window-state:allow-save-window-state"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
use tauri::Manager;
|
|
2
|
+
#[cfg(not(mobile))]
|
|
3
|
+
use tauri_plugin_window_state::{AppHandleExt, StateFlags};
|
|
4
|
+
|
|
5
|
+
// Steam is only compiled on desktop targets when the "steam" feature is on.
|
|
6
|
+
#[cfg(all(feature = "steam", not(target_os = "ios"), not(target_os = "android")))]
|
|
7
|
+
mod steam;
|
|
8
|
+
|
|
9
|
+
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
10
|
+
pub fn run() {
|
|
11
|
+
#[allow(unused_mut)]
|
|
12
|
+
let mut builder = tauri::Builder::default()
|
|
13
|
+
.plugin(tauri_plugin_process::init())
|
|
14
|
+
.plugin(tauri_plugin_opener::init())
|
|
15
|
+
.on_page_load(on_page_load);
|
|
16
|
+
|
|
17
|
+
#[cfg(not(mobile))]
|
|
18
|
+
let mut builder = builder
|
|
19
|
+
.plugin(tauri_plugin_window_state::Builder::new().build())
|
|
20
|
+
.on_window_event(on_window_event);
|
|
21
|
+
|
|
22
|
+
// ── Steam ─────────────────────────────────────────────────────────────────
|
|
23
|
+
// Enabled only when `--features steam` is passed (or `default = ["steam"]`
|
|
24
|
+
// is set in Cargo.toml). Steam is not supported on iOS / Android.
|
|
25
|
+
#[cfg(all(feature = "steam", not(target_os = "ios"), not(target_os = "android")))]
|
|
26
|
+
{
|
|
27
|
+
builder = builder
|
|
28
|
+
.manage(steam::SteamClient {
|
|
29
|
+
client: std::sync::Mutex::new(steam::try_init()),
|
|
30
|
+
})
|
|
31
|
+
.invoke_handler(tauri::generate_handler![
|
|
32
|
+
steam::steam_is_available,
|
|
33
|
+
steam::steam_get_player_name,
|
|
34
|
+
steam::steam_get_app_id,
|
|
35
|
+
steam::steam_unlock_achievement,
|
|
36
|
+
steam::steam_is_achievement_unlocked,
|
|
37
|
+
steam::steam_clear_achievement,
|
|
38
|
+
steam::steam_set_stat_int,
|
|
39
|
+
steam::steam_get_stat_int,
|
|
40
|
+
steam::steam_set_stat_float,
|
|
41
|
+
steam::steam_get_stat_float,
|
|
42
|
+
steam::steam_store_stats,
|
|
43
|
+
steam::steam_is_dlc_installed,
|
|
44
|
+
steam::steam_open_overlay,
|
|
45
|
+
steam::steam_open_store,
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
builder
|
|
50
|
+
.run(tauri::generate_context!())
|
|
51
|
+
.expect("error while running tauri application");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fn on_page_load(window: &tauri::Webview, _: &tauri::webview::PageLoadPayload<'_>) {
|
|
55
|
+
#[cfg(not(debug_assertions))]
|
|
56
|
+
let _ = window.eval("document.addEventListener('contextmenu', e => e.preventDefault())");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
#[cfg(not(mobile))]
|
|
60
|
+
fn on_window_event(window: &tauri::Window, event: &tauri::WindowEvent) {
|
|
61
|
+
if let tauri::WindowEvent::CloseRequested { .. } = event {
|
|
62
|
+
let _ = window.app_handle().save_window_state(StateFlags::all());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
use std::sync::Mutex;
|
|
2
|
+
use steamworks::{AppId, Client, OverlayToStoreFlag};
|
|
3
|
+
use tauri::State;
|
|
4
|
+
|
|
5
|
+
pub struct SteamClient {
|
|
6
|
+
pub client: Mutex<Option<Client>>,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/// Try to initialise Steam. Returns `None` when Steam is not running or the
|
|
10
|
+
/// game is launched outside Steam (e.g. during CI builds).
|
|
11
|
+
///
|
|
12
|
+
/// A background thread is spawned to pump Steam callbacks every 100 ms so
|
|
13
|
+
/// that overlay notifications, stat uploads, and other async operations work.
|
|
14
|
+
pub fn try_init() -> Option<Client> {
|
|
15
|
+
match Client::init() {
|
|
16
|
+
Ok(client) => {
|
|
17
|
+
// Client is Clone + Send + Sync in steamworks 0.13 — safe to move into a thread.
|
|
18
|
+
let ticker = client.clone();
|
|
19
|
+
std::thread::spawn(move || loop {
|
|
20
|
+
ticker.run_callbacks();
|
|
21
|
+
std::thread::sleep(std::time::Duration::from_millis(100));
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
eprintln!("[Steam] Initialised — App ID {}", client.utils().app_id().0);
|
|
25
|
+
Some(client)
|
|
26
|
+
}
|
|
27
|
+
Err(e) => {
|
|
28
|
+
eprintln!("[Steam] Not available: {e}");
|
|
29
|
+
None
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/// Returns `true` when Steam was initialised successfully.
|
|
37
|
+
#[tauri::command]
|
|
38
|
+
pub fn steam_is_available(state: State<'_, SteamClient>) -> bool {
|
|
39
|
+
state.client.lock().map_or(false, |g| g.is_some())
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Steam display name of the current user (`null` when Steam unavailable).
|
|
43
|
+
#[tauri::command]
|
|
44
|
+
pub fn steam_get_player_name(state: State<'_, SteamClient>) -> Option<String> {
|
|
45
|
+
state
|
|
46
|
+
.client
|
|
47
|
+
.lock()
|
|
48
|
+
.ok()
|
|
49
|
+
.and_then(|g| g.as_ref().map(|c| c.friends().name()))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Numeric Steam App ID of the running application.
|
|
53
|
+
#[tauri::command]
|
|
54
|
+
pub fn steam_get_app_id(state: State<'_, SteamClient>) -> Option<u32> {
|
|
55
|
+
state
|
|
56
|
+
.client
|
|
57
|
+
.lock()
|
|
58
|
+
.ok()
|
|
59
|
+
.and_then(|g| g.as_ref().map(|c| c.utils().app_id().0))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── Achievements ──────────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
/// Unlock an achievement and persist it to Steam immediately.
|
|
65
|
+
///
|
|
66
|
+
/// `achievement_id` must match the API Name defined in Steamworks Partner.
|
|
67
|
+
#[tauri::command]
|
|
68
|
+
pub fn steam_unlock_achievement(
|
|
69
|
+
state: State<'_, SteamClient>,
|
|
70
|
+
achievement_id: String,
|
|
71
|
+
) -> Result<(), String> {
|
|
72
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
73
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
74
|
+
let stats = client.user_stats();
|
|
75
|
+
stats
|
|
76
|
+
.achievement(&achievement_id)
|
|
77
|
+
.set()
|
|
78
|
+
.map_err(|_| format!("Achievement '{}' not found or stats not ready", achievement_id))?;
|
|
79
|
+
stats
|
|
80
|
+
.store_stats()
|
|
81
|
+
.map_err(|_| "Failed to store stats".to_string())
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// Returns `true` if the current user has already unlocked the achievement.
|
|
85
|
+
///
|
|
86
|
+
/// Stats are fetched automatically when Steam initialises. Allow a few seconds
|
|
87
|
+
/// after launch before calling this for the most reliable result.
|
|
88
|
+
#[tauri::command]
|
|
89
|
+
pub fn steam_is_achievement_unlocked(
|
|
90
|
+
state: State<'_, SteamClient>,
|
|
91
|
+
achievement_id: String,
|
|
92
|
+
) -> Result<bool, String> {
|
|
93
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
94
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
95
|
+
client
|
|
96
|
+
.user_stats()
|
|
97
|
+
.achievement(&achievement_id)
|
|
98
|
+
.get()
|
|
99
|
+
.map_err(|_| format!("Achievement '{}' not found or stats not ready", achievement_id))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// Reset an achievement (useful during development / QA).
|
|
103
|
+
#[tauri::command]
|
|
104
|
+
pub fn steam_clear_achievement(
|
|
105
|
+
state: State<'_, SteamClient>,
|
|
106
|
+
achievement_id: String,
|
|
107
|
+
) -> Result<(), String> {
|
|
108
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
109
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
110
|
+
let stats = client.user_stats();
|
|
111
|
+
stats
|
|
112
|
+
.achievement(&achievement_id)
|
|
113
|
+
.clear()
|
|
114
|
+
.map_err(|_| format!("Achievement '{}' not found or stats not ready", achievement_id))?;
|
|
115
|
+
stats
|
|
116
|
+
.store_stats()
|
|
117
|
+
.map_err(|_| "Failed to store stats".to_string())
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── Stats ─────────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
/// Set an integer stat. Call `steam_store_stats` to persist.
|
|
123
|
+
#[tauri::command]
|
|
124
|
+
pub fn steam_set_stat_int(
|
|
125
|
+
state: State<'_, SteamClient>,
|
|
126
|
+
name: String,
|
|
127
|
+
value: i32,
|
|
128
|
+
) -> Result<(), String> {
|
|
129
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
130
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
131
|
+
client
|
|
132
|
+
.user_stats()
|
|
133
|
+
.set_stat_i32(&name, value)
|
|
134
|
+
.map_err(|_| format!("Failed to set stat '{}'", name))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// Read an integer stat.
|
|
138
|
+
#[tauri::command]
|
|
139
|
+
pub fn steam_get_stat_int(
|
|
140
|
+
state: State<'_, SteamClient>,
|
|
141
|
+
name: String,
|
|
142
|
+
) -> Result<i32, String> {
|
|
143
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
144
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
145
|
+
client
|
|
146
|
+
.user_stats()
|
|
147
|
+
.get_stat_i32(&name)
|
|
148
|
+
.map_err(|_| format!("Failed to get stat '{}'", name))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// Set a float stat. Call `steam_store_stats` to persist.
|
|
152
|
+
#[tauri::command]
|
|
153
|
+
pub fn steam_set_stat_float(
|
|
154
|
+
state: State<'_, SteamClient>,
|
|
155
|
+
name: String,
|
|
156
|
+
value: f32,
|
|
157
|
+
) -> Result<(), String> {
|
|
158
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
159
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
160
|
+
client
|
|
161
|
+
.user_stats()
|
|
162
|
+
.set_stat_f32(&name, value)
|
|
163
|
+
.map_err(|_| format!("Failed to set stat '{}'", name))
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Read a float stat.
|
|
167
|
+
#[tauri::command]
|
|
168
|
+
pub fn steam_get_stat_float(
|
|
169
|
+
state: State<'_, SteamClient>,
|
|
170
|
+
name: String,
|
|
171
|
+
) -> Result<f32, String> {
|
|
172
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
173
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
174
|
+
client
|
|
175
|
+
.user_stats()
|
|
176
|
+
.get_stat_f32(&name)
|
|
177
|
+
.map_err(|_| format!("Failed to get stat '{}'", name))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// Commit all pending stat changes to Steam servers.
|
|
181
|
+
/// Achievement commands already call this automatically.
|
|
182
|
+
#[tauri::command]
|
|
183
|
+
pub fn steam_store_stats(state: State<'_, SteamClient>) -> Result<(), String> {
|
|
184
|
+
let guard = state.client.lock().map_err(|e| e.to_string())?;
|
|
185
|
+
let client = guard.as_ref().ok_or("Steam not available")?;
|
|
186
|
+
client
|
|
187
|
+
.user_stats()
|
|
188
|
+
.store_stats()
|
|
189
|
+
.map_err(|_| "Failed to store stats".to_string())
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ── DLC ───────────────────────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
/// Returns `true` if the user owns and has the specified DLC installed.
|
|
195
|
+
#[tauri::command]
|
|
196
|
+
pub fn steam_is_dlc_installed(state: State<'_, SteamClient>, app_id: u32) -> bool {
|
|
197
|
+
state.client.lock().map_or(false, |g| {
|
|
198
|
+
g.as_ref()
|
|
199
|
+
.map_or(false, |c| c.apps().is_dlc_installed(AppId(app_id)))
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ── Overlay ───────────────────────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
/// Open the Steam overlay to a specific dialog.
|
|
206
|
+
///
|
|
207
|
+
/// Valid `dialog` values:
|
|
208
|
+
/// "achievements", "community", "friends", "players",
|
|
209
|
+
/// "settings", "officialgamegroup", "stats"
|
|
210
|
+
#[tauri::command]
|
|
211
|
+
pub fn steam_open_overlay(state: State<'_, SteamClient>, dialog: String) -> bool {
|
|
212
|
+
let Ok(guard) = state.client.lock() else {
|
|
213
|
+
return false;
|
|
214
|
+
};
|
|
215
|
+
let Some(client) = guard.as_ref() else {
|
|
216
|
+
return false;
|
|
217
|
+
};
|
|
218
|
+
client.friends().activate_game_overlay(&dialog);
|
|
219
|
+
true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/// Open the Steam store page for this game (or a specific `app_id`).
|
|
223
|
+
#[tauri::command]
|
|
224
|
+
pub fn steam_open_store(state: State<'_, SteamClient>, app_id: Option<u32>) -> bool {
|
|
225
|
+
let Ok(guard) = state.client.lock() else {
|
|
226
|
+
return false;
|
|
227
|
+
};
|
|
228
|
+
let Some(client) = guard.as_ref() else {
|
|
229
|
+
return false;
|
|
230
|
+
};
|
|
231
|
+
let target = app_id
|
|
232
|
+
.map(AppId)
|
|
233
|
+
.unwrap_or_else(|| client.utils().app_id());
|
|
234
|
+
client
|
|
235
|
+
.friends()
|
|
236
|
+
.activate_game_overlay_to_store(target, OverlayToStoreFlag::None);
|
|
237
|
+
true
|
|
238
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://schema.tauri.app/config/2",
|
|
3
|
+
"productName": "my-app-package-name",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"identifier": "com.my-app-identifier.app",
|
|
6
|
+
"build": {
|
|
7
|
+
"beforeDevCommand": "npm run dev",
|
|
8
|
+
"devUrl": "http://localhost:5173",
|
|
9
|
+
"beforeBuildCommand": "npm run build",
|
|
10
|
+
"frontendDist": "../dist"
|
|
11
|
+
},
|
|
12
|
+
"app": {
|
|
13
|
+
"withGlobalTauri": true,
|
|
14
|
+
"windows": [
|
|
15
|
+
{
|
|
16
|
+
"title": "my-app-project-name",
|
|
17
|
+
"backgroundColor": "#303030",
|
|
18
|
+
"theme": "Dark",
|
|
19
|
+
"width": 1280,
|
|
20
|
+
"height": 720,
|
|
21
|
+
"minWidth": 640,
|
|
22
|
+
"minHeight": 360,
|
|
23
|
+
"center": true,
|
|
24
|
+
"fullscreen": false,
|
|
25
|
+
"resizable": true,
|
|
26
|
+
"dragDropEnabled": false,
|
|
27
|
+
"zoomHotkeysEnabled": false
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"security": {
|
|
31
|
+
"csp": null
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"bundle": {
|
|
35
|
+
"active": true,
|
|
36
|
+
"targets": "all",
|
|
37
|
+
"icon": [
|
|
38
|
+
"icons/32x32.png",
|
|
39
|
+
"icons/128x128.png",
|
|
40
|
+
"icons/128x128@2x.png",
|
|
41
|
+
"icons/icon.icns",
|
|
42
|
+
"icons/icon.ico"
|
|
43
|
+
],
|
|
44
|
+
"windows": {
|
|
45
|
+
"nsis": {
|
|
46
|
+
"installerIcon": "icons/icon.ico"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -18,6 +18,8 @@ import assetPackConfig from "./.assetpack.ts";
|
|
|
18
18
|
*/
|
|
19
19
|
const CACHED_EXTERNAL_HOSTNAMES: string[] = ["raw.githubusercontent.com"];
|
|
20
20
|
|
|
21
|
+
const host = process.env.TAURI_DEV_HOST;
|
|
22
|
+
|
|
21
23
|
// https://vite.dev/config/
|
|
22
24
|
export default defineConfig(({ mode }) => ({
|
|
23
25
|
plugins: [
|
|
@@ -112,6 +114,28 @@ export default defineConfig(({ mode }) => ({
|
|
|
112
114
|
},
|
|
113
115
|
},
|
|
114
116
|
},
|
|
117
|
+
|
|
118
|
+
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
|
119
|
+
//
|
|
120
|
+
// 1. prevent vite from obscuring rust errors
|
|
121
|
+
clearScreen: false,
|
|
122
|
+
// 2. tauri expects a fixed port, fail if that port is not available
|
|
123
|
+
server: {
|
|
124
|
+
port: 5173,
|
|
125
|
+
strictPort: true,
|
|
126
|
+
host: host || false,
|
|
127
|
+
hmr: host
|
|
128
|
+
? {
|
|
129
|
+
protocol: "ws",
|
|
130
|
+
host,
|
|
131
|
+
port: 1421,
|
|
132
|
+
}
|
|
133
|
+
: undefined,
|
|
134
|
+
watch: {
|
|
135
|
+
// 3. tell vite to ignore watching `src-tauri`
|
|
136
|
+
ignored: ["**/src-tauri/**"],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
115
139
|
}));
|
|
116
140
|
|
|
117
141
|
function assetpackPlugin(): Plugin {
|