mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-02-16 15:22:01 +03:00
Implemented #28
This commit is contained in:
parent
56ed3b13e8
commit
9d1ade6e4a
13 changed files with 283 additions and 273 deletions
|
@ -16,7 +16,6 @@ opt-level = 3
|
||||||
glib-build-tools = "0.16"
|
glib-build-tools = "0.16"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
discord-rich-presence = "0.2.3"
|
|
||||||
gtk = { package = "gtk4", version = "0.5", features = ["v4_8"] }
|
gtk = { package = "gtk4", version = "0.5", features = ["v4_8"] }
|
||||||
adw = { package = "libadwaita", version = "0.2", features = ["v1_2"] }
|
adw = { package = "libadwaita", version = "0.2", features = ["v1_2"] }
|
||||||
rfd = { version = "0.10", features = ["xdg-portal"], default-features = false }
|
rfd = { version = "0.10", features = ["xdg-portal"], default-features = false }
|
||||||
|
@ -33,3 +32,4 @@ lazy_static = "1.4.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
md5 = "0.7"
|
md5 = "0.7"
|
||||||
cached = { version = "0.42", features = ["proc_macro"] }
|
cached = { version = "0.42", features = ["proc_macro"] }
|
||||||
|
discord-rich-presence = "0.2.3"
|
||||||
|
|
|
@ -55,35 +55,6 @@ Adw.PreferencesPage page {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Adw.ActionRow discord_rpc_row
|
|
||||||
{
|
|
||||||
title: "Discord RPC";
|
|
||||||
subtitle: "Discord RPC allows you to provide Discord the info that you are currently playing the game to let your friends know.";
|
|
||||||
Gtk.Switch discord_rpc_switch {
|
|
||||||
valign: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Adw.ActionRow discord_rpc_desc_row
|
|
||||||
{
|
|
||||||
title: "Discord RPC Heading";
|
|
||||||
subtitle: "Set a custom heading for the activity status!\n(Requires launcher restart, or disable and re-enable the RPC)";
|
|
||||||
Gtk.Entry discord_rpc_desc
|
|
||||||
{
|
|
||||||
valign:center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Adw.ActionRow discord_rpc_state_row
|
|
||||||
{
|
|
||||||
title: "Discord RPC State";
|
|
||||||
subtitle: "Set a custom description for the activity status!\n(Requires launcher restart, or disable and re-enable the RPC)";
|
|
||||||
Gtk.Entry discord_rpc_state
|
|
||||||
{
|
|
||||||
valign:center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Adw.ComboRow fsr_combo {
|
Adw.ComboRow fsr_combo {
|
||||||
title: "FSR";
|
title: "FSR";
|
||||||
|
@ -103,8 +74,6 @@ Adw.PreferencesPage page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Adw.ActionRow gamemode_row {
|
Adw.ActionRow gamemode_row {
|
||||||
title: "Gamemode";
|
title: "Gamemode";
|
||||||
subtitle: "This prioritizes the game over the rest of the processes";
|
subtitle: "This prioritizes the game over the rest of the processes";
|
||||||
|
@ -131,6 +100,27 @@ Adw.PreferencesPage page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Adw.PreferencesGroup {
|
||||||
|
title: "Discord RPC";
|
||||||
|
|
||||||
|
Adw.ActionRow discord_rpc_row {
|
||||||
|
title: "Enabled";
|
||||||
|
subtitle: "Discord RPC allows you to provide Discord the info that you are currently playing the game to let your friends know";
|
||||||
|
|
||||||
|
Gtk.Switch discord_rpc_switch {
|
||||||
|
valign: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.EntryRow discord_rpc_title {
|
||||||
|
title: "Title";
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.EntryRow discord_rpc_subtitle {
|
||||||
|
title: "Description";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Adw.PreferencesGroup {
|
Adw.PreferencesGroup {
|
||||||
title: "FPS Unlocker";
|
title: "FPS Unlocker";
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
use std::thread::JoinHandle;
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::Value as JsonValue;
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct DiscordRpc {
|
|
||||||
pub enabled: bool,
|
|
||||||
pub large_image_key: String,
|
|
||||||
pub app_id: String,
|
|
||||||
pub description: String,
|
|
||||||
pub state: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DiscordRpc {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
enabled: true,
|
|
||||||
large_image_key: "gi-icon".to_string(),
|
|
||||||
app_id: "901534333360304168".to_string(),
|
|
||||||
description: "Bullying Paimon".to_string(),
|
|
||||||
state: "In the weeb game".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&JsonValue> for DiscordRpc {
|
|
||||||
fn from(value: &JsonValue) -> Self {
|
|
||||||
let default = Self::default();
|
|
||||||
Self {
|
|
||||||
enabled: match value.get("enabled") {
|
|
||||||
Some(value) => value.as_bool().unwrap_or(default.enabled),
|
|
||||||
None => default.enabled,
|
|
||||||
},
|
|
||||||
|
|
||||||
description: match value.get("description") {
|
|
||||||
Some(value) => value.as_str().unwrap_or(&default.description).to_string(),
|
|
||||||
None => default.description,
|
|
||||||
},
|
|
||||||
|
|
||||||
state: match value.get("state") {
|
|
||||||
Some(value) => value.as_str().unwrap_or(&default.state).to_string(),
|
|
||||||
None => default.state,
|
|
||||||
},
|
|
||||||
|
|
||||||
large_image_key: match value.get("large_image_key") {
|
|
||||||
Some(value) => value
|
|
||||||
.as_str()
|
|
||||||
.unwrap_or(&default.large_image_key)
|
|
||||||
.to_string(),
|
|
||||||
None => default.large_image_key,
|
|
||||||
},
|
|
||||||
app_id: "901534333360304168".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ pub mod fsr;
|
||||||
pub mod hud;
|
pub mod hud;
|
||||||
pub mod fps_unlocker;
|
pub mod fps_unlocker;
|
||||||
pub mod gamescope;
|
pub mod gamescope;
|
||||||
pub mod discordrpc;
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::gamescope::prelude::*;
|
pub use super::gamescope::prelude::*;
|
||||||
pub use super::fps_unlocker::prelude::*;
|
pub use super::fps_unlocker::prelude::*;
|
||||||
|
@ -14,21 +14,17 @@ pub mod prelude {
|
||||||
pub use super::fsr::Fsr;
|
pub use super::fsr::Fsr;
|
||||||
pub use super::hud::HUD;
|
pub use super::hud::HUD;
|
||||||
pub use super::fps_unlocker::FpsUnlocker;
|
pub use super::fps_unlocker::FpsUnlocker;
|
||||||
pub use super::discordrpc::DiscordRpc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
use crate::lib::config;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct Enhancements {
|
pub struct Enhancements {
|
||||||
pub fsr: Fsr,
|
pub fsr: Fsr,
|
||||||
pub gamemode: bool,
|
pub gamemode: bool,
|
||||||
pub hud: HUD,
|
pub hud: HUD,
|
||||||
pub fps_unlocker: FpsUnlocker,
|
pub fps_unlocker: FpsUnlocker,
|
||||||
pub gamescope: Gamescope,
|
pub gamescope: Gamescope
|
||||||
pub discord_rpc: DiscordRpc,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&JsonValue> for Enhancements {
|
impl From<&JsonValue> for Enhancements {
|
||||||
|
@ -59,11 +55,7 @@ impl From<&JsonValue> for Enhancements {
|
||||||
gamescope: match value.get("gamescope") {
|
gamescope: match value.get("gamescope") {
|
||||||
Some(value) => Gamescope::from(value),
|
Some(value) => Gamescope::from(value),
|
||||||
None => default.gamescope
|
None => default.gamescope
|
||||||
},
|
}
|
||||||
discord_rpc: match value.get("discord_rpc") {
|
|
||||||
Some(value) => DiscordRpc::from(value),
|
|
||||||
None => default.discord_rpc
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
58
src/lib/config/launcher/discord_rpc.rs
Normal file
58
src/lib/config/launcher/discord_rpc.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct DiscordRpc {
|
||||||
|
pub app_id: u64,
|
||||||
|
pub enabled: bool,
|
||||||
|
|
||||||
|
pub title: String,
|
||||||
|
pub subtitle: String,
|
||||||
|
pub image: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DiscordRpc {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
app_id: 901534333360304168,
|
||||||
|
enabled: false,
|
||||||
|
|
||||||
|
title: String::from("of Teyvat"),
|
||||||
|
subtitle: String::from("Researching the world"),
|
||||||
|
image: String::from("gi-icon")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&JsonValue> for DiscordRpc {
|
||||||
|
fn from(value: &JsonValue) -> Self {
|
||||||
|
let default = Self::default();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
app_id: match value.get("app_id") {
|
||||||
|
Some(value) => value.as_u64().unwrap_or(default.app_id),
|
||||||
|
None => default.app_id
|
||||||
|
},
|
||||||
|
|
||||||
|
enabled: match value.get("enabled") {
|
||||||
|
Some(value) => value.as_bool().unwrap_or(default.enabled),
|
||||||
|
None => default.enabled
|
||||||
|
},
|
||||||
|
|
||||||
|
title: match value.get("title") {
|
||||||
|
Some(value) => value.as_str().unwrap_or(&default.title).to_string(),
|
||||||
|
None => default.title
|
||||||
|
},
|
||||||
|
|
||||||
|
subtitle: match value.get("subtitle") {
|
||||||
|
Some(value) => value.as_str().unwrap_or(&default.subtitle).to_string(),
|
||||||
|
None => default.subtitle
|
||||||
|
},
|
||||||
|
|
||||||
|
image: match value.get("image") {
|
||||||
|
Some(value) => value.as_str().unwrap_or(&default.image).to_string(),
|
||||||
|
None => default.image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,10 +8,12 @@ use anime_game_core::genshin::consts::GameEdition as CoreGameEdition;
|
||||||
use crate::lib::consts::launcher_dir;
|
use crate::lib::consts::launcher_dir;
|
||||||
|
|
||||||
pub mod repairer;
|
pub mod repairer;
|
||||||
|
pub mod discord_rpc;
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::Launcher;
|
pub use super::Launcher;
|
||||||
pub use super::repairer::Repairer;
|
pub use super::repairer::Repairer;
|
||||||
|
pub use super::discord_rpc::DiscordRpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
@ -67,7 +69,8 @@ pub struct Launcher {
|
||||||
pub temp: Option<PathBuf>,
|
pub temp: Option<PathBuf>,
|
||||||
pub speed_limit: u64,
|
pub speed_limit: u64,
|
||||||
pub repairer: Repairer,
|
pub repairer: Repairer,
|
||||||
pub edition: GameEdition
|
pub edition: GameEdition,
|
||||||
|
pub discord_rpc: DiscordRpc
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Launcher {
|
impl Default for Launcher {
|
||||||
|
@ -77,7 +80,8 @@ impl Default for Launcher {
|
||||||
temp: launcher_dir(),
|
temp: launcher_dir(),
|
||||||
speed_limit: 0,
|
speed_limit: 0,
|
||||||
repairer: Repairer::default(),
|
repairer: Repairer::default(),
|
||||||
edition: GameEdition::default()
|
edition: GameEdition::default(),
|
||||||
|
discord_rpc: DiscordRpc::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,6 +123,11 @@ impl From<&JsonValue> for Launcher {
|
||||||
edition: match value.get("edition") {
|
edition: match value.get("edition") {
|
||||||
Some(value) => serde_json::from_value(value.clone()).unwrap_or(default.edition),
|
Some(value) => serde_json::from_value(value.clone()).unwrap_or(default.edition),
|
||||||
None => default.edition
|
None => default.edition
|
||||||
|
},
|
||||||
|
|
||||||
|
discord_rpc: match value.get("discord_rpc") {
|
||||||
|
Some(value) => DiscordRpc::from(value),
|
||||||
|
None => default.discord_rpc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
92
src/lib/discord_rpc.rs
Normal file
92
src/lib/discord_rpc.rs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
use std::sync::mpsc::{self, Sender, SendError};
|
||||||
|
|
||||||
|
use discord_rich_presence::{
|
||||||
|
activity::*,
|
||||||
|
DiscordIpc,
|
||||||
|
DiscordIpcClient
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::config::prelude::DiscordRpc as DiscordRpcConfig;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum RpcUpdates {
|
||||||
|
/// Establish RPC connection
|
||||||
|
Connect,
|
||||||
|
|
||||||
|
/// Terminate RPC connection. Panics if not connected
|
||||||
|
Disconnect,
|
||||||
|
|
||||||
|
/// Update RPC activity
|
||||||
|
UpdateActivity {
|
||||||
|
title: String,
|
||||||
|
subtitle: String,
|
||||||
|
image: String
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Clear RPC activity
|
||||||
|
ClearActivity
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DiscordRpc {
|
||||||
|
_thread: JoinHandle<()>,
|
||||||
|
sender: Sender<RpcUpdates>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiscordRpc {
|
||||||
|
pub fn new(mut config: DiscordRpcConfig) -> Self {
|
||||||
|
let (sender, receiver) = mpsc::channel();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_thread: std::thread::spawn(move || {
|
||||||
|
let mut client = DiscordIpcClient::new(&config.app_id.to_string())
|
||||||
|
.expect("Failed to register discord ipc client");
|
||||||
|
|
||||||
|
while let Ok(update) = receiver.recv() {
|
||||||
|
match update {
|
||||||
|
RpcUpdates::Connect => {
|
||||||
|
if !config.enabled {
|
||||||
|
config.enabled = true;
|
||||||
|
|
||||||
|
client.connect().expect("Failed to connect to discord");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcUpdates::Disconnect => {
|
||||||
|
if config.enabled {
|
||||||
|
config.enabled = false;
|
||||||
|
|
||||||
|
client.close().expect("Failed to disconnect from discord");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcUpdates::UpdateActivity { title, subtitle, image } => {
|
||||||
|
config.title = title;
|
||||||
|
config.subtitle = subtitle;
|
||||||
|
config.image = image;
|
||||||
|
|
||||||
|
client.set_activity(Self::get_activity(&config))
|
||||||
|
.expect("Failed to update discord rpc activity");
|
||||||
|
}
|
||||||
|
|
||||||
|
RpcUpdates::ClearActivity => {
|
||||||
|
client.clear_activity().expect("Failed to clear discord rpc activity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_activity(config: &DiscordRpcConfig) -> Activity {
|
||||||
|
Activity::new()
|
||||||
|
.state(&config.title)
|
||||||
|
.details(&config.subtitle)
|
||||||
|
.assets(Assets::new().large_image(&config.image))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&self, update: RpcUpdates) -> Result<(), SendError<RpcUpdates>> {
|
||||||
|
self.sender.send(update)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use std::process::Output;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::process::Command;
|
||||||
|
|
||||||
use anime_game_core::genshin::telemetry;
|
use anime_game_core::genshin::telemetry;
|
||||||
|
|
||||||
use super::config;
|
|
||||||
use super::consts;
|
use super::consts;
|
||||||
|
use super::config;
|
||||||
use super::fps_unlocker::FpsUnlocker;
|
use super::fps_unlocker::FpsUnlocker;
|
||||||
|
|
||||||
/*#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
/*#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -61,25 +61,24 @@ pub fn try_get_terminal() -> Option<Terminal> {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/// Try to run the game
|
/// Try to run the game
|
||||||
///
|
///
|
||||||
/// If `debug = true`, then the game will be run in the new terminal window
|
/// If `debug = true`, then the game will be run in the new terminal window
|
||||||
pub fn run() -> anyhow::Result<()> {
|
pub fn run() -> anyhow::Result<()> {
|
||||||
let config = config::get()?;
|
let config = config::get()?;
|
||||||
|
|
||||||
if !config.game.path.exists() {
|
if !config.game.path.exists() {
|
||||||
return Err(anyhow::anyhow!("Game is not installed"));
|
return Err(anyhow::anyhow!("Game is not installed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let wine_executable = match config.try_get_wine_executable() {
|
let wine_executable = match config.try_get_wine_executable() {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => return Err(anyhow::anyhow!("Couldn't find wine executable")),
|
None => return Err(anyhow::anyhow!("Couldn't find wine executable"))
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check telemetry servers
|
// Check telemetry servers
|
||||||
|
|
||||||
if let Some(server) = telemetry::is_disabled(consts::TELEMETRY_CHECK_TIMEOUT) {
|
if let Some(server) = telemetry::is_disabled(consts::TELEMETRY_CHECK_TIMEOUT) {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}"));
|
||||||
"Telemetry server is not disabled: {server}"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare fps unlocker
|
// Prepare fps unlocker
|
||||||
|
@ -95,51 +94,28 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
// Ok(None) means unknown version, so we should delete it before downloading newer one
|
// Ok(None) means unknown version, so we should delete it before downloading newer one
|
||||||
// because otherwise downloader will try to continue downloading "partially downloaded" file
|
// because otherwise downloader will try to continue downloading "partially downloaded" file
|
||||||
if let Ok(None) = other {
|
if let Ok(None) = other {
|
||||||
std::fs::remove_file(FpsUnlocker::get_binary_in(
|
std::fs::remove_file(FpsUnlocker::get_binary_in(&config.game.enhancements.fps_unlocker.path))?;
|
||||||
&config.game.enhancements.fps_unlocker.path,
|
|
||||||
))?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match FpsUnlocker::download(&config.game.enhancements.fps_unlocker.path) {
|
match FpsUnlocker::download(&config.game.enhancements.fps_unlocker.path) {
|
||||||
Ok(unlocker) => unlocker,
|
Ok(unlocker) => unlocker,
|
||||||
Err(err) => {
|
Err(err) => return Err(anyhow::anyhow!("Failed to download FPS unlocker: {err}"))
|
||||||
return Err(anyhow::anyhow!("Failed to download FPS unlocker: {err}"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate FPS unlocker config file
|
// Generate FPS unlocker config file
|
||||||
if let Err(err) =
|
if let Err(err) = unlocker.update_config(config.game.enhancements.fps_unlocker.config.clone()) {
|
||||||
unlocker.update_config(config.game.enhancements.fps_unlocker.config.clone())
|
return Err(anyhow::anyhow!("Failed to update FPS unlocker config: {err}"));
|
||||||
{
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"Failed to update FPS unlocker config: {err}"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let bat_path = config.game.path.join("fpsunlocker.bat");
|
let bat_path = config.game.path.join("fpsunlocker.bat");
|
||||||
let original_bat_path = config.game.path.join("launcher.bat");
|
let original_bat_path = config.game.path.join("launcher.bat");
|
||||||
|
|
||||||
// Generate fpsunlocker.bat from launcher.bat
|
// Generate fpsunlocker.bat from launcher.bat
|
||||||
std::fs::write(
|
std::fs::write(bat_path, std::fs::read_to_string(original_bat_path)?
|
||||||
bat_path,
|
.replace("start GenshinImpact.exe %*", &format!("start GenshinImpact.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy()))
|
||||||
std::fs::read_to_string(original_bat_path)?
|
.replace("start YuanShen.exe %*", &format!("start YuanShen.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy())))?;
|
||||||
.replace(
|
|
||||||
"start GenshinImpact.exe %*",
|
|
||||||
&format!(
|
|
||||||
"start GenshinImpact.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe",
|
|
||||||
unlocker.dir().to_string_lossy()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
"start YuanShen.exe %*",
|
|
||||||
&format!(
|
|
||||||
"start YuanShen.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe",
|
|
||||||
unlocker.dir().to_string_lossy()
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare bash -c '<command>'
|
// Prepare bash -c '<command>'
|
||||||
|
@ -156,11 +132,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
bash_chain += &format!("{virtual_desktop} ");
|
bash_chain += &format!("{virtual_desktop} ");
|
||||||
}
|
}
|
||||||
|
|
||||||
bash_chain += if config.game.enhancements.fps_unlocker.enabled {
|
bash_chain += if config.game.enhancements.fps_unlocker.enabled { "fpsunlocker.bat " } else { "launcher.bat " };
|
||||||
"fpsunlocker.bat "
|
|
||||||
} else {
|
|
||||||
"launcher.bat "
|
|
||||||
};
|
|
||||||
|
|
||||||
if config.game.wine.borderless {
|
if config.game.wine.borderless {
|
||||||
bash_chain += "-screen-fullscreen 0 -popupwindow ";
|
bash_chain += "-screen-fullscreen 0 -popupwindow ";
|
||||||
|
@ -178,7 +150,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let bash_chain = match &config.game.command {
|
let bash_chain = match &config.game.command {
|
||||||
Some(command) => command.replace("%command%", &bash_chain),
|
Some(command) => command.replace("%command%", &bash_chain),
|
||||||
None => bash_chain,
|
None => bash_chain
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut command = Command::new("bash");
|
let mut command = Command::new("bash");
|
||||||
|
@ -202,6 +174,7 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
command.envs(config.game.enhancements.hud.get_env_vars(&config));
|
command.envs(config.game.enhancements.hud.get_env_vars(&config));
|
||||||
command.envs(config.game.enhancements.fsr.get_env_vars());
|
command.envs(config.game.enhancements.fsr.get_env_vars());
|
||||||
command.envs(config.game.wine.language.get_env_vars());
|
command.envs(config.game.wine.language.get_env_vars());
|
||||||
|
|
||||||
command.envs(config.game.environment);
|
command.envs(config.game.environment);
|
||||||
|
|
||||||
// Run command
|
// Run command
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub mod wine;
|
||||||
pub mod launcher;
|
pub mod launcher;
|
||||||
pub mod prettify_bytes;
|
pub mod prettify_bytes;
|
||||||
pub mod fps_unlocker;
|
pub mod fps_unlocker;
|
||||||
|
pub mod discord_rpc;
|
||||||
|
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
|
97
src/main.rs
97
src/main.rs
|
@ -1,7 +1,3 @@
|
||||||
use discord_rich_presence::{
|
|
||||||
activity::{self, Activity, Party, Secrets},
|
|
||||||
DiscordIpc, DiscordIpcClient,
|
|
||||||
};
|
|
||||||
use gtk::gdk::Display;
|
use gtk::gdk::Display;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::glib::clone;
|
use gtk::glib::clone;
|
||||||
|
@ -40,7 +36,7 @@ fn main() {
|
||||||
glib::OptionFlags::empty(),
|
glib::OptionFlags::empty(),
|
||||||
glib::OptionArg::None,
|
glib::OptionArg::None,
|
||||||
"Run the game",
|
"Run the game",
|
||||||
None,
|
None
|
||||||
);
|
);
|
||||||
|
|
||||||
application.add_main_option(
|
application.add_main_option(
|
||||||
|
@ -49,7 +45,7 @@ fn main() {
|
||||||
glib::OptionFlags::empty(),
|
glib::OptionFlags::empty(),
|
||||||
glib::OptionArg::None,
|
glib::OptionArg::None,
|
||||||
"Run the game whenever it possible, ignoring updates predownloads",
|
"Run the game whenever it possible, ignoring updates predownloads",
|
||||||
None,
|
None
|
||||||
);
|
);
|
||||||
|
|
||||||
let run_game = std::rc::Rc::new(std::cell::Cell::new(false));
|
let run_game = std::rc::Rc::new(std::cell::Cell::new(false));
|
||||||
|
@ -73,62 +69,6 @@ fn main() {
|
||||||
application.connect_activate(move |app| {
|
application.connect_activate(move |app| {
|
||||||
let config = lib::config::get().expect("Failed to load config");
|
let config = lib::config::get().expect("Failed to load config");
|
||||||
|
|
||||||
let mut client =
|
|
||||||
DiscordIpcClient::new(config.game.enhancements.discord_rpc.app_id.as_str())
|
|
||||||
.expect("Failed to create client");
|
|
||||||
|
|
||||||
|
|
||||||
let mut activity_set:bool = false;
|
|
||||||
let mut connected: bool = false;
|
|
||||||
let _thread = std::thread::spawn(move || loop {
|
|
||||||
let conf = lib::config::get().expect("Failed to load config");
|
|
||||||
// println!("activity_set: {:?} connected: {:?}",activity_set,connected);
|
|
||||||
if conf.game.enhancements.discord_rpc.enabled {
|
|
||||||
if !connected{
|
|
||||||
match client.connect() {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("Client connected to Discord successfully.");connected=true;
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
println!(
|
|
||||||
"Client failed to connect to Discord, Please try again or relaunch Discord."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let act = activity::Activity::new()
|
|
||||||
.state(config.game.enhancements.discord_rpc.state.as_str())
|
|
||||||
.details(config.game.enhancements.discord_rpc.description.as_str())
|
|
||||||
.assets(activity::Assets::new()
|
|
||||||
.large_image(config.game.enhancements.discord_rpc.large_image_key.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
if !activity_set{
|
|
||||||
match client.set_activity(act) {
|
|
||||||
Ok(_) => {println!("Client set activity successfully."); activity_set=true;}
|
|
||||||
Err(_) => {println!("Client failed to set activity, Please try again or relaunch Discord.");}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
|
||||||
} else {
|
|
||||||
if activity_set{
|
|
||||||
match client.clear_activity(){
|
|
||||||
Ok(_) => {println!("Client activity cleared successfully.");connected=false;activity_set=false}
|
|
||||||
Err(_) => {println!("Failed to clear.");}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if connected{
|
|
||||||
match client.close(){
|
|
||||||
Ok(_) => {println!("Client connection closed.");connected=false;}
|
|
||||||
Err(_) => {println!("Failed to clear.");}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
|
||||||
});
|
|
||||||
// Apply CSS styles to the application
|
// Apply CSS styles to the application
|
||||||
let provider = CssProvider::new();
|
let provider = CssProvider::new();
|
||||||
|
|
||||||
|
@ -137,7 +77,7 @@ fn main() {
|
||||||
StyleContext::add_provider_for_display(
|
StyleContext::add_provider_for_display(
|
||||||
&Display::default().expect("Could not connect to a display"),
|
&Display::default().expect("Could not connect to a display"),
|
||||||
&provider,
|
&provider,
|
||||||
STYLE_PROVIDER_PRIORITY_APPLICATION,
|
STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create default launcher folder if needed
|
// Create default launcher folder if needed
|
||||||
|
@ -145,13 +85,14 @@ fn main() {
|
||||||
|
|
||||||
if !launcher_dir.exists() || launcher_dir.join(".first-run").exists() {
|
if !launcher_dir.exists() || launcher_dir.join(".first-run").exists() {
|
||||||
fs::create_dir_all(&launcher_dir).expect("Failed to create default launcher dir");
|
fs::create_dir_all(&launcher_dir).expect("Failed to create default launcher dir");
|
||||||
fs::write(launcher_dir.join(".first-run"), "")
|
fs::write(launcher_dir.join(".first-run"), "").expect("Failed to create .first-run file");
|
||||||
.expect("Failed to create .first-run file");
|
|
||||||
|
|
||||||
let first_run = FirstRunApp::new(app).expect("Failed to init FirstRunApp");
|
let first_run = FirstRunApp::new(app).expect("Failed to init FirstRunApp");
|
||||||
|
|
||||||
first_run.show();
|
first_run.show();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
// Create wine builds folder
|
// Create wine builds folder
|
||||||
if !Path::new(&config.game.wine.builds).exists() {
|
if !Path::new(&config.game.wine.builds).exists() {
|
||||||
fs::create_dir_all(config.game.wine.builds)
|
fs::create_dir_all(config.game.wine.builds)
|
||||||
|
@ -175,7 +116,9 @@ fn main() {
|
||||||
|
|
||||||
if !run_game.get() && !just_run_game.get() {
|
if !run_game.get() && !just_run_game.get() {
|
||||||
main.show();
|
main.show();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
use lib::launcher::states::LauncherState;
|
use lib::launcher::states::LauncherState;
|
||||||
|
|
||||||
let just_run_game = just_run_game.get();
|
let just_run_game = just_run_game.get();
|
||||||
|
@ -187,22 +130,20 @@ fn main() {
|
||||||
if let LauncherState::PredownloadAvailable { game, voices } = state {
|
if let LauncherState::PredownloadAvailable { game, voices } = state {
|
||||||
if just_run_game {
|
if just_run_game {
|
||||||
state = &LauncherState::Launch;
|
state = &LauncherState::Launch;
|
||||||
} else if let Ok(config) = lib::config::get() {
|
}
|
||||||
|
|
||||||
|
else if let Ok(config) = lib::config::get() {
|
||||||
let mut predownloaded = true;
|
let mut predownloaded = true;
|
||||||
|
|
||||||
let temp = config.launcher.temp.unwrap_or("/tmp".into());
|
let temp = config.launcher.temp.unwrap_or("/tmp".into());
|
||||||
|
|
||||||
if !temp
|
if !temp.join(game.file_name().unwrap_or(String::from("\0"))).exists() {
|
||||||
.join(game.file_name().unwrap_or(String::from("\0")))
|
|
||||||
.exists()
|
|
||||||
{
|
|
||||||
predownloaded = false;
|
predownloaded = false;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
for voice in voices {
|
for voice in voices {
|
||||||
if !temp
|
if !temp.join(voice.file_name().unwrap_or(String::from("\0"))).exists() {
|
||||||
.join(voice.file_name().unwrap_or(String::from("\0")))
|
|
||||||
.exists()
|
|
||||||
{
|
|
||||||
predownloaded = false;
|
predownloaded = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -224,7 +165,7 @@ fn main() {
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => main.show(),
|
_ => main.show()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ use crate::lib::wine::{
|
||||||
List as WineList
|
List as WineList
|
||||||
};
|
};
|
||||||
use crate::lib::prettify_bytes::prettify_bytes;
|
use crate::lib::prettify_bytes::prettify_bytes;
|
||||||
|
use crate::lib::discord_rpc::RpcUpdates;
|
||||||
|
|
||||||
/// This structure is used to describe widgets used in application
|
/// This structure is used to describe widgets used in application
|
||||||
///
|
///
|
||||||
|
@ -275,7 +276,6 @@ impl App {
|
||||||
///
|
///
|
||||||
/// Changes will happen in the main thread so you can call `update` method from separate thread
|
/// Changes will happen in the main thread so you can call `update` method from separate thread
|
||||||
pub fn init_actions(self) -> Self {
|
pub fn init_actions(self) -> Self {
|
||||||
|
|
||||||
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
||||||
|
|
||||||
// I prefer to avoid using clone! here because it breaks my code autocompletion
|
// I prefer to avoid using clone! here because it breaks my code autocompletion
|
||||||
|
@ -309,6 +309,23 @@ impl App {
|
||||||
this.widgets.leaflet.navigate(adw::NavigationDirection::Back);
|
this.widgets.leaflet.navigate(adw::NavigationDirection::Back);
|
||||||
|
|
||||||
config::flush().expect("Failed to save config file");
|
config::flush().expect("Failed to save config file");
|
||||||
|
|
||||||
|
// Update Discord RPC state
|
||||||
|
let config = config::get().expect("Failed to load config");
|
||||||
|
|
||||||
|
let result = this.widgets.preferences_stack.enhancements_page.discord_rpc.update(RpcUpdates::UpdateActivity {
|
||||||
|
title: config.launcher.discord_rpc.title,
|
||||||
|
subtitle: config.launcher.discord_rpc.subtitle,
|
||||||
|
image: config.launcher.discord_rpc.image
|
||||||
|
});
|
||||||
|
|
||||||
|
let this = this.clone();
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
glib::MainContext::default().invoke(move || {
|
||||||
|
this.toast("Failed to update Discord RPC", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions::PerformButtonEvent => {
|
Actions::PerformButtonEvent => {
|
||||||
|
@ -327,6 +344,7 @@ impl App {
|
||||||
|
|
||||||
this.widgets.window.hide();
|
this.widgets.window.hide();
|
||||||
|
|
||||||
|
#[allow(unused_must_use)]
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
// Display toast message if the game is failed to run
|
// Display toast message if the game is failed to run
|
||||||
if let Err(err) = game::run() {
|
if let Err(err) = game::run() {
|
||||||
|
@ -340,6 +358,8 @@ impl App {
|
||||||
else {
|
else {
|
||||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||||
|
|
||||||
|
this.widgets.preferences_stack.enhancements_page.discord_rpc.update(RpcUpdates::Connect);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_secs(3));
|
std::thread::sleep(std::time::Duration::from_secs(3));
|
||||||
|
|
||||||
|
@ -355,6 +375,8 @@ impl App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.widgets.preferences_stack.enhancements_page.discord_rpc.update(RpcUpdates::Disconnect);
|
||||||
|
|
||||||
this.widgets.window.show();
|
this.widgets.window.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -879,6 +901,7 @@ impl App {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.actions.set(actions);
|
self.actions.set(actions);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
use gtk::ffi::gtk_text_view_set_overwrite;
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::glib::clone;
|
use gtk::glib::clone;
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::lib;
|
use crate::lib;
|
||||||
use crate::lib::config;
|
use crate::lib::config;
|
||||||
use crate::lib::config::game::enhancements::discordrpc;
|
|
||||||
use crate::lib::config::prelude::*;
|
use crate::lib::config::prelude::*;
|
||||||
|
use crate::lib::discord_rpc::DiscordRpc;
|
||||||
|
|
||||||
use crate::ui::*;
|
use crate::ui::*;
|
||||||
|
|
||||||
|
@ -51,12 +52,8 @@ pub struct AppWidgets {
|
||||||
|
|
||||||
pub discord_rpc_row: adw::ActionRow,
|
pub discord_rpc_row: adw::ActionRow,
|
||||||
pub discord_rpc: gtk::Switch,
|
pub discord_rpc: gtk::Switch,
|
||||||
|
pub discord_rpc_title: adw::EntryRow,
|
||||||
pub discord_rpc_state_row: adw::ActionRow,
|
pub discord_rpc_subtitle: adw::EntryRow
|
||||||
pub discord_rpc_state: gtk::Entry,
|
|
||||||
|
|
||||||
pub discord_rpc_desc_row: adw::ActionRow,
|
|
||||||
pub discord_rpc_desc: gtk::Entry,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppWidgets {
|
impl AppWidgets {
|
||||||
|
@ -91,13 +88,11 @@ impl AppWidgets {
|
||||||
fps_unlocker_monitor_num: get_object(&builder, "fps_unlocker_monitor_num")?,
|
fps_unlocker_monitor_num: get_object(&builder, "fps_unlocker_monitor_num")?,
|
||||||
fps_unlocker_window_mode_combo: get_object(&builder, "fps_unlocker_window_mode_combo")?,
|
fps_unlocker_window_mode_combo: get_object(&builder, "fps_unlocker_window_mode_combo")?,
|
||||||
fps_unlocker_priority_combo: get_object(&builder, "fps_unlocker_priority_combo")?,
|
fps_unlocker_priority_combo: get_object(&builder, "fps_unlocker_priority_combo")?,
|
||||||
discord_rpc: get_object(&builder,"discord_rpc_switch")?,
|
|
||||||
discord_rpc_row: get_object(&builder, "discord_rpc_row")?,
|
|
||||||
discord_rpc_state: get_object(&builder, "discord_rpc_state")?,
|
|
||||||
discord_rpc_state_row: get_object(&builder, "discord_rpc_state_row")?,
|
|
||||||
|
|
||||||
discord_rpc_desc: get_object(&builder, "discord_rpc_desc")?,
|
discord_rpc_row: get_object(&builder, "discord_rpc_row")?,
|
||||||
discord_rpc_desc_row: get_object(&builder, "discord_rpc_desc_row")?,
|
discord_rpc: get_object(&builder,"discord_rpc_switch")?,
|
||||||
|
discord_rpc_title: get_object(&builder, "discord_rpc_title")?,
|
||||||
|
discord_rpc_subtitle: get_object(&builder, "discord_rpc_subtitle")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set availale wine languages
|
// Set availale wine languages
|
||||||
|
@ -120,11 +115,6 @@ impl AppWidgets {
|
||||||
result.gamescope_row.set_sensitive(false);
|
result.gamescope_row.set_sensitive(false);
|
||||||
result.gamescope_row.set_tooltip_text(Some("Gamescope is not installed"));
|
result.gamescope_row.set_tooltip_text(Some("Gamescope is not installed"));
|
||||||
}
|
}
|
||||||
// result.discord_rpc_desc_row.set_sensitive(true);
|
|
||||||
// result.discord_rpc_state_row.set_sensitive(true);
|
|
||||||
result.discord_rpc_row.set_sensitive(true);
|
|
||||||
result.discord_rpc.set_sensitive(true);
|
|
||||||
|
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -143,14 +133,19 @@ impl AppWidgets {
|
||||||
/// That's what we need and what we use in `App::update` method
|
/// That's what we need and what we use in `App::update` method
|
||||||
#[derive(Clone, glib::Downgrade)]
|
#[derive(Clone, glib::Downgrade)]
|
||||||
pub struct App {
|
pub struct App {
|
||||||
widgets: AppWidgets
|
widgets: AppWidgets,
|
||||||
|
|
||||||
|
pub discord_rpc: Rc<DiscordRpc>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
/// Create new application
|
/// Create new application
|
||||||
pub fn new(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
|
pub fn new(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
|
||||||
|
let config = config::get()?;
|
||||||
|
|
||||||
let result = Self {
|
let result = Self {
|
||||||
widgets: AppWidgets::try_get(window)?
|
widgets: AppWidgets::try_get(window)?,
|
||||||
|
discord_rpc: Rc::new(DiscordRpc::new(config.launcher.discord_rpc))
|
||||||
}.init_events();
|
}.init_events();
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@ -243,39 +238,35 @@ impl App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.widgets.discord_rpc.connect_state_notify(move |switch|{
|
// TODO: update RPC here or after preferences window's closing
|
||||||
if let Ok(mut config) = config::get()
|
|
||||||
{
|
// Discord RPC switching
|
||||||
config.game.enhancements.discord_rpc.enabled = switch.state();
|
self.widgets.discord_rpc.connect_state_notify(move |switch| {
|
||||||
// config.game.enhancements.discord_rpc.toggle();
|
if let Ok(mut config) = config::get() {
|
||||||
|
config.launcher.discord_rpc.enabled = switch.state();
|
||||||
|
|
||||||
config::update(config);
|
config::update(config);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.widgets.discord_rpc_state.connect_changed(move |state|
|
// Discord RPC title
|
||||||
{
|
self.widgets.discord_rpc_title.connect_changed(move |state| {
|
||||||
if let Ok(mut config) = config::get()
|
if let Ok(mut config) = config::get() {
|
||||||
{
|
config.launcher.discord_rpc.title = state.text().as_str().to_string();
|
||||||
let string = state.text().as_str().to_string();
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
config.game.enhancements.discord_rpc.state = string;
|
|
||||||
// println!("[Debug] Updated string: {}",config.game.enhancements.discord_rpc.state);
|
|
||||||
config::update(config);
|
config::update(config);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Discord RPC subtitle
|
||||||
|
self.widgets.discord_rpc_subtitle.connect_changed(move |state| {
|
||||||
|
if let Ok(mut config) = config::get() {
|
||||||
|
config.launcher.discord_rpc.subtitle = state.text().as_str().to_string();
|
||||||
|
|
||||||
self.widgets.discord_rpc_desc.connect_changed(move |state|
|
config::update(config);
|
||||||
{
|
}
|
||||||
if let Ok(mut config) = config::get()
|
|
||||||
{
|
|
||||||
let string = state.text().as_str().to_string();
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
config.game.enhancements.discord_rpc.description = string;
|
|
||||||
// println!("[Debug] Updated string: {}",config.game.enhancements.discord_rpc.description);
|
|
||||||
config::update(config);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gamemode switching
|
// Gamemode switching
|
||||||
self.widgets.gamemode_switcher.connect_state_notify(move |switch| {
|
self.widgets.gamemode_switcher.connect_state_notify(move |switch| {
|
||||||
if let Ok(mut config) = config::get() {
|
if let Ok(mut config) = config::get() {
|
||||||
|
@ -318,8 +309,6 @@ impl App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// FPS unlocker -> power saving swithing
|
// FPS unlocker -> power saving swithing
|
||||||
self.widgets.fps_unlocker_power_saving_switcher.connect_state_notify(move |switch| {
|
self.widgets.fps_unlocker_power_saving_switcher.connect_state_notify(move |switch| {
|
||||||
if let Ok(mut config) = config::get() {
|
if let Ok(mut config) = config::get() {
|
||||||
|
@ -353,8 +342,6 @@ impl App {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,9 +398,9 @@ impl App {
|
||||||
self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled);
|
self.widgets.fsr_switcher.set_state(config.game.enhancements.fsr.enabled);
|
||||||
|
|
||||||
// Discord RPC
|
// Discord RPC
|
||||||
self.widgets.discord_rpc.set_state(config.game.enhancements.discord_rpc.enabled);
|
self.widgets.discord_rpc.set_state(config.launcher.discord_rpc.enabled);
|
||||||
self.widgets.discord_rpc_state.set_placeholder_text(Some(config.game.enhancements.discord_rpc.state.as_str()));
|
self.widgets.discord_rpc_title.set_text(&config.launcher.discord_rpc.title);
|
||||||
self.widgets.discord_rpc_desc.set_placeholder_text(Some(config.game.enhancements.discord_rpc.description.as_str()));
|
self.widgets.discord_rpc_subtitle.set_text(&config.launcher.discord_rpc.subtitle);
|
||||||
|
|
||||||
// Gamemode switching
|
// Gamemode switching
|
||||||
self.widgets.gamemode_switcher.set_state(config.game.enhancements.gamemode);
|
self.widgets.gamemode_switcher.set_state(config.game.enhancements.gamemode);
|
||||||
|
|
Loading…
Add table
Reference in a new issue