Skip to content

Commit 6648a3e

Browse files
Add rest of bepinex installer plugin code
... And a small edit to the PackageInstaller trait install_package and uninstall_package functions to accept mutable self references, not immutable. In theory this is fine but it opens up problems if we plan on multithreading file ops due to rust's mutable borrow rules. If this becomes a problem (and we NEED mutability) we can rely on something like a RefCell<T: TrackedFile> at the cost of some runtime peformance.
1 parent 1697331 commit 6648a3e

File tree

2 files changed

+102
-24
lines changed

2 files changed

+102
-24
lines changed

src/package/install/bepinex.rs

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,124 @@ impl<T: TrackedFs> BpxInstaller<T> {
1919

2020
impl<T: TrackedFs> PackageInstaller<T> for BpxInstaller<T> {
2121
async fn install_package(
22-
&self,
23-
_package: &PackageReference,
22+
&mut self,
23+
package: &PackageReference,
2424
_package_deps: &[PackageReference],
2525
package_dir: &Path,
2626
state_dir: &Path,
2727
_staging_dir: &Path,
2828
game_dir: &Path,
29-
_is_modloader: bool,
29+
is_modloader: bool,
3030
) -> Result<(), Error> {
31-
// Figure out the root bepinex directory. This should, in theory, always be the folder
32-
// that contains the winhttp.dll binary.
33-
let bepinex_root = WalkDir::new(package_dir)
34-
.into_iter()
35-
.filter_map(|x| x.ok())
36-
.filter(|x| x.path().is_file())
37-
.find(|x| x.path().file_name().unwrap() == "winhttp.dll")
38-
.expect("Failed to find winhttp.dll within BepInEx directory.");
39-
let bepinex_root = bepinex_root.path().parent().unwrap();
31+
if is_modloader {
32+
// Figure out the root bepinex directory. This should, in theory, always be the folder
33+
// that contains the winhttp.dll binary.
34+
let bepinex_root = WalkDir::new(package_dir)
35+
.into_iter()
36+
.filter_map(|x| x.ok())
37+
.filter(|x| x.path().is_file())
38+
.find(|x| x.path().file_name().unwrap() == "winhttp.dll")
39+
.expect("Failed to find winhttp.dll within BepInEx directory.");
40+
let bepinex_root = bepinex_root.path().parent().unwrap();
41+
42+
let bep_dir = bepinex_root.join("BepInEx");
43+
let bep_dst = state_dir.join("BepInEx");
44+
45+
self.fs.dir_copy(&bep_dir, &bep_dst).await.unwrap();
46+
47+
// Install top-level doorstop files.
48+
let files = fs::read_dir(bepinex_root)
49+
.unwrap()
50+
.filter_map(|x| x.ok())
51+
.filter(|x| x.path().is_file());
52+
53+
for file in files {
54+
let dest = game_dir.join(file.path().file_name().unwrap());
55+
self.fs.file_copy(&file.path(), &dest, None).await?;
56+
}
57+
58+
return Ok(());
59+
}
60+
61+
let state_dir = state_dir.canonicalize()?;
62+
let full_name= format!("{}-{}", package.namespace, package.name);
63+
64+
let targets = vec![
65+
("plugins", true),
66+
("patchers", true),
67+
("monomod", true),
68+
("config", false),
69+
].into_iter()
70+
.map(|(x, y)| (Path::new(x), y));
4071

41-
let bep_dir = bepinex_root.join("BepInEx");
42-
let bep_dst = state_dir.join("BepInEx");
72+
let default = state_dir.join("BepInEx/plugins");
73+
for (target, relocate) in targets {
74+
// Packages may either have the target at their tld or BepInEx/target.
75+
let src = match package_dir.join("BepInEx").exists() {
76+
true => package_dir.join("BepInEx").join(target),
77+
false => package_dir.join(target),
78+
};
79+
80+
// let src = package_dir.join(target);
81+
let dest = state_dir.join("BepInEx").join(target);
4382

44-
// self.fs.dir_copy(&bep_dir, &bep_dst).await.unwrap();
83+
if !src.exists() {
84+
continue;
85+
}
4586

46-
// Install top-level doorstop files.
47-
let files = fs::read_dir(bepinex_root)
48-
.unwrap()
87+
if !dest.exists() {
88+
fs::create_dir_all(&dest)?;
89+
}
90+
91+
// Copy the directory contents of the target into the destination.
92+
let entries = fs::read_dir(&src)?
93+
.filter_map(|x| x.ok());
94+
95+
for entry in entries {
96+
let entry = entry.path();
97+
98+
let entry_dest = match relocate {
99+
true => dest.join(&full_name).join(entry.file_name().unwrap()),
100+
false => dest.join(entry.file_name().unwrap()),
101+
};
102+
103+
let entry_parent = entry_dest.parent().unwrap();
104+
105+
if !entry_parent.is_dir() {
106+
fs::create_dir_all(entry_parent)?;
107+
}
108+
109+
if entry.is_dir(){
110+
self.fs.dir_copy(&entry, &entry_dest).await?;
111+
}
112+
113+
if entry.is_file() {
114+
self.fs.file_copy(&entry, &entry_dest, None).await?;
115+
}
116+
}
117+
}
118+
119+
// Copy top-level files into the plugin directory.
120+
let tl_files = fs::read_dir(package_dir)?
49121
.filter_map(|x| x.ok())
50122
.filter(|x| x.path().is_file());
51123

52-
for file in files {
53-
let dest = game_dir.join(file.path().file_name().unwrap());
54-
// self.fs.file_copy(&file.path(), &dest, None).await?;
124+
for file in tl_files {
125+
let parent = default.join(&full_name);
126+
let dest = parent.join(file.file_name());
127+
128+
if !parent.exists() {
129+
fs::create_dir_all(&parent)?;
130+
}
131+
132+
self.fs.file_copy(&file.path(), &dest, None).await?;
55133
}
56134

57135
Ok(())
58136
}
59137

60138
async fn uninstall_package(
61-
&self,
139+
&mut self,
62140
_package: &PackageReference,
63141
_package_deps: &[PackageReference],
64142
_package_dir: &Path,

src/package/install/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub trait PackageInstaller<T: TrackedFs> {
3535
/// `state_dir` is the directory that is "linked" to at runtime by the modloader.
3636
/// `staging_dir` is the directory that contains files that are directly installed into the game directory.
3737
async fn install_package(
38-
&self,
38+
&mut self,
3939
package: &PackageReference,
4040
package_deps: &[PackageReference],
4141
package_dir: &Path,
@@ -47,7 +47,7 @@ pub trait PackageInstaller<T: TrackedFs> {
4747

4848
/// Uninstall a package from this profile.
4949
async fn uninstall_package(
50-
&self,
50+
&mut self,
5151
package: &PackageReference,
5252
package_deps: &[PackageReference],
5353
package_dir: &Path,

0 commit comments

Comments
 (0)