Copyright (c) 2024-2026 GreyHak
A set of Python tools for parsing Satisfactory save files, and then displaying and manipulating the contents. Supports Satisfactory release v1.2.0.0.
Satisfactory is a non-competitive, first-person, open-world, factory-building and exploration game produced by Coffee Stain Studios.
Table of Contents:
- sav_parse.py - Parser script
- sav_to_resave.py - Save generation script
- sav_cli.py - Save editor CLI
- sav_to_html.py - HTML and Map generator
- sav_monitor.py - Automation for sav_to_html.py
- Support for older save files
- Credits and Thanks
- License
sav_parse.py will decode the save file. It can be used as either a library
or a program.
When used as a library, call sav_parse.readFullSaveFile(filename: str) to
parse the entire save file, or sav_parse.readSaveFileInfo(filename: str) to
parse just the header information.
When used as a program, from the command line call py sav_parse.py <filename>
to generate a text file representation of the save file.
sav_to_resave.py will create a save file based on the data producted by
sav_parse.py or a manipulated varient of that data. The interface is
saveFile(parsedSave: sav_parse.ParsedSave, outFilename: str) where
the first parameter are the variable returned by sav_parse.readSaveFileInfo.
sav_cli.py makes use of sav_parse.py and sav_to_resave.py to either
provide specific information from the save file or change data in a save file.
Usage:
py sav_cli.py --helppy sav_cli.py --info <save-filename>py sav_cli.py --to-json <save-filename> <output-json-filename>py sav_cli.py --from-json <input-json-filename> <new-save-filename>py sav_cli.py --set-session-name <new-session-name> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --find-free-stuff [item] [save-filename]py sav_cli.py --list-players <save-filename>py sav_cli.py --list-player-inventory <player-num> <save-filename>py sav_cli.py --find-node <x> <y> [save-filename]py sav_cli.py --find-node-near <player-num> <save-filename>py sav_cli.py --set-node <name> <type> <purity> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --export-node-types <save-filename> <output-json-filename>py sav_cli.py --import-node-types <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --export-player-inventory <player-num> <save-filename> <output-json-filename>py sav_cli.py --import-player-inventory <player-num> <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --tweak-player-inventory <player-num> <slot-index> <item> <quantity> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --rotate-foundations <primary-color-hex-or-preset> <secondary-color-hex-or-preset> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --clear-fog <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --export-hotbar <player-num> <save-filename> <output-json-filename>py sav_cli.py --import-hotbar <player-num> <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --change-num-inventory-slots <num-inventory-slots> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --restore-somersloops <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --restore-mercer-spheres <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --export-somersloops <save-filename> <output-json-filename>py sav_cli.py --export-mercer-spheres <save-filename> <output-json-filename>py sav_cli.py --import-somersloops <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --import-mercer-spheres <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --remember-username <player-num> <username-alias>py sav_cli.py --list-vehicle-paths <save-filename>py sav_cli.py --export-vehicle-path <path-name> <save-filename> <output-json-filename>py sav_cli.py --import-vehicle-path <path-name> <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --export-dimensional-depot <save-filename> <output-json-filename>py sav_cli.py --reorder-dimensional-depot <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --adjust-dimensional-depot <original-save-filename> <item-name> <new-quantity> <new-save-filename> [--same-time]py sav_cli.py --export-crash-sites <save-filename> <output-json-filename>py sav_cli.py --dismantle-crash-site <drop-pod-name> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --list-map-markers <save-filename>py sav_cli.py --export-map-markers <save-filename> <output-json-filename>py sav_cli.py --remove-marker <marker-guid> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --add-map-markers-json <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --add-map-markers-somersloops <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --add-map-markers-mercer-spheres <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --add-map-markers-hard-drives <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --add-map-markers-collectable <item> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --show <save-filename>py sav_cli.py --blueprint --sort <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --export <save-filename> <output-json-filename>py sav_cli.py --blueprint --import <original-save-filename> <input-json-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --add-category <category> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --add-subcategory <category> <subcategory> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --add-blueprint <category> <subcategory> <blueprint> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --remove-category <category> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --remove-subcategory <category> <subcategory> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --remove-blueprint <category> <subcategory> <blueprint> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --move-blueprint <old-category> <old-subcategory> <new-category> <new-subcategory> <blueprint> <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --blueprint --reset <original-save-filename> <new-save-filename> [--same-time]py sav_cli.py --resave-only <original-save-filename> <new-save-filename>py sav_cli.py --add-missing-items-to-sav_stack_sizespy sav_cli.py --list-crash-site-guards
If --find-free-stuff is used inconjunction with sav_to_html.py and a blank
map, it will generate a map of all the locations for the specified item.
With v1.0.0.4 release, there isn't much point to the --blueprint --sort
operation since the game's reverse-sorting is performed on save-open time.
sav_to_html.py can be used as either a library or a program.
Command line: py sav_to_html.py <save-filename> [output-html-directory]
Library: sav_to_html.generateHTML(savFilePath: str, outputDirectory: str, htmlBaseName: str)
sav_to_html.py makes use of sav_parse.py to decode a save file and creates
a save.html. The HTML page contains:
- Session Name
- Save Date
- Play Time
- Game Phase
- Active Milestone
- Mined Resource Count
- Collected Power Slugs, Somersloops, and Mercer Sphere Counts
- Unopened, Looted, and Opened/Unlooted Hard Drive Counts
- Unlock Progress Counts
- Sink Point Progress
- Dimensional Depot Contains: List by item with quantity and percent full
- Currently Built Items: List of items by quantity
When a blank map, included in the release as blank_map20.png,
is provided, this script also creates maps of:
- The location of all the remaining power slugs.
- The location of all the remaining somersloops.
- The location of all the remaining mercer spheres.
- The location of all the hard drives including which are opened, looted and opened/unlooted.
- The power grid.
- The resource nodes including their type, locations, purity, and usage.
The map size can be increased or decreased by changing two things.
blank_map20.png is 2048x2048. The "20" in the filename is a scale,
configured in sav_to_html.py by the variable MAP_DESCALE. The size is
relative to a scale of 1 representing 40960x40960. So 2048 = 40960 / 20.
A slightly larger map than the default could be MAP_DESCALE = 16 and a
2560x2560 blank_map16.png. You can either manually resize blank_map20.png
yourself, or contact grey.hak on Discord or submit an Issue request on github.
The maps get labeled using the .ttf font file defined in sav_to_html.py by the variable
FONT_FILENAME. On Linux this defaults to /usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf.
On Windows this defaults to C:\Windows\Fonts\DejaVuSerif.ttf. If neither of
these files are available on your system, you can obtain a .ttf font file from
https://github.com/kiwi0fruit/open-fonts.
- Somersloops and Mercer Spheres are solid circles.
Somersloops are red
and Mercer Spheres are dark purple
.
- Slugs are non-solid circle outlines;
blue,
yellow and
purple.
- The size of the circle is smaller if the node is mined, and larger if the node is unused.
- The center color represents the node purity;
for impure,
for normal,
for pure
- The outline color represents the node type;
Usage: py sav_monitor.py [save-directory] [html-output-directory] [monitor-period] [archive-directory] [sheets-config] [save-pattern] [game-save-name]
sav_monitor.py will check for new save files, generate html/png summary of
new save files, and optionally archive the save files.
[save-directory] defaults to .config/Epic/FactoryGame/Saved/SaveGames/server
or %LOCALAPPDATA%/FactoryGame/Saved/SaveGames/*. The [save-directory] must
exist for the monitor to start.
[html-output-directory] defaults to the current-working-directory. HTML and
map generation is only performed if the provided [html-output-directory] exists.
[monitor-period] is the rate in seconds that the monitor looks for new saves.
The default [monitor-period] is 1.0 second. Settings between 0.2 and 120.0
would be completely reasonable.
Archiving is only performed if the [archive-directory] is provided and exists.
You can also place monitor settings in a .env file in the project folder.
The monitor reads this file at startup.
SAV_GAME_SAVE=Stinkyfilters to files likeStinky_YYMMDD-HHMMSS.savand chooses the newest one.SAV_SHEETS_CONFIG=sheets_config.jsonsets the Sheets config path.SAV_SAVE_PATTERN=*.savsets the save filename glob.
See .env.example for a starter template.
If you want to run the monitor without opening VS Code:
- Double-click
start_monitor.bat. - To stop it later, double-click
stop_monitor.bat.
If you want a small control app with Start/Stop buttons and a save-title input:
- Double-click
monitor_control.bat. - Enter a save title (optional), for example
Stinky. - Click
StartorStop.
The save title sets SAV_GAME_SAVE for that monitor process only, so it filters
to filenames like Stinky_YYMMDD-HHMMSS.sav.
What these do:
start_monitor.batrunsstart_monitor.ps1, which startssav_monitor.pyin the background.- The monitor PID is stored in
sav_monitor.pid. - Output logs are written to
sav_monitor.logandsav_monitor.err.log. stop_monitor.batrunsstop_monitor.ps1, which stops the running monitor process.
Tip: Create desktop shortcuts to start_monitor.bat and stop_monitor.bat for true one-click control.
For a single desktop shortcut app:
- Right-click
monitor_control.batand choose "Show more options" -> "Send to" -> "Desktop (create shortcut)". - Launch from that desktop shortcut whenever you want to control the monitor.
If you want a local JS-powered desktop app (no browser tabs), use the Electron app in desktop-app.
Persistent settings: The app saves your inputs (save title, HTML output directory, monitor interval) to local storage. Next time you launch, your previous settings are pre-filled—just click Start.
Important: The monitor only reacts to new save files created after it starts. If you run it but don't save the game, no HTML will be generated. Save your game in Satisfactory to trigger output.
Quick start:
- Double-click
launch_monitor_desktop.bat. - Enter your save title filter (optional).
- Enter HTML output directory (optional) if you want to save generated files elsewhere.
- Set monitor check interval in seconds (defaults to 60).
- Click Start.
All your settings are automatically saved and will be there next time you launch.
Manual run:
cd desktop-appnpm installnpm run start
Build a standalone Windows executable:
cd desktop-appnpm installnpm run dist
This creates a portable .exe in desktop-app/dist that runs fully local on your PC.
The main branch and latest release supports Satisfactory release v1.2.0.0.
The main branch and latest release of sav_parse.py and save_to_resave.py
scripts also support releases v1.1.1.6, v1.1.1.7, v1.1.2.0, v1.1.2.1,
v1.1.2.2, v1.1.3.0, and v1.1.3.1, but the supporting sav_data, and therefore
the tools sav_cli.py, sav_to_html.py and sav_monitor.py are not
supported. If you want sav_cli.py or sav_to_html.py for these, please use
release v1.14.
For v1.0.0.7, please use release v1.6.
For v1.0.0.4, please use release v1.5.
For v1.0.0.3, please use release v1.1.
The source code in this repo was developed by GreyHak.
Source code credit for the the quaternion/euler rotation conversions used by
sav_cli.py goes to Addison Sears-Collins.
Thanks go to AnthorNet of Satisfactory Calculator Interactive Map fame.
- The map used by
sav_to_html.pyis a modified version of the map extracted from Anthor's Interactive Map. - Resource purities, available in the
sav_parse.pyRESOURCE_PURITY variable, used bysav_to_html.py, were extracted from Anthor's Interactive Map. - Anthor's pre-Update-8 JavaScript code was used as a reference.
- Anthor's Interactive Map was also a great test tool to verify the save files
produced by
sav_to_resave.pyandsav_cli.py.
Thanks go to the Wiki authors who documented the old, but still very helpful, v0.6.1.3 version of the save file format at Satisfactory GG Wiki Save Files. I updated the Satisfactory GG Wiki for v1.0.0.4 based on the information I gained during creation of this tools.
Huge thanks to Moritz for explaining how the UE5 versioning impacted the 1.2.0.0 (58) save file format.
Thanks to robison4th, JP Eagles and Katz, Buggy, Tomtores, Mattigins, and TheRealBeef for sharing their save files to allow for expanded support.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

























