feat: integrated new FPS unlocker
This commit is contained in:
parent
e3f4677a2b
commit
ebebb65e74
4 changed files with 21 additions and 127 deletions
|
@ -1,15 +1,11 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::config::schema_blanks::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
pub fps: u64, // TODO: Fps enum
|
||||
pub power_saving: bool,
|
||||
pub monitor: u64,
|
||||
pub window_mode: WindowMode,
|
||||
pub priority: u64
|
||||
pub periodic_writes: bool,
|
||||
pub interval: u64
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -17,10 +13,8 @@ impl Default for Config {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
fps: 120,
|
||||
power_saving: false,
|
||||
monitor: 1,
|
||||
window_mode: WindowMode::default(),
|
||||
priority: 3
|
||||
periodic_writes: true,
|
||||
interval: 5000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,24 +29,14 @@ impl From<&JsonValue> for Config {
|
|||
None => default.fps
|
||||
},
|
||||
|
||||
power_saving: match value.get("power_saving") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.power_saving),
|
||||
None => default.power_saving
|
||||
periodic_writes: match value.get("periodic_writes") {
|
||||
Some(value) => value.as_bool().unwrap_or(default.periodic_writes),
|
||||
None => default.periodic_writes
|
||||
},
|
||||
|
||||
monitor: match value.get("monitor") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.monitor),
|
||||
None => default.monitor
|
||||
},
|
||||
|
||||
window_mode: match value.get("window_mode") {
|
||||
Some(value) => WindowMode::from(value),
|
||||
None => default.window_mode
|
||||
},
|
||||
|
||||
priority: match value.get("priority") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.priority),
|
||||
None => default.priority
|
||||
interval: match value.get("interval") {
|
||||
Some(value) => value.as_u64().unwrap_or(default.interval),
|
||||
None => default.interval
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,9 @@ use md5::{Md5, Digest};
|
|||
|
||||
use anime_game_core::installer::downloader::Downloader;
|
||||
|
||||
use super::config::schema::prelude::FpsUnlockerConfig;
|
||||
|
||||
pub mod config_schema;
|
||||
|
||||
const LATEST_INFO: (&str, &str) = (
|
||||
"cff81830eebd3566d51b73ffaa444035",
|
||||
"https://github.com/34736384/genshin-fps-unlock/releases/download/v2.2.0/unlockfps_clr.exe"
|
||||
"53cb34d292d6b1dd1d8310318fe49bad",
|
||||
"https://codeberg.org/mkrsym1/fpsunlock/releases/download/v1.0.2/fpsunlock.exe"
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -22,13 +18,13 @@ impl FpsUnlocker {
|
|||
/// Get FpsUnlocker from its containment directory
|
||||
///
|
||||
/// Returns
|
||||
/// - `Err(..)` if failed to read `unlocker.exe` file
|
||||
/// - `Err(..)` if failed to read `fpsunlock.exe` file
|
||||
/// - `Ok(None)` if version is not latest
|
||||
/// - `Ok(..)` if version is latest
|
||||
pub fn from_dir<T: Into<PathBuf> + std::fmt::Debug>(dir: T) -> anyhow::Result<Option<Self>> {
|
||||
let dir = dir.into();
|
||||
|
||||
let hash = format!("{:x}", Md5::digest(std::fs::read(dir.join("unlocker.exe"))?));
|
||||
let hash = format!("{:x}", Md5::digest(std::fs::read(dir.join("fpsunlock.exe"))?));
|
||||
|
||||
Ok(if hash == LATEST_INFO.0 {
|
||||
Some(Self { dir })
|
||||
|
@ -51,7 +47,7 @@ impl FpsUnlocker {
|
|||
std::fs::create_dir_all(&dir)?;
|
||||
}
|
||||
|
||||
match downloader.download(dir.join("unlocker.exe"), |_, _| {}) {
|
||||
match downloader.download(dir.join("fpsunlock.exe"), |_, _| {}) {
|
||||
Ok(_) => Ok(Self { dir }),
|
||||
Err(err) => {
|
||||
tracing::error!("Downloading failed: {err}");
|
||||
|
@ -68,24 +64,11 @@ impl FpsUnlocker {
|
|||
|
||||
#[inline]
|
||||
pub fn get_binary_in<T: Into<PathBuf>>(dir: T) -> PathBuf {
|
||||
dir.into().join("unlocker.exe")
|
||||
dir.into().join("fpsunlock.exe")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dir(&self) -> &PathBuf {
|
||||
&self.dir
|
||||
}
|
||||
|
||||
/// Generate and save FPS unlocker config file to the game's directory
|
||||
#[tracing::instrument(level = "debug", ret)]
|
||||
pub fn update_config(&self, config: FpsUnlockerConfig) -> anyhow::Result<()> {
|
||||
tracing::debug!("Updating FPS unlocker config");
|
||||
|
||||
let config = config_schema::ConfigSchema::from_config(config);
|
||||
|
||||
Ok(std::fs::write(
|
||||
self.dir.join("fps_config.json"),
|
||||
config.json()?
|
||||
)?)
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::config::schema_blanks::prelude::*;
|
||||
use super::FpsUnlockerConfig;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ConfigSchema {
|
||||
pub DllList: Vec<String>,
|
||||
pub Priority: u64,
|
||||
pub MonitorNum: u64,
|
||||
pub CustomResY: u64,
|
||||
pub CustomResX: u64,
|
||||
pub FPSTarget: u64,
|
||||
pub UsePowerSave: bool,
|
||||
pub StartMinimized: bool,
|
||||
pub IsExclusiveFullscreen: bool,
|
||||
pub UseCustomRes: bool,
|
||||
pub Fullscreen: bool,
|
||||
pub PopupWindow: bool,
|
||||
pub AutoClose: bool,
|
||||
pub AutoDisableVSync: bool,
|
||||
pub AutoStart: bool,
|
||||
pub GamePath: Option<String>
|
||||
}
|
||||
|
||||
impl Default for ConfigSchema {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
DllList: vec![],
|
||||
Priority: 3,
|
||||
MonitorNum: 1,
|
||||
CustomResY: 1080,
|
||||
CustomResX: 1920,
|
||||
FPSTarget: 120,
|
||||
UsePowerSave: false,
|
||||
IsExclusiveFullscreen: false,
|
||||
UseCustomRes: false,
|
||||
Fullscreen: false,
|
||||
PopupWindow: false,
|
||||
AutoDisableVSync: true,
|
||||
GamePath: None,
|
||||
|
||||
// Launcher-specific settings
|
||||
AutoStart: true,
|
||||
AutoClose: true,
|
||||
StartMinimized: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigSchema {
|
||||
pub fn from_config(config: FpsUnlockerConfig) -> Self {
|
||||
Self {
|
||||
FPSTarget: config.fps,
|
||||
UsePowerSave: config.power_saving,
|
||||
PopupWindow: config.window_mode == WindowMode::Popup,
|
||||
Fullscreen: config.window_mode == WindowMode::Fullscreen,
|
||||
MonitorNum: config.monitor,
|
||||
Priority: config.priority,
|
||||
|
||||
..Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn json(&self) -> serde_json::Result<String> {
|
||||
serde_json::to_string(self)
|
||||
}
|
||||
}
|
|
@ -89,8 +89,7 @@ pub fn run() -> anyhow::Result<()> {
|
|||
|
||||
// Prepare fps unlocker
|
||||
// 1) Download if needed
|
||||
// 2) Generate config file
|
||||
// 3) Generate fpsunlocker.bat from launcher.bat
|
||||
// 2) Generate fps_unlocker.bat
|
||||
|
||||
#[cfg(feature = "fps-unlocker")]
|
||||
if config.game.enhancements.fps_unlocker.enabled {
|
||||
|
@ -115,14 +114,11 @@ pub fn run() -> anyhow::Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
// Generate FPS unlocker config file
|
||||
if let Err(err) = unlocker.update_config(config.game.enhancements.fps_unlocker.config) {
|
||||
return Err(anyhow::anyhow!("Failed to update FPS unlocker config: {err}"));
|
||||
}
|
||||
|
||||
// If patch applying is disabled, then game_executable is either GenshinImpact.exe or YuanShen.exe
|
||||
// so we don't need to check it here
|
||||
std::fs::write(game_path.join("fps_unlocker.bat"), format!("start {game_executable} %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy()))?;
|
||||
let unlocker_config = &config.game.enhancements.fps_unlocker.config;
|
||||
let unlocker_interval = if unlocker_config.periodic_writes { unlocker_config.interval as i64 } else { -1 };
|
||||
std::fs::write(game_path.join("fps_unlocker.bat"), format!("start {game_executable} %*\n\nZ:\ncd \"{}\"\nstart fpsunlock.exe {} {unlocker_interval}", unlocker.dir().to_string_lossy(), unlocker_config.fps))?;
|
||||
}
|
||||
|
||||
// Generate `config.ini` if environment emulation feature is presented
|
||||
|
@ -314,7 +310,7 @@ pub fn run() -> anyhow::Result<()> {
|
|||
let output = Command::new("ps").arg("-A").stdout(Stdio::piped()).output()?;
|
||||
let output = String::from_utf8_lossy(&output.stdout);
|
||||
|
||||
if !output.contains("GenshinImpact.e") && !output.contains("YuanShen.exe") && !output.contains("unlocker.exe") {
|
||||
if !output.contains("GenshinImpact.e") && !output.contains("YuanShen.exe") && !output.contains("fpsunlock.exe") {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue