diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 76254b13c44..a8a33784263 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -419,3 +419,26 @@ var/global/list/bad_blocks[0] unique_enzymes = md5(character.real_name) reg_dna[unique_enzymes] = character.real_name + +// Hmm, I wonder how to go about this without a huge convention break +/datum/dna/proc/serialize() + var/data = list() + data["UE"] = unique_enzymes + data["SE"] = SE.Copy() // This is probably too lazy for my own good + data["UI"] = UI.Copy() + data["species"] = species // This works because `species` is a string, not a datum + // Because old DNA coders were insane or something + data["b_type"] = b_type + data["real_name"] = real_name + return data + +/datum/dna/proc/deserialize(data) + unique_enzymes = data["UE"] + // The de-serializer is unlikely to tamper with the lists + SE = data["SE"] + UI = data["UI"] + UpdateUI() + UpdateSE() + species = data["species"] + b_type = data["b_type"] + real_name = data["real_name"] \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 90ad26039db..aed9270bf57 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -113,7 +113,8 @@ var/list/admin_verbs_event = list( var/list/admin_verbs_spawn = list( /datum/admins/proc/spawn_atom, /*allows us to spawn instances*/ - /client/proc/respawn_character + /client/proc/respawn_character, + /client/proc/admin_deserialize ) var/list/admin_verbs_server = list( /client/proc/ToRban, @@ -161,7 +162,9 @@ var/list/admin_verbs_debug = list( /proc/machine_upgrade, /client/proc/map_template_load, /client/proc/map_template_upload, - /client/proc/view_runtimes + /client/proc/view_runtimes, + /client/proc/admin_serialize, + /client/proc/admin_deserialize ) var/list/admin_verbs_possess = list( /proc/possess, diff --git a/code/modules/admin/verbs/serialization.dm b/code/modules/admin/verbs/serialization.dm new file mode 100644 index 00000000000..41ba5d11aa1 --- /dev/null +++ b/code/modules/admin/verbs/serialization.dm @@ -0,0 +1,26 @@ +/client/proc/admin_serialize() + set name = "Serialize Marked Datum" + set desc = "Turns your marked object into a JSON string you can later use to re-create the object" + set category = "Debug" + + if(!check_rights(R_ADMIN)) + return + + if(!istype(holder.marked_datum, /atom/movable)) + to_chat(src, "The marked datum is not an atom/movable!") + return + + var/atom/movable/AM = holder.marked_datum + to_chat(src, json_encode(AM.serialize())) + +/client/proc/admin_deserialize() + set name = "Deserialize JSON datum" + set desc = "Creates an object from a JSON string" + set category = "Debug" + + if(!check_rights(R_ADMIN|R_DEBUG)) + return + + var/json_text = input("Enter the JSON code:","Text") as message|null + if(json_text) + json_to_object(json_text, get_turf(usr)) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f9c448df5e3..12cabc68a5f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -8,7 +8,7 @@ //why are these here and not in human_defines.dm //var/list/hud_list[10] var/datum/species/species //Contains icon generation and language information, set during New(). - var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. + var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. var/obj/item/weapon/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call. /mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna = 0) @@ -482,8 +482,8 @@ if(3 to 4) stunprob = 30 if(5 to 6) stunprob = 40 if(7 to 8) stunprob = 60 - if(9) stunprob = 70 - if(10) stunprob = 95 + if(9) stunprob = 70 + if(10) stunprob = 95 if(prob(stunprob)) M.powerlevel -= 3 @@ -944,7 +944,7 @@ for(var/datum/data/record/R in data_core.security) if(R.fields["id"] == E.fields["id"]) if(hasHUD(usr,"security")) - var/t1 = sanitize(copytext(input("Add Comment:", "Sec. records", null, null) as message,1,MAX_MESSAGE_LEN)) + var/t1 = sanitize(copytext(input("Add Comment:", "Sec. records", null, null) as message,1,MAX_MESSAGE_LEN)) if( !(t1) || usr.stat || usr.restrained() || !(hasHUD(usr,"security")) ) return var/counter = 1 @@ -1075,7 +1075,7 @@ for(var/datum/data/record/R in data_core.medical) if(R.fields["id"] == E.fields["id"]) if(hasHUD(usr,"medical")) - var/t1 = sanitize(copytext(input("Add Comment:", "Med. records", null, null) as message,1,MAX_MESSAGE_LEN)) + var/t1 = sanitize(copytext(input("Add Comment:", "Med. records", null, null) as message,1,MAX_MESSAGE_LEN)) if( !(t1) || usr.stat || usr.restrained() || !(hasHUD(usr,"medical")) ) return var/counter = 1 @@ -1285,8 +1285,8 @@ var/limb_path = organ_data["path"] var/obj/item/organ/external/O = new limb_path(temp_holder) if(H.get_limb_by_name(O.name)) //Check to see if the user already has an limb with the same name as the 'missing limb'. If they do, skip regrowth. - continue //In an example, this will prevent duplication of the mob's right arm if the mob is a Human and they have a Diona right arm, since, - //while the limb with the name 'right_arm' the mob has may not be listed in their species' bodyparts definition, it is still viable and has the appropriate limb name. + continue //In an example, this will prevent duplication of the mob's right arm if the mob is a Human and they have a Diona right arm, since, + //while the limb with the name 'right_arm' the mob has may not be listed in their species' bodyparts definition, it is still viable and has the appropriate limb name. else O = new limb_path(H) //Create the limb on the player. O.owner = H @@ -1704,7 +1704,7 @@ if((head_organ.species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use. hair += i - var/new_style = input(src, "Select a monitor display", "Monitor Display", head_organ.h_style) as null|anything in hair + var/new_style = input(src, "Select a monitor display", "Monitor Display", head_organ.h_style) as null|anything in hair if(incapacitated()) to_chat(src, "You were interrupted while changing your monitor display.") return @@ -1909,7 +1909,7 @@ if(current_size >= STAGE_THREE) var/list/handlist = list(l_hand, r_hand) for(var/obj/item/hand in handlist) - if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) + if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) step_towards(hand, src) to_chat(src, "\The [S] pulls \the [hand] from your grip!") apply_effect(current_size * 3, IRRADIATE) @@ -2031,3 +2031,59 @@ return 0 return . + +/mob/living/carbon/human/serialize() + // Currently: Limbs/organs only + var/list/data = ..() + var/list/limbs_list = list() + var/list/organs_list = list() + data["limbs"] = limbs_list + data["iorgans"] = organs_list + data["dna"] = dna.serialize() + data["ushirt"] = undershirt + for(var/limb in organs_by_name) + var/obj/item/organ/O = organs_by_name[limb] + if(!O) + limbs_list[limb] = "missing" + continue + + limbs_list[limb] = O.serialize() + + for(var/organ in internal_organs) + var/obj/item/organ/O = organ + organs_list[O.name] = O.serialize() + + return json_encode(data) + +/mob/living/carbon/human/deserialize(list/data) + var/list/limbs_list = data["limbs"] + var/list/organs_list = data["iorgans"] + if(!islist(data["limbs"])) + throw EXCEPTION("Expected a limbs list, but found none") + + if(islist(data["dna"])) + dna.deserialize(data["dna"]) + real_name = dna.real_name + name = real_name + UpdateAppearance() + set_species(dna.species) + undershirt = data["ushirt"] + for(var/obj/item/organ/internal/iorgan in internal_organs) + qdel(iorgan) + + for(var/obj/item/organ/external/organ in organs) + qdel(organ) + + for(var/limb in limbs_list) + // Missing means skip this part - it's missing + if(limbs_list[limb] == "missing") + continue + // "New" code handles insertion and DNA sync'ing + var/obj/item/organ/external/E = list_to_object(limbs_list[limb], src) + E.sync_colour_to_dna() + + for(var/organ in organs_list) + // As above, "New" code handles insertion, DNA sync + list_to_object(organs_list[organ], src) + update_icons() + ..() diff --git a/code/modules/persistence/persistence.dm b/code/modules/persistence/persistence.dm new file mode 100644 index 00000000000..cc5a7684947 --- /dev/null +++ b/code/modules/persistence/persistence.dm @@ -0,0 +1,38 @@ +/* +* Returns a byond list that can be passed to the "deserialize" proc +* to bring a new instance of this atom to its original state +* +* If we want to store this info, we can pass it to `json_encode` or some other +* interface that suits our fancy, to make it into an easily-handled string +*/ +/atom/movable/proc/serialize() + return list("type" = "[type]") + +/* +* This is given the byond list from above, to bring this atom to the state +* described in the list. +* This will be called after `New` but before `initialize`, so linking and stuff +* would probably be handled in `initialize` +* +* Also, this should only be called by `json_to_object` in persistence.dm - at least +* with current plans - that way it can actually initialize the type from the list +*/ +/atom/movable/proc/deserialize(var/data) + return + +/proc/json_to_object(var/json_data, var/loc) + var/data = json_decode(json_data) + return list_to_object(data, loc) + +/proc/list_to_object(var/list/data, var/loc) + if(!islist(data)) + throw EXCEPTION("You didn't give me a list, bucko") + if(!("type" in data)) + throw EXCEPTION("No 'type' field in the data") + var/path = text2path(data["type"]) + if(!path) + throw EXCEPTION("Path not found: [path]") + + var/atom/movable/thing = new path(loc) + thing.deserialize(data) + return thing diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 5e49a97fc59..b49ccc6a838 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -343,3 +343,32 @@ I use this so that this can be made better once the organ overhaul rolls out -- if(!istype(owner)) // You're not the primary organ of ANYTHING, bucko return 0 return src == O.get_int_organ(organ_tag) + +/obj/item/organ/serialize() + var/data = ..() + if(status != 0) + data["status"] = status + if(robotic > 0) + data["robotic"] = robotic + + // Save the DNA datum if: The owner doesn't exist, or the dna doesn't match + // the owner + if(!(owner && dna.unique_enzymes == owner.dna.unique_enzymes)) + data["dna"] = dna.serialize() + return data + +/obj/item/organ/deserialize(var/data) + switch(data["robotic"]) + if(1) + mechassist() + if(2) + robotize() + else + // Nothing + if(isnum(data["status"])) + status = data["status"] + if(islist(data["dna"])) + // The only thing the official proc does is + //instantiate the list and call this proc + dna.deserialize(data["dna"]) + ..() diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index 10d7fe724ea..1c3f05f5816 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -836,12 +836,7 @@ Note that amputating the affected organ does in fact remove the infection from t ..() if(company && istext(company)) - model = company - var/datum/robolimb/R = all_robolimbs[company] - if(R) - force_icon = R.icon - name = "[R.company] [initial(name)]" - desc = "[R.desc]" + set_company(company) cannot_break = 1 get_icon() @@ -849,6 +844,16 @@ Note that amputating the affected organ does in fact remove the infection from t if(T) T.robotize() + + +/obj/item/organ/external/proc/set_company(var/company) + model = company + var/datum/robolimb/R = all_robolimbs[company] + if(R) + force_icon = R.icon + name = "[R.company] [initial(name)]" + desc = "[R.desc]" + /obj/item/organ/external/proc/mutate() src.status |= ORGAN_MUTATED if(owner) owner.update_body() @@ -969,3 +974,19 @@ Note that amputating the affected organ does in fact remove the infection from t continue wounds -= W qdel(W) + + +/obj/item/organ/external/serialize() + var/list/data = ..() + if(robotic == 2) + data["company"] = model + // If we wanted to store wound information, here is where it would go + return data + +/obj/item/organ/external/deserialize(list/data) + var/company = data["company"] + if(company && istext(company)) + set_company(company) + ..() // Parent call loads in the DNA + if(data["dna"]) + sync_colour_to_dna() diff --git a/paradise.dme b/paradise.dme index d79069d135d..5c184d781ea 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1043,6 +1043,7 @@ #include "code\modules\admin\verbs\possess.dm" #include "code\modules\admin\verbs\pray.dm" #include "code\modules\admin\verbs\randomverbs.dm" +#include "code\modules\admin\verbs\serialization.dm" #include "code\modules\admin\verbs\striketeam.dm" #include "code\modules\admin\verbs\striketeam_syndicate.dm" #include "code\modules\admin\verbs\ticklag.dm" @@ -1739,6 +1740,7 @@ #include "code\modules\pda\pdas.dm" #include "code\modules\pda\radio.dm" #include "code\modules\pda\utilities.dm" +#include "code\modules\persistence\persistence.dm" #include "code\modules\pooling\pool.dm" #include "code\modules\power\apc.dm" #include "code\modules\power\cable.dm"