tangled
alpha
login
or
join now
regnault.dev
/
webfishing-macos-installer
0
fork
atom
A native webfishing installer for macos
0
fork
atom
overview
issues
pulls
pipelines
1.2.0 - Build system that allows full modding
regnault.dev
1 year ago
71c67fd3
1de70e92
+289
-99
11 changed files
expand all
collapse all
unified
split
.gitignore
Cargo.lock
Cargo.toml
src
godot_pck
Cargo.lock
Cargo.toml
src
lib.rs
structs.rs
main.rs
patches
options_menu_patch.rs
steam_network_patch.rs
utils
gd_utils.rs
+3
-3
.gitignore
···
1
1
-
/target
2
2
-
/build
3
3
-
/.idea
1
1
+
**/target
2
2
+
**/build
3
3
+
**/.idea
+30
Cargo.lock
···
174
174
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
175
175
176
176
[[package]]
177
177
+
name = "binary-reader"
178
178
+
version = "0.4.5"
179
179
+
source = "registry+https://github.com/rust-lang/crates.io-index"
180
180
+
checksum = "1d173c51941d642588ed6a13d464617e3a9176b8fe00dc2de182434c36812a5e"
181
181
+
dependencies = [
182
182
+
"byteorder",
183
183
+
]
184
184
+
185
185
+
[[package]]
177
186
name = "bitflags"
178
187
version = "1.3.2"
179
188
source = "registry+https://github.com/rust-lang/crates.io-index"
···
212
221
version = "3.16.0"
213
222
source = "registry+https://github.com/rust-lang/crates.io-index"
214
223
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
224
224
+
225
225
+
[[package]]
226
226
+
name = "byteorder"
227
227
+
version = "1.5.0"
228
228
+
source = "registry+https://github.com/rust-lang/crates.io-index"
229
229
+
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
215
230
216
231
[[package]]
217
232
name = "bytes"
···
566
581
]
567
582
568
583
[[package]]
584
584
+
name = "godot_pck"
585
585
+
version = "0.1.0"
586
586
+
dependencies = [
587
587
+
"binary-reader",
588
588
+
"md5",
589
589
+
]
590
590
+
591
591
+
[[package]]
569
592
name = "h2"
570
593
version = "0.4.7"
571
594
source = "registry+https://github.com/rust-lang/crates.io-index"
···
961
984
dependencies = [
962
985
"value-bag",
963
986
]
987
987
+
988
988
+
[[package]]
989
989
+
name = "md5"
990
990
+
version = "0.7.0"
991
991
+
source = "registry+https://github.com/rust-lang/crates.io-index"
992
992
+
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
964
993
965
994
[[package]]
966
995
name = "memchr"
···
1963
1992
dependencies = [
1964
1993
"asky",
1965
1994
"async-std",
1995
1995
+
"godot_pck",
1966
1996
"reqwest",
1967
1997
"steamlocate",
1968
1998
"sudo",
+2
-1
Cargo.toml
···
10
10
sysinfo = "0.33.0"
11
11
async-std = "1.13.0"
12
12
sudo = "0.6.0"
13
13
-
asky = "0.1.1"
13
13
+
asky = "0.1.1"
14
14
+
godot_pck = {path = "./src/godot_pck"}
+32
src/godot_pck/Cargo.lock
···
1
1
+
# This file is automatically @generated by Cargo.
2
2
+
# It is not intended for manual editing.
3
3
+
version = 4
4
4
+
5
5
+
[[package]]
6
6
+
name = "binary-reader"
7
7
+
version = "0.4.5"
8
8
+
source = "registry+https://github.com/rust-lang/crates.io-index"
9
9
+
checksum = "1d173c51941d642588ed6a13d464617e3a9176b8fe00dc2de182434c36812a5e"
10
10
+
dependencies = [
11
11
+
"byteorder",
12
12
+
]
13
13
+
14
14
+
[[package]]
15
15
+
name = "byteorder"
16
16
+
version = "1.5.0"
17
17
+
source = "registry+https://github.com/rust-lang/crates.io-index"
18
18
+
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
19
19
+
20
20
+
[[package]]
21
21
+
name = "godot_pck"
22
22
+
version = "0.1.0"
23
23
+
dependencies = [
24
24
+
"binary-reader",
25
25
+
"md5",
26
26
+
]
27
27
+
28
28
+
[[package]]
29
29
+
name = "md5"
30
30
+
version = "0.7.0"
31
31
+
source = "registry+https://github.com/rust-lang/crates.io-index"
32
32
+
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
+8
src/godot_pck/Cargo.toml
···
1
1
+
[package]
2
2
+
name = "godot_pck"
3
3
+
version = "0.1.0"
4
4
+
edition = "2021"
5
5
+
6
6
+
[dependencies]
7
7
+
binary-reader = "0.4.5"
8
8
+
md5 = "0.7.0"
+1
src/godot_pck/src/lib.rs
···
1
1
+
pub mod structs;
+153
src/godot_pck/src/structs.rs
···
1
1
+
use binary_reader::{BinaryReader, Endian};
2
2
+
3
3
+
#[derive(Debug)]
4
4
+
pub struct PCK {
5
5
+
version: u8,
6
6
+
major_version: u8,
7
7
+
minor_version: u8,
8
8
+
patch_version: u8,
9
9
+
files: Vec<PckFile>,
10
10
+
}
11
11
+
12
12
+
#[derive(Debug, Clone)]
13
13
+
pub struct PckFile {
14
14
+
path: String,
15
15
+
offset: u64,
16
16
+
content: Vec<u8>,
17
17
+
md5: [u8; 16],
18
18
+
}
19
19
+
20
20
+
impl PCK {
21
21
+
/// Converts pck file bytes to a PCK struct
22
22
+
pub fn from_bytes(bytes: &[u8]) -> Result<PCK, &str> {
23
23
+
let chunked_start = bytes.chunks(16).position(|chunk| chunk.starts_with("GDPC".as_ref()));
24
24
+
if let None = chunked_start {
25
25
+
return Err("Invalid PCK");
26
26
+
};
27
27
+
28
28
+
let start_offset = chunked_start.unwrap() * 16;
29
29
+
let pck: Vec<u8> = bytes.to_vec().into_iter().skip(start_offset).collect();
30
30
+
let mut pck_reader = BinaryReader::from_vec(&pck);
31
31
+
pck_reader.set_endian(Endian::Little);
32
32
+
33
33
+
let _magic = pck_reader.read_u32().unwrap();
34
34
+
let version = pck_reader.read_u32().unwrap();
35
35
+
let major_version = pck_reader.read_u32().unwrap();
36
36
+
let minor_version = pck_reader.read_u32().unwrap();
37
37
+
let patch_version = pck_reader.read_u32().unwrap();
38
38
+
39
39
+
// Skip unused
40
40
+
let _ = pck_reader.read(64);
41
41
+
42
42
+
let num_files = pck_reader.read_u32().unwrap();
43
43
+
let mut files = vec![];
44
44
+
for _ in 0..num_files {
45
45
+
files.push(PckFile::from_bytes(&mut pck_reader, bytes));
46
46
+
}
47
47
+
48
48
+
Ok(PCK {
49
49
+
version: version as u8,
50
50
+
major_version: major_version as u8,
51
51
+
minor_version: minor_version as u8,
52
52
+
patch_version: patch_version as u8,
53
53
+
files
54
54
+
})
55
55
+
}
56
56
+
57
57
+
/// Converts a PCK struct to the byte vector representing a pck file
58
58
+
pub fn to_bytes(&self) -> Vec<u8> {
59
59
+
let mut bytes = vec![];
60
60
+
bytes.append(&mut "GDPC".as_bytes().to_vec());
61
61
+
bytes.append((self.version as u32).to_le_bytes().to_vec().as_mut());
62
62
+
bytes.append((self.major_version as u32).to_le_bytes().to_vec().as_mut());
63
63
+
bytes.append((self.minor_version as u32).to_le_bytes().to_vec().as_mut());
64
64
+
bytes.append((self.patch_version as u32).to_le_bytes().to_vec().as_mut());
65
65
+
bytes.append([0u8; 16*4].to_vec().as_mut());
66
66
+
bytes.append((self.files.len() as u32).to_le_bytes().to_vec().as_mut());
67
67
+
68
68
+
let mut file_offset = bytes.len()
69
69
+
+ self.files.len() * (4 + 8 + 8 + 16)
70
70
+
+ self.files.iter().map(|x| x.path.len() + (4 - (x.path.len() % 4))).sum::<usize>();
71
71
+
72
72
+
if file_offset % 16 != 0 {
73
73
+
file_offset = file_offset + (16 - (file_offset % 16));
74
74
+
}
75
75
+
76
76
+
let file_base_offset = file_offset;
77
77
+
78
78
+
let mut content : Vec<u8> = vec![];
79
79
+
80
80
+
for file in &self.files {
81
81
+
content.extend(&file.content);
82
82
+
83
83
+
let mut padded_content_len = file.content.len();
84
84
+
if padded_content_len % 16 != 0 {
85
85
+
padded_content_len = padded_content_len + (16 - (padded_content_len % 16));
86
86
+
}
87
87
+
88
88
+
for _ in file.content.len()..padded_content_len {
89
89
+
content.push(0);
90
90
+
}
91
91
+
92
92
+
let padded_length = file.path.len() + (4 - (file.path.len() % 4));
93
93
+
94
94
+
bytes.append((padded_length as u32).to_le_bytes().to_vec().as_mut());
95
95
+
bytes.append(file.path.as_bytes().to_vec().as_mut());
96
96
+
for _ in file.path.len()..padded_length {
97
97
+
bytes.push(0);
98
98
+
}
99
99
+
bytes.append((file_offset as u64).to_le_bytes().to_vec().as_mut());
100
100
+
bytes.append((padded_content_len as u64).to_le_bytes().to_vec().as_mut());
101
101
+
bytes.extend(file.md5);
102
102
+
103
103
+
file_offset += padded_content_len;
104
104
+
}
105
105
+
106
106
+
for _ in bytes.len()..file_base_offset {
107
107
+
bytes.push(0);
108
108
+
}
109
109
+
110
110
+
bytes.extend(content);
111
111
+
bytes
112
112
+
}
113
113
+
114
114
+
pub fn get_file_by_path(&self, path: &str) -> Option<&PckFile> {
115
115
+
self.files.iter().find(|x| x.path == path)
116
116
+
}
117
117
+
118
118
+
pub fn get_file_by_path_mut(&mut self, path: &str) -> Option<&mut PckFile> {
119
119
+
self.files.iter_mut().find(|x| x.path == path)
120
120
+
}
121
121
+
122
122
+
pub fn add_file(&mut self, new_file: PckFile) {
123
123
+
self.files.retain(|x| x.path != new_file.path);
124
124
+
self.files.push(new_file);
125
125
+
}
126
126
+
}
127
127
+
128
128
+
impl PckFile {
129
129
+
pub fn from_bytes(pck_reader: &mut BinaryReader, file_bytes: &[u8]) -> PckFile {
130
130
+
let path_length = pck_reader.read_u32().unwrap();
131
131
+
let path_bytes= pck_reader.read(path_length as usize).unwrap();
132
132
+
let path: String = String::from_utf8_lossy(path_bytes).replace("\0", "").to_string();
133
133
+
let offset = pck_reader.read_u64().unwrap();
134
134
+
let size = pck_reader.read_u64().unwrap();
135
135
+
let md5 = pck_reader.read(16).unwrap();
136
136
+
let content: Vec<u8> = file_bytes.iter().skip(offset as usize).take(size as usize).cloned().collect();
137
137
+
PckFile {
138
138
+
path,
139
139
+
offset,
140
140
+
content,
141
141
+
md5: <[u8; 16]>::try_from(md5).unwrap(),
142
142
+
}
143
143
+
}
144
144
+
145
145
+
pub fn get_content(&self) -> &[u8] {
146
146
+
&self.content
147
147
+
}
148
148
+
149
149
+
pub fn set_content(&mut self, content: Vec<u8>) {
150
150
+
self.md5 = *md5::compute(&content);
151
151
+
self.content = content;
152
152
+
}
153
153
+
}
+13
-17
src/main.rs
···
2
2
mod patches;
3
3
4
4
use std::fs::File;
5
5
-
use std::io::{Write};
5
5
+
use std::io::{Read, Write};
6
6
use std::path::Path;
7
7
use std::process::Command;
8
8
use std::time::Duration;
···
11
11
use steamlocate::SteamDir;
12
12
use sudo::RunningAs;
13
13
use sysinfo::ProcessesToUpdate;
14
14
+
use godot_pck::structs::PCK;
14
15
15
16
static WEBFISHING_APPID: u32 = 3146520;
16
17
···
101
102
.output().expect("Could not copy webfishing.app");
102
103
}
103
104
104
104
-
fn decomp_game() {
105
105
-
let webfishing_pck_path = Path::new("build").join("webfishing.app").join("Contents").join("Resources").join("webfishing.pck");
106
106
-
let decomp_command = "build/Godot RE Tools.app/Contents/MacOS/Godot RE Tools";
107
107
-
Command::new(decomp_command)
108
108
-
.arg("--headless")
109
109
-
.arg(format!("--extract={}", webfishing_pck_path.display()))
110
110
-
.arg("--include=\"*options_menu*\"")
111
111
-
.arg("--include=\"*SteamNetwork*\"")
112
112
-
.arg("--output-dir=build/webfishing-export")
113
113
-
.output().expect("Could not extract game");
114
114
-
}
115
115
-
116
105
#[tokio::main]
117
106
async fn main() {
118
107
if !Path::exists("build".as_ref()) {
···
164
153
build_webfishing_macos(webfishing_path);
165
154
}
166
155
167
167
-
if sudo::check() != RunningAs::Root {
168
168
-
decomp_game();
169
169
-
patches::steam_network_patch::patch().await;
170
170
-
patches::options_menu_patch::patch().await;
156
156
+
if sudo::check()!= RunningAs::Root {
157
157
+
let _ = create_dir("build/webfishing-export").await;
158
158
+
let mut bytes = vec![];
159
159
+
File::open(webfishing_path.join("webfishing.exe")).unwrap().read_to_end(&mut bytes).unwrap();
160
160
+
let mut pck = PCK::from_bytes(&*bytes).unwrap();
161
161
+
162
162
+
patches::steam_network_patch::patch(&mut pck).await;
163
163
+
patches::options_menu_patch::patch(&mut pck).await;
171
164
println!("Root permissions needed to sign webfishing");
165
165
+
166
166
+
let bytes = &pck.to_bytes();
167
167
+
File::create("build/webfishing.app/Contents/Resources/webfishing.pck").unwrap().write(bytes).expect("Could not write to webfishing.pck");
172
168
}
173
169
174
170
sudo::escalate_if_needed().expect("Could not escalate to sign the app");
+17
-45
src/patches/options_menu_patch.rs
···
1
1
use async_std::fs::File;
2
2
use async_std::io::{ReadExt, WriteExt};
3
3
-
use crate::utils::gd_utils::replace_slice;
3
3
+
use godot_pck::structs::PCK;
4
4
5
5
+
const RESOURCE_PATH: &str = "res://Scenes/Singletons/OptionsMenu/options_menu.gdc";
6
6
+
const FILE_PATH: &str = "build/webfishing-export/options_menu.gdc";
5
7
const SCRIPT_PATH: &str = "build/webfishing-decomp/options_menu.gd";
6
8
const COMPILED_PATH: &str = "build/webfishing-recomp/options_menu.gdc";
7
7
-
const GAME_PCK: &str = "build/webfishing.app/Contents/Resources/webfishing.pck";
9
9
+
pub(crate) async fn patch(pck: &mut PCK) {
10
10
+
println!("Patching {} files...", RESOURCE_PATH);
11
11
+
let mut pck_file = pck.get_file_by_path_mut(RESOURCE_PATH).expect("Couldn't find options_menu.gdc file");
8
12
9
9
-
pub(crate) async fn patch() {
10
10
-
crate::utils::gd_utils::decomp_file("build/webfishing-export/Scenes/Singletons/OptionsMenu/options_menu.gdc");
13
13
+
let content = pck_file.get_content();
14
14
+
let mut exported_file = File::create(FILE_PATH).await.expect("Couldn't create file");
15
15
+
exported_file.write_all(content).await.unwrap();
16
16
+
drop(exported_file);
17
17
+
18
18
+
crate::utils::gd_utils::decomp_file(FILE_PATH);
11
19
12
20
let mut script = File::open(SCRIPT_PATH).await.expect("Cannot open script");
13
21
let mut script_txt = String::new();
14
22
script.read_to_string(&mut script_txt).await.expect("Cannot read script");
15
23
drop(script);
16
24
17
17
-
let patched_script = script_txt.replace("OS.window_borderless = PlayerData.player_options.fullscreen == 1", "OS.window_borderless\n");
25
25
+
let patched_script = script_txt.replace("OS.window_borderless = PlayerData.player_options.fullscreen == 1", "");
18
26
let mut script = File::create(SCRIPT_PATH).await.expect("Cannot open script");
19
27
script.write_all(patched_script.as_bytes()).await.expect("Cannot write");
20
28
drop(script);
21
29
22
30
crate::utils::gd_utils::recomp_file(SCRIPT_PATH);
23
31
24
24
-
let mut compiled_script_bytes = Vec::new();
25
25
-
let mut compiled_script = File::open(COMPILED_PATH).await.expect("Cannot open script");
26
26
-
compiled_script.read_to_end(&mut compiled_script_bytes).await.expect("Cannot read");
27
27
-
drop(compiled_script);
28
28
-
29
29
-
let mut compiled_pck_bytes = Vec::new();
30
30
-
let mut compiled_pck = File::open(GAME_PCK).await.expect("Cannot open pck");
31
31
-
compiled_pck.read_to_end(&mut compiled_pck_bytes).await.expect("Cannot read");
32
32
-
drop(compiled_pck);
33
33
-
let mut compiled_pck_bytes: Vec<u8> = compiled_pck_bytes.into_iter().rev().skip_while(|b| (*b) == 0).collect::<Vec<u8>>().into_iter().rev().collect();
34
34
-
35
35
-
if compiled_script_bytes.len() % 16 > 0 {
36
36
-
let to_add = 16 - (compiled_script_bytes.len() % 16);
37
37
-
for _ in 0..to_add {
38
38
-
compiled_script_bytes.push(0);
39
39
-
}
40
40
-
}
41
41
-
42
42
-
let mut tsc_bytes = Vec::new();
43
43
-
let mut tsc = File::open("build/webfishing-export/Scenes/Singletons/OptionsMenu/options_menu.tscn").await.expect("Cannot open options menu");
44
44
-
tsc.read_to_end(&mut tsc_bytes).await.expect("Cannot read");
45
45
-
drop(tsc);
32
32
+
let mut file = File::open(COMPILED_PATH).await.expect("Cannot open compiled script");
33
33
+
let mut new_content = vec![];
34
34
+
file.read_to_end(&mut new_content).await.unwrap();
46
35
47
47
-
compiled_script_bytes.append(&mut tsc_bytes);
48
48
-
let mut compiled_pck_bytes: Vec<u8> = compiled_pck_bytes.into_iter().rev().skip_while(|b| (*b) == 0).collect::<Vec<u8>>().into_iter().rev().collect();
49
49
-
if compiled_script_bytes.len() % 16 > 0 {
50
50
-
let to_add = 16 - (compiled_script_bytes.len() % 16);
51
51
-
for _ in 0..to_add {
52
52
-
compiled_script_bytes.push(0);
53
53
-
}
54
54
-
}
55
55
-
56
56
-
replace_slice(&mut compiled_pck_bytes,
57
57
-
&[0x47, 0x44, 0x53, 0x43, 0x0D, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00],
58
58
-
"GDSC".as_ref(),
59
59
-
&compiled_script_bytes
60
60
-
);
61
61
-
62
62
-
63
63
-
let mut compiled_pck = File::create(GAME_PCK).await.expect("Cannot open pck");
64
64
-
compiled_pck.write_all(compiled_pck_bytes.as_slice()).await.expect("Cannot write");
36
36
+
pck_file.set_content(new_content);
65
37
}
+18
-21
src/patches/steam_network_patch.rs
···
1
1
+
use godot_pck::structs::PckFile;
1
2
use async_std::fs::File;
2
3
use async_std::io::{ReadExt, WriteExt};
3
3
-
use crate::utils::gd_utils::replace_slice;
4
4
+
use godot_pck::structs::PCK;
4
5
6
6
+
const RESOURCE_PATH: &str = "res://Scenes/Singletons/SteamNetwork.gdc";
7
7
+
const FILE_PATH: &str = "build/webfishing-export/SteamNetwork.gdc";
5
8
const SCRIPT_PATH: &str = "build/webfishing-decomp/SteamNetwork.gd";
6
9
const COMPILED_PATH: &str = "build/webfishing-recomp/SteamNetwork.gdc";
7
7
-
const GAME_PCK: &str = "build/webfishing.app/Contents/Resources/webfishing.pck";
8
10
9
9
-
pub(crate) async fn patch() {
10
10
-
crate::utils::gd_utils::decomp_file("build/webfishing-export/Scenes/Singletons/SteamNetwork.gdc");
11
11
+
pub(crate) async fn patch(pck: &mut PCK) {
12
12
+
println!("Patching {} files...", RESOURCE_PATH);
13
13
+
let mut pck_file: &mut PckFile = pck.get_file_by_path_mut(RESOURCE_PATH).expect("Couldn't find options_menu.gdc file");
14
14
+
15
15
+
let content = pck_file.get_content();
16
16
+
let mut exported_file = File::create(FILE_PATH).await.expect("Couldn't create file");
17
17
+
exported_file.write_all(content).await.expect("Couldn't write file");
18
18
+
drop(exported_file);
19
19
+
20
20
+
crate::utils::gd_utils::decomp_file(FILE_PATH);
11
21
12
22
let mut script = File::open(SCRIPT_PATH).await.expect("Cannot open script");
13
23
let mut script_txt = String::new();
···
21
31
22
32
crate::utils::gd_utils::recomp_file(SCRIPT_PATH);
23
33
24
24
-
let mut compiled_script_bytes = Vec::new();
25
25
-
let mut compiled_script = File::open(COMPILED_PATH).await.expect("Cannot open script");
26
26
-
compiled_script.read_to_end(&mut compiled_script_bytes).await.expect("Cannot read");
27
27
-
drop(compiled_script);
34
34
+
let mut file = File::open(COMPILED_PATH).await.expect("Cannot open compiled script");
35
35
+
let mut new_content = vec![];
36
36
+
file.read_to_end(&mut new_content).await.unwrap();
28
37
29
29
-
let mut compiled_pck_bytes = Vec::new();
30
30
-
let mut compiled_pck = File::open(GAME_PCK).await.expect("Cannot open pck");
31
31
-
compiled_pck.read_to_end(&mut compiled_pck_bytes).await.expect("Cannot read");
32
32
-
drop(compiled_pck);
33
33
-
34
34
-
replace_slice(&mut compiled_pck_bytes,
35
35
-
&[0x47, 0x44, 0x53, 0x43, 0x0D, 0x00, 0x00, 0x00, 0x5B, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00],
36
36
-
"GDSC".as_ref(),
37
37
-
&compiled_script_bytes
38
38
-
);
39
39
-
40
40
-
let mut compiled_pck = File::create(GAME_PCK).await.expect("Cannot open pck");
41
41
-
compiled_pck.write_all(compiled_pck_bytes.as_slice()).await.expect("Cannot write");
38
38
+
pck_file.set_content(new_content);
42
39
}
+12
-12
src/utils/gd_utils.rs
···
3
3
const RE_TOOLS: &str = "build/Godot RE Tools.app/Contents/MacOS/Godot RE Tools";
4
4
5
5
// https://stackoverflow.com/a/54152901
6
6
-
pub(crate) fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T], replace_with: &[T])
6
6
+
pub(crate) fn replace_slice<T>(buf: &[T], from: &[T], to: &[T], replace_with: &mut [T]) -> Vec<T>
7
7
where
8
8
T: Clone + PartialEq + From<u8>,
9
9
{
10
10
-
for mut i in 0..=buf.len() - replace_with.len() {
10
10
+
let mut last_j = 0;
11
11
+
let mut res : Vec<T> = Vec::new();
12
12
+
for i in 0..=buf.len() {
11
13
if buf[i..].starts_with(from) {
14
14
+
res.append(&mut buf[last_j..i].to_vec());
12
15
for j in (i + 1)..=buf.len() {
13
16
if buf[j..].starts_with(to) {
14
14
-
let mut vec = Vec::new();
15
15
-
vec.extend_from_slice(replace_with);
16
16
-
if replace_with.len() < j-i {
17
17
-
for _ in 0.. (j-i-replace_with.len()) {
18
18
-
vec.push(T::try_from(0).expect("Failed to convert from usize"));
19
19
-
}
20
20
-
}
21
21
-
buf[i..j].clone_from_slice(vec.as_slice());
17
17
+
res.append(replace_with.to_vec().as_mut());
18
18
+
last_j = j;
22
19
break;
23
20
}
24
21
}
25
22
}
26
23
}
24
24
+
25
25
+
res.append(&mut buf[last_j..].to_vec());
26
26
+
res
27
27
}
28
28
29
29
pub(crate) fn decomp_file(path: &str) {
30
30
-
Command::new(RE_TOOLS)
30
30
+
dbg!(Command::new(RE_TOOLS)
31
31
.arg("--headless")
32
32
.arg(format!("--decompile=\"{}\"", path))
33
33
.arg("--bytecode=3.5.0")
34
34
.arg("--output-dir=build/webfishing-decomp")
35
35
-
.output().expect(format!("Failed to decompile file: {}", path).as_str());
35
35
+
.output().expect(format!("Failed to decompile file: {}", path).as_str()));
36
36
}
37
37
38
38
pub(crate) fn recomp_file(path: &str) {