Dynamically change game background based on user's game completion (#298)
2
.github/workflows/build.yaml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
platform: [ubuntu-20.04, windows-latest, macos-12]
|
platform: [ubuntu-20.04, windows-latest, macos-11]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|
2
.github/workflows/release.yaml
vendored
|
@ -105,7 +105,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
platform: [ubuntu-20.04, windows-latest, macos-12]
|
platform: [ubuntu-20.04, windows-latest, macos-11]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
# NOTE - there is technically a race condition here if multiple releases go out
|
# NOTE - there is technically a race condition here if multiple releases go out
|
||||||
|
|
BIN
public/images/jak1/basin.jpg
Normal file
After Width: | Height: | Size: 197 KiB |
BIN
public/images/jak1/cave.jpg
Normal file
After Width: | Height: | Size: 170 KiB |
BIN
public/images/jak1/citadel.jpg
Normal file
After Width: | Height: | Size: 162 KiB |
BIN
public/images/jak1/end.jpg
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
public/images/jak1/finalboss.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
public/images/jak1/firecanyon.jpg
Normal file
After Width: | Height: | Size: 195 KiB |
BIN
public/images/jak1/geyser.jpg
Normal file
After Width: | Height: | Size: 264 KiB |
BIN
public/images/jak1/jungle.jpg
Normal file
After Width: | Height: | Size: 189 KiB |
BIN
public/images/jak1/klaww.jpg
Normal file
After Width: | Height: | Size: 154 KiB |
BIN
public/images/jak1/lavatube.jpg
Normal file
After Width: | Height: | Size: 169 KiB |
BIN
public/images/jak1/lpc.jpg
Normal file
After Width: | Height: | Size: 137 KiB |
BIN
public/images/jak1/misty.jpg
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
public/images/jak1/mountainpass.jpg
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
public/images/jak1/sandover.jpg
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
public/images/jak1/sentinel.jpg
Normal file
After Width: | Height: | Size: 234 KiB |
BIN
public/images/jak1/snowy.jpg
Normal file
After Width: | Height: | Size: 194 KiB |
BIN
public/images/jak1/swamp.jpg
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
public/images/jak1/village2.jpg
Normal file
After Width: | Height: | Size: 174 KiB |
BIN
public/images/jak1/village3.jpg
Normal file
After Width: | Height: | Size: 198 KiB |
|
@ -1,8 +1,16 @@
|
||||||
use std::path::Path;
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
use tauri::{api::path::config_dir, Manager};
|
use tauri::{api::path::config_dir, Manager};
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::config::LauncherConfig;
|
use crate::{
|
||||||
|
config::LauncherConfig,
|
||||||
|
util::game_milestones::{get_jak1_milestones, GameTaskStatus, MilestoneCriteria},
|
||||||
|
};
|
||||||
|
|
||||||
use super::CommandError;
|
use super::CommandError;
|
||||||
|
|
||||||
|
@ -68,3 +76,132 @@ pub async fn reset_game_settings(game_name: String) -> Result<(), CommandError>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_saves_highest_milestone(
|
||||||
|
path: &PathBuf,
|
||||||
|
milestones: &Vec<MilestoneCriteria>,
|
||||||
|
) -> Option<(String, i32)> {
|
||||||
|
// Read the file's bytes and generate a list of all completed tasks
|
||||||
|
let mut tasks: HashMap<u8, GameTaskStatus> = HashMap::new();
|
||||||
|
let save_bytes = match std::fs::read(path) {
|
||||||
|
Ok(bytes) => bytes,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to read save file: {:?}", err);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut reading_tasks = false;
|
||||||
|
let mut tasks_remaining = 0;
|
||||||
|
// Iterate through bytes in 16 byte chunks
|
||||||
|
for chunk in save_bytes.chunks(16) {
|
||||||
|
if reading_tasks {
|
||||||
|
// Otherwise, it's a task, parse it
|
||||||
|
let new_game_task = GameTaskStatus {
|
||||||
|
introduced: chunk[0] != 0 && chunk[0] != 1 && chunk[0] != 6 && chunk[0] != 7,
|
||||||
|
completed: chunk[0] == 7,
|
||||||
|
};
|
||||||
|
tasks.insert(chunk[11], new_game_task);
|
||||||
|
tasks_remaining -= 1;
|
||||||
|
if tasks_remaining <= 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check to see if we've reached the task list
|
||||||
|
if chunk[14] == 0x2C && chunk[15] == 0x01 {
|
||||||
|
// Retrieve the amount of tasks that we need to iterate through
|
||||||
|
reading_tasks = true;
|
||||||
|
tasks_remaining = i32::from_le_bytes([chunk[8], chunk[9], chunk[10], chunk[11]]);
|
||||||
|
info!("Found {} tasks", tasks_remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through the milestones backwards
|
||||||
|
for (index, milestone) in milestones.iter().rev().enumerate() {
|
||||||
|
for task_id in &milestone.introduced {
|
||||||
|
if tasks.contains_key(&task_id) && tasks[&task_id].introduced {
|
||||||
|
return Some((milestone.name.to_owned(), (milestones.len() - index) as i32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for task_id in &milestone.completed {
|
||||||
|
if tasks.contains_key(&task_id) && tasks[&task_id].completed {
|
||||||
|
return Some((milestone.name.to_owned(), (milestones.len() - index) as i32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the most significant milestone in the game the user has achieved
|
||||||
|
// this is determined by scanning the user's save files
|
||||||
|
// and displaying a relevant screenshot in the frontend to reflect their progress
|
||||||
|
//
|
||||||
|
// Otherwise, it will default to a default picture (geyser)
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_furthest_game_milestone(game_name: String) -> Result<String, CommandError> {
|
||||||
|
// TODO - currently only checking Jak 1
|
||||||
|
// TODO - It would be cool if the launcher had save-game editing features and the like
|
||||||
|
// Scan each save file, we inspect the `game-save`'s tag list.
|
||||||
|
// - to find the beginning of the tags, scan 16 bytes at a time, find the group that ends with `00 01 00 64` aka 1 element type 100 (name)
|
||||||
|
// - the name tag always comes first
|
||||||
|
// - next, we continue to scan until we find type `300` which is the task-list
|
||||||
|
// - this group also says how many tasks there are, each are 16 bytes as well
|
||||||
|
// - then it's just a matter of going through each task and seeing if it's completed or not, they are in order of the `game-task` enum
|
||||||
|
// - for each entity-perm, byte 0-4 corresponds with it's `task-status`:
|
||||||
|
// (invalid 0)
|
||||||
|
// (unknown 1)
|
||||||
|
// (need-hint 2)
|
||||||
|
// (need-introduction 3)
|
||||||
|
// (need-reminder-a 4)
|
||||||
|
// (need-reminder 5)
|
||||||
|
// (need-reward-speech 6)
|
||||||
|
// (need-resolution 7)
|
||||||
|
// - byte 11 corresponds with it's task id
|
||||||
|
// there is also a task status field but we don't really care about it, the task-status entry is sufficient
|
||||||
|
let game_save_dir = if let Some(config_dir) = config_dir() {
|
||||||
|
let expected_dir = config_dir.join("OpenGOAL").join(game_name).join("saves");
|
||||||
|
if !expected_dir.exists() {
|
||||||
|
info!(
|
||||||
|
"Expected save directory {} does not exist",
|
||||||
|
expected_dir.display()
|
||||||
|
);
|
||||||
|
return Ok("geyser".to_owned());
|
||||||
|
}
|
||||||
|
expected_dir
|
||||||
|
} else {
|
||||||
|
info!("Couldn't determine game save directory");
|
||||||
|
return Ok("geyser".to_owned());
|
||||||
|
};
|
||||||
|
|
||||||
|
let milestones = get_jak1_milestones();
|
||||||
|
|
||||||
|
// Scan the directory recursively for any `*.bin` files
|
||||||
|
// Check each save's contents, we don't assume save 0 is the only important one
|
||||||
|
let mut highest_milestone_idx = 0;
|
||||||
|
let mut furthest_milestone_name = "geyser".to_owned();
|
||||||
|
// TODO - a find all X in a dir function would be nice
|
||||||
|
for entry in WalkDir::new(&game_save_dir)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|e| e.ok())
|
||||||
|
{
|
||||||
|
if let Some(ext) = entry.path().extension() {
|
||||||
|
if ext == "bin" {
|
||||||
|
info!("Scanning save {}", entry.path().display());
|
||||||
|
match get_saves_highest_milestone(&entry.into_path(), &milestones) {
|
||||||
|
Some((name, idx)) => {
|
||||||
|
info!("Furthest milestone {} at index {}", name, idx);
|
||||||
|
if idx > highest_milestone_idx {
|
||||||
|
highest_milestone_idx = idx;
|
||||||
|
furthest_milestone_name = name.to_owned();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(furthest_milestone_name);
|
||||||
|
}
|
||||||
|
|
|
@ -160,6 +160,7 @@ fn main() {
|
||||||
commands::config::cleanup_enabled_texture_packs,
|
commands::config::cleanup_enabled_texture_packs,
|
||||||
commands::game::reset_game_settings,
|
commands::game::reset_game_settings,
|
||||||
commands::game::uninstall_game,
|
commands::game::uninstall_game,
|
||||||
|
commands::game::get_furthest_game_milestone,
|
||||||
commands::features::update_texture_pack_data,
|
commands::features::update_texture_pack_data,
|
||||||
commands::features::extract_new_texture_pack,
|
commands::features::extract_new_texture_pack,
|
||||||
commands::features::list_extracted_texture_pack_info,
|
commands::features::list_extracted_texture_pack_info,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
pub mod game_milestones;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
pub mod tar;
|
pub mod tar;
|
||||||
|
|
229
src-tauri/src/util/game_milestones.rs
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
use std::vec;
|
||||||
|
|
||||||
|
pub struct MilestoneCriteria {
|
||||||
|
pub name: String,
|
||||||
|
// some milestones are considered reached once you've completed something
|
||||||
|
// (ie. collecting a cell in an area)
|
||||||
|
pub completed: Vec<u8>,
|
||||||
|
// others are reached when they've been introduced
|
||||||
|
// (ie. preparing for a boss fight)
|
||||||
|
pub introduced: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GameTaskStatus {
|
||||||
|
pub introduced: bool,
|
||||||
|
pub completed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_jak1_milestones() -> Vec<MilestoneCriteria> {
|
||||||
|
return vec![
|
||||||
|
MilestoneCriteria {
|
||||||
|
name: "geyser".to_string(),
|
||||||
|
completed: vec![],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (village1-yakow 10)
|
||||||
|
// (village1-mayor-money 11)
|
||||||
|
// (village1-uncle-money 12)
|
||||||
|
// (village1-oracle-money1 13)
|
||||||
|
// (village1-oracle-money2 14)
|
||||||
|
// (beach-ecorocks 15)
|
||||||
|
// (village1-buzzer 75)
|
||||||
|
name: "sandover".to_string(),
|
||||||
|
completed: vec![10, 11, 12, 13, 14, 75],
|
||||||
|
introduced: vec![15],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (beach-ecorocks 15)
|
||||||
|
// (beach-pelican 16)
|
||||||
|
// (beach-flutflut 17)
|
||||||
|
// (beach-seagull 18)
|
||||||
|
// (beach-cannon 19)
|
||||||
|
// (beach-buzzer 20)
|
||||||
|
// (beach-gimmie 21)
|
||||||
|
// (beach-sentinel 22)
|
||||||
|
name: "sentinel".to_string(),
|
||||||
|
completed: vec![15, 16, 17, 18, 19, 20, 21, 22],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (jungle-eggtop 2)
|
||||||
|
// (jungle-lurkerm 3)
|
||||||
|
// (jungle-tower 4)
|
||||||
|
// (jungle-fishgame 5)
|
||||||
|
// (jungle-plant 6)
|
||||||
|
// (jungle-buzzer 7)
|
||||||
|
// (jungle-canyon-end 8)
|
||||||
|
// (jungle-temple-door 9)
|
||||||
|
name: "jungle".to_string(),
|
||||||
|
completed: vec![2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (misty-muse 23)
|
||||||
|
// (misty-boat 24)
|
||||||
|
// (misty-warehouse 25)
|
||||||
|
// (misty-cannon 26)
|
||||||
|
// (misty-bike 27)
|
||||||
|
// (misty-buzzer 28)
|
||||||
|
// (misty-bike-jump 29)
|
||||||
|
// (misty-eco-challenge 30)
|
||||||
|
// (leaving-misty 114)
|
||||||
|
name: "misty".to_string(),
|
||||||
|
completed: vec![23, 24, 25, 26, 27, 28, 29, 30, 114],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (firecanyon-buzzer 68)
|
||||||
|
// (firecanyon-end 69)
|
||||||
|
// (firecanyon-assistant 102)
|
||||||
|
name: "firecanyon".to_string(),
|
||||||
|
completed: vec![68, 69],
|
||||||
|
introduced: vec![102],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (village2-gambler-money 31)
|
||||||
|
// (village2-geologist-money 32)
|
||||||
|
// (village2-warrior-money 33)
|
||||||
|
// (village2-oracle-money1 34)
|
||||||
|
// (village2-oracle-money2 35)
|
||||||
|
// (firecanyon-buzzer 68)
|
||||||
|
// (firecanyon-end 69)
|
||||||
|
// (village2-buzzer 76)
|
||||||
|
// (firecanyon-assistant 102)
|
||||||
|
name: "village2".to_string(),
|
||||||
|
completed: vec![31, 32, 33, 34, 35, 68, 69],
|
||||||
|
introduced: vec![76, 102],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (rolling-race 52)
|
||||||
|
// (rolling-robbers 53)
|
||||||
|
// (rolling-moles 54)
|
||||||
|
// (rolling-plants 55)
|
||||||
|
// (rolling-lake 56)
|
||||||
|
// (rolling-buzzer 57)
|
||||||
|
// (rolling-ring-chase-1 58)
|
||||||
|
// (rolling-ring-chase-2 59)
|
||||||
|
name: "basin".to_string(),
|
||||||
|
completed: vec![52, 53, 54, 55, 56, 57, 58, 59],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (swamp-billy 36)
|
||||||
|
// (swamp-flutflut 37)
|
||||||
|
// (swamp-battle 38)
|
||||||
|
// (swamp-tether-1 39)
|
||||||
|
// (swamp-tether-2 40)
|
||||||
|
// (swamp-tether-3 41)
|
||||||
|
// (swamp-tether-4 42)
|
||||||
|
// (swamp-buzzer 43)
|
||||||
|
// (swamp-arm 104)
|
||||||
|
name: "swamp".to_string(),
|
||||||
|
completed: vec![36, 37, 38, 39, 40, 41, 42, 43, 104],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (sunken-platforms 44)
|
||||||
|
// (sunken-pipe 45)
|
||||||
|
// (sunken-slide 46)
|
||||||
|
// (sunken-room 47)
|
||||||
|
// (sunken-sharks 48)
|
||||||
|
// (sunken-buzzer 49)
|
||||||
|
// (sunken-top-of-helix 50)
|
||||||
|
// (sunken-spinning-room 51)
|
||||||
|
name: "lpc".to_string(),
|
||||||
|
completed: vec![44, 45, 46, 47, 48, 49, 50, 51],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (ogre-boss 86)
|
||||||
|
// (village2-levitator 103)
|
||||||
|
name: "klaww".to_string(),
|
||||||
|
completed: vec![103],
|
||||||
|
introduced: vec![86],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (ogre-boss 86)
|
||||||
|
// (ogre-end 87)
|
||||||
|
// (ogre-buzzer 88)
|
||||||
|
// (ogre-secret 110)
|
||||||
|
name: "mountainpass".to_string(),
|
||||||
|
completed: vec![86, 88, 110],
|
||||||
|
introduced: vec![87],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (village3-extra1 74)
|
||||||
|
// (village3-buzzer 77)
|
||||||
|
// (village3-miner-money1 96)
|
||||||
|
// (village3-miner-money2 97)
|
||||||
|
// (village3-miner-money3 98)
|
||||||
|
// (village3-miner-money4 99)
|
||||||
|
// (village3-oracle-money1 100)
|
||||||
|
// (village3-oracle-money2 101)
|
||||||
|
// (village3-button 105)
|
||||||
|
name: "village3".to_string(),
|
||||||
|
completed: vec![74, 77, 96, 97, 98, 99, 100, 101, 105],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (cave-gnawers 78)
|
||||||
|
// (cave-dark-crystals 79)
|
||||||
|
// (cave-dark-climb 80)
|
||||||
|
// (cave-robot-climb 81)
|
||||||
|
// (cave-swing-poles 82)
|
||||||
|
// (cave-spider-tunnel 83)
|
||||||
|
// (cave-platforms 84)
|
||||||
|
// (cave-buzzer 85)
|
||||||
|
name: "cave".to_string(),
|
||||||
|
completed: vec![78, 79, 80, 81, 82, 83, 84, 85],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (snow-eggtop 60)
|
||||||
|
// (snow-ram 61)
|
||||||
|
// (snow-fort 62)
|
||||||
|
// (snow-ball 63)
|
||||||
|
// (snow-bunnies 64)
|
||||||
|
// (snow-buzzer 65)
|
||||||
|
// (snow-bumpers 66)
|
||||||
|
// (snow-cage 67)
|
||||||
|
name: "snowy".to_string(),
|
||||||
|
completed: vec![60, 61, 62, 63, 64, 65, 66, 67],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (lavatube-end 89)
|
||||||
|
// (lavatube-buzzer 90)
|
||||||
|
// (lavatube-balls 107)
|
||||||
|
// (lavatube-start 108)
|
||||||
|
// (assistant-village3 115)
|
||||||
|
name: "lavatube".to_string(),
|
||||||
|
completed: vec![90, 107, 108, 115],
|
||||||
|
introduced: vec![89],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (citadel-sage-green 70)
|
||||||
|
// (citadel-sage-blue 71)
|
||||||
|
// (citadel-sage-red 72)
|
||||||
|
// (citadel-sage-yellow 73)
|
||||||
|
// (lavatube-end 89)
|
||||||
|
// (citadel-buzzer 91)
|
||||||
|
name: "citadel".to_string(),
|
||||||
|
completed: vec![71, 72, 73, 89, 91],
|
||||||
|
introduced: vec![70],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (citadel-sage-green 70)
|
||||||
|
name: "finalboss".to_string(),
|
||||||
|
completed: vec![70],
|
||||||
|
introduced: vec![],
|
||||||
|
},
|
||||||
|
MilestoneCriteria {
|
||||||
|
// (finalboss-movies 112)
|
||||||
|
name: "end".to_string(),
|
||||||
|
completed: vec![],
|
||||||
|
introduced: vec![112],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
|
@ -19,9 +19,6 @@
|
||||||
"dmg",
|
"dmg",
|
||||||
"updater"
|
"updater"
|
||||||
],
|
],
|
||||||
"appimage": {
|
|
||||||
"bundleMediaFramework": true
|
|
||||||
},
|
|
||||||
"identifier": "OpenGOAL-Launcher",
|
"identifier": "OpenGOAL-Launcher",
|
||||||
"icon": [
|
"icon": [
|
||||||
"icons/32x32.png",
|
"icons/32x32.png",
|
||||||
|
|
Before Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 34 KiB |
|
@ -1,17 +1,16 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import bgVideoJak1 from "$assets/videos/background-jak1.webm";
|
|
||||||
import bgVideoPosterJak1 from "$assets/images/background-jak1.webp";
|
|
||||||
import bgVideoJak2 from "$assets/videos/background-jak2.webm";
|
|
||||||
import bgVideoPosterJak2 from "$assets/images/background-jak2.webp";
|
|
||||||
import { useLocation } from "svelte-navigator";
|
import { useLocation } from "svelte-navigator";
|
||||||
import { isGameInstalled } from "$lib/rpc/config";
|
import { isGameInstalled } from "$lib/rpc/config";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
|
import { getFurthestGameMilestone } from "$lib/rpc/game";
|
||||||
|
import jak2Background from "$assets/images/background-jak2.webp";
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
$: $location.pathname, updateStyle();
|
$: $location.pathname, updateStyle();
|
||||||
|
|
||||||
let style = "absolute object-fill h-screen";
|
let style = "absolute object-fill h-screen brightness-75";
|
||||||
|
let jak1Image = "";
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const unlistenInstalled = await listen("gameInstalled", (event) => {
|
const unlistenInstalled = await listen("gameInstalled", (event) => {
|
||||||
|
@ -20,10 +19,13 @@
|
||||||
const unlistenUninstalled = await listen("gameUninstalled", (event) => {
|
const unlistenUninstalled = await listen("gameUninstalled", (event) => {
|
||||||
updateStyle();
|
updateStyle();
|
||||||
});
|
});
|
||||||
|
// TODO - call this if the game is closed as well
|
||||||
|
const jak1_milestone = await getFurthestGameMilestone("jak1");
|
||||||
|
jak1Image = `/images/jak1/${jak1_milestone}.jpg`;
|
||||||
});
|
});
|
||||||
|
|
||||||
async function updateStyle(): Promise<void> {
|
async function updateStyle(): Promise<void> {
|
||||||
let newStyle = "absolute object-fill h-screen";
|
let newStyle = "absolute object-fill h-screen brightness-75";
|
||||||
let pathname = $location.pathname;
|
let pathname = $location.pathname;
|
||||||
if (pathname === "/jak1" || pathname === "/") {
|
if (pathname === "/jak1" || pathname === "/") {
|
||||||
if (!(await isGameInstalled("jak1"))) {
|
if (!(await isGameInstalled("jak1"))) {
|
||||||
|
@ -47,21 +49,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $location.pathname == "/jak1" || $location.pathname == "/"}
|
{#if $location.pathname == "/jak1" || $location.pathname == "/"}
|
||||||
<video
|
<img class={style} src={jak1Image} />
|
||||||
class={style}
|
|
||||||
poster={bgVideoPosterJak1}
|
|
||||||
src={bgVideoJak1}
|
|
||||||
autoplay
|
|
||||||
muted
|
|
||||||
loop
|
|
||||||
/>
|
|
||||||
{:else if $location.pathname == "/jak2"}
|
{:else if $location.pathname == "/jak2"}
|
||||||
<video
|
<img class={style} src={jak2Background} />
|
||||||
class={style}
|
|
||||||
poster={bgVideoPosterJak2}
|
|
||||||
src={bgVideoJak2}
|
|
||||||
autoplay
|
|
||||||
muted
|
|
||||||
loop
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -17,3 +17,14 @@ export async function resetGameSettings(gameName: string): Promise<void> {
|
||||||
"Unable to reset game settings",
|
"Unable to reset game settings",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getFurthestGameMilestone(
|
||||||
|
gameName: string,
|
||||||
|
): Promise<String> {
|
||||||
|
return await invoke_rpc(
|
||||||
|
"get_furthest_game_milestone",
|
||||||
|
{ gameName },
|
||||||
|
() => "geyser", // TODO - default for only jak 1 right now
|
||||||
|
"Unable to get furthest game milestone",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|