feat: playtime counting

This commit is contained in:
neoapps-dev
2026-05-25 17:46:56 +03:00
parent e1a49069f0
commit c3c3abb2e3
6 changed files with 305 additions and 1 deletions
+24
View File
@@ -1,5 +1,6 @@
use std::fs;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::{AppHandle, Manager, State};
use tauri_plugin_opener::OpenerExt;
use crate::commands::runners;
@@ -8,6 +9,7 @@ use crate::config;
use crate::platform::macos;
#[cfg(unix)]
use crate::platform::linux;
use crate::playtime::{self, PlaytimeResponse};
use crate::state::GameState;
use crate::types::McServer;
use crate::util;
@@ -113,6 +115,7 @@ pub async fn launch_game(
cmd.arg(a);
}
cmd.current_dir(&working_dir);
let playtime_start = std::time::Instant::now();
let child = cmd.spawn().map_err(|e| e.to_string())?;
{
let mut lock = state.child.lock().await;
@@ -138,6 +141,11 @@ pub async fn launch_game(
*lock = None;
}
let duration = playtime_start.elapsed();
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let start = now - duration.as_secs();
playtime::record_session(&app, &instance_id, start, now);
return if status.success() || status.code() == Some(253) || status.code() == Some(96) {
Ok(())
} else {
@@ -222,6 +230,7 @@ pub async fn launch_game(
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null());
let playtime_start = std::time::Instant::now();
let child = cmd.spawn().map_err(|e| e.to_string())?;
{
let mut lock = state.child.lock().await;
@@ -247,6 +256,11 @@ pub async fn launch_game(
*lock = None;
}
let duration = playtime_start.elapsed();
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let start = now - duration.as_secs();
playtime::record_session(&app, &instance_id, start, now);
return if status.success() || status.code() == Some(253) || status.code() == Some(96) {
Ok(())
} else {
@@ -263,6 +277,7 @@ pub async fn launch_game(
#[cfg(unix)]
cmd.process_group(0);
cmd.current_dir(&working_dir);
let playtime_start = std::time::Instant::now();
let child = cmd.spawn().map_err(|e| e.to_string())?;
{
let mut lock = state.child.lock().await;
@@ -285,6 +300,10 @@ pub async fn launch_game(
let mut lock = state.child.lock().await;
*lock = None;
}
let duration = playtime_start.elapsed();
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let start = now - duration.as_secs();
playtime::record_session(&app, &instance_id, start, now);
return if status.success() || status.code() == Some(253) || status.code() == Some(96) {
Ok(())
} else {
@@ -362,6 +381,11 @@ pub fn get_instance_path(app: AppHandle, instance_id: String) -> String {
.to_string()
}
#[tauri::command]
pub fn get_playtime(app: AppHandle, instance_id: String) -> PlaytimeResponse {
playtime::get_playtime(&app, &instance_id)
}
pub fn ensure_server_list(instance_dir: &PathBuf, servers: Vec<McServer>) {
let servers_db = instance_dir.join("servers.db");
let mut all_servers = Vec::new();
+2
View File
@@ -2,6 +2,7 @@ mod types;
mod state;
mod config;
mod util;
mod playtime;
mod platform;
mod networking;
mod workshop_server;
@@ -80,6 +81,7 @@ pub fn run() {
steam::add_to_steam,
proxy_cmd::http_proxy_request,
game::get_instance_path,
game::get_playtime,
commands::console2lce::import_world,
stun::stun_discover,
direct::start_direct_proxy,
+74
View File
@@ -0,0 +1,74 @@
use std::collections::HashMap;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;
use serde::{Serialize, Deserialize};
use crate::util;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PlaytimeSession {
pub start: u64,
pub end: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PlaytimeData {
pub sessions: HashMap<String, Vec<PlaytimeSession>>,
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PlaytimeResponse {
pub total_seconds: u64,
pub week_seconds: u64,
pub day_seconds: u64,
}
fn playtime_path(app: &AppHandle) -> PathBuf {
util::get_app_dir(app).join("playtime.json")
}
pub fn load(app: &AppHandle) -> PlaytimeData {
let path = playtime_path(app);
if path.exists() {
let content = std::fs::read_to_string(&path).unwrap_or_default();
serde_json::from_str(&content).unwrap_or(PlaytimeData { sessions: HashMap::new() })
} else {
PlaytimeData { sessions: HashMap::new() }
}
}
pub fn save(app: &AppHandle, data: &PlaytimeData) {
let path = playtime_path(app);
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
if let Ok(content) = serde_json::to_string_pretty(data) {
let _ = std::fs::write(&path, content);
}
}
pub fn record_session(app: &AppHandle, instance_id: &str, start: u64, end: u64) {
let mut data = load(app);
let sessions = data.sessions.entry(instance_id.to_string()).or_default();
sessions.push(PlaytimeSession { start, end });
save(app, &data);
}
pub fn get_playtime(app: &AppHandle, instance_id: &str) -> PlaytimeResponse {
let data = load(app);
let sessions = data.sessions.get(instance_id);
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let week_ago = now - 7 * 24 * 60 * 60;
let day_ago = now - 24 * 60 * 60;
let total_seconds: u64 = sessions.map_or(0, |s| s.iter().map(|s| s.end - s.start).sum());
let week_seconds: u64 = sessions.map_or(0, |s| s.iter()
.filter(|s| s.start >= week_ago)
.map(|s| s.end - s.start)
.sum());
let day_seconds: u64 = sessions.map_or(0, |s| s.iter()
.filter(|s| s.start >= day_ago)
.map(|s| s.end - s.start)
.sum());
PlaytimeResponse { total_seconds, week_seconds, day_seconds }
}