Several changes

- added `components::mfc140` to install mfc140 in games where it's needed
- renamed `WincompatlibWine` to `UnifiedWine`;
  implemented new traits
- removed `Serialize` & `Deserialize` derives from `LauncherState`-s
- added `Mfc140NotInstalled` and `CorefontsNotInstalled` states for PGR
This commit is contained in:
Observer KRypt0n_ 2023-06-07 14:24:41 +02:00
parent 5526e5df93
commit 9e18ba7e24
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
14 changed files with 383 additions and 211 deletions

View file

@ -21,10 +21,10 @@ tracing = "0.1"
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }
cached = { version = "0.43", features = ["proc_macro"] }
cached = { version = "0.44", features = ["proc_macro"] }
enum-ordinalize = { version = "3.1", optional = true }
wincompatlib = { version = "0.4", features = ["all"], optional = true }
wincompatlib = { version = "0.7.2", features = ["all"], optional = true }
lazy_static = { version = "1.4", optional = true }
md-5 = { version = "0.10", features = ["asm"], optional = true }
discord-rich-presence = { version = "0.2.3", optional = true }

View file

@ -171,7 +171,7 @@ impl Version {
#[inline]
#[tracing::instrument(level = "debug", ret)]
/// Install current dxvk
pub fn install<T: Into<PathBuf> + std::fmt::Debug>(&self, dxvks_folder: T, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
pub fn install<T: Into<PathBuf> + std::fmt::Debug>(&self, dxvks_folder: T, wine: &Wine, params: InstallParams) -> anyhow::Result<()> {
tracing::debug!("Installing DXVK");
Dxvk::install(
@ -184,7 +184,7 @@ impl Version {
#[inline]
#[tracing::instrument(level = "debug", ret)]
/// Uninstall current dxvk
pub fn uninstall(&self, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
pub fn uninstall(&self, wine: &Wine, params: InstallParams) -> anyhow::Result<()> {
tracing::debug!("Uninstalling DXVK");
Dxvk::uninstall(

69
src/components/mfc140.rs Normal file
View file

@ -0,0 +1,69 @@
use std::path::Path;
use std::process::Command;
use anime_game_core::installer::downloader::Downloader;
// Source: https://github.com/Winetricks/winetricks/blob/e9454179686b3659ad3f47a5d49e6e4e82862cd5/src/winetricks#L13206
const URL: &str = "https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe";
const LIBRARIES: &[&str] = &[
"mfc140.dll",
"mfc140u.dll",
"mfcm140.dll",
"mfcm140u.dll"
];
pub fn is_installed(wine_prefix: impl AsRef<Path>) -> bool {
wine_prefix.as_ref().join("drive_c/windows/system32/mfc140.dll").exists()
}
pub fn install(wine_prefix: impl AsRef<Path>) -> anyhow::Result<()> {
let vcredist = std::env::temp_dir().join("vcredist/vc_redist.x86.exe");
let vcredist_extracted = std::env::temp_dir().join("vcredist/extracted");
Downloader::new(URL)?
.with_continue_downloading(false)
.download(&vcredist, |_, _| {})?;
// w_try_cabextract --directory="${W_TMP}/win64" "${W_CACHE}"/vcrun2015/vc_redist.x64.exe -F 'a11'
let output = Command::new("cabextract")
.arg("-d")
.arg(&vcredist_extracted)
.arg(vcredist)
.arg("-F")
.arg("a11")
.spawn()?
.wait_with_output()?;
if !output.status.success() {
anyhow::bail!("Failed to extract vcrun2015 (1): {}", String::from_utf8_lossy(&output.stderr));
}
// w_try_cabextract --directory="${W_TMP}/win64" "${W_TMP}/win64/a11"
let output = Command::new("cabextract")
.arg("-d")
.arg(&vcredist_extracted)
.arg(vcredist_extracted.join("a11"))
.arg("-F")
.arg("a11")
.spawn()?
.wait_with_output()?;
if !output.status.success() {
anyhow::bail!("Failed to extract vcrun2015 (2): {}", String::from_utf8_lossy(&output.stderr));
}
// w_try_cp_dll "${W_TMP}/win64"/mfc140.dll "${W_SYSTEM64_DLLS}"/mfc140.dll
for lib in LIBRARIES {
let dest = wine_prefix.as_ref().join("drive_c/windows/system32").join(lib);
if dest.exists() {
std::fs::remove_file(&dest)?;
}
std::fs::copy(vcredist_extracted.join(lib), dest)?;
}
Ok(())
}

View file

@ -1,3 +1,4 @@
pub mod loader;
pub mod wine;
pub mod dxvk;
pub mod mfc140;

View file

@ -1,15 +1,17 @@
use std::path::PathBuf;
use std::collections::HashMap;
use std::process::{Child, Output};
use std::io::Result;
use std::ffi::OsStr;
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
use wincompatlib::prelude::*;
use super::loader::ComponentsLoader;
mod unified_wine;
pub use unified_wine::UnifiedWine;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Group {
pub name: String,
@ -224,7 +226,7 @@ impl Version {
/// Convert current wine struct to one from `wincompatlib`
///
/// `wine_folder` should point to the folder with wine binaries, so e.g. `/path/to/runners/wine-proton-ge-7.11`
pub fn to_wine<T: Into<PathBuf>>(&self, components: T, wine_folder: Option<T>) -> WincompatlibWine {
pub fn to_wine<T: Into<PathBuf>>(&self, components: T, wine_folder: Option<T>) -> UnifiedWine {
let wine_folder = wine_folder.map(|folder| folder.into()).unwrap_or_default();
let (wine, arch) = match self.files.wine64.as_ref() {
@ -253,18 +255,23 @@ impl Version {
// Small workaround. Most of stuff will work with just this
proton.steam_client_path = Some(PathBuf::from(""));
return WincompatlibWine::Proton(proton);
return UnifiedWine::Proton(proton);
}
}
WincompatlibWine::Default(Wine::new(
wine_folder.join(wine),
None,
Some(arch),
wineboot,
wineserver,
WineLoader::Current
))
let mut wine = Wine::from_binary(wine_folder.join(wine))
.with_loader(WineLoader::Current)
.with_arch(arch);
if let Some(wineboot) = wineboot {
wine = wine.with_boot(wineboot);
}
if let Some(wineserver) = wineserver {
wine = wine.with_server(wineserver);
}
UnifiedWine::Default(wine)
}
}
@ -276,161 +283,6 @@ pub struct Files {
pub wineboot: Option<String>
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WincompatlibWine {
Default(Wine),
Proton(Proton)
}
impl From<Wine> for WincompatlibWine {
#[inline]
fn from(wine: Wine) -> Self {
Self::Default(wine)
}
}
impl From<Proton> for WincompatlibWine {
#[inline]
fn from(proton: Proton) -> Self {
Self::Proton(proton)
}
}
impl WineWithExt for WincompatlibWine {
#[inline]
fn with_prefix<T: Into<PathBuf>>(self, prefix: T) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_prefix(prefix)),
Self::Proton(proton) => Self::Proton(proton.with_prefix(prefix))
}
}
#[inline]
fn with_arch(self, arch: WineArch) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_arch(arch)),
Self::Proton(proton) => Self::Proton(proton.with_arch(arch))
}
}
#[inline]
fn with_boot(self, boot: WineBoot) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_boot(boot)),
Self::Proton(proton) => Self::Proton(proton.with_boot(boot))
}
}
#[inline]
fn with_server<T: Into<PathBuf>>(self, server: T) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_server(server)),
Self::Proton(proton) => Self::Proton(proton.with_server(server))
}
}
#[inline]
fn with_loader(self, loader: WineLoader) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_loader(loader)),
Self::Proton(proton) => Self::Proton(proton.with_loader(loader))
}
}
}
impl WineBootExt for WincompatlibWine {
#[inline]
fn wineboot_command(&self) -> std::process::Command {
match self {
Self::Default(wine) => wine.wineboot_command(),
Self::Proton(proton) => proton.wineboot_command()
}
}
#[inline]
fn update_prefix<T: Into<PathBuf>>(&self, path: Option<T>) -> Result<Output> {
match self {
Self::Default(wine) => wine.update_prefix(path),
Self::Proton(proton) => proton.update_prefix(path)
}
}
#[inline]
fn stop_processes(&self, force: bool) -> Result<Output> {
match self {
Self::Default(wine) => wine.stop_processes(force),
Self::Proton(proton) => proton.stop_processes(force)
}
}
#[inline]
fn restart(&self) -> Result<Output> {
match self {
Self::Default(wine) => wine.restart(),
Self::Proton(proton) => proton.restart()
}
}
#[inline]
fn shutdown(&self) -> Result<Output> {
match self {
Self::Default(wine) => wine.shutdown(),
Self::Proton(proton) => proton.shutdown()
}
}
#[inline]
fn end_session(&self) -> Result<Output> {
match self {
Self::Default(wine) => wine.end_session(),
Self::Proton(proton) => proton.end_session()
}
}
}
impl WineRunExt for WincompatlibWine {
#[inline]
fn run<T: AsRef<OsStr>>(&self, binary: T) -> Result<Child> {
match self {
Self::Default(wine) => wine.run(binary),
Self::Proton(proton) => proton.run(binary)
}
}
#[inline]
fn run_args<T, S>(&self, args: T) -> Result<Child>
where
T: IntoIterator<Item = S>,
S: AsRef<OsStr>
{
match self {
Self::Default(wine) => wine.run_args(args),
Self::Proton(proton) => proton.run_args(args)
}
}
#[inline]
fn run_args_with_env<T, K, S>(&self, args: T, envs: K) -> Result<Child>
where
T: IntoIterator<Item = S>,
K: IntoIterator<Item = (S, S)>,
S: AsRef<OsStr>
{
match self {
Self::Default(wine) => wine.run_args_with_env(args, envs),
Self::Proton(proton) => proton.run_args_with_env(args, envs)
}
}
#[inline]
fn winepath(&self, path: &str) -> Result<PathBuf> {
match self {
Self::Default(wine) => wine.winepath(path),
Self::Proton(proton) => proton.winepath(path)
}
}
}
#[inline]
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
ComponentsLoader::new(components).get_wine_versions()

