diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0d81bc2501..ae89712e66 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -465,6 +465,22 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
"
+ dat += ""
+ var/client_file = user.client.Import()
+ var/savefile_name
+ if(client_file)
+ var/savefile/cache_savefile = new(user.client.Import())
+ if(!cache_savefile["deleted"] || savefile_needs_update(cache_savefile) != -2)
+ cache_savefile["real_name"] >> savefile_name
+ dat += "Local storage: [savefile_name ? savefile_name : "Empty"]"
+ dat += "
"
+ dat += "Export current slot"
+ dat += "Import into current slot"
+ dat += "Delete locally saved character"
+ dat += ""
+
+ dat += "
"
+
dat += ""
dat += "General"
dat += "Appearance"
@@ -3920,6 +3936,30 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("cumontopref")
cit_toggles ^= CUM_ONTO
//
+ if("export_slot")
+ var/savefile/S = save_character(export = TRUE)
+ if(istype(S, /savefile))
+ user.client.Export(S)
+ tgui_alert_async(user, "Successfully saved character slot")
+ else
+ tgui_alert_async(user, "Failed saving character slot")
+ return
+
+ if("import_slot")
+ var/savefile/S = new(user.client.Import())
+ if(istype(S, /savefile))
+ if(load_character(provided = S) == TRUE)
+ tgui_alert_async(user, "Successfully loaded character slot.")
+ else
+ tgui_alert_async(user, "Failed loading character slot")
+ return
+ else
+ tgui_alert_async(user, "Failed loading character slot")
+ return
+
+ if("delete_local_copy")
+ user.client.clear_export()
+ tgui_alert_async(user, "Local save data erased.")
if(href_list["preference"] == "gear")
if(href_list["clear_loadout"])
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 521c5ef368..85ade29e20 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -723,9 +723,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
return 1
-/datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE)
- if(!path)
- return FALSE
+/datum/preferences/proc/load_character(slot, bypass_cooldown = FALSE, savefile/provided)
+ if(!provided)
+ if(!path)
+ return FALSE
if(!bypass_cooldown)
if(world.time < loadcharcooldown) //This is before the check to see if the filepath exists to ensure that BYOND can't get hung up on read attempts when the hard drive is a little slow
if(istype(parent))
@@ -734,9 +735,30 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
loadcharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
if(!fexists(path))
return FALSE
- var/savefile/S = new /savefile(path)
+ var/savefile/S
+ if(provided)
+ S = provided
+ else
+ S = new /savefile(path)
if(!S)
return FALSE
+
+ S.cd = "/"
+ if(!slot)
+ slot = default_slot
+ slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
+ if(slot != default_slot)
+ default_slot = slot
+ WRITE_FILE(S["default_slot"] , slot)
+
+ if(!provided)
+ S.cd = "/character[slot]"
+ var/needs_update = savefile_needs_update(S)
+ if(needs_update == -2) //fatal, can't load any data
+ return FALSE
+
+ . = TRUE
+
features = list(
"mcolor" = "FFFFFF",
"mcolor2" = "FFFFFF",
@@ -829,22 +851,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
"neckfire_color" = "ffffff"
)
-
- S.cd = "/"
- if(!slot)
- slot = default_slot
- slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
- if(slot != default_slot)
- default_slot = slot
- WRITE_FILE(S["default_slot"] , slot)
-
- S.cd = "/character[slot]"
- var/needs_update = savefile_needs_update(S)
- if(needs_update == -2) //fatal, can't load any data
- return FALSE
-
- . = TRUE
-
//Species
var/species_id
S["species"] >> species_id
@@ -1311,7 +1317,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
return 1
-/datum/preferences/proc/save_character(bypass_cooldown = FALSE)
+/datum/preferences/proc/save_character(bypass_cooldown = FALSE, export = FALSE)
if(!path)
return 0
if(!bypass_cooldown)
@@ -1320,10 +1326,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
to_chat(parent, "You're attempting to save your character a little too fast. Wait half a second, then try again.")
return 0
savecharcooldown = world.time + PREF_SAVELOAD_COOLDOWN
- var/savefile/S = new /savefile(path)
+ var/savefile/S = new /savefile(export ? null : path)
if(!S)
return 0
- S.cd = "/character[default_slot]"
+ if(!export)
+ S.cd = "/character[default_slot]"
WRITE_FILE(S["version"] , SAVEFILE_VERSION_MAX) //load_character will sanitize any bad data, so assume up-to-date.)
@@ -1556,7 +1563,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
splurt_character_pref_save(S)
- return 1
+ return S
#undef SAVEFILE_VERSION_MAX
diff --git a/html/changelogs/archive/2023-09.yml b/html/changelogs/archive/2023-09.yml
index 74cd9974b3..661b844cc0 100644
--- a/html/changelogs/archive/2023-09.yml
+++ b/html/changelogs/archive/2023-09.yml
@@ -100,3 +100,6 @@
remuluson2:
- rscadd: Added Messy trait, allowing you to cover stuff with cum while not meeting
size requirements.
+2023-09-28:
+ SandPoot:
+ - rscadd: Added importing/exporting characters, they will be saved on your computer.
diff --git a/modular_sand/code/modules/client/client_procs.dm b/modular_sand/code/modules/client/client_procs.dm
new file mode 100644
index 0000000000..e00adda2dc
--- /dev/null
+++ b/modular_sand/code/modules/client/client_procs.dm
@@ -0,0 +1,4 @@
+/client/proc/clear_export()
+ var/savefile/S = new()
+ S["deleted"] << 1
+ Export(S)
diff --git a/tgstation.dme b/tgstation.dme
index 2572017fdb..dccb621e04 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -4139,6 +4139,7 @@
#include "modular_sand\code\modules\cargo\packs\supply_pack.dm"
#include "modular_sand\code\modules\cargo\packs\vending.dm"
#include "modular_sand\code\modules\client\asset_cache.dm"
+#include "modular_sand\code\modules\client\client_procs.dm"
#include "modular_sand\code\modules\client\preferences.dm"
#include "modular_sand\code\modules\client\preferences_savefile.dm"
#include "modular_sand\code\modules\client\loadout\_security.dm"