Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
283410617e | ||
|
|
7eb9916fea | ||
|
|
50d5fbee05 | ||
|
|
071ab25fa7 | ||
|
|
1b67c96c8c | ||
|
|
b037722432 | ||
|
|
b9d0eb6afd | ||
|
|
dee80627cd | ||
|
|
0fd7866e24 |
No files matched your search
+3
-1
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(AutoSave VERSION 1.0.0)
|
project(AutoSave VERSION 1.2.1)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "-static -static-libgcc -static-libstdc++ -Wall -Werror")
|
set(CMAKE_CXX_FLAGS "-static -static-libgcc -static-libstdc++ -Wall -Werror")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2 -DTSFUNCS_DEBUG=false")
|
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2 -DTSFUNCS_DEBUG=false")
|
||||||
@@ -54,4 +54,6 @@ target_link_libraries(${CMAKE_PROJECT_NAME}
|
|||||||
${TSFUNCS_LIB}
|
${TSFUNCS_LIB}
|
||||||
minhook
|
minhook
|
||||||
psapi
|
psapi
|
||||||
|
gdiplus
|
||||||
|
shlwapi
|
||||||
)
|
)
|
||||||
@@ -8,6 +8,8 @@ The files use the stock `.bls` format and can be loaded from the normal load scr
|
|||||||
|
|
||||||
Place `AutoSave.dll` in the game's `modules` folder, then quit and start Blockland from Steam. A DLL that is already loaded stays mapped until that restart.
|
Place `AutoSave.dll` in the game's `modules` folder, then quit and start Blockland from Steam. A DLL that is already loaded stays mapped until that restart.
|
||||||
|
|
||||||
|
AutoSave installs its scripts from a timer on the game's main loop. It does not patch the console's `evaluate` function, so modules that load after it and look that function up by its first bytes keep working. The console shows `AutoSave: /autosaver is ready` once the chat command is in.
|
||||||
|
|
||||||
It only saves while this game is the server: a local single-player or multiplayer host, or a dedicated server.
|
It only saves while this game is the server: a local single-player or multiplayer host, or a dedicated server.
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
@@ -16,22 +18,44 @@ Each save is named for the local time it started, for example `saves/autosave/20
|
|||||||
|
|
||||||
The save is written to `saves/autosave/writing.bls.tmp` and renamed when it is complete, so a crash or cancel never leaves a half-written `.bls`. Old autosaves are not deleted.
|
The save is written to `saves/autosave/writing.bls.tmp` and renamed when it is complete, so a crash or cancel never leaves a half-written `.bls`. Old autosaves are not deleted.
|
||||||
|
|
||||||
`$pref::SaveOwnership` and `$pref::SaveExtendedBrickInfo` are followed the same way the stock save follows them. No screenshot is taken.
|
`$pref::SaveOwnership` and `$pref::SaveExtendedBrickInfo` are followed the same way the stock save follows them.
|
||||||
|
|
||||||
|
## Preview picture
|
||||||
|
|
||||||
|
Each save gets a picture next to it with the same name, for example `saves/autosave/2026-10-26 00-29-28.jpg`. That is the file the load screen shows for a save.
|
||||||
|
|
||||||
|
The picture comes from the server preview: the overhead view the game traces for the server list. It is a 768x768 image traced a few pixels per tick on the server, so it works on a dedicated server with no camera. A preview centered with `/setPreviewCenter` keeps that center.
|
||||||
|
|
||||||
|
- The engine traces at most 128 pixels per tick. While a picture is wanted, AutoSave also traces pixels itself through the same engine function, 6 ms at a time with a 12 ms pause, and stops while a save is being written. The engine traces the last pixel, so its normal finish still produces the image.
|
||||||
|
- If nothing is tracing, AutoSave starts the tracer at the engine's top rate (128 work per tick instead of the default 64). When the picture is done, AutoSave stops the tracer, puts the rate back, and nothing is uploaded.
|
||||||
|
- If the game is already tracing its own preview (an internet server does this all the time), AutoSave helps that image along and keeps a copy. The game's upload to the server list is not changed.
|
||||||
|
- The console shows the progress every 30 seconds and the time taken, and the chat says when the picture is saved. If the game quits first, that save has no picture. Clearing all bricks stops the tracer, so that save has no picture either.
|
||||||
|
- If another save finishes while a picture is still being traced, the picture goes to the newest save.
|
||||||
|
|
||||||
|
`/autosaver screenshot off` turns this off. The setting is saved with the other prefs, so it stays off after a restart.
|
||||||
|
|
||||||
## When it saves
|
## When it saves
|
||||||
|
|
||||||
The first save after starting always runs. After that, a save is skipped if nothing changed. Planting, loading, removing or killing a brick counts as a change. So does adding or clearing events, renaming a brick, and changing its color, paint effect, shape effect, print, collision, raycasting, rendering, light, emitter, item, music, sound or vehicle.
|
The first save after starting always runs. After that, a save is skipped if nothing changed. Planting, loading, removing or killing a brick counts as a change. So does adding or clearing events, renaming a brick, and changing its color, paint effect, shape effect, print, collision, raycasting, rendering, light, emitter, item, music, sound or vehicle.
|
||||||
|
|
||||||
|
While bricks are loading, the per-brick change checks are skipped, and a finished or cancelled load counts as one change.
|
||||||
|
|
||||||
|
The game turns off packages added after the client add-ons when a server shuts down, which includes AutoSave's change watcher. AutoSave installs it again afterwards, and the first save on each new server always runs.
|
||||||
|
|
||||||
A save is also skipped while bricks are loading, while bricks are being cleared, and while the mission is being cleaned up. If a load or a clear starts in the middle of a save, the save stops, its temp file is removed, and the next interval tries again.
|
A save is also skipped while bricks are loading, while bricks are being cleared, and while the mission is being cleaned up. If a load or a clear starts in the middle of a save, the save stops, its temp file is removed, and the next interval tries again.
|
||||||
|
|
||||||
## Large builds
|
## Large builds
|
||||||
|
|
||||||
Each slice handles up to the chunk size and stops after 8 ms, then waits at least 12 ms before the next slice. Progress is written to the console every 2 seconds.
|
Each slice handles up to the chunk size and stops after 8 ms, then waits at least 12 ms before the next slice. Progress is written to the console every 2 seconds.
|
||||||
|
|
||||||
|
Brick values the stock loader sets as fields (angle, baseplate, color, print, color and shape effect, position) are read as fields instead of through method calls. Field names are looked up once, and each datablock's name and print flag are cached per save. The first 64 bricks of each save are also read through the methods; if anything differs, the console says so and the methods are used until the game restarts.
|
||||||
|
|
||||||
Up to 75000 bricks, bricks are sorted by height like the stock save. Over 75000, the sort and the wrench-extras pass are skipped and the file is written in one pass. The brick count in the header is filled in when the write finishes.
|
Up to 75000 bricks, bricks are sorted by height like the stock save. Over 75000, the sort and the wrench-extras pass are skipped and the file is written in one pass. The brick count in the header is filled in when the write finishes.
|
||||||
|
|
||||||
## Chat commands
|
## Chat commands
|
||||||
|
|
||||||
|
`/as` is short for `/autosaver` and works with every command below, for example `/as save` or `/as load 08-55-15`.
|
||||||
|
|
||||||
Anyone can use:
|
Anyone can use:
|
||||||
|
|
||||||
- `/autosaver help`
|
- `/autosaver help`
|
||||||
@@ -42,20 +66,53 @@ Admins can use:
|
|||||||
- `/autosaver on` and `/autosaver off`
|
- `/autosaver on` and `/autosaver off`
|
||||||
- `/autosaver save` (or `now`): save right away
|
- `/autosaver save` (or `now`): save right away
|
||||||
- `/autosaver load` (or `reload`): clear all bricks, then load the newest file in `saves/autosave/`
|
- `/autosaver load` (or `reload`): clear all bricks, then load the newest file in `saves/autosave/`
|
||||||
|
- `/autosaver load <name>`: clear all bricks, then load that autosave instead, for example `/autosaver load 2026-10-26 08-55-15`
|
||||||
- `/autosaver interval <seconds>`: 30 to 86400, default 300
|
- `/autosaver interval <seconds>`: 30 to 86400, default 300
|
||||||
- `/autosaver chunk <bricks>`: bricks per slice, 1 to 20000, default 4000
|
- `/autosaver chunk <bricks>`: bricks per slice, 1 to 20000, default 4000
|
||||||
- `/autosaver tick <milliseconds>`: pause between slices, 1 to 1000, default 1 (never less than 12 ms in practice)
|
- `/autosaver tick <milliseconds>`: pause between slices, 1 to 1000, default 1 (never less than 12 ms in practice)
|
||||||
|
- `/autosaver screenshot on` or `off` (also `screenshots` or `preview`): picture for each save, default on
|
||||||
|
- `/autosaver autoload on` or `off`: load the newest autosave when a server starts, default off
|
||||||
|
|
||||||
Out-of-range values are clamped. Changes are announced to everyone. They are not stored, so the defaults return when the game restarts.
|
Out-of-range values are clamped. Changes are announced to everyone and saved right away.
|
||||||
|
|
||||||
`load` uses the file with the newest modified time on disk, including saves made since the game started. It loads with saved ownership and exact colors. The command is case-insensitive.
|
`load` with no name uses the file with the newest modified time on disk, including saves made since the game started. With a name, `.bls` is optional, case does not matter, and any part of the name works if only one autosave matches it (`/autosaver load 08-55-15`). If several match, nothing is cleared and you are told how many. Names cannot point outside `saves/autosave/`. Either way it loads with saved ownership and exact colors. The command is case-insensitive.
|
||||||
|
|
||||||
|
## Autoload
|
||||||
|
|
||||||
|
With autoload on, the newest file in `saves/autosave/` is loaded when a server starts, with saved ownership and exact colors, the same as `/autosaver load`. It waits until the mission is running. It is skipped, with a console line saying why, when:
|
||||||
|
|
||||||
|
- a game mode is running (game modes bring their own build);
|
||||||
|
- a save was picked when the server was set up, or bricks are already loaded or loading;
|
||||||
|
- there is no autosave.
|
||||||
|
|
||||||
|
The loaded build counts as already saved, so the next interval does not write the same build again.
|
||||||
|
|
||||||
|
## Preferences
|
||||||
|
|
||||||
|
Settings are server prefs, stored in `config/server/prefs.cs` with the game's other server prefs:
|
||||||
|
|
||||||
|
```
|
||||||
|
$Pref::Server::AutoSave::AutoLoad = 0;
|
||||||
|
$Pref::Server::AutoSave::Chunk = 4000;
|
||||||
|
$Pref::Server::AutoSave::Enabled = 1;
|
||||||
|
$Pref::Server::AutoSave::Interval = 300;
|
||||||
|
$Pref::Server::AutoSave::Preview = 1;
|
||||||
|
$Pref::Server::AutoSave::Tick = 1;
|
||||||
|
```
|
||||||
|
|
||||||
|
They are read each time a server starts. AutoSave checks every 5 seconds for a new server, which it tells apart by the mission's `MissionGroup`, so stopping one server and starting another is noticed even within one save interval. The save timer restarts with each new server. If a pref is missing, the default is used and added to the file the next time the game writes its prefs.
|
||||||
|
|
||||||
|
Every `/autosaver on`, `off`, `interval`, `chunk`, `tick`, `screenshot` and `autoload` writes `prefs.cs` right away, using the same export the game runs when custom game settings change. AutoSave only writes the file while a server is running, after the game has loaded it, so other prefs are kept. You can also edit the lines while the game is closed. Values out of range are clamped the same way as in chat.
|
||||||
|
|
||||||
## Console
|
## Console
|
||||||
|
|
||||||
- `autoSave()` starts a save now
|
- `autoSave()` starts a save now
|
||||||
- `autoSaveNewest()` returns the newest autosave path
|
- `autoSaveNewest()` returns the newest autosave path
|
||||||
- `autoSaveApply()` clamps the settings and restarts the timer
|
- `autoSaveFind(name)` returns the autosave path for a name, `*N` if N files match, or nothing
|
||||||
- `$AutoSave::Enabled`, `$AutoSave::Interval`, `$AutoSave::Chunk`, `$AutoSave::Tick`
|
- `autoSaveApply()` clamps the settings, copies them to `$Pref::Server::AutoSave::*`, writes `config/server/prefs.cs` while hosting, and restarts the timer
|
||||||
|
- `$AutoSave::Enabled`, `$AutoSave::Interval`, `$AutoSave::Chunk`, `$AutoSave::Tick`, `$AutoSave::Preview`, `$AutoSave::AutoLoad` are the live values
|
||||||
|
|
||||||
|
A value set on `$AutoSave::*` in the console is not saved, and a new interval does not take effect, until `autoSaveApply()` is called.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
@@ -70,6 +127,4 @@ cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_POLICY_VERSION_MIN
|
|||||||
cmake --build build
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
The result is `build/AutoSave.dll`. CMake is set so the filename has no `lib` prefix. The link line is tsfuncs, MinHook and `psapi`, with static libgcc and libstdc++.
|
The result is `build/AutoSave.dll`. CMa
|
||||||
|
|
||||||
Source is `src/main.cpp` and `CMakeLists.txt`. The current DLL is attached to the v1.0.0 release.
|
|
||||||
+1030
-154
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user