- added support for dynamic components loading
This commit is contained in:
Observer KRypt0n_ 2023-03-06 12:38:37 +02:00
parent 9d6aeff526
commit 42b738dc1e
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
10 changed files with 200 additions and 111 deletions

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "anime-game-core"]
path = anime-game-core
url = https://github.com/an-anime-team/anime-game-core
[submodule "components"]
path = components
url = https://github.com/an-anime-team/components

View file

@ -1,6 +1,6 @@
[package]
name = "anime-launcher-sdk"
version = "0.2.5"
version = "0.3.0"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0"
readme = "README.md"

@ -1 +1 @@
Subproject commit a90aae53797802b458670bd99428cd258ac1d902
Subproject commit 33dce6a6d0202e1f8b17a8193603cc05c4d6a5ef

@ -1 +0,0 @@
Subproject commit 50c93220b16ef7609f61fc0785a1e435683d4a0c

View file

@ -3,22 +3,12 @@ use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use wincompatlib::prelude::*;
lazy_static::lazy_static! {
static ref GROUPS: Vec<Group> = vec![
Group {
name: String::from("Vanilla"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/dxvk/vanilla.json")).unwrap().into_iter().take(12).collect()
},
Group {
name: String::from("Async"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/dxvk/async.json")).unwrap().into_iter().take(12).collect()
}
];
}
use super::loader::ComponentsLoader;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Group {
pub name: String,
pub title: String,
pub versions: Vec<Version>
}
@ -26,25 +16,23 @@ pub struct Group {
pub struct Version {
pub name: String,
pub version: String,
pub uri: String,
pub recommended: bool
pub uri: String
}
impl Version {
/// Get latest recommended dxvk version
#[inline]
pub fn latest() -> Self {
get_groups()[0].versions[0].clone()
pub fn latest<T: Into<PathBuf>>(components: T) -> anyhow::Result<Self> {
Ok(get_groups(components)?[0].versions[0].clone())
}
/// Check is current dxvk downloaded in specified folder
#[inline]
pub fn is_downloaded_in<T: Into<PathBuf> + std::fmt::Debug>(&self, folder: T) -> bool {
pub fn is_downloaded_in<T: Into<PathBuf>>(&self, folder: T) -> bool {
folder.into().join(&self.name).exists()
}
/// Install current dxvk
#[tracing::instrument(level = "debug")]
#[tracing::instrument(level = "debug", ret)]
#[inline]
pub fn install<T: Into<PathBuf> + std::fmt::Debug>(&self, dxvks_folder: T, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
tracing::debug!("Installing DXVK");
@ -57,7 +45,7 @@ impl Version {
}
/// Uninstall current dxvk
#[tracing::instrument(level = "debug")]
#[tracing::instrument(level = "debug", ret)]
#[inline]
pub fn uninstall(&self, wine: &Wine, params: InstallParams) -> std::io::Result<()> {
tracing::debug!("Uninstalling DXVK");
@ -69,17 +57,15 @@ impl Version {
}
}
/// Get dxvk groups
#[inline]
pub fn get_groups() -> Vec<Group> {
GROUPS.clone()
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
ComponentsLoader::new(components).get_dxvk_versions()
}
/// List downloaded dxvk versions in some specific folder
pub fn get_downloaded<T: Into<PathBuf>>(folder: T) -> std::io::Result<Vec<Version>> {
pub fn get_downloaded<T: Into<PathBuf>>(components: T, folder: T) -> anyhow::Result<Vec<Version>> {
let mut downloaded = Vec::new();
let list = get_groups()
let list = get_groups(components)?
.into_iter()
.flat_map(|group| group.versions)
.collect::<Vec<Version>>();

View file

@ -1 +1,148 @@
// TODO
use std::path::{Path, PathBuf};
use crate::anime_game_core::traits::git_sync::RemoteGitSync;
use super::wine;
use super::dxvk;
#[derive(Debug)]
pub struct ComponentsLoader {
folder: PathBuf
}
impl RemoteGitSync for ComponentsLoader {
fn folder(&self) -> &Path {
self.folder.as_path()
}
}
impl ComponentsLoader {
pub fn new<T: Into<PathBuf>>(folder: T) -> Self {
Self {
folder: folder.into()
}
}
/// Try to get wine versions from components index
#[tracing::instrument(level = "debug", ret)]
pub fn get_wine_versions(&self) -> anyhow::Result<Vec<wine::Group>> {
tracing::debug!("Getting wine versions");
let components = serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(self.folder.join("components.json"))?)?;
match components.get("wine") {
Some(wine) => match wine.as_array() {
Some(groups) => {
let mut wine_groups = Vec::with_capacity(groups.len());
for group in groups {
let name = match group.get("name") {
Some(name) => match name.as_str() {
Some(name) => name.to_string(),
None => anyhow::bail!("Wrong components index structure: wine group's name entry must be a string")
}
None => anyhow::bail!("Wrong components index structure: wine group's name not found")
};
let title = match group.get("title") {
Some(title) => match title.as_str() {
Some(title) => title.to_string(),
None => anyhow::bail!("Wrong components index structure: wine group's title entry must be a string")
}
None => anyhow::bail!("Wrong components index structure: wine group's title not found")
};
let versions = serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(self.folder.join("wine").join(format!("{name}.json")))?)?;
let mut wine_versions = Vec::new();
match versions.as_array() {
Some(versions) => {
for version in versions {
wine_versions.push(serde_json::from_value::<wine::Version>(version.to_owned())?);
}
}
None => anyhow::bail!("Wrong components index structure: wine versions must be a list")
}
wine_groups.push(wine::Group {
name,
title,
versions: wine_versions
});
}
Ok(wine_groups)
}
None => anyhow::bail!("Wrong components index structure: wine entry must be a list")
}
None => anyhow::bail!("Wrong components index structure: wine entry not found")
}
}
/// Try to get dxvk versions from components index
#[tracing::instrument(level = "debug", ret)]
pub fn get_dxvk_versions(&self) -> anyhow::Result<Vec<dxvk::Group>> {
tracing::debug!("Getting dxvk versions");
let components = serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(self.folder.join("components.json"))?)?;
match components.get("dxvk") {
Some(dxvk) => match dxvk.as_array() {
Some(groups) => {
let mut dxvk_groups = Vec::with_capacity(groups.len());
for group in groups {
let name = match group.get("name") {
Some(name) => match name.as_str() {
Some(name) => name.to_string(),
None => anyhow::bail!("Wrong components index structure: dxvk group's name entry must be a string")
}
None => anyhow::bail!("Wrong components index structure: dxvk group's name not found")
};
let title = match group.get("title") {
Some(title) => match title.as_str() {
Some(title) => title.to_string(),
None => anyhow::bail!("Wrong components index structure: dxvk group's title entry must be a string")
}
None => anyhow::bail!("Wrong components index structure: dxvk group's title not found")
};
let versions = serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(self.folder.join("dxvk").join(format!("{name}.json")))?)?;
let mut dxvk_versions = Vec::new();
match versions.as_array() {
Some(versions) => {
for version in versions {
dxvk_versions.push(serde_json::from_value::<dxvk::Version>(version.to_owned())?);
}
}
None => anyhow::bail!("Wrong components index structure: wine versions must be a list")
}
dxvk_groups.push(dxvk::Group {
name,
title,
versions: dxvk_versions
});
}
Ok(dxvk_groups)
}
None => anyhow::bail!("Wrong components index structure: wine entry must be a list")
}
None => anyhow::bail!("Wrong components index structure: wine entry not found")
}
}
}

View file

@ -3,30 +3,12 @@ use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use wincompatlib::prelude::*;
lazy_static::lazy_static! {
static ref GROUPS: Vec<Group> = vec![
Group {
name: String::from("Wine-GE-Proton"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/wine/wine-ge-proton.json")).unwrap().into_iter().take(12).collect()
},
Group {
name: String::from("GE-Proton"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/wine/ge-proton.json")).unwrap().into_iter().take(12).collect()
},
Group {
name: String::from("Soda"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/wine/soda.json")).unwrap().into_iter().take(12).collect()
},
Group {
name: String::from("Lutris"),
versions: serde_json::from_str::<Vec<Version>>(include_str!("../../components/wine/lutris.json")).unwrap().into_iter().take(12).collect()
}
];
}
use super::loader::ComponentsLoader;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Group {
pub name: String,
pub title: String,
pub versions: Vec<Version>
}
@ -35,20 +17,27 @@ pub struct Version {
pub name: String,
pub title: String,
pub uri: String,
pub files: Files,
pub recommended: bool
pub files: Files
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Files {
pub wine: String,
pub wine64: String,
pub wineserver: String,
pub wineboot: String,
pub winecfg: String
}
impl Version {
/// Get latest recommended wine version
#[inline]
pub fn latest() -> Self {
get_groups()[0].versions[0].clone()
pub fn latest<T: Into<PathBuf>>(components: T) -> anyhow::Result<Self> {
Ok(get_groups(components)?[0].versions[0].clone())
}
/// Check is current wine downloaded in specified folder
#[inline]
pub fn is_downloaded_in<T: Into<PathBuf> + std::fmt::Debug>(&self, folder: T) -> bool {
pub fn is_downloaded_in<T: Into<PathBuf>>(&self, folder: T) -> bool {
folder.into().join(&self.name).exists()
}
@ -70,26 +59,15 @@ impl Version {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Files {
pub wine: String,
pub wine64: String,
pub wineserver: String,
pub wineboot: String,
pub winecfg: String
}
/// Get wine groups
#[inline]
pub fn get_groups() -> Vec<Group> {
GROUPS.clone()
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
ComponentsLoader::new(components).get_wine_versions()
}
/// List downloaded wine versions in some specific folder
pub fn get_downloaded<T: Into<PathBuf> + std::fmt::Debug>(folder: T) -> std::io::Result<Vec<Version>> {
pub fn get_downloaded<T: Into<PathBuf>>(components: T, folder: T) -> anyhow::Result<Vec<Version>> {
let mut downloaded = Vec::new();
let list = get_groups()
let list = get_groups(components)?
.into_iter()
.flat_map(|group| group.versions)
.collect::<Vec<Version>>();

View file

@ -1,7 +1,6 @@
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::io::Write;
use std::io::{Read, Write};
use std::path::Path;
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
@ -198,33 +197,16 @@ use crate::components::dxvk::{self, Version as DxvkVersion};
#[cfg(feature = "components")]
impl Config {
pub fn try_get_selected_wine_info(&self) -> Option<WineVersion> {
pub fn try_get_selected_wine_info(&self) -> anyhow::Result<Option<WineVersion>> {
match &self.game.wine.selected {
Some(selected) => {
wine::get_groups()
Ok(wine::get_groups(&self.components.path)?
.iter()
.flat_map(|group| group.versions.clone())
.find(|version| version.name.eq(selected))
},
None => None
}
.find(|version| version.name.eq(selected)))
}
/// Try to get a path to the wine64 executable based on `game.wine.builds` and `game.wine.selected`
///
/// Returns `Some("wine64")` if:
/// 1) `game.wine.selected = None`
/// 2) wine64 installed and available in system
pub fn try_get_wine_executable(&self) -> Option<PathBuf> {
match self.try_get_selected_wine_info() {
Some(selected) => Some(self.game.wine.builds.join(selected.name).join(selected.files.wine64)),
None => {
if crate::is_available("wine64") {
Some(PathBuf::from("wine64"))
} else {
None
}
}
None => Ok(None)
}
}
@ -234,16 +216,17 @@ impl Config {
/// 1) `Ok(Some(..))` if version was found
/// 2) `Ok(None)` if version wasn't found, so too old or dxvk is not applied
/// 3) `Err(..)` if failed to get applied dxvk version, likely because wrong prefix path specified
pub fn try_get_selected_dxvk_info(&self) -> std::io::Result<Option<DxvkVersion>> {
Ok(match wincompatlib::dxvk::Dxvk::get_version(&self.game.wine.prefix)? {
pub fn try_get_selected_dxvk_info(&self) -> anyhow::Result<Option<DxvkVersion>> {
match wincompatlib::dxvk::Dxvk::get_version(&self.game.wine.prefix)? {
Some(version) => {
dxvk::get_groups()
Ok(dxvk::get_groups(&self.components.path)?
.iter()
.flat_map(|group| group.versions.clone())
.find(move |dxvk| dxvk.version == version)
},
None => None
})
.find(move |dxvk| dxvk.version == version))
}
None => Ok(None)
}
}
}

View file

@ -24,9 +24,8 @@ pub fn run() -> anyhow::Result<()> {
return Err(anyhow::anyhow!("Game is not installed"));
}
let wine_executable = match config.try_get_wine_executable() {
Some(path) => path,
None => return Err(anyhow::anyhow!("Couldn't find wine executable"))
let Some(wine) = config.try_get_selected_wine_info()? else {
anyhow::bail!("Couldn't find wine executable");
};
// Check telemetry servers
@ -87,7 +86,7 @@ pub fn run() -> anyhow::Result<()> {
bash_chain += "gamemoderun ";
}
bash_chain += &format!("'{}' ", wine_executable.to_string_lossy());
bash_chain += &format!("'{}' ", wine.files.wine64);
if let Some(virtual_desktop) = config.game.wine.virtual_desktop.get_command() {
bash_chain += &format!("{virtual_desktop} ");

View file

@ -148,7 +148,7 @@ impl LauncherState {
// Check wine existence
#[cfg(feature = "components")]
{
if config.try_get_wine_executable().is_none() {
if config.try_get_selected_wine_info()?.is_none() {
return Ok(Self::WineNotInstalled);
}
}