···2525- renaming `steam_id_remote` dictionnary key to `remote_steam_id` to fix network spam detection that resulted in timeouts
2626- prevent the game from crashing when saving the options by not setting any values to `OS.windowed_borderless` because setting a value to it crashes the game somehow
27272828+2929+## How to install a mod?
3030+3131+When running the software for the first time and building webfishing, you'll notice that a `mods` folder has appeared in the folder where the installer is.
3232+3333+In order to install a mod, just copy a mod folder in it, a mod folder has a `manifest.json` file in it.
3434+3535+After that, run the installer again ! It will tell you in the terminal if the mod is installed or if something went wrong.
3636+3737+Here's a small mod list : [link to the mod list](modlist.md)
3838+2839## How to make a mod?
29403041As you can see in the `example_mods` folder, a mod has typically two folders and a single `manifest.json` file having the following structure:
3131-```json
4242+```jsonc
3243{
3344 "name": "Ship Mod", // Mod name
3445 "author": "Estym", // Author
+20-29
example_mods/ship/patch/player.patch
···11-diff --git a/webfishing/Scenes/Entities/Player/player.gd b/Users/evann/Godot/Webfishing/Scenes/Entities/Player/player.gd
22-index 3879ff8..cc20048 100644
33---- a/webfishing/Scenes/Entities/Player/player.gd
44-+++ b/Users/evann/Godot/Webfishing/Scenes/Entities/Player/player.gd
55-@@ -30,6 +30,7 @@ export var NPC_cosmetics = {"species": "species_cat", "pattern": "pattern_none"
11+diff --git a/player.gd b/player copie.gd
22+index c84af29..4cb41f9 100644
33+--- a/player.gd
44++++ b/player copie.gd
55+@@ -23,6 +23,7 @@ const PARTICLE_DATA = {
66+ "music": preload("res://Scenes/Particles/music_particle.tscn"),
77+ "kiss": preload("res://Scenes/Particles/kiss.tscn"),
88+ }
99++var ship_mod_instance = preload("res://Mods/Ship/ship.gd").new()
1010+1111+ export (NodePath) var hand_sprite_node
1212+ export (NodePath) var hand_bone_node
1313+@@ -31,6 +32,7 @@ export var NPC_cosmetics = {"species": "species_cat", "pattern": "pattern_none"
614 export var NPC_name = "NPC Test"
715 export var NPC_title = "npc title here"
81699-+var ship_mod_instance = preload("res://Mods/Ship/ship.gd").new()
1717++
1018 var camera_zoom = 5.0
11191220 var direction = Vector3()
1313-@@ -341,6 +342,7 @@ func _process(delta):
1414-1515- func _controlled_process(delta):
1616- _get_input()
1717-+
1818- _process_movement(delta)
1919- _process_timers()
2020- _interact_check()
2121-@@ -480,7 +482,7 @@ func _process_timers():
2222-2323- func _get_input():
2424- direction = Vector3.ZERO
2525--
2626-+
2727- if Input.is_action_just_released("primary_action"): _primary_action_release()
2828- if Input.is_action_pressed("primary_action"): _primary_action_hold()
2929- else: primary_hold_timer = 0
3030-@@ -538,8 +540,10 @@ func _get_input():
2121+@@ -531,6 +533,10 @@ func _get_input():
31223223 mouse_look = false
33243425+ if ship_mod_instance.is_sitting_on_ship(self):
3526+ ship_mod_instance.process_ship(self, get_world())
3627+ return
2828++
3729 if sitting: return
3838--
3030+3931 if Input.is_action_pressed("move_forward"): direction -= cam_base.transform.basis.z
4040- if Input.is_action_pressed("move_back"): direction += cam_base.transform.basis.z
4141- if Input.is_action_pressed("move_right"): direction += cam_base.transform.basis.x
4242-@@ -1405,16 +1409,6 @@ func _create_prop(ref, offset = Vector3(0, 1, 0), restrict_to_one = false):
3232+@@ -1389,17 +1395,6 @@ func _create_prop(ref, offset = Vector3(0, 1, 0), restrict_to_one = false):
3333+ PlayerData.emit_signal("_prop_update")
4334 return false
44354545-3636+-
4637- if $detection_zones / prop_detect.get_overlapping_bodies().size() > 0 or not is_on_floor() or not $detection_zones / prop_ray.is_colliding():
4738- PlayerData._send_notification("invalid prop placement", 1)
4839- return false
+7
modlist.md
···11+# List of currently existing mods compatible with the webfishing-macos-installer
22+33+## AtProto Webfishing
44+[Repository](https://forgejo.regnault.dev/estym/webfishing-macos-atproto)
55+66+A mod that adds remote saving using a Bluesky account (or a self-hosted PDS)
77+
+140-66
src/main.rs
···11-mod utils;
22-mod patches;
31mod mods;
22+mod patches;
33+mod utils;
4455+use asky::Text;
66+use async_std::fs::create_dir;
77+use godot_pck::structs::PCK;
58use std::env::{current_exe, set_current_dir};
69use std::fs::File;
710use std::io::{Read, Write};
811use std::path::Path;
99-use std::process::Command;
1212+use std::process::{exit, Command};
1013use std::time::Duration;
1111-use asky::Text;
1212-use async_std::fs::create_dir;
1314use steamlocate::SteamDir;
1415use sudo::RunningAs;
1516use sysinfo::ProcessesToUpdate;
1616-use godot_pck::structs::PCK;
17171818static WEBFISHING_APPID: u32 = 3146520;
19192020async fn install_webfishing(location: &SteamDir) {
2121 let steam_location = location.path();
2222- let acf_path = steam_location.join("steamapps").join(format!("appmanifest_{}.acf", WEBFISHING_APPID));
2222+ let acf_path = steam_location
2323+ .join("steamapps")
2424+ .join(format!("appmanifest_{}.acf", WEBFISHING_APPID));
23252426 println!("Creating Webfishing ACF");
2525- File::create(acf_path).unwrap().write(include_str!("../res/webfishing.acf").as_bytes()).expect("could not write acf");
2727+ File::create(acf_path)
2828+ .unwrap()
2929+ .write(include_str!("../res/webfishing.acf").as_bytes())
3030+ .expect("could not write acf");
26312732 println!("Waiting for steam to close");
2833 let mut system = sysinfo::System::new_all();
···4045 }
41464247 println!("Steam launched, downloading webfishing");
4343- let download_path = steam_location.join("steamapps").join("downloading").join(format!("{}", WEBFISHING_APPID));
4848+ let download_path = steam_location
4949+ .join("steamapps")
5050+ .join("downloading")
5151+ .join(format!("{}", WEBFISHING_APPID));
44524553 while Path::exists(download_path.as_path()) {
4654 println!("Downloading webfishing...");
···50585159async fn download_godot_steam_template() {
5260 println!("Downloading GodotSteam template...");
5353- let res = reqwest::get("https://github.com/GodotSteam/GodotSteam/releases/download/v3.27/macos-g36-s160-gs327.zip").await.expect("Could not download godotsteam template");
6161+ let res = reqwest::get(
6262+ "https://codeberg.org/godotsteam/godotsteam/releases/download/v3.24/macos-g353-s159-gs324.zip",
6363+ )
6464+ .await
6565+ .expect("Could not download godotsteam template");
5466 let body = res.bytes().await.expect("Could not read body");
55675656- let mut file = File::create("build/godot_steam_template.zip").expect("Could not create godotsteam template");
5757- file.write_all(&body).expect("Could not write godotsteam template");
6868+ let mut file = File::create("build/godot_steam_template_324.zip")
6969+ .expect("Could not create godotsteam template");
7070+ file.write_all(&body)
7171+ .expect("Could not write godotsteam template");
5872}
59736074async fn download_gd_decomp() {
···6983 Command::new("unzip")
7084 .arg("decompiler.zip")
7185 .current_dir("build")
7272- .output().expect("Could not unzip godotsteam template");
8686+ .output()
8787+ .expect("Could not unzip godotsteam template");
7388}
74897590fn build_webfishing_macos(webfishing_path: &Path) {
7691 let template_path = Path::new("build/osx_template.app");
9292+7793 Command::new("rm")
7894 .current_dir(template_path)
7979- .arg("Contents/MacOS/godot_osx_debug.64")
8080- .output().expect("Could not remove delete godot_osx_debug.64");
9595+ .arg("Contents/MacOS/godot_osx_debug.universal")
9696+ .output()
9797+ .expect("Could not remove delete godot_osx_debug.universal");
81988299 Command::new("mv")
83100 .current_dir(template_path)
8484- .arg("Contents/MacOS/godot_osx_release.64")
101101+ .arg("Contents/MacOS/godot_osx_release.universal")
85102 .arg("Contents/MacOS/webfishing")
8686- .output().expect("Could not rename godot_osc_release.64");
103103+ .output()
104104+ .expect("Could not rename godot_osc_release.universal");
871058888- let mut steamappid = File::create(template_path.join("Contents").join("MacOS").join("steam_appid.txt")).expect("could not create steam_appid.txt file");
8989- steamappid.write(include_str!("../res/steam_appid.txt").as_bytes()).expect("could not write steam_appid.txt");
106106+ let mut steamappid = File::create(
107107+ template_path
108108+ .join("Contents")
109109+ .join("MacOS")
110110+ .join("steam_appid.txt"),
111111+ )
112112+ .expect("could not create steam_appid.txt file");
113113+ steamappid
114114+ .write(include_str!("../res/steam_appid.txt").as_bytes())
115115+ .expect("could not write steam_appid.txt");
9011691117 Command::new("cp")
92118 .arg(webfishing_path.join("webfishing.exe"))
9393- .arg(template_path.join("Contents").join("Resources").join("webfishing.pck"))
9494- .output().expect("Could not copy webfishing.exe");
119119+ .arg(
120120+ template_path
121121+ .join("Contents")
122122+ .join("Resources")
123123+ .join("webfishing.pck"),
124124+ )
125125+ .output()
126126+ .expect("Could not copy webfishing.exe");
951279696- let mut info_plist = File::create(template_path.join("Contents").join("Info.plist")).expect("Could not open Info.plist");
9797- info_plist.write_all(include_str!("../res/Info.plist").as_bytes()).expect("could not write Info.plist");
128128+ let mut info_plist = File::create(template_path.join("Contents").join("Info.plist"))
129129+ .expect("Could not open Info.plist");
130130+ info_plist
131131+ .write_all(include_str!("../res/Info.plist").as_bytes())
132132+ .expect("could not write Info.plist");
9813399134 Command::new("mv")
100135 .arg(template_path)
101136 .arg(Path::new("build/webfishing.app"))
102102- .output().expect("Could not copy webfishing.app");
137137+ .output()
138138+ .expect("Could not copy webfishing.app");
139139+}
140140+141141+fn sign_webfishing() {
142142+ Command::new("xattr")
143143+ .arg("-cr")
144144+ .arg("build/webfishing.app")
145145+ .output()
146146+ .expect("Could not execute xattr");
147147+148148+ Command::new("rm")
149149+ .arg("build/signing-step")
150150+ .output()
151151+ .expect("Could not remove signing-step file");
152152+153153+ println!("Webfishing is in the build folder !");
154154+155155+ Text::new("Press Enter to quit")
156156+ .prompt()
157157+ .expect("Could not confirm to quit");
158158+159159+103160}
104161105162#[tokio::main]
106163async fn main() {
107107- set_current_dir(current_exe().unwrap().parent().expect("Could not get current dir")).expect("Could not set current dir");
164164+ if sudo::check() == RunningAs::Root && Path::new("build/signing-step").exists() {
165165+ sign_webfishing();
166166+ exit(0);
167167+ }
168168+169169+ set_current_dir(
170170+ current_exe()
171171+ .unwrap()
172172+ .parent()
173173+ .expect("Could not get current dir"),
174174+ )
175175+ .expect("Could not set current dir");
108176 if !Path::exists("build".as_ref()) {
109177 println!("Creating build folder");
110110- create_dir("build").await.expect("could not create build folder");
178178+ create_dir("build")
179179+ .await
180180+ .expect("could not create build folder");
111181 }
112182113183 let location = SteamDir::locate().expect("could not locate steam directory");
···118188 install_webfishing(&location).await;
119189 }
120190121121- let (app, library) = location.find_app(WEBFISHING_APPID).unwrap().unwrap();
191191+ let (app, library) = location.find_app(WEBFISHING_APPID).unwrap().unwrap();
122192123193 if !Path::exists("build/decompiler.zip".as_ref()) {
124194 download_gd_decomp().await;
125195 }
126196127127- if !Path::exists("build/godot_steam_template.zip".as_ref()) {
197197+ if !Path::exists("build/godot_steam_template_324.zip".as_ref()) {
128198 download_godot_steam_template().await;
129199 }
130200131131- if !Path::exists("build/macos.zip".as_ref()) {
132132- println!("Unzipping template");
133133- Command::new("unzip")
134134- .arg("-o")
135135- .arg("godot_steam_template.zip")
136136- .current_dir("./build")
137137- .output().expect("Could not unzip godot_steam_template.zip");
138138- }
201201+ println!("Unzipping template 1/2");
202202+ Command::new("unzip")
203203+ .arg("-o")
204204+ .arg("godot_steam_template_324.zip")
205205+ .current_dir("./build")
206206+ .output()
207207+ .expect("Could not unzip godot_steam_template_324.zip");
139208140140- if !Path::exists("build/osx_template.app".as_ref()) && !Path::exists("build/webfishing.app".as_ref()) {
141141- println!("Unzipping template");
142142- Command::new("unzip")
143143- .arg("-o")
144144- .arg("macos.zip")
145145- .current_dir("./build")
146146- .output()
147147- .expect("Could not unzip macos.zip");
148148- }
209209+ Command::new("mv")
210210+ .arg("build/godot_steam_template_324/macos.zip")
211211+ .arg("build/macos.zip")
212212+ .current_dir("./build")
213213+ .output()
214214+ .expect("Could not copy godot_steam_template_324/macos.zip");
149215216216+ println!("Unzipping template 2/2");
217217+ Command::new("unzip")
218218+ .arg("-o")
219219+ .arg("macos.zip")
220220+ .current_dir("./build")
221221+ .output()
222222+ .expect("Could not unzip macos.zip");
150223151224 let binding = library.resolve_app_dir(&app);
152225 let webfishing_path = binding.as_path();
···154227 build_webfishing_macos(webfishing_path);
155228 }
156229157157- if sudo::check()!= RunningAs::Root {
158158- let _ = create_dir("build/webfishing-export").await;
159159- let mut bytes = vec![];
160160- File::open(webfishing_path.join("webfishing.exe")).unwrap().read_to_end(&mut bytes).unwrap();
161161- let mut pck = PCK::from_bytes(&*bytes).unwrap();
230230+ let _ = create_dir("build/webfishing-export").await;
231231+ let mut bytes = vec![];
232232+ File::open(webfishing_path.join("webfishing.exe"))
233233+ .unwrap()
234234+ .read_to_end(&mut bytes)
235235+ .unwrap();
236236+ let mut pck = PCK::from_bytes(&*bytes).unwrap();
162237163163- patches::steam_network_patch::patch(&mut pck).await;
164164- patches::options_menu_patch::patch(&mut pck).await;
165165- mods::mods::process_mods(&mut pck);
166166- println!("Root permissions needed to sign webfishing");
238238+ patches::steam_network_patch::patch(&mut pck).await;
239239+ patches::options_menu_patch::patch(&mut pck).await;
240240+ mods::mods::process_mods(&mut pck);
167241168168- let bytes = &pck.to_bytes();
169169- File::create("build/webfishing.app/Contents/Resources/webfishing.pck").unwrap().write(bytes).expect("Could not write to webfishing.pck");
170170- }
242242+ let bytes = &pck.to_bytes();
243243+ File::create("build/webfishing.app/Contents/Resources/webfishing.pck")
244244+ .unwrap()
245245+ .write(bytes)
246246+ .expect("Could not write to webfishing.pck");
171247172172- sudo::escalate_if_needed().expect("Could not escalate to sign the app");
248248+ File::create("build/signing-step").expect("Could not create signing step file");
173249174174- Command::new("xattr")
175175- .arg("-cr")
176176- .arg("build/webfishing.app")
177177- .output()
178178- .expect("Could not execute xattr");
179179-180180- println!("Webfishing is in the build folder !");
250250+ if sudo::check() != RunningAs::Root {
251251+ println!("In order to sign the app, you need to be root");
252252+ sudo::escalate_if_needed().expect("Could not escalate");
253253+ exit(1);
254254+ }
181255182182- Text::new("Press Enter to quit").prompt().expect("Could not confirm to quit");
256256+ sign_webfishing();
183257}
+1-1
src/patches/steam_network_patch.rs
···2424 script.read_to_string(&mut script_txt).await.expect("Cannot read script");
2525 drop(script);
26262727- let patched_script = script_txt.replace("steam_id_remote", "remote_steam_id");
2727+ let patched_script = script_txt.replace(".LOBBY_COMPARISON_EQUAL_TO_GREATER_THAN", ".OBBY_COMPARISON_EQUAL_TO_GREATER_THAN");
2828 let mut script = File::create(SCRIPT_PATH).await.expect("Cannot open script");
2929 script.write_all(patched_script.as_bytes()).await.expect("Cannot write");
3030 drop(script);