diff --git a/code/modules/client/preference_setup/antagonism/01_candidacy.dm b/code/modules/client/preference_setup/antagonism/01_candidacy.dm
index 94a86080253..0c9a4a0cb3d 100644
--- a/code/modules/client/preference_setup/antagonism/01_candidacy.dm
+++ b/code/modules/client/preference_setup/antagonism/01_candidacy.dm
@@ -8,6 +8,9 @@
/datum/category_item/player_setup_item/antagonism/candidacy/save_character(var/savefile/S)
S["be_special"] << pref.be_special_role
+/datum/category_item/player_setup_item/antagonism/candidacy/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("be_special_role"), "args" = list("id")))
+
/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character()
if(!istype(pref.be_special_role))
pref.be_special_role = list()
diff --git a/code/modules/client/preference_setup/antagonism/02_setup.dm b/code/modules/client/preference_setup/antagonism/02_setup.dm
index 249d7bf2bb5..c84c2a6781f 100644
--- a/code/modules/client/preference_setup/antagonism/02_setup.dm
+++ b/code/modules/client/preference_setup/antagonism/02_setup.dm
@@ -12,6 +12,10 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None")
S["uplinklocation"] << pref.uplinklocation
S["exploit_record"] << pref.exploit_record
+/datum/category_item/player_setup_item/antagonism/basic/gather_load_query()
+ return list("ss13_characters_flavour" = list("vars" = list("records_exploit" = "exploit_record"), "args" = list("char_id")),
+ "ss13_characters" = list("vars" = list("uplink_location" = "uplinklocation"), "args" = list("id")))
+
/datum/category_item/player_setup_item/antagonism/basic/sanitize_character()
pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation))
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 440cf90e59c..ac430e4caac 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -19,6 +19,15 @@
S["spawnpoint"] << pref.spawnpoint
S["OOC_Notes"] << pref.metadata
+/datum/category_item/player_setup_item/general/basic/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("name" = "real_name",
+ "random_name" = "be_random_name",
+ "gender",
+ "age",
+ "metadata",
+ "spawnpoint"),
+ "args" = list("id")))
+
/datum/category_item/player_setup_item/general/basic/sanitize_character()
pref.age = sanitize_integer(pref.age, AGE_MIN, AGE_MAX, initial(pref.age))
pref.gender = sanitize_inlist(pref.gender, valid_player_genders, pick(valid_player_genders))
diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm
index c7cb7afca74..96864e8eed8 100644
--- a/code/modules/client/preference_setup/general/02_language.dm
+++ b/code/modules/client/preference_setup/general/02_language.dm
@@ -8,6 +8,9 @@
/datum/category_item/player_setup_item/general/language/save_character(var/savefile/S)
S["language"] << pref.alternate_languages
+/datum/category_item/player_setup_item/general/language/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("language" = "alternate_languages"), "args" = list("id")))
+
/datum/category_item/player_setup_item/general/language/sanitize_character()
if(!islist(pref.alternate_languages)) pref.alternate_languages = list()
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 08330e5e811..7c66c59901e 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -48,6 +48,21 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["organ_data"] << pref.organ_data
S["rlimb_data"] << pref.rlimb_data
+/datum/category_item/player_setup_item/general/body/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("species",
+ "hair_colour",
+ "facial_colour",
+ "skin_tone" = "s_tone",
+ "skin_colour",
+ "hair_style" = "h_style",
+ "facial_style" = "f_style",
+ "eyes_colour",
+ "b_type",
+ "disabilities",
+ "organs_data" = "organ_data",
+ "organs_robotic" = "rlimb_data"),
+ "args" = list("id")))
+
/datum/category_item/player_setup_item/general/body/sanitize_character(var/savefile/S)
if(!pref.species || !(pref.species in playable_species))
pref.species = "Human"
@@ -210,7 +225,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.species = href_list["set_species"]
if(prev_species != pref.species)
mob_species = all_species[pref.species]
-
+
//grab one of the valid hair styles for the newly chosen species
var/list/valid_hairstyles = list()
for(var/hairstyle in hair_styles_list)
diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm
index bf933932b83..3d816dd6547 100644
--- a/code/modules/client/preference_setup/general/04_equipment.dm
+++ b/code/modules/client/preference_setup/general/04_equipment.dm
@@ -14,6 +14,9 @@
S["backbag"] << pref.backbag
S["gear"] << pref.gear
+/datum/category_item/player_setup_item/general/equipment/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("underwear", "undershirt", "backbag", "gear"), "args" = list("id")))
+
/datum/category_item/player_setup_item/general/equipment/sanitize_character()
pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag))
diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm
index 5708d3c757e..2abcb0bf989 100644
--- a/code/modules/client/preference_setup/general/05_background.dm
+++ b/code/modules/client/preference_setup/general/05_background.dm
@@ -22,6 +22,13 @@
S["religion"] << pref.religion
S["nanotrasen_relation"] << pref.nanotrasen_relation
+/datum/category_item/player_setup_item/general/background/gather_load_query()
+ return list("ss13_characters_flavour" = list("vars" = list("records_employment" = "gen_record",
+ "records_medical" = "med_record",
+ "records_security" = "sec_record"),
+ "args" = list("char_id")),
+ "ss13_characters" = list("vars" = list("home_system", "citizenship", "faction", "religion"), "args" = list("id")))
+
/datum/category_item/player_setup_item/general/background/sanitize_character()
if(!pref.home_system) pref.home_system = "Unset"
if(!pref.citizenship) pref.citizenship = "None"
diff --git a/code/modules/client/preference_setup/general/06_flavor.dm b/code/modules/client/preference_setup/general/06_flavor.dm
index b312bb95e9b..19873858e61 100644
--- a/code/modules/client/preference_setup/general/06_flavor.dm
+++ b/code/modules/client/preference_setup/general/06_flavor.dm
@@ -33,6 +33,23 @@
for(var/module in robot_module_types)
S["flavour_texts_robot_[module]"] << pref.flavour_texts_robot[module]
+/datum/category_item/player_setup_item/general/flavor/gather_load_query()
+ var/list/var_list = list("flavour_general" = "flavor_texts/general",
+ "flavour_head" = "flavour_texts/head",
+ "flavour_face" = "flavour_texts/face",
+ "flavour_eyes" = "flavour_texts/eyes",
+ "flavour_torso" = "flavour_texts/torso",
+ "flavour_arms" = "flavour_texts/arms",
+ "flavour_hands" = "flavour_texts/hands",
+ "flavour_legs" = "flavour_texts/legs",
+ "flavour_feet" = "flavour_texts/feet",
+ "robot_default" = "flavour_texts_robot/default")
+
+ for (var/module in robot_module_types)
+ var_list["robot_[module]"] = "flavour_texts_robot/[module]"
+
+ return list("ss13_characters_flavour" = list("vars" = var_list, "args" = list("char_id")))
+
/datum/category_item/player_setup_item/general/flavor/sanitize_character()
return
diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm
index 777a51d3549..3f21b4f2622 100644
--- a/code/modules/client/preference_setup/global/01_ui.dm
+++ b/code/modules/client/preference_setup/global/01_ui.dm
@@ -14,6 +14,9 @@
S["UI_style_alpha"] << pref.UI_style_alpha
S["ooccolor"] << pref.ooccolor
+/datum/category_item/player_setup_item/player_global/ui/gather_load_query()
+ return list("ss13_player_preferences" = list("vars" = list("UI_style", "UI_style_color", "UI_style_alpha", "ooccolor"), "args" = list("ckey")))
+
/datum/category_item/player_setup_item/player_global/ui/sanitize_preferences()
pref.UI_style = sanitize_inlist(pref.UI_style, all_ui_styles, initial(pref.UI_style))
pref.UI_style_color = sanitize_hexcolor(pref.UI_style_color, initial(pref.UI_style_color))
@@ -24,14 +27,14 @@
. += "UI Settings
"
. += "UI Style: [pref.UI_style]
"
. += "Custom UI (recommended for White UI):
"
- . += "-Color: [pref.UI_style_color]
reset
"
- . += "-Alpha(transparency): [pref.UI_style_alpha] reset
"
+ . += "-Color: [pref.UI_style_color]��reset
"
+ . += "-Alpha(transparency): [pref.UI_style_alpha]�reset
"
if(can_select_ooc_color(user))
- . += "OOC Color: "
+ . += "OOC Color:�"
if(pref.ooccolor == initial(pref.ooccolor))
. += "Using Default
"
else
- . += "[pref.ooccolor] reset
"
+ . += "[pref.ooccolor] �reset
"
/datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user)
if(href_list["select_style"])
diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm
index 7b61a86cb44..2e18610039e 100644
--- a/code/modules/client/preference_setup/global/02_settings.dm
+++ b/code/modules/client/preference_setup/global/02_settings.dm
@@ -12,6 +12,9 @@
S["default_slot"] << pref.default_slot
S["toggles"] << pref.toggles
+/datum/category_item/player_setup_item/player_global/settings/gather_load_query()
+ return list("ss13_player_preferences" = list("vars" = list("lastchangelog", "current_character", "toggles", "asfx_toggles"), "args" = list("ckey")))
+
/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences()
pref.lastchangelog = sanitize_text(pref.lastchangelog, initial(pref.lastchangelog))
pref.default_slot = sanitize_integer(pref.default_slot, 1, config.character_slots, initial(pref.default_slot))
diff --git a/code/modules/client/preference_setup/global/03_language.dm b/code/modules/client/preference_setup/global/03_language.dm
index fa3fdbe6e9b..bacb97564f4 100644
--- a/code/modules/client/preference_setup/global/03_language.dm
+++ b/code/modules/client/preference_setup/global/03_language.dm
@@ -8,6 +8,9 @@
/datum/category_item/player_setup_item/player_global/language/save_preferences(var/savefile/S)
S["language_prefixes"] << pref.language_prefixes
+/datum/category_item/player_setup_item/player_global/language/gather_load_query()
+ return list("ss13_player_preferences" = list("vars" = list("language_prefixes"), "args" = list("ckey")))
+
/datum/category_item/player_setup_item/player_global/language/sanitize_preferences()
if(isnull(pref.language_prefixes) || !pref.language_prefixes.len)
pref.language_prefixes = config.language_prefixes.Copy()
@@ -52,4 +55,3 @@
if(istype(prefixes) && prefixes.len)
preferences["language_prefixes"] = prefixes.Copy()
return 1
-
diff --git a/code/modules/client/preference_setup/global/04_pai.dm b/code/modules/client/preference_setup/global/04_pai.dm
index a7102069e1b..529a751f335 100644
--- a/code/modules/client/preference_setup/global/04_pai.dm
+++ b/code/modules/client/preference_setup/global/04_pai.dm
@@ -13,6 +13,8 @@
candidate.savefile_load(preference_mob())
+// #TODO-MERGE: Figure out how to handle pAI saving on SQL.
+
/datum/category_item/player_setup_item/player_global/pai/save_preferences(var/savefile/S)
if(!candidate)
return
diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm
index 92c6320c646..694efb92eeb 100644
--- a/code/modules/client/preference_setup/occupation/occupation.dm
+++ b/code/modules/client/preference_setup/occupation/occupation.dm
@@ -33,6 +33,9 @@
S["job_engsec_low"] << pref.job_engsec_low
S["player_alt_titles"] << pref.player_alt_titles
+/datum/category_item/player_setup_item/occupation/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("jobs" = "unsanitized_jobs", "alternate_option", "alternate_titles" = "player_alt_titles"), "args" = list("id")))
+
/datum/category_item/player_setup_item/occupation/sanitize_character()
pref.alternate_option = sanitize_integer(pref.alternate_option, 0, 2, initial(pref.alternate_option))
pref.job_civilian_high = sanitize_integer(pref.job_civilian_high, 0, 65535, initial(pref.job_civilian_high))
diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm
index 0fa0bfa10c8..7c9f7a055e5 100644
--- a/code/modules/client/preference_setup/preference_setup.dm
+++ b/code/modules/client/preference_setup/preference_setup.dm
@@ -125,12 +125,93 @@
for(var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_character()
+// For loading character by category. Utilizes query caching.
/datum/category_group/player_setup_category/proc/load_character_sql()
- var/static/list/query_cache = list()
- if (isnull(query_cache[type]))
- var/query = "FROM ss13_characters"
- for (var/datum/category_item/player_setup_item/PI in items)
+ var/static/list/query_cache
+ if (isnull(query_cache))
+ query_cache = list()
+
+ // This handles the generation of queries. One per category, total of 5 UNLESS one category wants to query more than one table.
+ // It uses like, 3+ levels of lists. But it works, and is only run once per category in the global sense. So technically, efficient!
+ // :D - Skull132
+ if (!query_cache.len || isnull(query_cache[type]))
+ query_cache[type] = list()
+ var/list/tables = list()
+
+ // First, consolidate the different lists into one.
+ for (var/datum/category_item/player_setup_item/PI in items)
+ var/list/pi_tables = PI.gather_load_query()
+ // Expected layout: list("table A name" = list("vars" = list("column name" = "var name"), "args" = list()),
+ // "table B name" = list("vars" = list(), "args" = list()))
+
+ for (var/table in pi_tables)
+ var/list/A = pi_tables[table]
+ if (isnull(tables[table]))
+ tables[table] = list("vars" = list(), "args" = list())
+
+ tables[table]["vars"] |= A["vars"]
+ tables[table]["args"] |= A["args"]
+
+ // Second, create the queries and save them.
+ for (var/table in tables)
+ var/query = "SELECT "
+ var/list/var_names = tables[table]["vars"]
+ var/count = var_names.len
+
+ // Process the variables and rows we want.
+ var/i = 1
+ for (var/name in var_names)
+ query += name
+
+ if (!isnull(var_names[name]))
+ var/new_name = var_names[name]
+ var_names.Remove(name)
+ var_names.Insert(i, new_name)
+
+ if (i != count)
+ query += ", "
+ else
+ query += " "
+
+ i++
+
+ query += "FROM [table] WHERE "
+
+ // Process the args.
+ var/list/arg_names = tables[table]["args"]
+ count = arg_names.len
+ for (i = 1, i <= count, i++)
+ query += "[arg_names[i]] = :[arg_names[i]]"
+ arg_names[i] = ":[arg_names[i]]"
+
+ if (i != count)
+ query += " AND "
+ else
+ query += ";"
+
+ // Save it.
+ query_cache[type][query] = var_names
+
+ // Actually utilize the query.
+ var/list/arg_list = gather_load_parameters()
+ for (var/query in query_cache[type])
+ var/DBQuery/query = dbcon.NewQuery(query)
+ query.Execute(arg_list, 1)
+
+ // Each query should only return exactly 1 row.
+ var/list/var_names = query_cache[type]
+ if (query.NextRow())
+ for (var/i = 1, i <= var_names.len, i++)
+ // We can do this, because when generating, we ensured that
+ preferences.vars[var_names[i]] = query.item[i]
+
+/datum/category_group/player_setup_category/proc/gather_load_parameters()
+ var/list/arg_list = list()
+ for (var/datum/category_item/player_setup_item/PI in items)
+ arg_list |= PI.gather_load_parameters()
+
+ return arg_list
/datum/category_group/player_setup_category/proc/save_character(var/savefile/S)
// Sanitize all data, then save it
@@ -219,6 +300,18 @@
/datum/category_item/player_setup_item/proc/update_setup(var/savefile/preferences, var/savefile/character)
return 0
+/*
+* Called when the owner category is composing its load query
+*/
+/datum/category_item/player_setup_item/proc/gather_load_query()
+ return list()
+
+/*
+* Called when the owner category is composing its query parameters for loading.
+*/
+/datum/category_item/player_setup_item/proc/gather_load_parameters()
+ return list()
+
/datum/category_item/player_setup_item/proc/content()
return
diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm
index 1f60cd3bb7f..7d525f315b7 100644
--- a/code/modules/client/preference_setup/skills/skills.dm
+++ b/code/modules/client/preference_setup/skills/skills.dm
@@ -12,6 +12,9 @@
S["used_skillpoints"] << pref.used_skillpoints
S["skill_specialization"] << pref.skill_specialization
+/datum/category_item/player_setup_item/skills/gather_load_query()
+ return list("ss13_characters" = list("vars" = list("skills", "skill_specialization"), "args" = list("id")))
+
/datum/category_item/player_setup_item/skills/sanitize_character()
if(SKILLS == null) setup_skills()
if(!pref.skills) pref.skills = list()