Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions code/game/machinery/cryopod.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
var/global/list/all_cryopods = list()
/proc/FindCryopod(var/uid)
for(var/obj/machinery/cryopod/pod in all_cryopods)
if(pod.unique_id == "[uid]")
return pod
/*
* Cryogenic refrigeration unit. Basically a despawner.
* Stealing a lot of concepts/code from sleepers due to massive laziness.
Expand Down Expand Up @@ -166,6 +171,7 @@
stat_immune = 0
var/open_sound = 'sound/machines/podopen.ogg'
var/close_sound = 'sound/machines/podclose.ogg'
var/unique_id

/obj/machinery/cryopod/robot
name = "robotic storage unit"
Expand Down Expand Up @@ -245,12 +251,18 @@
..()

/obj/machinery/cryopod/Destroy()
all_cryopods -= src
clear_control_computer()
if(occupant)
occupant.forceMove(loc)
occupant.resting = 1
. = ..()

/obj/machinery/cryopod/New()
unique_id = "[make_sequential_guid(/obj/machinery/cryopod)]"
all_cryopods += src
. = ..()

/obj/machinery/cryopod/Initialize()
. = ..()
find_control_computer()
Expand Down
2 changes: 2 additions & 0 deletions code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ var/global/list/time_prefs_fixed = list()
var/datum/category_collection/player_setup_collection/player_setup
var/datum/browser/panel

var/creation_slot = 0 // which slot the character will be created under.

/datum/preferences/New(client/C)
if(istype(C))

Expand Down
37 changes: 36 additions & 1 deletion code/modules/mob/new_player/new_player.dm
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ INITIALIZE_IMMEDIATE(/mob/new_player)
var/decl/species/S = get_species_by_key(client.prefs.species)
if(!check_species_allowed(S))
return 0

AttemptLateSpawn(job, client.prefs.spawnpoint)
return

Expand Down Expand Up @@ -345,6 +344,42 @@ INITIALIZE_IMMEDIATE(/mob/new_player)
popup.set_content(jointext(dat, null))
popup.open(0)


/mob/new_player/proc/create_character_first()

var/mob/living/carbon/human/new_character

var/decl/species/chosen_species
if(client.prefs.species)
chosen_species = get_species_by_key(client.prefs.species)

if(chosen_species)
if(!check_species_allowed(chosen_species))
spawning = 0 //abort
return null
new_character = new(null, chosen_species.name)

if(!new_character)
new_character = new(null)

client.prefs.copy_to(new_character)

if(!mind) mind = new()
mind.active = 0 //we wish to transfer the key manually
mind.original = new_character
var/memory = client.prefs.records[PREF_MEM_RECORD]
if(memory)
mind.StoreMemory(memory)
mind.transfer_to(new_character) //won't transfer key since the mind is not active

// Do the initial caching of the player's body icons.
new_character.force_update_limbs()
new_character.try_refresh_visible_overlays()


return new_character


/mob/new_player/proc/create_character(var/turf/spawn_turf)
spawning = 1
close_spawn_windows()
Expand Down
20 changes: 12 additions & 8 deletions mods/persistence/__defines/serializer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@
#define SQLS_TABLE_DATUM "thing"
#define SQLS_TABLE_DATUM_VARS "thing_var"
#define SQLS_TABLE_LIST_ELEM "list_element"
#define SQLS_TABLE_Z_LEVELS "z_level"
#define SQLS_TABLE_AREAS "areas"
#define SQLS_TABLE_LIMBO "limbo"
#define SQLS_TABLE_LIMBO_DATUM "limbo_thing"
#define SQLS_TABLE_LIMBO_DATUM_VARS "limbo_thing_var"
#define SQLS_TABLE_LIMBO_LIST_ELEM "limbo_list_element"
#define SQLS_TABLE_INSTANCES "instances"
#define SQLS_TABLE_WORLDS "worldsaves"
#define SQLS_TABLE_CHARACTERSAVES "charactersaves"
#define SQLS_TABLE_CHARACTERS "characters"


/////////////////////////////////////////////////////////
// SQL Stored Functions Names
Expand All @@ -41,8 +40,6 @@
#define SQLS_FUNC_GET_LAST_SAVE_TIME "GetLastWorldSaveTime"
///Log to the table when a world save begins, returns the current save log id.
#define SQLS_FUNC_LOG_SAVE_WORLD_START "LogSaveWorldStart"
///Log to the table when a limbo/storage save begins, returns the current save log id.
#define SQLS_FUNC_LOG_SAVE_STORAGE_START "LogSaveStorageStart"
///Log to the table when any save ends, returns the current save log id.
#define SQLS_FUNC_LOG_SAVE_END "LogSaveEnd"

Expand All @@ -53,6 +50,13 @@
///Delete the current world save from the db, so we can write a newer one. Procedures are executed with CALL, and don't return anything.
#define SQLS_PROC_CLEAR_WORLD_SAVE "ClearWorldSave"

/////////////////////////////////////////////////////////
// Character Status ENUM
/////////////////////////////////////////////////////////
#define SQLS_CHAR_STATUS_CRYO 1
#define SQLS_CHAR_STATUS_WORLD 2
#define SQLS_CHAR_STATUS_FIRST 3
#define SQLS_CHAR_STATUS_DELETED 4
/////////////////////////////////////////////////////////
// SQL Helpers
/////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion mods/persistence/_global_vars/serialization.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var/global/list/reference_only_vars = list("home_spawn")
var/global/list/reference_only_vars = list()

// Dictionary keyed by AREA_KEY = "[area.type], [area.name]". Used for
// deserialization of areas.
Expand Down
3 changes: 0 additions & 3 deletions mods/persistence/_persistence.dme
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#include "_global_vars\serialization.dm"
#include "_onclick\click.dm"
#include "code\__defines\computers.dm"
#include "code\__defines\limbo.dm"
#include "code\__defines\persistent_id.dm"
#include "code\__defines\world_save.dm"
#include "code\controllers\configuration.dm"
Expand All @@ -32,7 +31,6 @@
#include "controllers\subsystems\persistence\persistence_loading.dm"
#include "controllers\subsystems\persistence\persistence_saving.dm"
#include "controllers\subsystems\persistence\persistence_stats.dm"
#include "controllers\subsystems\persistence\persistence_storage.dm"
#include "controllers\subsystems\processing\specifications.dm"
#include "datums\extensions\extensions.dm"
#include "datums\extensions\holster.dm"
Expand Down Expand Up @@ -308,7 +306,6 @@
#include "modules\world_save\saved_vars\saved_skipped.dm"
#include "modules\world_save\serializers\_serializer.dm"
#include "modules\world_save\serializers\json_serializer.dm"
#include "modules\world_save\serializers\one_off_serializer.dm"
#include "modules\world_save\serializers\sql_serializer.dm"
#include "modules\world_save\serializers\sql_serializer_db.dm"
#include "modules\world_save\wrappers\_late_wrapper.dm"
Expand Down
3 changes: 0 additions & 3 deletions mods/persistence/code/__defines/limbo.dm

This file was deleted.

145 changes: 125 additions & 20 deletions mods/persistence/controllers/subsystems/persistence.dm
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,7 @@
/// The serializer impl for actually saving.
var/serializer/sql/serializer = new()
/// The serializer impl for one off serialization/deserialization.
var/serializer/sql/one_off/one_off = new()

//#FIXME: Ideally, this shouldn't be handled by the server. The database could cross-reference atoms that were in limbo with those already in the world,
// and just clear their limbo entry. It would thousands of time faster.
/// Objects which will be removed from limbo on the next save. Format is list(limbo_key, limbo_type)
var/list/limbo_removals = list()
/// Objects which are deserialized out of limbo don't have their refs in the database immediately, so we add them here until the next save. Format is p_id -> ref
var/list/limbo_refs = list()

/// Some wrapped objects need special behavior post-load. This list is cleared post-atom Init.
var/list/late_wrappers = list()
Expand All @@ -96,10 +89,17 @@
///Returns true if a save already exists on the DB
/datum/controller/subsystem/persistence/proc/SaveExists()
if(!save_exists)
save_exists = establish_save_db_connection() && serializer.save_exists()

establish_save_db_connection()
var/list/combo = serializer.GetLatestWorldid()
if(!combo || !combo.len > 1)
return 0

save_exists = establish_save_db_connection() && serializer.save_exists(combo[2])
in_loaded_world = save_exists
return save_exists


///Timestamp of when the currently loaded save was made.
/datum/controller/subsystem/persistence/proc/LoadedSaveTimestamp()
if(!in_loaded_world)
Expand Down Expand Up @@ -135,6 +135,44 @@
// Save/Load
/////////////////////////////////////////////////////////////////

/datum/controller/subsystem/persistence/proc/AcceptDeath(var/c_id, var/ckey)
if(ckey)
if(!serializer.VerifyCharacterOwner(c_id,ckey)) return
return serializer.AcceptDeath(c_id)

///Causes a character to be saved.
/datum/controller/subsystem/persistence/proc/SaveCharacter(var/mob/target, var/status)
var/exception/last_except
var/instanceid
if(!target || !istype(target) || !target.mind || !target.mind.unique_id)
return 1
try

instanceid = _save_instance()
var/datum/persistence/load_cache/character/head = new()
head.target = target
serializer.SaveCharacter(instanceid, head, status)

catch(var/exception/e)
throw e
//If exceptions end up in here, then we must interrupt saving completely.
//Exceptions should be filtered in the sub-procs depending on severity and the error tolerance threshold set.
save_complete_span_class = "danger"
save_complete_text = "CHARACTER SAVE FAILED: [EXCEPTION_TEXT(e)]"
. = FALSE

//Throw any exception, so it's a bit more obvious to people looking at the runtime log that it actually runtimed and failed
if(last_except)
throw last_except
return 1








///Causes a world save to be started.
/datum/controller/subsystem/persistence/proc/SaveWorld(var/save_initiator)
//Make sure we log who started the save.
Expand All @@ -153,24 +191,30 @@
// Do preparation first
_before_save(save_initiator)

var/instanceid
var/datum/persistence/load_cache/world/world_cache = new()
try

instanceid = _save_instance()

//Prepare z levels structure for saving
var/list/z_transform = _prepare_zlevels_indexing()

//Save all individual turfs marked for saving
_save_turfs(z_transform)
_save_turfs(z_transform, instanceid)

//Save area related stuff
_save_areas(z_transform)

serializer.save_z_level_remaps(z_transform, world_cache)
world_cache.area_chunks = _save_areas(z_transform, instanceid)
// Now save all the extensions which have marked themselves to be saved.
// As with areas, we create a dummy wrapper holder to hold these during load etc.
_save_extensions()
_save_extensions(instanceid)

// Save escrow accounts which are normally held on the SSmoney_accounts subsystem
_save_bank_accounts()
_save_bank_accounts(instanceid)

catch(var/exception/e)
throw e
//If exceptions end up in here, then we must interrupt saving completely.
//Exceptions should be filtered in the sub-procs depending on severity and the error tolerance threshold set.
save_complete_span_class = "danger"
Expand All @@ -184,6 +228,7 @@
save_complete_text = "Save complete! Took [REALTIMEOFDAY2SEC(start)]s to save world."
. = TRUE

_finish_save_world(instanceid, world_cache)
//Handle post-save cleanup and such
_after_save()

Expand All @@ -199,19 +244,80 @@
if(last_except)
throw last_except


///Save Character
/datum/controller/subsystem/persistence/proc/NewCharacter(var/realname, var/ckey, var/slot, var/mob/target)

var/c_id = serializer.NewCharacter(realname,ckey,slot,target)
var/cs_id = SaveCharacter(target, SQLS_CHAR_STATUS_FIRST)
serializer.UpdateCharacterOriginalSave(c_id, cs_id)
return




/datum/controller/subsystem/persistence/proc/LoadCharacter(var/c_id)
var/instanceid
var/datum/persistence/load_cache/character/head
var/exception/first_except
try
//Establish connection and etc..
_before_load()
var/list/id_combo = serializer.GetLatestCharacterSave(c_id)
// worldid = text2num(id_combo[1])
instanceid = text2num(id_combo[2])

serializer.resolver.load_cache(instanceid) //This is entirely unrecoverable if it throws and exception.
head = serializer.GetHead(instanceid)
catch(var/exception/e_load)
//Don't return in here, we need to let the code try to run cleanup below!
to_world_log("Load failed: [EXCEPTION_TEXT(e_load)].")
first_except = e_load

try
serializer.Clear()
serializer.resolver.clear_cache()
serializer._after_deserialize()
catch(var/exception/e_cleanup)
to_world_log("Load cleanup failed: [EXCEPTION_TEXT(e_cleanup)]")
if(!first_except)
first_except = e_cleanup
//Throw any exception that were allowed, so it's a bit more obvious to people looking at the runtime log that it actually runtimed and failed
if(first_except)
throw first_except

if(head)
return head.target

/datum/controller/subsystem/persistence/proc/ClearName(var/realname)
return serializer.ClearName(realname)

///Load the last saved world.
/datum/controller/subsystem/persistence/proc/LoadWorld()
var/time_total = REALTIMEOFDAY
var/exception/first_except
loading_world = TRUE
// var/worldid
var/instanceid

try
//Establish connection and etc..
_before_load()
var/list/id_combo = serializer.GetLatestWorldid()

// worldid = text2num(id_combo[1])
instanceid = text2num(id_combo[2])


// We start by loading the cache. This will load everything from SQL into an object structure
// and is much faster than live-querying for information.
serializer.resolver.load_cache() //This is entirely unrecoverable if it throws and exception.
serializer.resolver.load_cache(instanceid) //This is entirely unrecoverable if it throws and exception.
var/datum/persistence/load_cache/world/world_cache = serializer.GetHead(instanceid)
serializer.resolver.z_levels = world_cache.z_levels
serializer.resolver.area_chunks = world_cache.area_chunks
serializer.resolver.world_cache_s = world_cache


report_progress_serializer("Cached DB data in [REALTIMEOFDAY2SEC(time_total)]s.")
sleep(5)

Expand All @@ -231,14 +337,13 @@
_run_after_deserialize()

//Sync references
try
serializer.CommitRefUpdates()
catch(var/exception/e_commit_ref)
// try
// serializer.CommitRefUpdates()
// catch(var/exception/e_commit_ref)
//If refs fails, it's pretty bad. So filter it as a critical exception.
_handle_critical_load_exception(e_commit_ref, "running CommitRefUpdates()")
// to_world("[e_commit_ref]")
// _handle_critical_load_exception(e_commit_ref, "running CommitRefUpdates()")

//Make sure objects loaded onto the world that are still in the limbo table are removed
_update_limbo_state()

catch(var/exception/e_load)
//Don't return in here, we need to let the code try to run cleanup below!
Expand Down
Loading