Satisfied (WIP)
Satisfied is a 2D factory planner tool for the Satisfactory.
This is a work in progress, and not usable yet.
Quick start
For now, you need to build the project yourself.
Building from source
Windows
I would recommend using w64devkit to setup the build environment on windows.
Extract it as instructed in the README, and add the .../w64devkit/bin
folder to your PATH
environment variable.
Not tested but it should work; it may need some tweaks, (at least for the icon).
Refers to the raylib-go instructions for your platform.
Debug build
go build
Release build
CGO_CPPFLAGS="-O3 -DNDEBUG -flto" go build -ldflags="-s -w -H=windowsgui"
Security / Privacy
This application does not collect any data, is 100% offline, does not read any file other than
the project files (.satisfied) you select.
Usage
Usage: satisfied.exe [options] [FILE]
FILE is an optional path to a satisfied project file to load.
Options:
--fps (int) Target / Max FPS (default 30)
(use a low value when using -vv to reduce the ammount of logs)
-q WARN verbosity
-v DEBUG verbosity
-vv TRACE verbosity
Why this project?
I'm learning Go and I had wanted to play with Raylib.
When I started to write this tool, Coffe Stain Studios had announced the release of the much awaited
1.0 version of Satisfactory.
I have few hundreds of hours on the game and never found a tool/way to plan my factories the way I wanted so I decided to write one.
This is more of a learning & personal project right now, so use it at your own risk.
V1 Features Roadmap
- Infinite grid canvas
- Place buildings
- Draw paths (belt and pipes)
- Snap to grid (resolution of 1 game meter)
- Rotate by 90° increments
- Single / multi selection
- Click and drag to move selection
- Delete selection
- Undo / redo (may be buggy, hard to reproduce)
- Move paths by their ends
- Save and load projects
- Complete buildings list for Production / Power / Logistics related buildings
- Scroll bar in side panel
- Keybindings displayed somewhere (status bar or popup)
- Logs/crash reports (logging is mostly done in the console, need to save a log file on crash)
- Free text box tool (text area GUI could use some improvements)
Other goals
A list of features that may or may not happen in the future.
- Add gifs to README
- Foundations: add foundations & foundation mode
- Add cache file (window size/pos, last opened projects, recent projects)
- Reasonable performances (~30fps and low GPU usage for < 1000 buildings on screen)
- Maybe use a render texture for all buildings ?
- Make side panels collapsible
- Add / remove to selection
- Add / remove single object to selection by ctrl/shift + click
- Add / remove rectangle to selection by ctrl/shift + drag
- Selector filter: allows to select / deselect a specific type of object
- Add train tracks ?
- Anchor paths to building inputs / outputs
- Porting to app to the web, Rust + raylib-rs + WASM
- Local storage auto save
- Import / export (to file or clipboard)
- Deploy
- Make it look nice (game icons, texture for each building, nicer UI)
- Quick access bar
- Zones / groups to represents factories and/or production lines
- Add items and recipes
- Add them for planning / display only
- Item cost of factory / selection
- Compute production (static)
- Settings / customization (only if this is used by anyone other than me)
- Keyboard layout handling (at least AZERTY + QWERTY)
- Remap keybindings
- Change fonts / colors
- Depth support: could be a system of layers ?
Design / Architecture
The application is written in Go and uses Raylib for rendering.
I use a slightly modified version of raylib-go bindings
(check out the original here).
I also rely on tinyfiledialogs with custom bindinds,
to display files and message native dialogs.
The codebase is split into files by topic; each of them may contains update and/or draw logic.
TODO: Update this part: - new files - Kbd/mouseInput -> GetAction
-> action -> Dispatch
-> doXXX
methods - Dispatch
bypass: GetAction
directly calls doXXX
methods
main package
main.go
: entry point, contains the render loop, calls into app/app.go
app package (most of the code)
-
app/app.go
: defines the main functions:
Init()
: initializes the application & creates a window
Close()
: destroys the window and cleans up resources
Step()
: the render loop body, performs updates and draw a frame
Update()
: updates the application state based on mouse and keyboard input(s)
Draw()
: draws the scene without updating the state
DrawGUI()
: draws the GUI and may update the state based on GUI controls events
-
app/appMode.go
: AppMode enum definition and methods and appMode state variable
-
app/drawState.go
: DrawState enum definition and methods (normal, new, selected, hovered, shadow, ...)
-
app/assets.go
: static assets (fonts, buildings definitions, etc.)
-
app/gui.go
: GUI (topbar, sidebar, statusbar) related code
Draw() GuiEvent
: draws the GUI and returns an GUI event
update only
app/animations.go
: animations timers
app/dims.go
: Screen and scene dimensions
app/mouse.go
: holds mouse state (position, button press, down, release, ...)
app/keyboard.go
: holds keyboard state (pressed key, shift, ctrl, alt, ...)
app/camera.go
: camera state (position, zoom, rotation)
Update()
: updates the camera state based on mouse and keyboard input
BeginMode2D()
: starts a 2D camera mode
EndMode2D()
: ends a 2D camera mode
WorldPos()
: converts a screen position to a world position
ScreenPos()
: converts a world position to a screen position
draw only
app/grid.go
: grid drawing code
app/scene.go
: holds the scene objects (buildings and pipes) and some helper functions
Draw()
: draws the 'normal' scene objects (those not handled in other places)
app/buildings.go
: buildings struct and drawing code
Draw(DrawState)
: draws the building in a given state
app/path.go
: paths (belts and pipes) struct and drawing code
Draw(DrawState)
: draws the path in a given state (normal, new, selected, hovered, shadow, ...)
app mode specific; update and draw
app/newobj.go
: handles placing a new buildings
Update()
: move/rotate the new object(s) to be placed, on click add them to the scene
Draw()
: draw the new object(s) to be placed following the mouse
app/selector.go
: handles creating an selection and hovering
Update()
: find hovered object, create a selection (-> selection.go
)
Draw()
: draw the hovered object and the selection rectangle
app/selection.go
: handles the selection
Update()
: manipulate the selection, delete, duplicate (-> newobj.go
), drag and move/rotate
Draw()
: draw the selected objects, the bounding box, the shadow of the original object when dragging
other packages
matrix
: 3x3 transform matrix (translation, rotation, scaling)
colors
: color palette
math32
: some math functions on float32
(std math
only supports float64
)
log
: logging package, with a colored terminal handler and an extra Trace
level
Each of the update related files usually defines a main struct representing its topic state,
and instanciate a global variable of that type, (eg: in mouse.go
, there is a Mouse
struct and a mouse
global variable of that type).
As most of the code belongs to the main
, we avoid cyclic dependencies and passing state around
(eg: the mouse
variable is available anywhere in the codebase) which makes for a consise code.
But we also need extra care on how we update those variable state to keep the data flow reasonable.
Because the codebase is mainly a single package, every variable, functions, and types are accessible from anywhere.
I use exported indentifier as a indication that it is safe to access from outside its file
(exceptions includes the global variable).
Dependencies
License
This project is licensed under the GNU Affero General Public License v3.0.