View file

@ -0,0 +1,240 @@
use std::path::PathBuf;
use std::process::{Output, Child};
use std::ffi::OsStr;
use wincompatlib::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnifiedWine {
Default(Wine),
Proton(Proton)
}
impl From<Wine> for UnifiedWine {
#[inline]
fn from(wine: Wine) -> Self {
Self::Default(wine)
}
}
impl From<Proton> for UnifiedWine {
#[inline]
fn from(proton: Proton) -> Self {
Self::Proton(proton)
}
}
impl From<UnifiedWine> for Wine {
fn from(wine: UnifiedWine) -> Self {
match wine {
UnifiedWine::Default(wine) => wine,
// Kind of unsafe but who cares?
// I don't like proton anyway lol
UnifiedWine::Proton(proton) => proton.wine().to_owned()
}
}
}
impl WineWithExt for UnifiedWine {
#[inline]
fn with_prefix<T: Into<PathBuf>>(self, prefix: T) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_prefix(prefix)),
Self::Proton(proton) => Self::Proton(proton.with_prefix(prefix))
}
}
#[inline]
fn with_arch(self, arch: WineArch) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_arch(arch)),
Self::Proton(proton) => Self::Proton(proton.with_arch(arch))
}
}
#[inline]
fn with_boot(self, boot: WineBoot) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_boot(boot)),
Self::Proton(proton) => Self::Proton(proton.with_boot(boot))
}
}
#[inline]
fn with_server<T: Into<PathBuf>>(self, server: T) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_server(server)),
Self::Proton(proton) => Self::Proton(proton.with_server(server))
}
}
#[inline]
fn with_loader(self, loader: WineLoader) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_loader(loader)),
Self::Proton(proton) => Self::Proton(proton.with_loader(loader))
}
}
#[inline]
fn with_wine_libs(self, wine_libs: WineSharedLibs) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_wine_libs(wine_libs)),
Self::Proton(proton) => Self::Proton(proton.with_wine_libs(wine_libs))
}
}
#[inline]
fn with_gstreamer_libs(self, gstreamer_libs: GstreamerSharedLibs) -> Self {
match self {
Self::Default(wine) => Self::Default(wine.with_gstreamer_libs(gstreamer_libs)),
Self::Proton(proton) => Self::Proton(proton.with_gstreamer_libs(gstreamer_libs))
}
}
}
impl WineBootExt for UnifiedWine {
#[inline]
fn wineboot_command(&self) -> std::process::Command {
match self {
Self::Default(wine) => wine.wineboot_command(),
Self::Proton(proton) => proton.wineboot_command()
}
}
#[inline]
fn init_prefix(&self, path: Option<impl Into<PathBuf>>) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.init_prefix(path),
Self::Proton(proton) => proton.init_prefix(path)
}
}
#[inline]
fn update_prefix(&self, path: Option<impl Into<PathBuf>>) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.update_prefix(path),
Self::Proton(proton) => proton.update_prefix(path)
}
}
#[inline]
fn stop_processes(&self, force: bool) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.stop_processes(force),
Self::Proton(proton) => proton.stop_processes(force)
}
}
#[inline]
fn restart(&self) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.restart(),
Self::Proton(proton) => proton.restart()
}
}
#[inline]
fn shutdown(&self) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.shutdown(),
Self::Proton(proton) => proton.shutdown()
}
}
#[inline]
fn end_session(&self) -> anyhow::Result<Output> {
match self {
Self::Default(wine) => wine.end_session(),
Self::Proton(proton) => proton.end_session()
}
}
}
impl WineRunExt for UnifiedWine {
#[inline]
fn run<T: AsRef<OsStr>>(&self, binary: T) -> anyhow::Result<Child> {
match self {
Self::Default(wine) => wine.run(binary),
Self::Proton(proton) => proton.run(binary)
}
}
#[inline]
fn run_args<T, S>(&self, args: T) -> anyhow::Result<Child>
where
T: IntoIterator<Item = S>,
S: AsRef<OsStr>
{
match self {
Self::Default(wine) => wine.run_args(args),
Self::Proton(proton) => proton.run_args(args)
}
}
#[inline]
fn run_args_with_env<T, K, S>(&self, args: T, envs: K) -> anyhow::Result<Child>
where
T: IntoIterator<Item = S>,
K: IntoIterator<Item = (S, S)>,
S: AsRef<OsStr>
{
match self {
Self::Default(wine) => wine.run_args_with_env(args, envs),
Self::Proton(proton) => proton.run_args_with_env(args, envs)
}
}
#[inline]
fn winepath(&self, path: &str) -> anyhow::Result<PathBuf> {
match self {
Self::Default(wine) => wine.winepath(path),
Self::Proton(proton) => proton.winepath(path)
}
}
}
impl WineOverridesExt for UnifiedWine {
#[inline]
fn add_override(&self, dll_name: impl AsRef<str>, modes: impl IntoIterator<Item = OverrideMode>) -> anyhow::Result<()> {
match self {
Self::Default(wine) => wine.add_override(dll_name, modes),
Self::Proton(proton) => proton.add_override(dll_name, modes)
}
}
#[inline]
fn delete_override(&self, dll_name: impl AsRef<str>) -> anyhow::Result<()> {
match self {
Self::Default(wine) => wine.delete_override(dll_name),
Self::Proton(proton) => proton.delete_override(dll_name)
}
}
}
impl WineFontsExt for UnifiedWine {
#[inline]
fn register_font(&self, ttf: impl AsRef<str>, font_name: impl AsRef<str>) -> anyhow::Result<()> {
match self {
Self::Default(wine) => wine.register_font(ttf, font_name),
Self::Proton(proton) => proton.register_font(ttf, font_name)
}
}
#[inline]
fn font_is_installed(&self, ttf: impl AsRef<str>) -> bool {
match self {
Self::Default(wine) => wine.font_is_installed(ttf),
Self::Proton(proton) => proton.font_is_installed(ttf)
}
}
#[inline]
fn install_corefont(&self, corefont: Corefont) -> anyhow::Result<()> {
match self {
Self::Default(wine) => wine.install_corefont(corefont),
Self::Proton(proton) => proton.install_corefont(corefont)
}
}
}

