loadsmith_loader/loaders/
gd_weave.rs1use std::{path::PathBuf, sync::LazyLock};
2
3use camino::Utf8Path;
4use globset::GlobBuilder;
5use loadsmith_install::{GlobRule, InstallRule, InstallRuleset};
6
7use crate::{LaunchArgs, LaunchContext, Loader, Result, glob_rule};
8
9#[derive(Debug, Clone)]
24pub struct GDWeave;
25
26impl GDWeave {
27 pub fn new() -> Self {
29 Self
30 }
31}
32
33impl Default for GDWeave {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl Loader for GDWeave {
40 fn id(&self) -> &'static str {
41 "GDWeave"
42 }
43
44 fn loader_install_rules(&self) -> InstallRuleset<'_> {
45 static RULES: LazyLock<Vec<InstallRule>> = LazyLock::new(|| {
46 vec![
47 glob_rule!("GDWeave/*" => ".").use_links(true).into(),
48 glob_rule!("*.dll" => ".").use_links(true).into(),
49 ]
50 });
51
52 InstallRuleset::new(&RULES)
53 }
54
55 fn package_install_rules(&self) -> InstallRuleset<'_> {
56 static RULES: LazyLock<Vec<InstallRule>> = LazyLock::new(|| {
57 vec![
58 GlobRule::new(
59 GlobBuilder::new("GDWeave/mods/*/**")
60 .case_insensitive(true)
61 .literal_separator(true)
62 .build()
63 .expect("constant glob should be valid"),
64 Utf8Path::new("GDWeave/mods"),
65 )
66 .strip_levels(3)
67 .with_subdir(true)
68 .use_links(true)
69 .into(),
70 ]
71 });
72
73 InstallRuleset::new(&RULES)
74 }
75
76 fn generate_launch_args(&self, ctx: &LaunchContext) -> Result<LaunchArgs> {
77 let gd_weave = ctx.profile_path().join("GDWeave");
78 let path = ctx.format_proton_path(&gd_weave);
79
80 let args = LaunchArgs::new().arg(format!("--gdweave-folder-override={path}"));
81
82 Ok(args)
83 }
84
85 fn package_dir(&self, package: &loadsmith_core::PackageRef) -> Option<PathBuf> {
86 Some(PathBuf::from("GDWeave/mods").join(package.id().as_str()))
87 }
88
89 fn package_config_dirs(&self) -> Vec<PathBuf> {
90 vec!["GDWeave/configs".into()]
91 }
92
93 fn log_file(&self) -> Option<PathBuf> {
94 Some("GDWeave/GDWeave.log".into())
95 }
96
97 fn proxy_dll(&self) -> Option<PathBuf> {
98 Some("winmm.dll".into())
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use loadsmith_core::{PackageRef, Version};
105
106 use crate::{assert_map, assert_maps, test_util::MapFileTester};
107
108 use super::*;
109
110 #[test]
111 fn map_loader_files() {
112 assert_maps!(MapFileTester::new(
113 GDWeave::new(),
114 PackageRef::new("NotNet-GDWeave".to_string(), Version::new(2, 0, 14)),
115 true,
116 ), [
117 "README.md" => None,
118 "winmm.dll" => "./winmm.dll",
119 "GDWeave/core/GDWeave.dll" => "./GDWeave/core/GDWeave.dll",
120 "GDWeave/core/GDWeave.pub" => "./GDWeave/core/GDWeave.pub",
121 ]);
122 }
123
124 #[test]
125 fn map_package_files() {
126 assert_maps!(
127 MapFileTester::new(
128 GDWeave::new(),
129 PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0)),
130 false,
131 ),
132 [
133 "manifest.json" => None,
134 "other/file.txt" => None,
135 "mod/other/file.txt" => None,
136 "mod/other/nested/file.txt" => None,
137 "GDWeave/mods/Author.Name/manifest.json" => "GDWeave/mods/Author-Name/manifest.json",
138 "GDWeave/mods/Author.Name/nested/file.txt" => "GDWeave/mods/Author-Name/nested/file.txt",
139 "GDWeave/mods/Author.Name/1/2/file.txt" => "GDWeave/mods/Author-Name/1/2/file.txt",
140 "gdweave/mods/author.name/file.txt" => "GDWeave/mods/Author-Name/file.txt",
141 "GDWEAVE/MODS/AUTHOR.NAME/FILE.txt" => "GDWeave/mods/Author-Name/FILE.txt",
142 ]
143 );
144 }
145
146 #[test]
147 fn package_dir_works() {
148 let loader = GDWeave::new();
149 let package = PackageRef::new("Author-Name".to_string(), Version::new(1, 0, 0));
150
151 let package_dir = loader.package_dir(&package);
152
153 assert_eq!(package_dir, Some(PathBuf::from("GDWeave/mods/Author-Name")));
154 }
155}