From 74a02b1f99ae78280f3b5ec3386cfdf05903736c Mon Sep 17 00:00:00 2001
From: FabianK3 <21039694+FabianK3@users.noreply.github.com>
Date: Wed, 22 Apr 2026 22:21:39 +0200
Subject: [PATCH] Fix persistence on non-Horizon and admin persistence toggle
admin verb (#22301)
# Summary
This PR fixes persistence on non-Horizon maps and adds an admin verb to
toggle saving at round end.
## Changes
- Fixed persistency being used on non-Horizon maps, prevents loading and
saving.
- Added admin verb "Toggle persistence" to prevent saving at round end.
## Verb preview
Verb location
Input to disable
Disable output
Input to re-enable
Re-enable output
---------
Signed-off-by: FabianK3 <21039694+FabianK3@users.noreply.github.com>
Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
---
.github/workflows/byond.yml | 159 ++++++++++--------
.../subsystems/persistence/persistence.dm | 39 ++++-
.../persistence/persistence_objects.dm | 10 ++
.../persistence/persistence_objects_public.dm | 2 +-
code/modules/admin/admin_verbs.dm | 3 +-
...abiank3-fix-persistence-on-non-horizon.yml | 7 +
6 files changed, 147 insertions(+), 73 deletions(-)
create mode 100644 html/changelogs/fabiank3-fix-persistence-on-non-horizon.yml
diff --git a/.github/workflows/byond.yml b/.github/workflows/byond.yml
index abeb258dfb3..3c0012a9ce5 100644
--- a/.github/workflows/byond.yml
+++ b/.github/workflows/byond.yml
@@ -4,18 +4,18 @@ on:
workflow_dispatch:
merge_group:
branches:
- - master
+ - master
push:
branches:
- - master
+ - master
pull_request:
branches:
- - master
+ - master
env:
MACRO_COUNT: 0
GENDER_COUNT: 6
- TO_WORLD_COUNT: 176
+ TO_WORLD_COUNT: 178
#These variables are filled from dependencies.sh inside the steps, DO NOT SET THEM HERE
BYOND_MAJOR: ""
@@ -40,10 +40,9 @@ concurrency:
cancel-in-progress: true
jobs:
-
-###########################################
-################# BASH/AWK ################
-###########################################
+ ###########################################
+ ################# BASH/AWK ################
+ ###########################################
validate-structure:
name: Validate Structure
outputs:
@@ -56,7 +55,6 @@ jobs:
cancel-in-progress: true
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -121,9 +119,9 @@ jobs:
echo "Continuing with CI."
fi
-###########################################
-############### EditorConfig ##############
-###########################################
+ ###########################################
+ ############### EditorConfig ##############
+ ###########################################
megalinter:
name: Validate EditorConfig Compliance
runs-on: ubuntu-24.04
@@ -143,7 +141,6 @@ jobs:
APPLY_FIXES_MODE: commit
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -177,10 +174,9 @@ jobs:
mega-linter.log
retention-days: 5
-
-###########################################
-############### SPACEMANDMM ###############
-###########################################
+ ###########################################
+ ############### SPACEMANDMM ###############
+ ###########################################
lint-spacemandmm:
name: Lint SpacemanDMM
runs-on: ubuntu-24.04
@@ -192,7 +188,6 @@ jobs:
cancel-in-progress: true
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -224,10 +219,9 @@ jobs:
with:
outputFile: output-annotations.txt
-
-###########################################
-################ OPENDREAM ################
-###########################################
+ ###########################################
+ ################ OPENDREAM ################
+ ###########################################
lint-opendream:
name: Lint OpenDream
runs-on: ubuntu-24.04
@@ -239,7 +233,6 @@ jobs:
cancel-in-progress: true
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -266,9 +259,9 @@ jobs:
run: |
dotnet $HOME/DMCompiler_linux-x64/DMCompiler.dll --suppress-unimplemented aurorastation.dme
-###########################################
-############### TGUI LINTING ##############
-###########################################
+ ###########################################
+ ############### TGUI LINTING ##############
+ ###########################################
lint-tgui:
name: Lint TGUI
runs-on: ubuntu-24.04
@@ -280,7 +273,6 @@ jobs:
cancel-in-progress: true
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -294,7 +286,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION_LTS }}
- cache: 'yarn'
+ cache: "yarn"
cache-dependency-path: tgui/yarn.lock
#Lint TGUI
@@ -302,10 +294,9 @@ jobs:
run: |
tools/build/build --ci lint tgui-test
-
-###########################################
-############### MISC LINTING ##############
-###########################################
+ ###########################################
+ ############### MISC LINTING ##############
+ ###########################################
lint-misc:
name: Lint Misc
runs-on: ubuntu-24.04
@@ -317,7 +308,6 @@ jobs:
cancel-in-progress: true
steps:
-
#Checkout the repository
- name: Checkout repository
uses: actions/checkout@v4
@@ -331,7 +321,7 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- cache: 'pip'
+ cache: "pip"
#Install python packages and tools
- name: Install Python Packages
@@ -356,14 +346,21 @@ jobs:
tools/bootstrap/python -m mapmerge2.dmm_test
tools/bootstrap/python -m tools.maplint.source
-###########################################
-############## GENERIC TESTS ##############
-###########################################
+ ###########################################
+ ############## GENERIC TESTS ##############
+ ###########################################
generic-tests:
name: Generic Tests
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -387,7 +384,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
@@ -495,14 +491,21 @@ jobs:
path: ./data/logs/**/condensed.log
retention-days: 5
-###########################################
-########### CREATE AND DESTROY ############
-###########################################
+ ###########################################
+ ########### CREATE AND DESTROY ############
+ ###########################################
create-and-destroy:
name: Create and Destroy Test
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -526,7 +529,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
@@ -634,16 +636,21 @@ jobs:
path: ./data/logs/**/condensed.log
retention-days: 5
-
-
-###########################################
-################ TEST MAPS ################
-###########################################
+ ###########################################
+ ################ TEST MAPS ################
+ ###########################################
map-tests:
name: Run Map Tests
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -667,7 +674,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
@@ -775,16 +781,21 @@ jobs:
path: ./data/logs/**/condensed.log
retention-days: 5
-
-
-###########################################
-############# EXOPLANETS TESTS ############
-###########################################
+ ###########################################
+ ############# EXOPLANETS TESTS ############
+ ###########################################
exoplanet_testing:
name: Run Exoplanet Tests
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -808,7 +819,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
@@ -916,15 +926,21 @@ jobs:
path: ./data/logs/**/condensed.log
retention-days: 5
-
-###########################################
-############# TEST AWAY SITES #############
-###########################################
+ ###########################################
+ ############# TEST AWAY SITES #############
+ ###########################################
away-sites-tests:
name: Run Map Tests
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -948,7 +964,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
@@ -1056,14 +1071,21 @@ jobs:
path: ./data/logs/**/condensed.log
retention-days: 5
-###########################################
-################ TEST RUINS ###############
-###########################################
+ ###########################################
+ ################ TEST RUINS ###############
+ ###########################################
ruins-tests:
name: Run Ruins Tests
runs-on: ubuntu-24.04
if: ${{ !failure() }}
- needs: [validate-structure, lint-spacemandmm, lint-opendream, lint-tgui, lint-misc]
+ needs:
+ [
+ validate-structure,
+ lint-spacemandmm,
+ lint-opendream,
+ lint-tgui,
+ lint-misc,
+ ]
services:
mariadb:
@@ -1087,7 +1109,6 @@ jobs:
fail-fast: false
steps:
-
- name: "Check if CI or UT ignored"
id: check
if: ${{ needs.validate-structure.outputs.skipci == 'true' || needs.validate-structure.outputs.skiput == 'true' }}
diff --git a/code/controllers/subsystems/persistence/persistence.dm b/code/controllers/subsystems/persistence/persistence.dm
index 5448d95507c..0a364309a92 100644
--- a/code/controllers/subsystems/persistence/persistence.dm
+++ b/code/controllers/subsystems/persistence/persistence.dm
@@ -13,13 +13,14 @@ SUBSYSTEM_DEF(persistence)
name = "Persistence"
init_order = INIT_ORDER_PERSISTENCE // The order is tied with the init and maploading subsystem.
flags = SS_NO_FIRE // This subsystem has no continues workload, it's init and shutdown only.
+ var/prevent_saving = FALSE // Toggle to prevent saving at round end, changed by toggle_persistence proc, used for admin purposes.
/**
* Subsystem info stub message generation.
*/
/datum/controller/subsystem/persistence/stat_entry(msg)
- msg = ("Tracked object register: [length(GLOB.persistence_object_track_register)]")
- return ..()
+ msg = ("Register: [length(GLOB.persistence_object_track_register)] | Prevent saving: [SSpersistence.prevent_saving ? "TRUE" : "FALSE"]")
+ return msg
/**
* Helper method to check and log database connection.
@@ -48,6 +49,36 @@ SUBSYSTEM_DEF(persistence)
return FALSE
return TRUE
+/datum/admins/proc/toggle_persistence()
+ set name = "Toggle Persistence"
+ set category = "Special Verbs"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ var/message = ""
+ var/options = list()
+ if(SSpersistence.prevent_saving)
+ message = "The persistence subsystem will NOT save at the end of the round. Do you want to re-enable it?"
+ options = list("Re-enable saving", "Cancel")
+ else
+ message = "The persistence subsystem will save at the end of the round. Do you want to prevent this? This can be un-done before the round ends."
+ options = list("Prevent saving", "Cancel")
+
+ var/confirm = tgui_alert(usr, message, "Toggle Persistence Saving", options)
+ if(confirm == "Prevent saving")
+ SSpersistence.prevent_saving = TRUE
+ to_world(FONT_LARGE(EXAMINE_BLOCK_RED("Persistence saving at the end of the round has been [SPAN_BOLD(SPAN_WARNING("disabled"))] by an administrator.")))
+ log_and_message_admins("has toggled persistence saving at round end, it is now disabled", usr)
+ else if (confirm == "Re-enable saving")
+ SSpersistence.prevent_saving = FALSE
+ to_world(FONT_LARGE(EXAMINE_BLOCK_RED("Persistence saving at the end of the round has been [SPAN_BOLD(SPAN_GOOD("re-enabled"))] by an administrator.")))
+ log_and_message_admins("has toggled persistence saving at round end, it is now re-enabled", usr)
+ else
+ return
+
+ feedback_add_details("admin_verb","TP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
/**
* Initialization of the persistence subsystem.
* Includes generic startup checks and init of the different persistent data types.
@@ -74,6 +105,10 @@ SUBSYSTEM_DEF(persistence)
* The shutdown consists of finalization steps for each persistent data type.
*/
/datum/controller/subsystem/persistence/Shutdown()
+ if(prevent_saving)
+ log_subsystem_persistence_warning("Persistence subsystem was toggled to not save. Skipping subsystem finalization.")
+ return
+
if(!databaseCheckConnection("subsystem shutdown"))
log_subsystem_persistence_panic("SQL error during persistence subsystem shutdown. Cannot finalise persistence of the round.")
return
diff --git a/code/controllers/subsystems/persistence/persistence_objects.dm b/code/controllers/subsystems/persistence/persistence_objects.dm
index 5e0d8a59e73..24fb3e05665 100644
--- a/code/controllers/subsystems/persistence/persistence_objects.dm
+++ b/code/controllers/subsystems/persistence/persistence_objects.dm
@@ -6,6 +6,10 @@
PRIVATE_PROC(TRUE)
GLOB.persistence_object_track_register = list()
+ if(SSatlas.current_map.path != "sccv_horizon") // The persistence system only supports objects from the main map levels for multiple reasons, e.g. Z level value, mapping support
+ log_subsystem_persistence_info("Persistent objects: Current map did not match SCCV Horizon, skipping persistent object initialization.")
+ return
+
// Delete all persistent objects in the database that have expired and have passed the cleanup grace period (PERSISTENT_EXPIRATION_CLEANUP_DELAY_DAYS)
objectsDatabaseCleanEntries()
@@ -36,6 +40,12 @@
/datum/controller/subsystem/persistence/proc/objectsFinalize()
PRIVATE_PROC(TRUE)
+ if(SSatlas.current_map.path != "sccv_horizon") // The persistence system only supports objects from the main map levels for multiple reasons, e.g. Z level value, mapping support
+ log_subsystem_persistence_info("Persistent objects: Current map did not match SCCV Horizon, skipping persistent object finalization.")
+ if(length(GLOB.persistence_object_track_register) > 0)
+ log_subsystem_persistence_warning("Persistent objects: There are [length(GLOB.persistence_object_track_register)] tracked objects at finalization, while the map is not supported! These track will not be saved! Verify that SSatlas.current_map.path has not changed during the round!")
+ return
+
// Subsystem shutdown:
// Create new persistent records for objects that have been created in the round
// Update tracked objects that have an ID (already existing from previous rounds)
diff --git a/code/controllers/subsystems/persistence/persistence_objects_public.dm b/code/controllers/subsystems/persistence/persistence_objects_public.dm
index 2a3452694b1..391f9ce97fc 100644
--- a/code/controllers/subsystems/persistence/persistence_objects_public.dm
+++ b/code/controllers/subsystems/persistence/persistence_objects_public.dm
@@ -10,7 +10,7 @@
return
var/turf/T = get_turf(new_track)
- if(!T || !is_station_level(T.z)) // The persistence system only supports objects from the main map levels for multiple reasons, e.g. Z level value, mapping support
+ if(!T || !is_station_level(T.z) || SSatlas.current_map.path != "sccv_horizon") // The persistence system only supports objects from the main map levels for multiple reasons, e.g. Z level value, mapping support
return
new_track.persistent_objects_track_active = TRUE
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 48f9c973ae0..cc2a6f8f3f1 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -146,7 +146,8 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/apply_sunstate,
/datum/admins/proc/ccannoucment,
/datum/admins/proc/set_odyssey,
- /datum/admins/proc/set_odyssey_canonicity
+ /datum/admins/proc/set_odyssey_canonicity,
+ /datum/admins/proc/toggle_persistence
))
GLOBAL_LIST_INIT(admin_verbs_spawn, list(
diff --git a/html/changelogs/fabiank3-fix-persistence-on-non-horizon.yml b/html/changelogs/fabiank3-fix-persistence-on-non-horizon.yml
new file mode 100644
index 00000000000..fc17f3e08e1
--- /dev/null
+++ b/html/changelogs/fabiank3-fix-persistence-on-non-horizon.yml
@@ -0,0 +1,7 @@
+author: FabianK3
+
+delete-after: True
+
+changes:
+ - bugfix: "Fixed persistence being used on non-Horizon maps."
+ - rscadd: "Added an admin verb to toggle persistence saving."