added game type
This commit is contained in:
@@ -34,7 +34,8 @@ pub fn handle_nxm(root_config: &mut RootConfig, raw_url: &str) -> anyhow::Result
|
|||||||
|
|
||||||
unpack(root_config, &mod_id, dl_file)?;
|
unpack(root_config, &mod_id, dl_file)?;
|
||||||
|
|
||||||
let new_mod = ModConfig::from_mod_info(&mod_id, &mod_id, &mod_info);
|
let file_id: u64 = nxm_url.file.parse()?;
|
||||||
|
let new_mod = ModConfig::from_mod_info(&mod_id, &mod_id, &mod_info, file_id);
|
||||||
|
|
||||||
root_config.add_mod(&new_mod);
|
root_config.add_mod(&new_mod);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::nexus::NXMUrl;
|
use crate::{nexus::NXMUrl, types::GameType};
|
||||||
|
|
||||||
const NEXUS_ENDPOINT: &str = "https://api.nexusmods.com";
|
const NEXUS_ENDPOINT: &str = "https://api.nexusmods.com";
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ pub struct ModInfo {
|
|||||||
pub mod_id: u64,
|
pub mod_id: u64,
|
||||||
// pub game_id: u64,
|
// pub game_id: u64,
|
||||||
// pub allow_rating: bool,
|
// pub allow_rating: bool,
|
||||||
// pub domain_name: String,
|
pub domain_name: String,
|
||||||
// pub category_id: u64,
|
// pub category_id: u64,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
// pub endorsement_count: u64,
|
// pub endorsement_count: u64,
|
||||||
@@ -145,6 +145,10 @@ impl ModInfo {
|
|||||||
if short_name.len() > MAX_CHARS {
|
if short_name.len() > MAX_CHARS {
|
||||||
short_name.truncate(MAX_CHARS);
|
short_name.truncate(MAX_CHARS);
|
||||||
}
|
}
|
||||||
format!("{}-{}", short_name, self.mod_id)
|
format!("{}-{}", short_name.to_lowercase(), self.mod_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_game_type(&self) -> GameType {
|
||||||
|
GameType::from_nexus_domain(&self.domain_name).unwrap_or(GameType::Unknown)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
mod game;
|
mod game;
|
||||||
|
mod game_type;
|
||||||
mod installed_mod;
|
mod installed_mod;
|
||||||
mod link;
|
mod link;
|
||||||
mod mod_config;
|
mod mod_config;
|
||||||
mod mod_file;
|
mod mod_file;
|
||||||
mod modded_instance;
|
mod modded_instance;
|
||||||
mod root_config;
|
mod root_config;
|
||||||
|
mod nexus_id;
|
||||||
|
|
||||||
pub use game::*;
|
pub use game::*;
|
||||||
|
pub use game_type::GameType;
|
||||||
pub use installed_mod::*;
|
pub use installed_mod::*;
|
||||||
pub use link::*;
|
pub use link::*;
|
||||||
pub use mod_config::*;
|
pub use mod_config::*;
|
||||||
pub use mod_file::*;
|
pub use mod_file::*;
|
||||||
pub use modded_instance::*;
|
pub use modded_instance::*;
|
||||||
pub use root_config::*;
|
pub use root_config::*;
|
||||||
|
pub use nexus_id::*;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ConfigReadWriteError {
|
pub enum ConfigReadWriteError {
|
||||||
|
|||||||
@@ -6,18 +6,23 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{types::link::Link, utils::walk_all_files};
|
use crate::{
|
||||||
|
types::{GameType, link::Link},
|
||||||
|
utils::walk_all_files,
|
||||||
|
};
|
||||||
|
|
||||||
/// Available game
|
/// Available game
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
kind: GameType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new(path: impl AsRef<Path>) -> Self {
|
pub fn new(path: impl AsRef<Path>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
path: path.as_ref().to_owned(),
|
path: path.as_ref().to_owned(),
|
||||||
|
kind: GameType::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
186
src/types/game_type.rs
Normal file
186
src/types/game_type.rs
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||||
|
pub enum GameType {
|
||||||
|
Oblivion,
|
||||||
|
Skyrim,
|
||||||
|
Fallout3,
|
||||||
|
FalloutNV,
|
||||||
|
Fallout4,
|
||||||
|
SkyrimSE,
|
||||||
|
Fallout4VR,
|
||||||
|
SkyrimVR,
|
||||||
|
Morrowind,
|
||||||
|
Starfield,
|
||||||
|
OpenMW,
|
||||||
|
OblivionRemastered,
|
||||||
|
Custom(String),
|
||||||
|
|
||||||
|
#[default]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameType {
|
||||||
|
pub fn to_libloot_type(self) -> Option<libloot::GameType> {
|
||||||
|
match self {
|
||||||
|
GameType::Oblivion => Some(libloot::GameType::Oblivion),
|
||||||
|
GameType::Skyrim => Some(libloot::GameType::Skyrim),
|
||||||
|
GameType::Fallout3 => Some(libloot::GameType::Fallout3),
|
||||||
|
GameType::FalloutNV => Some(libloot::GameType::FalloutNV),
|
||||||
|
GameType::Fallout4 => Some(libloot::GameType::Fallout4),
|
||||||
|
GameType::SkyrimSE => Some(libloot::GameType::SkyrimSE),
|
||||||
|
GameType::Fallout4VR => Some(libloot::GameType::Fallout4VR),
|
||||||
|
GameType::SkyrimVR => Some(libloot::GameType::SkyrimVR),
|
||||||
|
GameType::Morrowind => Some(libloot::GameType::Morrowind),
|
||||||
|
GameType::Starfield => Some(libloot::GameType::Starfield),
|
||||||
|
GameType::OpenMW => Some(libloot::GameType::OpenMW),
|
||||||
|
GameType::OblivionRemastered => Some(libloot::GameType::OblivionRemastered),
|
||||||
|
GameType::Custom(_) => None,
|
||||||
|
GameType::Unknown => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_nexus_domain(self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
GameType::Oblivion => Some("oblivion".to_owned()),
|
||||||
|
GameType::Skyrim => Some("skyrim".to_owned()),
|
||||||
|
GameType::Fallout3 => Some("fallout3".to_owned()),
|
||||||
|
GameType::FalloutNV => Some("newvegas".to_owned()),
|
||||||
|
GameType::Fallout4 => Some("fallout4".to_owned()),
|
||||||
|
GameType::SkyrimSE => Some("skyrimspecialedition".to_owned()),
|
||||||
|
GameType::Fallout4VR => Some("fallout4".to_owned()),
|
||||||
|
GameType::SkyrimVR => Some("skyrimspecialedition".to_owned()),
|
||||||
|
GameType::Morrowind => Some("morrowind".to_owned()),
|
||||||
|
GameType::Starfield => Some("starfield".to_owned()),
|
||||||
|
GameType::OpenMW => Some("morrowind".to_owned()),
|
||||||
|
GameType::OblivionRemastered => Some("oblivionremastered".to_owned()),
|
||||||
|
GameType::Custom(_) => None,
|
||||||
|
GameType::Unknown => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_nexus_domain(domain: &str) -> Option<Self> {
|
||||||
|
match domain {
|
||||||
|
"oblivion" => Some(GameType::Oblivion),
|
||||||
|
"skyrim" => Some(GameType::Skyrim),
|
||||||
|
"fallout3" => Some(GameType::Fallout3),
|
||||||
|
"newvegas" => Some(GameType::FalloutNV),
|
||||||
|
"fallout4" => Some(GameType::Fallout4),
|
||||||
|
"skyrimspecialedition" => Some(GameType::SkyrimSE),
|
||||||
|
"morrowind" => Some(GameType::Morrowind),
|
||||||
|
"starfield" => Some(GameType::Starfield),
|
||||||
|
"oblivionremastered" => Some(GameType::OblivionRemastered),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for GameType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let s = match self {
|
||||||
|
GameType::Oblivion => "Oblivion",
|
||||||
|
GameType::Skyrim => "Skyrim",
|
||||||
|
GameType::Fallout3 => "Fallout 3",
|
||||||
|
GameType::FalloutNV => "Fallout New Vegas",
|
||||||
|
GameType::Fallout4 => "Fallout 4",
|
||||||
|
GameType::SkyrimSE => "Skyrim Special Edition",
|
||||||
|
GameType::Fallout4VR => "Fallout 4 VR",
|
||||||
|
GameType::SkyrimVR => "Skyrim VR",
|
||||||
|
GameType::Morrowind => "Morrowind",
|
||||||
|
GameType::Starfield => "Starfield",
|
||||||
|
GameType::OpenMW => "OpenMW",
|
||||||
|
GameType::OblivionRemastered => "Oblivion Remastered",
|
||||||
|
GameType::Custom(name) => name,
|
||||||
|
GameType::Unknown => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for GameType {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
let s = String::deserialize(deserializer)?;
|
||||||
|
Ok(match s.as_str() {
|
||||||
|
"oblivion" => Self::Oblivion,
|
||||||
|
"skyrim" => Self::Skyrim,
|
||||||
|
"fo3" => Self::Fallout3,
|
||||||
|
"fonv" => Self::FalloutNV,
|
||||||
|
"fo4" => Self::Fallout4,
|
||||||
|
"sse" => Self::SkyrimSE,
|
||||||
|
"fo4vr" => Self::Fallout4VR,
|
||||||
|
"skyrimvr" => Self::SkyrimVR,
|
||||||
|
"morrowind" => Self::Morrowind,
|
||||||
|
"starfield" => Self::Starfield,
|
||||||
|
"openmw" => Self::OpenMW,
|
||||||
|
"oblivionrm" => Self::OblivionRemastered,
|
||||||
|
"unknown" => Self::Unknown,
|
||||||
|
_ => Self::Custom(s),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for GameType {
|
||||||
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let s = match self {
|
||||||
|
Self::Custom(s) => s,
|
||||||
|
Self::Oblivion => "oblivion",
|
||||||
|
Self::Skyrim => "skyrim",
|
||||||
|
Self::Fallout3 => "fo3",
|
||||||
|
Self::FalloutNV => "fonv",
|
||||||
|
Self::Fallout4 => "fo4",
|
||||||
|
Self::SkyrimSE => "sse",
|
||||||
|
Self::Fallout4VR => "fo4vr",
|
||||||
|
Self::SkyrimVR => "skyrimvr",
|
||||||
|
Self::Morrowind => "morrowind",
|
||||||
|
Self::Starfield => "starfield",
|
||||||
|
Self::OpenMW => "openmw",
|
||||||
|
Self::OblivionRemastered => "oblivionrm",
|
||||||
|
Self::Unknown => "unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
serializer.serialize_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, PartialEq, Debug)]
|
||||||
|
struct Wrapper {
|
||||||
|
value: GameType,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roundtrip(game_type: GameType) {
|
||||||
|
let val = Wrapper { value: game_type };
|
||||||
|
let serialized = toml::to_string(&val).unwrap();
|
||||||
|
let deserialized: Wrapper = toml::from_str(&serialized).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(val, deserialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_back_and_forth_all() {
|
||||||
|
for e in [
|
||||||
|
GameType::Oblivion,
|
||||||
|
GameType::Skyrim,
|
||||||
|
GameType::Fallout3,
|
||||||
|
GameType::FalloutNV,
|
||||||
|
GameType::Fallout4,
|
||||||
|
GameType::SkyrimSE,
|
||||||
|
GameType::Fallout4VR,
|
||||||
|
GameType::SkyrimVR,
|
||||||
|
GameType::Morrowind,
|
||||||
|
GameType::Starfield,
|
||||||
|
GameType::OpenMW,
|
||||||
|
GameType::OblivionRemastered,
|
||||||
|
GameType::Custom("custom".to_owned()),
|
||||||
|
GameType::Unknown,
|
||||||
|
] {
|
||||||
|
roundtrip(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,10 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::nexus::ModInfo;
|
use crate::{
|
||||||
|
nexus::ModInfo,
|
||||||
|
types::{GameType, NexusID},
|
||||||
|
};
|
||||||
|
|
||||||
/// Config for an available mod
|
/// Config for an available mod
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
@@ -26,7 +29,10 @@ pub struct ModConfig {
|
|||||||
ignore: Vec<String>,
|
ignore: Vec<String>,
|
||||||
|
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
nexus_id: Option<String>,
|
|
||||||
|
nexus_id: Option<NexusID>,
|
||||||
|
|
||||||
|
game: GameType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModConfig {
|
impl ModConfig {
|
||||||
@@ -38,12 +44,20 @@ impl ModConfig {
|
|||||||
ignore: Vec::new(),
|
ignore: Vec::new(),
|
||||||
name: None,
|
name: None,
|
||||||
nexus_id: None,
|
nexus_id: None,
|
||||||
|
game: GameType::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_mod_info(id: &str, source: impl AsRef<Path>, mod_info: &ModInfo) -> Self {
|
pub fn from_mod_info(
|
||||||
|
id: &str,
|
||||||
|
source: impl AsRef<Path>,
|
||||||
|
mod_info: &ModInfo,
|
||||||
|
file_id: u64,
|
||||||
|
) -> Self {
|
||||||
let mut normal = Self::new(id, source);
|
let mut normal = Self::new(id, source);
|
||||||
normal.name = Some(mod_info.name.clone());
|
normal.name = Some(mod_info.name.clone());
|
||||||
|
normal.game = mod_info.get_game_type();
|
||||||
|
normal.nexus_id = Some(NexusID::new(mod_info.mod_id, file_id));
|
||||||
|
|
||||||
normal
|
normal
|
||||||
}
|
}
|
||||||
@@ -69,6 +83,14 @@ impl ModConfig {
|
|||||||
pub fn ignore(&self) -> &[String] {
|
pub fn ignore(&self) -> &[String] {
|
||||||
&self.ignore
|
&self.ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nexus_id(&self) -> Option<&NexusID> {
|
||||||
|
self.nexus_id.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_false(b: &bool) -> bool {
|
fn is_false(b: &bool) -> bool {
|
||||||
|
|||||||
13
src/types/nexus_id.rs
Normal file
13
src/types/nexus_id.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
|
||||||
|
pub struct NexusID {
|
||||||
|
mod_id: u64,
|
||||||
|
file_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NexusID {
|
||||||
|
pub fn new(mod_id: u64, file_id: u64) -> Self {
|
||||||
|
Self { mod_id, file_id }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,11 @@ nexus_api_key = "1234"
|
|||||||
|
|
||||||
[games.example_game]
|
[games.example_game]
|
||||||
path = "/home/user/games/sse"
|
path = "/home/user/games/sse"
|
||||||
|
kind = "sse"
|
||||||
|
|
||||||
[games.sse]
|
[games.sse]
|
||||||
path = "games/sse"
|
path = "games/sse"
|
||||||
|
kind = "unkown"
|
||||||
|
|
||||||
[instances.example1]
|
[instances.example1]
|
||||||
path = "example1.toml"
|
path = "example1.toml"
|
||||||
|
|||||||
Reference in New Issue
Block a user