loadsmith_loader/loaders/
rivet.rs1use std::{path::PathBuf, sync::LazyLock};
2
3use loadsmith_core::PackageRef;
4use loadsmith_install::{InstallRule, InstallRuleset};
5
6use crate::{LaunchArgs, LaunchContext, Loader, Result, glob_rule};
7
8#[derive(Debug, Clone)]
23pub struct Rivet;
24
25impl Rivet {
26 pub fn new() -> Self {
28 Self
29 }
30}
31
32impl Default for Rivet {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl Loader for Rivet {
39 fn id(&self) -> &'static str {
40 "Rivet"
41 }
42
43 fn loader_install_rules(&self) -> InstallRuleset<'_> {
44 static RULES: LazyLock<Vec<InstallRule>> = LazyLock::new(|| {
45 vec![glob_rule!("*/*" => ".").strip_top_level(true).into()]
47 });
48
49 InstallRuleset::new(&RULES)
50 }
51
52 fn package_install_rules(&self) -> InstallRuleset<'_> {
53 static RULES: LazyLock<Vec<InstallRule>> = LazyLock::new(|| {
54 vec![
55 glob_rule!("*" => "Rivet/Mods")
56 .with_subdir(true)
57 .use_links(true)
58 .into(),
59 ]
60 });
61
62 InstallRuleset::new(&RULES)
63 }
64
65 fn generate_launch_args(&self, ctx: &LaunchContext) -> Result<LaunchArgs> {
66 let rivet_directory = ctx.format_proton_path(ctx.profile_path().join("Rivet"));
67 let rivet_target =
68 ctx.format_proton_path(ctx.profile_path().join("Rivet").join("Loader.dll"));
69
70 let args = LaunchArgs::new()
71 .arg("-rivetEnable")
72 .arg("true")
73 .arg("-rivetTarget")
74 .arg(rivet_target)
75 .arg("-rivetDirectory")
76 .arg(rivet_directory);
77
78 Ok(args)
79 }
80
81 fn package_dir(&self, package: &PackageRef) -> Option<PathBuf> {
82 Some(PathBuf::from("Rivet/Mods").join(package.id().as_str()))
83 }
84
85 fn package_config_dirs(&self) -> Vec<PathBuf> {
86 Vec::new()
87 }
88
89 fn log_file(&self) -> Option<PathBuf> {
90 Some("Rivet/Rivet.log".into())
91 }
92
93 fn proxy_dll(&self) -> Option<PathBuf> {
94 Some("version.dll".into())
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use loadsmith_core::{PackageRef, Version};
101
102 use crate::{assert_map, assert_maps, test_util::MapFileTester};
103
104 use super::*;
105
106 #[test]
107 fn map_loader_files() {
108 assert_maps!(MapFileTester::new(
109 Rivet::new(),
110 PackageRef::new("ReDoIngMods-Rivet".to_string(), Version::new(0, 1, 9)),
111 true,
112 ), [
113 "README.md" => None,
114 "RivetPack/version.dll" => "./version.dll",
115 "RivetPack/Rivet.ini" => "./Rivet.ini",
116 "OtherFolder/file.txt" => "./file.txt",
117 "RivetPack/Rivet/Loader.dll" => "./Rivet/Loader.dll",
118 ]);
119 }
120
121 #[test]
122 fn map_package_files() {
123 assert_maps!(
124 MapFileTester::new(
125 Rivet::new(),
126 PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0)),
127 false,
128 ),
129 [
130 "manifest.json" => "Rivet/Mods/Author-Name/manifest.json",
131 "nested/file.txt" => "Rivet/Mods/Author-Name/nested/file.txt",
132 "1/2/file.txt" => "Rivet/Mods/Author-Name/1/2/file.txt",
133 ]
134 );
135 }
136
137 #[test]
138 fn package_dir_works() {
139 let loader = Rivet::new();
140 let package = PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0));
141
142 let package_dir = loader.package_dir(&package);
143
144 assert_eq!(package_dir, Some(PathBuf::from("Rivet/Mods/Author-Name")));
145 }
146}