View file

@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
#[cfg(feature = "components")]
use crate::components::{
wine::{
WincompatlibWine,
UnifiedWine,
Version as WineVersion
},
dxvk::Version as DxvkVersion
@ -118,13 +118,11 @@ impl Schema {
.with_prefix(&self.game.wine.prefix);
let prefix = match wine {
WincompatlibWine::Default(wine) => wine.prefix,
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
UnifiedWine::Default(wine) => wine.prefix,
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
};
if let Some(prefix) = prefix {
return prefix;
}
return prefix;
}
self.game.wine.prefix.clone()

View file

@ -1,14 +1,12 @@
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use anime_game_core::prelude::*;
use anime_game_core::genshin::prelude::*;
use crate::config::ConfigExt;
use crate::genshin::config::Config;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub enum LauncherState {
Launch,
@ -51,7 +49,7 @@ pub enum LauncherState {
GameNotInstalled(VersionDiff)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateUpdating {
Game,
Voice(VoiceLocale),

View file

@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
#[cfg(feature = "components")]
use crate::components::{
wine::{
WincompatlibWine,
UnifiedWine,
Version as WineVersion
},
dxvk::Version as DxvkVersion
@ -118,13 +118,11 @@ impl Schema {
.with_prefix(&self.game.wine.prefix);
let prefix = match wine {
WincompatlibWine::Default(wine) => wine.prefix,
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
UnifiedWine::Default(wine) => wine.prefix,
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
};
if let Some(prefix) = prefix {
return prefix;
}
return prefix;
}
self.game.wine.prefix.clone()

View file

@ -1,13 +1,11 @@
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use anime_game_core::prelude::*;
use anime_game_core::honkai::prelude::*;
use crate::config::ConfigExt;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub enum LauncherState {
Launch,
@ -26,7 +24,7 @@ pub enum LauncherState {
GameNotInstalled(VersionDiff)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateUpdating {
Game,
Patch

View file

@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
#[cfg(feature = "components")]
use crate::components::{
wine::{
WincompatlibWine,
UnifiedWine,
Version as WineVersion
},
dxvk::Version as DxvkVersion
@ -109,13 +109,11 @@ impl Schema {
.with_prefix(&self.game.wine.prefix);
let prefix = match wine {
WincompatlibWine::Default(wine) => wine.prefix,
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
UnifiedWine::Default(wine) => wine.prefix,
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
};
if let Some(prefix) = prefix {
return prefix;
}
return prefix;
}
self.game.wine.prefix.clone()

View file

@ -1,13 +1,14 @@
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use wincompatlib::wine::ext::Corefont;
use anime_game_core::prelude::*;
use anime_game_core::pgr::prelude::*;
use crate::config::ConfigExt;
use crate::components::mfc140;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub enum LauncherState {
Launch,
@ -16,6 +17,9 @@ pub enum LauncherState {
PrefixNotExists,
Mfc140NotInstalled,
CorefontsNotInstalled(Vec<Corefont>),
// Always contains `VersionDiff::Diff`
GameUpdateAvailable(VersionDiff),
@ -23,8 +27,9 @@ pub enum LauncherState {
GameNotInstalled(VersionDiff)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateUpdating {
Components,
Game
}
@ -45,6 +50,25 @@ impl LauncherState {
return Ok(Self::PrefixNotExists);
}
// Check wine components installation status
(params.status_updater)(StateUpdating::Components);
if !mfc140::is_installed(&params.wine_prefix) {
return Ok(Self::Mfc140NotInstalled);
}
let mut corefonts = Vec::new();
for font in Corefont::iterator() {
if !font.is_installed(&params.wine_prefix) {
corefonts.push(font);
}
}
if !corefonts.is_empty() {
return Ok(Self::CorefontsNotInstalled(corefonts));
}
// Check game installation status
(params.status_updater)(StateUpdating::Game);

View file

@ -11,7 +11,7 @@ use crate::config::schema_blanks::sandbox::Sandbox;
#[cfg(feature = "components")]
use crate::components::{
wine::{
WincompatlibWine,
UnifiedWine,
Version as WineVersion
},
dxvk::Version as DxvkVersion
@ -118,13 +118,11 @@ impl Schema {
.with_prefix(&self.game.wine.prefix);
let prefix = match wine {
WincompatlibWine::Default(wine) => wine.prefix,
WincompatlibWine::Proton(proton) => proton.wine().prefix.clone()
UnifiedWine::Default(wine) => wine.prefix,
UnifiedWine::Proton(proton) => proton.wine().prefix.clone()
};
if let Some(prefix) = prefix {
return prefix;
}
return prefix;
}
self.game.wine.prefix.clone()

View file

@ -1,14 +1,12 @@
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use anime_game_core::prelude::*;
use anime_game_core::star_rail::prelude::*;
use crate::config::ConfigExt;
use crate::star_rail::config::Config;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone)]
pub enum LauncherState {
Launch,
@ -32,7 +30,7 @@ pub enum LauncherState {
GameNotInstalled(VersionDiff)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateUpdating {
Game,
Patch