Compare commits
4 Commits
03a127f24b
...
ddf76602be
| Author | SHA1 | Date | |
|---|---|---|---|
|
ddf76602be
|
|||
|
4a152f07da
|
|||
|
afc3f68f36
|
|||
|
fcc65f68bb
|
@@ -19,10 +19,10 @@ pub struct Game {
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn new(path: impl AsRef<Path>) -> Self {
|
||||
pub fn new(path: impl AsRef<Path>, game_type: GameType) -> Self {
|
||||
Self {
|
||||
path: path.as_ref().to_owned(),
|
||||
kind: GameType::default(),
|
||||
kind: game_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,4 +45,8 @@ impl Game {
|
||||
pub fn install_location(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn game_type(&self) -> GameType {
|
||||
self.kind.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use serde::{
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
de::{self, Visitor},
|
||||
};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
fmt::{self, Debug},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::mod_file::ModFile;
|
||||
|
||||
/// A link between a file from a mod and a destination in a ModdedInstance
|
||||
#[derive(Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
|
||||
#[serde(from = "(PathBuf, PathBuf)", into = "(PathBuf,PathBuf)")]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Link {
|
||||
src: PathBuf,
|
||||
dst: PathBuf,
|
||||
@@ -36,18 +37,46 @@ impl Link {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(PathBuf, PathBuf)> for Link {
|
||||
fn from(value: (PathBuf, PathBuf)) -> Self {
|
||||
Self {
|
||||
src: value.0,
|
||||
dst: value.1,
|
||||
impl Serialize for Link {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
if self.src == self.dst {
|
||||
serializer.serialize_str(&self.src.to_string_lossy())
|
||||
} else {
|
||||
serializer.serialize_str(&format!(
|
||||
"{} -> {}",
|
||||
self.src.to_string_lossy(),
|
||||
self.dst.to_string_lossy()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Link> for (PathBuf, PathBuf) {
|
||||
fn from(value: Link) -> Self {
|
||||
(value.src, value.dst)
|
||||
impl<'de> Deserialize<'de> for Link {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
struct LinkVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for LinkVisitor {
|
||||
type Value = Link;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(r#"a string like "src -> dst" or "path" if they are the same"#)
|
||||
}
|
||||
|
||||
fn visit_str<E: de::Error>(self, value: &str) -> Result<Link, E> {
|
||||
match value.split_once(" -> ") {
|
||||
Some((src, dst)) => Ok(Link {
|
||||
src: PathBuf::from(src),
|
||||
dst: PathBuf::from(dst),
|
||||
}),
|
||||
None => Ok(Link {
|
||||
src: PathBuf::from(value),
|
||||
dst: PathBuf::from(value),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(LinkVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ pub struct ModConfig {
|
||||
|
||||
nexus_id: Option<NexusID>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "is_default")]
|
||||
game: GameType,
|
||||
}
|
||||
|
||||
@@ -96,3 +98,7 @@ impl ModConfig {
|
||||
fn is_false(b: &bool) -> bool {
|
||||
!b
|
||||
}
|
||||
|
||||
fn is_default<T: Default + PartialEq>(t: &T) -> bool {
|
||||
t == &T::default()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct NexusID {
|
||||
mod_id: u64,
|
||||
file_id: u64,
|
||||
@@ -11,3 +12,59 @@ impl NexusID {
|
||||
Self { mod_id, file_id }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for NexusID {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let s = format!("{}:{}", self.mod_id, self.file_id);
|
||||
serializer.serialize_str(&s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for NexusID {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let mut parts = s.split(':');
|
||||
|
||||
let mod_id = parts
|
||||
.next()
|
||||
.ok_or_else(|| serde::de::Error::custom("missing first value"))
|
||||
.and_then(|p| u64::from_str(p).map_err(serde::de::Error::custom))?;
|
||||
|
||||
let file_id = parts
|
||||
.next()
|
||||
.ok_or_else(|| serde::de::Error::custom("missing second value"))
|
||||
.and_then(|p| u64::from_str(p).map_err(serde::de::Error::custom))?;
|
||||
|
||||
if parts.next().is_some() {
|
||||
return Err(serde::de::Error::custom("too many parts"));
|
||||
}
|
||||
|
||||
Ok(Self { mod_id, file_id })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Debug)]
|
||||
struct Wrapper {
|
||||
value: NexusID,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_roundtrip() {
|
||||
let val = Wrapper {
|
||||
value: NexusID::new(1234, 5678),
|
||||
};
|
||||
let serialized = toml::to_string(&val).unwrap();
|
||||
let deserialized: Wrapper = toml::from_str(&serialized).unwrap();
|
||||
assert_eq!(val, deserialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ impl RootConfig {
|
||||
}
|
||||
|
||||
pub fn save_to_file(&self) -> Result<(), ConfigReadWriteError> {
|
||||
debug!(
|
||||
"Saving root_config to: {}",
|
||||
self.self_path.to_string_lossy()
|
||||
);
|
||||
let content = toml::to_string_pretty(self)?;
|
||||
let mut file = fs::File::create(&self.self_path)?;
|
||||
write!(file, "{}", content)?;
|
||||
@@ -66,7 +70,13 @@ impl RootConfig {
|
||||
pub fn game_by_id(&self, id: &str) -> Option<Game> {
|
||||
self.games.get(id).map(|parsed_game| {
|
||||
if parsed_game.install_location().is_relative() {
|
||||
Game::new(self.self_parent.join(parsed_game.install_location()))
|
||||
let abs_path = self.self_parent.join(parsed_game.install_location());
|
||||
debug!(
|
||||
"game path for {} is relative. Resolving to {}",
|
||||
id,
|
||||
abs_path.to_string_lossy()
|
||||
);
|
||||
Game::new(abs_path, parsed_game.game_type())
|
||||
} else {
|
||||
parsed_game.clone()
|
||||
}
|
||||
@@ -82,13 +92,19 @@ impl RootConfig {
|
||||
}
|
||||
|
||||
pub fn load_instance_by_id(&self, id: &str) -> Result<ModdedInstance, ConfigReadWriteError> {
|
||||
debug!("Loading instance {}", id);
|
||||
let conf = self
|
||||
.instances
|
||||
.get(id)
|
||||
.ok_or(ConfigReadWriteError::IDNotFound)?;
|
||||
|
||||
if conf.path.is_relative() {
|
||||
ModdedInstance::load_from_file(self.self_parent.join(&conf.path))
|
||||
let abs_path = self.self_parent.join(&conf.path);
|
||||
debug!(
|
||||
"instance path is relative. Resolving to {}",
|
||||
abs_path.to_string_lossy()
|
||||
);
|
||||
ModdedInstance::load_from_file(abs_path)
|
||||
} else {
|
||||
ModdedInstance::load_from_file(&conf.path)
|
||||
}
|
||||
@@ -96,7 +112,12 @@ impl RootConfig {
|
||||
|
||||
pub fn mod_location(&self) -> PathBuf {
|
||||
if self.mod_location.is_relative() {
|
||||
self.self_parent.join(&self.mod_location)
|
||||
let abs_path = self.self_parent.join(&self.mod_location);
|
||||
debug!(
|
||||
"mod_location path is relative. Resolving to {}",
|
||||
abs_path.to_string_lossy()
|
||||
);
|
||||
abs_path
|
||||
} else {
|
||||
self.mod_location.clone()
|
||||
}
|
||||
@@ -109,7 +130,12 @@ impl RootConfig {
|
||||
pub fn download_location(&self) -> Option<PathBuf> {
|
||||
self.download_location.as_ref().map(|e| {
|
||||
if e.is_relative() {
|
||||
self.self_parent.join(e)
|
||||
let abs_path = self.self_parent.join(e);
|
||||
debug!(
|
||||
"download_location path is relative. Resolving to {}",
|
||||
abs_path.to_string_lossy()
|
||||
);
|
||||
abs_path
|
||||
} else {
|
||||
e.clone()
|
||||
}
|
||||
@@ -124,11 +150,16 @@ struct InstancePointer {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::GameType;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn create_config() -> RootConfig {
|
||||
RootConfig {
|
||||
games: HashMap::from([("sse".to_owned(), Game::new("/games/sse"))]),
|
||||
games: HashMap::from([(
|
||||
"sse".to_owned(),
|
||||
Game::new("/games/sse", GameType::SkyrimSE),
|
||||
)]),
|
||||
mod_location: PathBuf::from("mods"),
|
||||
download_location: Some(PathBuf::from("download")),
|
||||
nexus_api_key: Some("1234".to_owned()),
|
||||
@@ -157,6 +188,7 @@ mod tests {
|
||||
|
||||
let unwraped = game.expect("Asserted before");
|
||||
assert_eq!(unwraped.install_location(), "/games/sse");
|
||||
assert_eq!(unwraped.game_type(), GameType::SkyrimSE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -10,6 +10,7 @@ pub fn path_to_lowercase(path: impl AsRef<Path>) -> PathBuf {
|
||||
PathBuf::from(path.as_ref().to_string_lossy().to_lowercase())
|
||||
}
|
||||
|
||||
/// Searches for a path but ignores case. Returns the first it finds.
|
||||
pub fn resolve_case_insensitive(
|
||||
base: impl AsRef<Path>,
|
||||
rel: impl AsRef<Path>,
|
||||
@@ -44,7 +45,7 @@ pub fn resolve_case_insensitive(
|
||||
}
|
||||
|
||||
/// Use walkdir to walk all actual files in a dir
|
||||
/// Returns early id any error occurs
|
||||
/// Returns early if any error occurs
|
||||
pub fn walk_all_files(
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<impl Iterator<Item = walkdir::DirEntry>, walkdir::Error> {
|
||||
|
||||
@@ -10,171 +10,99 @@ load_order = [
|
||||
"ccBGSSSE037-Curios.esl",
|
||||
"ccBGSSSE025-AdvDSGS.esm",
|
||||
"_ResourcePack.esl",
|
||||
"RaceMenu.esp",
|
||||
"SkyUI_SE.esp",
|
||||
"RaceMenuPlugin.esp",
|
||||
]
|
||||
game_file_overrides = [[
|
||||
"skse64_loader.exe",
|
||||
"SkyrimSELauncher.exe",
|
||||
]]
|
||||
|
||||
[[mods]]
|
||||
id = "skyui"
|
||||
files = [
|
||||
[
|
||||
"SkyUI_SE.esp",
|
||||
"Data/SkyUI_SE.esp",
|
||||
],
|
||||
[
|
||||
"SkyUI_SE.bsa",
|
||||
"Data/SkyUI_SE.bsa",
|
||||
],
|
||||
game_file_overrides = [
|
||||
"skse64_loader.exe -> SkyrimSELauncher.exe"
|
||||
]
|
||||
priority = 0
|
||||
|
||||
[[mods]]
|
||||
id = "skse"
|
||||
files = [
|
||||
[
|
||||
"Data/Scripts/actorbase.pex",
|
||||
"Data/Scripts/actorbase.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/weather.pex",
|
||||
"Data/Scripts/weather.pex",
|
||||
],
|
||||
[
|
||||
"skse64_loader.exe",
|
||||
"skse64_loader.exe",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/headpart.pex",
|
||||
"Data/Scripts/headpart.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/math.pex",
|
||||
"Data/Scripts/form.pex",
|
||||
"Data/Scripts/soulgem.pex",
|
||||
"Data/Scripts/soulgem.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/modevent.pex",
|
||||
"Data/Scripts/modevent.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/actorvalueinfo.pex",
|
||||
"Data/Scripts/actorvalueinfo.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/book.pex",
|
||||
"Data/Scripts/book.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/formlist.pex",
|
||||
"Data/Scripts/stringutil.pex",
|
||||
"Data/Scripts/colorcomponent.pex",
|
||||
"Data/Scripts/quest.pex",
|
||||
"Data/Scripts/faction.pex",
|
||||
"Data/Scripts/combatstyle.pex",
|
||||
"Data/Scripts/actorbase.pex",
|
||||
"Data/Scripts/potion.pex",
|
||||
"Data/Scripts/potion.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/spell.pex",
|
||||
"Data/Scripts/spell.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/perk.pex",
|
||||
"Data/Scripts/perk.pex",
|
||||
],
|
||||
[
|
||||
"Data/Scripts/actor.pex",
|
||||
"Data/Scripts/game.pex",
|
||||
"Data/Scripts/armor.pex",
|
||||
"Data/Scripts/headpart.pex",
|
||||
"Data/Scripts/objectreference.pex",
|
||||
"Data/Scripts/objectreference.pex",
|
||||
],
|
||||
"Data/Scripts/weapon.pex",
|
||||
"Data/Scripts/perk.pex",
|
||||
"Data/Scripts/constructibleobject.pex",
|
||||
"Data/Scripts/armoraddon.pex",
|
||||
"Data/Scripts/textureset.pex",
|
||||
"Data/Scripts/scroll.pex",
|
||||
"Data/Scripts/actorvalueinfo.pex",
|
||||
"Data/Scripts/equipslot.pex",
|
||||
"Data/Scripts/art.pex",
|
||||
"Data/Scripts/colorform.pex",
|
||||
"Data/Scripts/weather.pex",
|
||||
"Data/Scripts/gamedata.pex",
|
||||
"Data/Scripts/skse.pex",
|
||||
"Data/Scripts/sound.pex",
|
||||
"Data/Scripts/formtype.pex",
|
||||
"Data/Scripts/spawnertask.pex",
|
||||
"Data/Scripts/netimmerse.pex",
|
||||
"Data/Scripts/ingredient.pex",
|
||||
"Data/Scripts/book.pex",
|
||||
"Data/Scripts/ui.pex",
|
||||
"Data/Scripts/leveleditem.pex",
|
||||
"Data/Scripts/spell.pex",
|
||||
"Data/Scripts/leveledspell.pex",
|
||||
"Data/Scripts/modevent.pex",
|
||||
"Data/Scripts/keyword.pex",
|
||||
"Data/Scripts/activemagiceffect.pex",
|
||||
"Data/Scripts/utility.pex",
|
||||
"Data/Scripts/shout.pex",
|
||||
"Data/Scripts/input.pex",
|
||||
"Data/Scripts/race.pex",
|
||||
"Data/Scripts/sounddescriptor.pex",
|
||||
"Data/Scripts/wornobject.pex",
|
||||
"Data/Scripts/ammo.pex",
|
||||
"Data/Scripts/defaultobjectmanager.pex",
|
||||
"Data/Scripts/camera.pex",
|
||||
"Data/Scripts/apparatus.pex",
|
||||
"skse64_1_6_1170.dll",
|
||||
"Data/Scripts/magiceffect.pex",
|
||||
"Data/Scripts/location.pex",
|
||||
"Data/Scripts/alias.pex",
|
||||
"Data/Scripts/treeobject.pex",
|
||||
"Data/Scripts/leveledactor.pex",
|
||||
"Data/Scripts/enchantment.pex",
|
||||
"Data/Scripts/uicallback.pex",
|
||||
"Data/Scripts/flora.pex",
|
||||
"Data/Scripts/outfit.pex",
|
||||
"Data/Scripts/cell.pex",
|
||||
]
|
||||
priority = 0
|
||||
|
||||
[[mods]]
|
||||
id = "deadly_spells"
|
||||
id = "SkyUI-12604-35407"
|
||||
files = [
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowhole01_n.dds",
|
||||
"Data/textures/impactdecals/decalsnowhole01_n.dds",
|
||||
],
|
||||
[
|
||||
"40 Two Fire Esp/textures/impactdecals/decalflamespread01_g.dds",
|
||||
"Data/textures/impactdecals/decalflamespread01_g.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsparkburn01_g.dds",
|
||||
"Data/textures/impactdecals/decalsparkburn01_g.dds",
|
||||
],
|
||||
[
|
||||
"40 Two Fire Esp/textures/impactdecals/decalflamespread01.dds",
|
||||
"Data/textures/impactdecals/decalflamespread01.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalfrostimpact01_n.dds",
|
||||
"Data/textures/impactdecals/decalfrostimpact01_n.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalspitimpact01_n.dds",
|
||||
"Data/textures/impactdecals/decalspitimpact01_n.dds",
|
||||
],
|
||||
[
|
||||
"40 Two Fire Esp/DeadlySpellImpacts - Two Fire.esp",
|
||||
"Data/DeadlySpellImpacts - Two Fire.esp",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowmelt01.dds",
|
||||
"Data/textures/impactdecals/decalsnowmelt01.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalspitimpact01.dds",
|
||||
"Data/textures/impactdecals/decalspitimpact01.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowhole01.dds",
|
||||
"Data/textures/impactdecals/decalsnowhole01.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsparkburn01.dds",
|
||||
"Data/textures/impactdecals/decalsparkburn01.dds",
|
||||
],
|
||||
[
|
||||
"10 Fire Cracks/textures/impactdecals/decalflameburn01_g.dds",
|
||||
"Data/textures/impactdecals/decalflameburn01_g.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowmelt01_n.dds",
|
||||
"Data/textures/impactdecals/decalsnowmelt01_n.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalfrostimpact01.dds",
|
||||
"Data/textures/impactdecals/decalfrostimpact01.dds",
|
||||
],
|
||||
[
|
||||
"10 Fire Cracks/textures/impactdecals/decalflameburn01_n.dds",
|
||||
"Data/textures/impactdecals/decalflameburn01_n.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowmelt01_g.dds",
|
||||
"Data/textures/impactdecals/decalsnowmelt01_g.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsparkburn01_n.dds",
|
||||
"Data/textures/impactdecals/decalsparkburn01_n.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/textures/impactdecals/decalsnowhole01_g.dds",
|
||||
"Data/textures/impactdecals/decalsnowhole01_g.dds",
|
||||
],
|
||||
[
|
||||
"40 Two Fire Esp/Manual Installation of the Two Fire Option.txt",
|
||||
"Data/Manual Installation of the Two Fire Option.txt",
|
||||
],
|
||||
[
|
||||
"10 Fire Cracks/textures/impactdecals/decalflameburn01.dds",
|
||||
"Data/textures/impactdecals/decalflameburn01.dds",
|
||||
],
|
||||
[
|
||||
"40 Two Fire Esp/textures/impactdecals/decalflamespread01_n.dds",
|
||||
"Data/textures/impactdecals/decalflamespread01_n.dds",
|
||||
],
|
||||
[
|
||||
"000 Core Files/DeadlySpellImpacts.esp",
|
||||
"Data/DeadlySpellImpacts.esp",
|
||||
],
|
||||
"SkyUI_SE.bsa -> Data/SkyUI_SE.bsa",
|
||||
"SkyUI_SE.esp -> Data/SkyUI_SE.esp",
|
||||
]
|
||||
priority = 1
|
||||
priority = 0
|
||||
|
||||
[[mods]]
|
||||
id = "racemenu-19080-465102"
|
||||
files = [
|
||||
"RaceMenu.esp -> Data/RaceMenu.esp",
|
||||
"SKSE/Plugins/skee64.ini -> Data/SKSE/Plugins/skee64.ini",
|
||||
"RaceMenu.bsa -> Data/RaceMenu.bsa",
|
||||
"RaceMenuPlugin.esp -> Data/RaceMenuPlugin.esp",
|
||||
"SKSE/Plugins/skee64.dll -> Data/SKSE/Plugins/skee64.dll",
|
||||
]
|
||||
priority = 0
|
||||
|
||||
|
||||
@@ -38,14 +38,14 @@ fn parse_complex() {
|
||||
let unwraped = inst.expect("Asserted before");
|
||||
|
||||
assert_eq!(unwraped.game_id(), "sse");
|
||||
assert_eq!(unwraped.load_order().len(), 11);
|
||||
assert_eq!(unwraped.load_order().len(), 13);
|
||||
assert_eq!(
|
||||
unwraped.game_file_overrides().first().unwrap(),
|
||||
&Link::new("skse64_loader.exe", "SkyrimSELauncher.exe")
|
||||
);
|
||||
|
||||
assert_eq!(unwraped.mods().len(), 3);
|
||||
let test_mod = unwraped.mods().iter().find(|e| e.mod_id() == "skyui");
|
||||
let test_mod = unwraped.mods().iter().find(|e| e.mod_id() == "SkyUI-12604-35407");
|
||||
assert!(test_mod.is_some());
|
||||
|
||||
assert_eq!(test_mod.unwrap().priority(), 0);
|
||||
|
||||
Reference in New Issue
Block a user