loadsmith_loader/loaders/
return_of_modding.rs1use std::{path::PathBuf, sync::LazyLock};
2
3use loadsmith_install::{InstallRule, InstallRuleset, OwnedInstallRuleset, RouteRule};
4
5use crate::{LaunchArgs, LaunchContext, Loader, Result, glob_rule};
6
7#[derive(Debug, Clone)]
23pub struct ReturnOfModding {
24 package_install_ruleset: OwnedInstallRuleset,
25}
26
27impl ReturnOfModding {
28 pub fn with_rules(package_install_ruleset: OwnedInstallRuleset) -> Self {
30 Self {
31 package_install_ruleset,
32 }
33 }
34
35 pub fn with_default_rules() -> Self {
43 OwnedInstallRuleset::from_rule_iter(
44 [
45 RouteRule::new_static("ReturnOfModding/plugins").with_flatten(false),
46 RouteRule::new_static("ReturnOfModding/plugins_data").with_flatten(false),
47 RouteRule::new_static("ReturnOfModding/config")
48 .with_flatten(false)
49 .with_mutable(true),
50 ],
51 Some(0),
52 )
53 .map(Self::with_rules)
54 .expect("rules are not empty so there should always be a valid default rule index")
55 }
56}
57
58impl Loader for ReturnOfModding {
59 fn id(&self) -> &'static str {
60 "Shimloader"
61 }
62
63 fn loader_install_rules(&self) -> InstallRuleset<'_> {
64 static RULES: LazyLock<Vec<InstallRule>> = LazyLock::new(|| {
65 vec![
66 glob_rule!("*/**" => ".").strip_top_level(true).into(),
68 ]
69 });
70
71 InstallRuleset::new(&RULES)
72 }
73
74 fn package_install_rules(&self) -> InstallRuleset<'_> {
75 self.package_install_ruleset.as_ref()
76 }
77
78 fn generate_launch_args(&self, ctx: &LaunchContext) -> Result<LaunchArgs> {
79 let path = ctx.format_proton_path(ctx.profile_path());
80
81 let args = LaunchArgs::new()
82 .arg("--rom_modding_root_folder")
83 .arg(&*path);
84
85 Ok(args)
86 }
87
88 fn package_config_dirs(&self) -> Vec<PathBuf> {
89 vec!["ReturnOfModding/config".into()]
90 }
91
92 fn log_file(&self) -> Option<PathBuf> {
93 None
94 }
95
96 fn proxy_dll(&self) -> Option<PathBuf> {
97 None
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use loadsmith_core::{PackageRef, Version};
104
105 use crate::{assert_map, assert_maps, test_util::MapFileTester};
106
107 use super::*;
108
109 #[test]
110 fn map_loader_files() {
111 assert_maps!(MapFileTester::new(
112 ReturnOfModding::with_default_rules(),
113 PackageRef::new("Hell2Modding-Hell2Modding".to_string(), Version::new(1, 0, 105)),
114 true,
115 ), [
116 "icon.png" => None,
117 "README.md" => None,
118 "ReturnOfModdingPack/d3d12.dll" => "./d3d12.dll",
119 "ReturnOfModdingPack/version.dll" => "./version.dll",
120 "Other/file.txt" => "./file.txt",
121 ]);
122 }
123
124 #[test]
125 fn map_package_files() {
126 assert_maps!(
127 MapFileTester::new(
128 ReturnOfModding::with_default_rules(),
129 PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0)),
130 false,
131 ),
132 [
133 "README.md" => "ReturnOfModding/plugins/Author-Name/README.md",
134 "nested/file.txt" => "ReturnOfModding/plugins/Author-Name/nested/file.txt",
135 "plugins/nested/file.txt" => "ReturnOfModding/plugins/Author-Name/nested/file.txt",
136 "config/settings.json" => "ReturnOfModding/config/Author-Name/settings.json",
137 "plugins_data/file.txt" => "ReturnOfModding/plugins_data/Author-Name/file.txt",
138 "plugins_data/nested/file.txt" => "ReturnOfModding/plugins_data/Author-Name/nested/file.txt",
139 "nested/plugins_data/file.txt" => "ReturnOfModding/plugins_data/Author-Name/nested/file.txt",
140 ]
141 );
142 }
143
144 #[test]
145 fn package_dir_works() {
146 let loader = ReturnOfModding::with_default_rules();
147 let package = PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0));
148
149 let package_dir = loader.package_dir(&package);
150
151 assert_eq!(
152 package_dir,
153 Some(PathBuf::from("ReturnOfModding/plugins/Author-Name"))
154 );
155 }
156}