SQL Saves - Season 2 Episode 2 - The Fixening (#1286)

Update the schema
 Modify player_preferences and character related tables
 Readd the incidents + missing CCIAA tables to it
 Fix loading
 Fix saving
 Make it impossible to edit character name after a while
 Sanity check so you cannot enter without a valid (saved) character
 Fix New Character button
 Remove debug messages

Fixes #600 
Fixes #588
This commit is contained in:
skull132
2016-12-25 00:56:36 +02:00
committed by GitHub
parent 7c8cf8408e
commit 24258106da
19 changed files with 363 additions and 147 deletions
@@ -15,10 +15,10 @@
return list(":id" = pref.current_character)
/datum/category_item/player_setup_item/antagonism/candidacy/gather_save_query()
return list("ss13_characters" = list("be_special_role", "id" = 1))
return list("ss13_characters" = list("be_special_role", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/antagonism/candidacy/gather_save_parameters()
return list(":be_special_role" = list2params(pref.be_special_role), ":id" = pref.current_character)
return list(":be_special_role" = list2params(pref.be_special_role), ":id" = pref.current_character, ":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/antagonism/candidacy/sanitize_character(var/sql_load = 0)
if (sql_load)
@@ -21,10 +21,10 @@ var/global/list/uplink_locations = list("PDA", "Headset", "None")
/datum/category_item/player_setup_item/antagonism/basic/gather_save_query()
return list("ss13_characters_flavour" = list("records_exploit", "char_id" = 1),
"ss13_characters" = list("uplink_location", "id" = 1))
"ss13_characters" = list("uplink_location", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/antagonism/basic/gather_save_parameters()
return list(":records_exploit" = pref.exploit_record, ":char_id" = pref.current_character, ":uplink_location" = pref.uplinklocation, ":id" = pref.current_character)
return list(":records_exploit" = pref.exploit_record, ":char_id" = pref.current_character, ":uplink_location" = pref.uplinklocation, ":id" = pref.current_character, ":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/antagonism/basic/sanitize_character()
pref.uplinklocation = sanitize_inlist(pref.uplinklocation, uplink_locations, initial(pref.uplinklocation))
@@ -5,7 +5,6 @@
/datum/category_item/player_setup_item/general/basic/load_character(var/savefile/S)
S["real_name"] >> pref.real_name
S["name_is_always_random"] >> pref.be_random_name
S["gender"] >> pref.gender
S["age"] >> pref.age
S["spawnpoint"] >> pref.spawnpoint
@@ -13,7 +12,6 @@
/datum/category_item/player_setup_item/general/basic/save_character(var/savefile/S)
S["real_name"] << pref.real_name
S["name_is_always_random"] << pref.be_random_name
S["gender"] << pref.gender
S["age"] << pref.age
S["spawnpoint"] << pref.spawnpoint
@@ -21,7 +19,6 @@
/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",
@@ -33,21 +30,40 @@
/datum/category_item/player_setup_item/general/basic/gather_save_query()
return list("ss13_characters" = list("name",
"random_name",
"gender",
"age",
"metadata",
"spawnpoint",
"id" = 1))
"id" = 1,
"ckey" = 1))
/datum/category_item/player_setup_item/general/basic/gather_save_parameters()
return list(":name" = pref.real_name,
":random_name" = pref.be_random_name,
":gender" = pref.gender,
":age" = pref.age,
":metadata" = pref.metadata,
":spawnpoint" = pref.spawnpoint,
":id" = pref.current_character)
":id" = pref.current_character,
":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/general/basic/load_special()
pref.can_edit_name = 1
if (config.sql_saves && pref.current_character)
if (!establish_db_connection(dbcon))
return
// Called /after/ loading and /before/ sanitization.
// So we have pref.current_character. It's just in text format.
var/DBQuery/query = dbcon.NewQuery("SELECT DATEDIFF(NOW(), created_at) AS DiffDate FROM ss13_characters WHERE id = :id")
query.Execute(list(":id" = text2num(pref.current_character)))
if (query.NextRow())
if (text2num(query.item[1]) > 5)
pref.can_edit_name = 0
else
error("SQL CHARACTER LOAD: Logic error, general/basic/load_special() didn't return any rows when it should have.")
log_debug("SQL CHARACTER LOAD: Logic error, general/basic/load_special() didn't return any rows when it should have. Character ID: [pref.current_character].")
/datum/category_item/player_setup_item/general/basic/sanitize_character()
pref.age = sanitize_integer(text2num(pref.age), AGE_MIN, AGE_MAX, initial(pref.age))
@@ -56,13 +72,15 @@
if(!pref.real_name)
pref.real_name = random_name(pref.gender, pref.species)
pref.spawnpoint = sanitize_inlist(pref.spawnpoint, spawntypes, initial(pref.spawnpoint))
pref.be_random_name = sanitize_integer(text2num(pref.be_random_name), 0, 1, initial(pref.be_random_name))
/datum/category_item/player_setup_item/general/basic/content()
. = "<b>Name:</b> "
. += "<a href='?src=\ref[src];rename=1'><b>[pref.real_name]</b></a><br>"
. += "(<a href='?src=\ref[src];random_name=1'>Random Name</A>) "
. += "(<a href='?src=\ref[src];always_random_name=1'>Always Random Name: [pref.be_random_name ? "Yes" : "No"]</a>)"
if (pref.can_edit_name)
. += "<a href='?src=\ref[src];rename=1'><b>[pref.real_name]</b></a><br>"
else
. += "<b>[pref.real_name]</b><br> (<a href='?src=\ref[src];namehelp=1'>?</a>)"
if (pref.can_edit_name)
. += "(<a href='?src=\ref[src];random_name=1'>Random Name</A>)"
. += "<br>"
. += "<b>Gender:</b> <a href='?src=\ref[src];gender=1'><b>[capitalize(lowertext(pref.gender))]</b></a><br>"
. += "<b>Age:</b> <a href='?src=\ref[src];age=1'>[pref.age]</a><br>"
@@ -72,6 +90,10 @@
/datum/category_item/player_setup_item/general/basic/OnTopic(var/href,var/list/href_list, var/mob/user)
if(href_list["rename"])
if (!pref.can_edit_name)
alert(user, "You can no longer edit the name of your character.<br><br>If there is a legitimate need, please contact an administrator regarding the matter.")
return TOPIC_NOACTION
var/raw_name = input(user, "Choose your character's name:", "Character Name") as text|null
if (!isnull(raw_name) && CanUseTopic(user))
var/new_name = sanitize_name(raw_name, pref.species)
@@ -82,12 +104,16 @@
user << "<span class='warning'>Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .</span>"
return TOPIC_NOACTION
else if(href_list["random_name"])
pref.real_name = random_name(pref.gender, pref.species)
return TOPIC_REFRESH
else if(href_list["namehelp"])
alert(user, "Due to game mechanics, you are no longer able to edit the name for this character. The grace period offered is 5 days since the character's initial save.<br><br>If you have a need to change the character's name, or further questions regarding this policy, please contact an administrator.")
return TOPIC_NOACTION
else if(href_list["always_random_name"])
pref.be_random_name = !pref.be_random_name
else if(href_list["random_name"])
if (!pref.can_edit_name)
alert(user, "You can no longer edit the name of your character.<br><br>If there is a legitimate need, please contact an administrator regarding the matter.")
return TOPIC_NOACTION
pref.real_name = random_name(pref.gender, pref.species)
return TOPIC_REFRESH
else if(href_list["gender"])
@@ -15,12 +15,14 @@
return list(":id" = pref.current_character)
/datum/category_item/player_setup_item/general/language/gather_save_query()
return list("ss13_characters" = list("language",
"id" = 1))
return list("ss13_characters" = list("id" = 1,
"ckey" = 1,
"language"))
/datum/category_item/player_setup_item/general/language/gather_save_parameters()
return list(":language" = list2params(pref.alternate_languages),
":id" = pref.current_character)
":id" = pref.current_character,
":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/general/language/sanitize_character(var/sql_load = 0)
if (sql_load)
@@ -79,7 +79,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"disabilities",
"organs_data",
"organs_robotic",
"id" = 1))
"id" = 1,
"ckey" = 1))
/datum/category_item/player_setup_item/general/body/gather_save_parameters()
return list(":species" = pref.species,
@@ -94,7 +95,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
":disabilities" = pref.disabilities,
":organs_data" = list2params(pref.organ_data),
":organs_robotic"= list2params(pref.rlimb_data),
":id" = pref.current_character)
":id" = pref.current_character,
":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/general/body/sanitize_character(var/sql_load = 0)
if(!pref.species || !(pref.species in playable_species))
@@ -23,10 +23,10 @@
return list(":id" = pref.current_character)
/datum/category_item/player_setup_item/general/equipment/gather_save_query()
return list("ss13_characters" = list("underwear", "undershirt", "socks", "backbag", "gear", "id" = 1))
return list("ss13_characters" = list("underwear", "undershirt", "socks", "backbag", "gear", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/general/equipment/gather_save_parameters()
return list(":underwear" = pref.underwear, ":undershirt" = pref.undershirt, ":socks" = pref.socks, ":backbag" = pref.backbag, ":gear" = list2params(pref.gear), ":id" = pref.current_character)
return list(":underwear" = pref.underwear, ":undershirt" = pref.undershirt, ":socks" = pref.socks, ":backbag" = pref.backbag, ":gear" = list2params(pref.gear), ":id" = pref.current_character, ":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/general/equipment/sanitize_character(var/sql_load = 0)
if (sql_load)
@@ -89,7 +89,7 @@
/datum/category_item/player_setup_item/general/equipment/proc/get_undies()
return pref.gender == MALE ? underwear_m : underwear_f
/datum/category_item/player_setup_item/general/equipment/proc/get_gender_socks()
return pref.gender == MALE ? socks_m : socks_f
@@ -38,7 +38,7 @@
"records_medical",
"records_security",
"char_id" = 1),
"ss13_characters" = list("home_system", "citizenship", "faction", "religion", "id" = 1))
"ss13_characters" = list("home_system", "citizenship", "faction", "religion", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/general/background/gather_save_parameters()
return list(":records_employment" = pref.gen_record,
@@ -49,7 +49,8 @@
":citizenship" = pref.citizenship,
":faction" = pref.faction,
":religion" = pref.religion,
":id" = pref.current_character)
":id" = pref.current_character,
":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/general/background/sanitize_character()
if(!pref.home_system)
@@ -73,6 +73,7 @@
/datum/category_item/player_setup_item/general/flavor/gather_save_parameters()
var/list/var_list = list(":char_id" = pref.current_character,
":flavour_general" = pref.flavor_texts["general"],
":flavour_head" = pref.flavor_texts["head"],
":flavour_face" = pref.flavor_texts["face"],
":flavour_eyes" = pref.flavor_texts["eyes"],
@@ -19,13 +19,13 @@
S["memo_hash"] << pref.memo_hash
/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_togs" = "asfx_toggles", "motd_hash", "memo_hash"), "args" = list("ckey")))
return list("ss13_player_preferences" = list("vars" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "lastmotd" = "motd_hash", "lastmemo" = "memo_hash"), "args" = list("ckey")))
/datum/category_item/player_setup_item/player_global/settings/gather_load_parameters()
return list(":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/player_global/settings/gather_save_query()
return list("ss13_player_preferences" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "motd_hash", "memo_hash", "ckey" = 1))
return list("ss13_player_preferences" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "lastmotd", "lastmemo", "ckey" = 1))
/datum/category_item/player_setup_item/player_global/settings/gather_save_parameters()
return list(":ckey" = pref.client.ckey,
@@ -33,8 +33,8 @@
":current_character" = pref.current_character,
":toggles" = pref.toggles,
":asfx_togs" = pref.asfx_togs,
":motd_hash" = pref.motd_hash,
":memo_hash" = pref.memo_hash)
":lastmotd" = pref.motd_hash,
":lastmemo" = pref.memo_hash)
/datum/category_item/player_setup_item/player_global/settings/sanitize_preferences(var/sql_load = 0)
if (sql_load)
@@ -40,7 +40,7 @@
return list(":id" = pref.current_character)
/datum/category_item/player_setup_item/occupation/gather_save_query()
return list("ss13_characters" = list("jobs", "alternate_option", "alternate_titles", "id" = 1))
return list("ss13_characters" = list("jobs", "alternate_option", "alternate_titles", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/occupation/gather_save_parameters()
var/list/compiled_jobs = list("job_civilian_high" = pref.job_civilian_high,
@@ -53,11 +53,12 @@
"job_engsec_med" = pref.job_engsec_med,
"job_engsec_low" = pref.job_engsec_low)
return list(":jobs" = list2params(compiled_jobs), ":alternate_option" = pref.alternate_option, ":alternate_titles" = list2params(pref.player_alt_titles), ":id" = pref.current_character)
return list(":jobs" = list2params(compiled_jobs), ":alternate_option" = pref.alternate_option, ":alternate_titles" = list2params(pref.player_alt_titles), ":id" = pref.current_character, ":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/occupation/sanitize_character(var/sql_load = 0)
if (sql_load)
pref.alternate_option = text2num(pref.alternate_option)
pref.player_alt_titles = params2list(pref.player_alt_titles)
var/list/jobs = params2list(pref.unsanitized_jobs)
@@ -62,8 +62,8 @@
pref.incidents.Add(infraction)
log_debug("Added infraction with [infraction.UID]")
/datum/category_item/player_setup_item/other/incidents/content(var/mob/user)
pref.incidents = list()
. += "<b>Incident Information</b><br>"
. += "The following incidents are on file for your character<br>"
for (var/datum/char_infraction/I in pref.incidents)
@@ -157,7 +157,8 @@
for (var/datum/category_item/player_setup_item/PI in items)
PI.load_preferences(S)
else
handle_sql_loading(SQL_PREFERENCES)
if (sql_role == SQL_PREFERENCES)
handle_sql_loading(SQL_PREFERENCES)
for (var/datum/category_item/player_setup_item/PI in items)
PI.sanitize_preferences(config.sql_saves)
@@ -170,7 +171,8 @@
for (var/datum/category_item/player_setup_item/PI in items)
PI.save_preferences(S)
else
handle_sql_saving(SQL_PREFERENCES)
if (sql_role == SQL_PREFERENCES)
handle_sql_saving(SQL_PREFERENCES)
/datum/category_group/player_setup_category/proc/update_setup(var/savefile/preferences, var/savefile/character)
for(var/datum/category_item/player_setup_item/PI in items)
@@ -84,7 +84,11 @@
var/DBQuery/query = dbcon.NewQuery(query_text)
query.Execute(arg_list, 1)
if (query.ErrorMsg())
error("Error loading character from SQL: [query.ErrorMsg()]")
error("SQL CHARACTER LOAD: SQL query error: [query.ErrorMsg()]")
log_debug("SQL CHARACTER LOAD: SQL query error: [query.ErrorMsg()]")
log_debug("SQL CHARACTER LOAD: query args: [json_encode(arg_list)]")
continue
// Each query should only return exactly 1 row.
var/list/var_names = query_cache[type][query_text]
@@ -97,9 +101,9 @@
else
cc.preferences.vars[layers[1]][layers[2]] = query.item[i]
catch(var/exception/e)
error("Error loading character from SQL: [e.name]")
log_debug("SQL Saves: [e.name]")
log_debug("SQL Saves: [e.desc]")
error("SQL CHARACTER LOAD: bad variable name: [e.name]")
log_debug("SQL CHARACTER LOAD: bad variable name: [e.name]")
log_debug("SQL CHARACTER LOAD: var name: [var_names[i]]")
/datum/category_group/player_setup_category/proc/gather_load_parameters()
var/list/arg_list = list()
@@ -162,11 +166,15 @@
for (var/variable in var_names)
if (isnull(var_names[variable]))
query += " [variable] = [arg_names[i]]"
if (i < var_names.len)
query += ", "
if (i < var_names.len)
query += ","
i++
// Remove any potentially damaging commas from the end.
query = replacetext(query, ",", "", length(query) - 1)
// Save it.
query_cache[type] += query
@@ -180,7 +188,11 @@
query.Execute(arg_list, 1)
if (query.ErrorMsg())
error("Error saving character to SQL: [query.ErrorMsg()]")
error("SQL CHARACTER SAVE: SQL query error: [query.ErrorMsg()]")
log_debug("SQL CHARACTER SAVE: SQL query error: [query.ErrorMsg()]")
log_debug("SQL CHARACTER SAVE: query args: [json_encode(arg_list)]")
continue
if (role_type == SQL_CHARACTER && !cc.preferences.current_character)
// No current character, means we're doing insert queries.
@@ -193,9 +205,11 @@
arg_list[":char_id"] = text2num(query.item[1])
cc.preferences.current_character = text2num(query.item[1])
else
error("Error inserting character to SQL: New ID was not recovered.")
error("SQL CHARACTER SAVE: New ID was not recovered.")
log_debug("SQL CHARACTER SAVE: New ID was not recovered.")
if (query.ErrorMsg())
error("Error retreiving new character ID: [query.ErrorMsg()]")
error("SQL CHARACTER SAVE: SQL query error from last_insert_id: [query.ErrorMsg()]")
log_debug("SQL CHARACTER SAVE: SQL query error from last_insert_id: [query.ErrorMsg()]")
/datum/category_group/player_setup_category/proc/gather_save_parameters()
var/list/arg_list = list()
@@ -19,10 +19,10 @@
return list(":id" = pref.current_character)
/datum/category_item/player_setup_item/skills/gather_save_query()
return list("ss13_characters" = list("skills", "skill_specialization", "id" = 1))
return list("ss13_characters" = list("skills", "skill_specialization", "id" = 1, "ckey" = 1))
/datum/category_item/player_setup_item/skills/gather_save_parameters()
return list(":skills" = list2params(pref.skills), ":skill_specialization" = pref.skill_specialization, ":id" = pref.current_character)
return list(":skills" = list2params(pref.skills), ":skill_specialization" = pref.skill_specialization, ":id" = pref.current_character, ":ckey" = pref.client.ckey)
/datum/category_item/player_setup_item/skills/sanitize_character(var/sql_load = 0)
if (SKILLS == null)
@@ -31,6 +31,11 @@
pref.skills = list()
if (sql_load)
pref.skills = params2list(pref.skills)
for (var/skill in pref.skills)
pref.skills[skill] = text2num(pref.skills[skill])
pref.CalculateSkillPoints()
if (!pref.skills.len)
pref.ZeroSkills()
if (pref.used_skillpoints < 0)