diff --git a/.gitignore b/.gitignore index 0f3f289..d07d1b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ backups save -7z.exe -node.exe -config.json \ No newline at end of file +*.exe +*.7z +config.json diff --git a/README.md b/README.md index 523e6e6..45658b7 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,65 @@ # SnowRunnerSaveMerge -Tool for SnowRunner to enable progress sync from you co-op host +Tool for SnowRunner to enable progress sync from you co-op host. + +## Requirements +Written in Node v 22.2.0 for Windows + +Need to provide 7z.exe in the same directory as script for compression + +## Usage +This script will overwrite most of your save file, it's best to only use this with a save file dedicated to co-op play, with a consistent host!
+Your save file must be on the same slot in game as the host! + +### Installation +1. Download the saveMerge.js file or clone the repo. +1. Run the script once to create template config file +1. Fill your config according to instructions inside +1. Make sure your load location and backup location exist +1. Copy 7z.exe to the repo directory + +### Running the script +It's best to run the script directly after ending your game session. To prevent accidental merges with old files if hosts save was uploaded more than 1 hour ago the script will not automatically download and merge it. If you're sure that the file is correct, download it manually and extract the files in you load location `remote` directory then run just `merge` operation + +#### Host +1. Get all your vehicles inside a garage, best to retain them +1. Leave all newly acquired trucks, that the guest doesn't have, outside on the map +1. Exit the game +1. Run the script with `upload` operation `node .\saveMerge.js upload` additionally provide save slot if different than first + +#### Guest +1. Get all your vehicles inside a garage, best to retain them +1. Exit the game +1. Run the script with `download` and `merge` operations `node .\saveMerge.js download,merge` additionally provide save slot if different than first +1. Restart Steam for safety. Sometimes the game behaves funny if steam is not restarted after save manipulation + +#### Things that will be overwritten +- Map files +- Visited maps +- Watch towers +- Upgrades +- Tasks +- Contracts +- Objective states (half completed tasks etc.) +- Game settings (hard mode, recover and fuel costs etc.) +- Waypoints, not sure if it matters, but the game creates new array elements for them only on host side. You have to redo your route when joining anyway. + +#### Things that are preserved +- Trucks (customizations, addons etc.) +- Money +- Exp + +#### Auto save backup +1. Run the script with `backup` operation `node .\saveMerge.js backup`, save slot doesn't matter in this case. Whole save is backed up so it still might useful in single player game +1. The script will enter an endless loop that will backup you saves every set interval, default 10 minutes +1. Do not exit the script while files are copying, there is a message displayed when it's safe to kill the script + +### Script help as shown when used with unknown operation + + saveMerge [operations=download,merge] [save_slot=1] + + operations - comma separated list of operations, from these: download, merge, upload, backup + download - download save from file.io, this will delete contents of loadLocation + merge - merge the save from loadLocation + upload - pack the current save and upload to filebin.net + backup - will auto backup save file on set interval + save_slot - which slot to merge, values 1 to 4 are accepted, need to play on the same slot as host \ No newline at end of file diff --git a/saveMerge.js b/saveMerge.js index 87749e9..44c7bfb 100644 --- a/saveMerge.js +++ b/saveMerge.js @@ -5,7 +5,7 @@ const exec = require("child_process").execSync; var CONFIG = null; const configTemplate = { - "info": "This script will overwrite most of you save file, it's best to only use this with a save file dedicated to co-op play, with a consistent host!", + "info": "This script will overwrite most of your save file, it's best to only use this with a save file dedicated to co-op play, with a consistent host!", "saveLocation": "C:/Program Files (x86)/Steam/userdata//1465360", "loadLocation": "./save", "backupLocation": "./backups", @@ -194,9 +194,11 @@ async function main(args) { break; case "upload": + // Create 7z archive from latest backup let archivePath = `${__dirname}\\${backupName}.7z`; exec(`${__dirname}\\7z.exe a ${archivePath} ${__dirname}\\backups\\${backupName}\\*`); + // Upload the file to filebin fileInput = await fs.readFile(archivePath); await fetch(CONFIG.filebinURL + "/" + backupName + ".7z", { body: fileInput, @@ -207,15 +209,17 @@ async function main(args) { method: "POST" }); + // Remove the archive await fs.rm(archivePath); break; case "backup": + // Auto backcup will loop forever and create a backup of you save files every set interval while (true) { console.log("Waiting for next backup, you can stop the script using Ctrl+C!"); await sleep(CONFIG.backupInterval); - await backupSave(); console.log("Performing backup, wait before terminating the program!"); + await backupSave(); } break; @@ -224,32 +228,15 @@ async function main(args) { Unknown parameter!\n\ saveMerge [operations=download,merge] [save_slot=1]\n\ \n\ - operations - comma separated list of operations, from these: download, merge, upload\n\ + operations - comma separated list of operations, from these: download, merge, upload, backup\n\ download - download save from file.io, this will delete contents of loadLocation\n\ merge - merge the save from loadLocation\n\ upload - pack the current save and upload to filebin.net\n\ backup - will auto backup save file on set interval\n\ - save_slot - which slot to merge, values 1 to 4 are accepted"); + save_slot - which slot to merge, values 1 to 4 are accepted, need to play on the same slot as host"); return; } } - - - - // case "upload": // from saveLocation backups - - // if (operation == "upload") { - - // fileInput = await fs.readFile("./remote.7z"); - // await fetch("https://filebin.net/plrho4w60pe25pae/SR_24-06-10_01-35.7z", { - // body: fileInput, - // headers: { - // Accept: "application/json", - // "Content-Type": "application/octet-stream" - // }, - // method: "POST" - // }); - // } } main(process.argv); \ No newline at end of file