Files
Aurora.3/code/__DEFINES/global.dm
802d3fe01f Persistency subsystem update - Generics and history records (#22114)
# Summary

This PR is the next update to the persistency subsystem. The goal of
this PR is to provide more framework like functions to allow more types
of content to be made persistent.

Currently only volatile game objects created during a round can be (*in
a [clean](https://www.youtube.com/watch?v=rZ3ETK7-ZM8) way*) saved and
made persistent. This update attempts to provide methods to make
*everything*¹ persistent.

This introduces persistent generics and history.

## Database

The following things are going to be changed and added in the database  
(open in new tab for better visibility, PNG file includes the drawIO
code):

<img width="1692" height="1041" alt="aurora_persistency_db drawio"
src="https://github.com/user-attachments/assets/ea53f419-f9aa-4592-af8f-3a8d5edf3177"
/>

**Deviations on database implementation from diagram:**  
- Removed unique constraint on history table - Prevented adding multiple
records per round per attribute.

## Framework surface changes

- MC/VV: Moved global object track register to subsystem var space.
- MC/VV: Point of interest: Added history_cache and generic_cache to
subsystem var space.
- MC/VV: Updated subsystem stat entry message, now providing information
on cache sizes of new types.
- Added `singleton/persistent_type` defines (Type, clean-up rules,
finalization hook) and macros allowing new definitions of said types.
- Added cache structures that are also used for returns on public procs
in generics and history persistent types.
- Major new framework features: Persistent history (example: Mining
yield records) and persistent generics (example: Persistent Horizon
overmap position). See documentation for more information.

DrawIO diagram for documentation, includes source in it (open in new
tab):

<img width="200" height="200" alt="Persistence-subsystem-flowchart
drawio"
src="https://github.com/user-attachments/assets/51f28331-f999-49a2-a7cc-58278f7ae416"
/>

## Tasks

(These lists are not comprehensive.)

**General**
- [x] Update DB - Write SQL scripts.
- [x] Add subsystem modular files for generics and history.
- [x] Add type definition logic, macros.
- [x] Add type-DB init logic.
- [x] Logging.
- [x] A lot of testing. *A lot.*
- [x] Changelog.
- [x] Self-Review.
- [x] Update documentation on the persistence subsystem.

**"Persistent history"**
- [x] Add init logic.
- [x] Add finalize logic.
- [x] Add framework surface procs.
  - [x] Get last record.
  - [x] Get last X records.
  - [x] Add record.
  - [x] Add character ID related validation.
- [x] Add initial example mechanic.

**"Persistent generics"**
- [x] Add init logic.
- [x] Add finalize logic.
- [x] Add framework surface procs.
  - [x] Save.
  - [x] Load.
- [x] Add initial example mechanic.

## Changes

Too many changes to be listed here - Check changelog and actual changes.

## Warning

There are certain use/test cases that *cannot* be tested locally due to
missing preexisting data in the database. This should only affect new
data structures (new persistent types), not existing data.

¹ _Large scale persistent mapping is excluded for this version._

---------

Co-authored-by: Copilot <copilot@github.com>
2026-07-19 20:56:17 +02:00

167 lines
5.0 KiB
Plaintext

//#define TESTING
#if DM_VERSION < 516 && !defined(OPENDREAM)
#error Your version of BYOND is too old to compile the code. At least BYOND 516 is required.
#endif
// Items that ask to be called every cycle.
GLOBAL_LIST_EMPTY(med_hud_users) // List of all entities using a medical HUD.
GLOBAL_LIST_EMPTY(sec_hud_users) // List of all entities using a security HUD.
GLOBAL_LIST_EMPTY(hud_icon_reference)
GLOBAL_LIST_EMPTY(janitorial_supplies) // List of all the janitorial supplies on the map that the PDA cart may be tracking.
GLOBAL_LIST_EMPTY(world_phylactery) //List of all phylactery in the world, used by liches
GLOBAL_LIST_EMPTY(listening_objects) // List of objects that need to be able to hear, used to avoid recursive searching through contents.
GLOBAL_DATUM_INIT(universe, /datum/universal_state, new)
GLOBAL_LIST(global_map)
GLOBAL_PROTECT(global_map)
GLOBAL_LIST_EMPTY(cable_list)
GLOBAL_VAR(diary)
GLOBAL_PROTECT(diary)
GLOBAL_VAR(diary_runtime)
GLOBAL_PROTECT(diary_runtime)
GLOBAL_VAR(diary_date_string)
GLOBAL_PROTECT(diary_date_string)
GLOBAL_VAR(href_logfile)
GLOBAL_PROTECT(href_logfile)
GLOBAL_VAR_INIT(game_version, "Aurorastation")
GLOBAL_PROTECT(game_version)
GLOBAL_VAR_INIT(game_year, (text2num(time2text(world.realtime, "YYYY")) + 442))
GLOBAL_VAR_INIT(round_progressing, 1)
GLOBAL_VAR_INIT(master_mode, "extended")
/// If this is anything but "secret", the secret rotation will forcibly choose this mode.
GLOBAL_VAR_INIT(secret_force_mode, "secret")
GLOBAL_LIST_EMPTY(bombers)
GLOBAL_PROTECT(bombers)
GLOBAL_LIST_EMPTY(admin_log)
GLOBAL_PROTECT(admin_log)
GLOBAL_LIST_EMPTY(signal_log)
GLOBAL_PROTECT(signal_log)
GLOBAL_LIST_EMPTY(lastsignalers) // Keeps last 100 signals here in format: "[src] used REF(src) @ location [src.loc]: [freq]/[code]"
GLOBAL_PROTECT(lastsignalers)
GLOBAL_LIST_EMPTY(lawchanges) // Stores who uploaded laws to which silicon-based lifeform, and what the law was.
GLOBAL_PROTECT(lawchanges)
GLOBAL_LIST_EMPTY(reg_dna)
GLOBAL_DATUM(newplayer_start, /turf)
GLOBAL_DATUM(lobby_mobs_location, /turf)
//Spawnpoints.
GLOBAL_LIST_EMPTY(latejoin)
GLOBAL_LIST_EMPTY(latejoin_cryo)
GLOBAL_LIST_EMPTY(latejoin_cyborg)
GLOBAL_LIST_EMPTY(latejoin_living_quarters_lift)
GLOBAL_LIST_EMPTY(latejoin_medbay_recovery)
GLOBAL_LIST_EMPTY(kickoffsloc)
GLOBAL_LIST_EMPTY(virtual_reality_spawn)
GLOBAL_LIST_EMPTY(tdome1)
GLOBAL_LIST_EMPTY(tdome2)
GLOBAL_LIST_EMPTY(tdomeobserve)
GLOBAL_LIST_EMPTY(tdomeadmin)
GLOBAL_LIST_EMPTY(ninjastart)
GLOBAL_LIST_INIT(all_days, list("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))
GLOBAL_LIST_EMPTY(combatlog)
GLOBAL_PROTECT(lawchanges)
GLOBAL_LIST_EMPTY(IClog)
GLOBAL_PROTECT(IClog)
GLOBAL_LIST_EMPTY(OOClog)
GLOBAL_PROTECT(OOClog)
GLOBAL_LIST_EMPTY(adminlog)
GLOBAL_PROTECT(adminlog)
GLOBAL_VAR_INIT(Debug2, 0)
GLOBAL_DATUM(debugobj, /datum/debug)
GLOBAL_DATUM_INIT(mods, /datum/moduletypes, new())
GLOBAL_LIST_EMPTY(awaydestinations) // Away missions. A list of landmarks that the warpgate can take you to.
// For FTP requests. (i.e. downloading runtime logs.)
// However it'd be ok to use for accessing attack logs and such too, which are even laggier.
GLOBAL_VAR_INIT(fileaccess_timer, 0)
GLOBAL_VAR(custom_event_msg)
// Database connections. A connection is established along with /hook/startup/proc/load_databases().
// Ideally, the connection dies when the server restarts (After feedback logging.).
GLOBAL_DATUM(dbcon, /DBConnection)
GLOBAL_PROTECT(dbcon)
// Added for Xenoarchaeology, might be useful for other stuff.
GLOBAL_LIST_INIT(alphabet_uppercase, list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"))
// Used by robots and robot preferences.
GLOBAL_LIST_INIT(robot_module_types, list(
"Engineering",
"Construction",
"Medical",
"Rescue",
"Mining",
"Custodial",
"Service",
"Clerical",
"Research"
))
// Some scary sounds.
GLOBAL_LIST_INIT(scarySounds, list(
'sound/weapons/thudswoosh.ogg',
'sound/weapons/Taser.ogg',
'sound/weapons/armbomb.ogg',
'sound/effects/glass_break1.ogg',
'sound/effects/glass_break2.ogg',
'sound/effects/glass_break3.ogg',
'sound/items/Welder.ogg',
'sound/items/welder_pry.ogg',
'sound/machines/airlock.ogg',
))
// Bomb cap!
GLOBAL_VAR_INIT(max_explosion_range, 14)
// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
GLOBAL_DATUM_INIT(global_announcer, /obj/item/radio/all_channels, new)
// the number next to it denotes how much money the department receives when its account is generated
GLOBAL_LIST_INIT(department_funds, list(
"Command" = 15000,
"Medical" = 15000,
"Engineering" = 15000,
"Science" = 15000,
"Security" = 15000,
"Operations" = 10000,
"Service" = 15000,
"Vendor" = 0
))
//List of exosuit tracking beacons, to save performance
GLOBAL_LIST_EMPTY(exo_beacons)
GLOBAL_VAR_INIT(minimum_exterior_lighting_alpha, 255)
/// The minimum amount of armour for objects in the game. Stops things from being destroyed by objects with a small force.
GLOBAL_LIST_INIT(default_object_armor, list(MELEE = ARMOR_MELEE_MINOR))