diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index d64711d19446..db216175bdc8 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -213,6 +213,8 @@ }\ }\ A.flags_1 &= ~OVERLAY_QUEUED_1;\ + if(isturf(A)){SSdemo.mark_turf(A);}\ + if(isobj(A) || ismob(A)){SSdemo.mark_dirty(A);}\ } while (FALSE) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 805fc0e82ae0..834cf6dc80a9 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -538,21 +538,6 @@ GLOBAL_LIST_EMPTY(species_list) to_chat(M, rendered_message, avoid_highlighting = speaker_key == M.key) else to_chat(M, message, avoid_highlighting = speaker_key == M.key) - - var/demo_message = message - - if(follow_target) - var/F - if(turf_target) - F = FOLLOW_OR_TURF_LINK(SSdemo, follow_target, turf_target) - else - F = FOLLOW_LINK(SSdemo, follow_target) - demo_message = "[F] [message]" - else if(turf_target) - var/turf_link = TURF_LINK(SSdemo, turf_target) - demo_message = "[turf_link] [message]" - - to_chat(SSdemo, demo_message) //Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value. /proc/create_random_mob(spawn_location, mob_class = HOSTILE_SPAWN) diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 3a14c08468fe..8ce8b4e09d78 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -57,7 +57,6 @@ #endif #define EXTOOLS (world.system_type == MS_WINDOWS ? "byond-extools.dll" : "libbyond-extools.so") -#define DEMO_WRITER (world.system_type == MS_WINDOWS ? "demo-writer.dll" : "libdemo-writer.so") //If you update these values, update the message in the #error #define MAX_BYOND_MAJOR 514 diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm index 7b820312a604..de3a4a58c425 100644 --- a/code/_onclick/hud/credits.dm +++ b/code/_onclick/hud/credits.dm @@ -16,7 +16,6 @@ GLOBAL_LIST(end_titles) for(var/client/C in GLOB.clients) if(C.prefs.show_credits) C.screen += new /atom/movable/screen/credit/title_card(null, null, SSticker.mode.title_icon) - SSdemo.flush() sleep(CREDIT_SPAWN_SPEED * 3) for(var/i in 1 to GLOB.end_titles.len) var/C = GLOB.end_titles[i] @@ -24,7 +23,6 @@ GLOBAL_LIST(end_titles) continue create_credit(C) - SSdemo.flush() sleep(CREDIT_SPAWN_SPEED) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index f3200a31a674..db615cb8e608 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -5,6 +5,11 @@ var/resolved = target.attackby(src, user, params) if(!resolved && target && !QDELETED(src)) afterattack(target, user, 1, params) // 1: clicking something Adjacent + SSdemo.mark_dirty(src) + if(isturf(target)) + SSdemo.mark_turf(target) + else + SSdemo.mark_dirty(target) //Checks if the item can work as a tool, calling the appropriate tool behavior on the target /obj/item/proc/tool_attack_chain(mob/user, atom/target) @@ -22,6 +27,7 @@ if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_NO_INTERACT) return interact(user) + SSdemo.mark_dirty(src) /obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby! if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK) diff --git a/code/controllers/subsystem/demo.dm b/code/controllers/subsystem/demo.dm index 7608d4070dcc..2396b5ea7467 100644 --- a/code/controllers/subsystem/demo.dm +++ b/code/controllers/subsystem/demo.dm @@ -5,135 +5,426 @@ SUBSYSTEM_DEF(demo) init_order = INIT_ORDER_DEMO runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY - loading_points = 1 SECONDS // Yogs -- loading times + loading_points = 12.6 SECONDS // Yogs -- loading times - var/last_size = 0 - var/last_embedded_size = 0 - var/demo_started = 0 + var/list/pre_init_lines = list() // stuff like chat before the init + var/list/icon_cache = list() + var/list/icon_state_caches = list() + var/list/name_cache = list() - var/ckey = "@@demoobserver" - var/mob/dead/observer/dummy_observer + var/list/marked_dirty = list() + var/list/marked_new = list() + var/list/marked_turfs = list() + var/list/del_list = list() - var/list/embed_list = list() - var/list/embedded_list = list() - var/list/chat_list = list() + var/last_written_time = null + var/last_chat_message = null -/datum/controller/subsystem/demo/proc/write_chat(target, message) - if(!demo_started && !chat_list) - return - var/list/target_list - if(target == GLOB.clients || target == world) - target_list = list(world) - else if(istype(target, /datum/controller/subsystem/demo) || target == dummy_observer || target == "d") - target_list = list("d") + // stats stuff + var/last_queued = 0 + var/last_completed = 0 + +/datum/controller/subsystem/demo/proc/write_time() + var/new_time = world.time + if(last_written_time != new_time) + if(initialized) + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "time [new_time]\n") + else + pre_init_lines += "time [new_time]" + last_written_time = new_time + +/datum/controller/subsystem/demo/proc/write_event_line(line) + write_time() + if(initialized) + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "[line]\n") + else + pre_init_lines += line + +/datum/controller/subsystem/demo/proc/write_chat(target, text) + var/target_text = "" + if(target == GLOB.clients) + target_text = "world" else if(islist(target)) - target_list = list() + var/list/target_keys = list() for(var/T in target) - if(istype(T, /datum/controller/subsystem/demo) || T == dummy_observer || T == "d") - target_list += "d" - else - var/client/C = CLIENT_FROM_VAR(target) - if(C) - target_list += C + var/client/C = CLIENT_FROM_VAR(T) + if(C) + target_keys += C.ckey + if(!target_keys.len) + return + target_text = jointext(target_keys, ",") else var/client/C = CLIENT_FROM_VAR(target) if(C) - target_list = list(C) - if(!target_list || !target_list.len) - return - - var/message_str = "" - var/is_text = FALSE - if(islist(message)) - if(message["text"]) - is_text = TRUE - message_str = message["text"] + target_text = C.ckey else - message_str = message["html"] - else if(istext(message)) - message_str = message - if(demo_started) - for(var/I in 1 to target_list.len) - if(!istext(target_list[I])) target_list[I] = "\ref[target_list[I]]" - call(DEMO_WRITER, "demo_chat")(target_list.Join(","), "\ref[message_str]", "[is_text]") - else if(chat_list) - chat_list[++chat_list.len] = list(world.time, target_list, message_str, is_text) + return + var/json_encoded = json_encode(text) + write_event_line("chat [target_text] [last_chat_message == json_encoded ? "=" : json_encoded]") + last_chat_message = json_encoded /datum/controller/subsystem/demo/Initialize() - dummy_observer = new - dummy_observer.forceMove(null) - dummy_observer.key = dummy_observer.ckey = ckey - dummy_observer.name = dummy_observer.real_name = "SSdemo Dummy Observer" - - var/revdata_list = list() + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "demo version 1\n") // increment this if you change the format if(GLOB.revdata) - revdata_list["commit"] = "[GLOB.revdata.commit || GLOB.revdata.originmastercommit]" - if(GLOB.revdata.originmastercommit) revdata_list["originmastercommit"] = "[GLOB.revdata.originmastercommit]" - revdata_list["repo"] = "yogstation13/Yogstation" - var/revdata_str = json_encode(revdata_list); - var/result = call(DEMO_WRITER, "demo_start")(GLOB.demo_log, revdata_str) - - if(result == "SUCCESS") - demo_started = 1 - for(var/L in embed_list) - embed_resource(arglist(L)) - - for(var/list/L in chat_list) - call(DEMO_WRITER, "demo_set_time_override")(L[1]) - var/list/target_list = L[2] - for(var/I in 1 to target_list.len) - if(!istext(target_list[I])) target_list[I] = "\ref[target_list[I]]" - call(DEMO_WRITER, "demo_chat")(target_list.Join(","), "\ref[L[3]]", "[L[4]]") - call(DEMO_WRITER, "demo_set_time_override")("null") - - last_size = text2num(call(DEMO_WRITER, "demo_get_size")()) - else - log_world("Failed to initialize demo system: [result]") - - embed_list = null - chat_list = null + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "commit [GLOB.revdata.commit || GLOB.revdata.originmastercommit]\n") + + // write a "snapshot" of the world at this point. + // start with turfs + log_world("Writing turfs...") + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "init [world.maxx] [world.maxy] [world.maxz]\n") + marked_turfs.Cut() + for(var/z in 1 to world.maxz) + var/row_list = list() + var/last_appearance + var/rle_count = 1 + for(var/y in 1 to world.maxy) + for(var/x in 1 to world.maxx) + var/turf/T = locate(x,y,z) + T.demo_last_appearance = T.appearance + var/this_appearance + // space turfs are difficult to RLE otherwise, because they all + // have different appearances despite being the same thing. + if(T.type == /turf/open/space || T.type == /turf/open/space/basic) + this_appearance = "s" // save the bytes + else if(istype(T, /turf/open/space/transit)) + this_appearance = "t[T.dir]" + else + this_appearance = T.appearance + if(this_appearance == last_appearance) + rle_count++ + else + if(rle_count > 1) + row_list += rle_count + rle_count = 1 + if(istext(this_appearance)) + row_list += this_appearance + else + // do a diff with the previous turf to save those bytes + row_list += encode_appearance(this_appearance, istext(last_appearance) ? null : last_appearance) + last_appearance = this_appearance + if(rle_count > 1) + row_list += rle_count + WRITE_LOG_NO_FORMAT(GLOB.demo_log, jointext(row_list, ",") + "\n") + CHECK_TICK + // then do objects + log_world("Writing objects") + marked_new.Cut() + marked_dirty.Cut() + for(var/z in 1 to world.maxz) + var/spacing = 0 + var/row_list = list() + for(var/y in 1 to world.maxy) + for(var/x in 1 to world.maxx) + var/turf/T = locate(x,y,z) + var/list/turf_list = list() + for(var/C in T.contents) + var/atom/movable/as_movable = C + if(as_movable.loc != T) + continue + if(isobj(C) || ismob(C)) + turf_list += encode_init_obj(C) + if(turf_list.len) + if(spacing) + row_list += spacing + spacing = 0 + row_list += turf_list + spacing++ + CHECK_TICK // This is a bit risky because something might change but meh, its not a big deal. + WRITE_LOG_NO_FORMAT(GLOB.demo_log, jointext(row_list, ",") + "\n") + + // track objects that exist in nullspace + var/nullspace_list = list() + for(var/M in world) + if(!isobj(M) && !ismob(M)) + continue + var/atom/movable/AM = M + if(AM.loc != null) + continue + nullspace_list += encode_init_obj(AM) + CHECK_TICK + WRITE_LOG_NO_FORMAT(GLOB.demo_log, jointext(nullspace_list, ",") + "\n") + + for(var/line in pre_init_lines) + WRITE_LOG_NO_FORMAT(GLOB.demo_log, "[line]\n") return ..() /datum/controller/subsystem/demo/fire() - if(demo_started) - last_size = text2num(call(DEMO_WRITER, "demo_flush")()) + if(!src.marked_new.len && !src.marked_dirty.len && !src.marked_turfs.len && !src.del_list.len) + return // nothing to do + + last_queued = src.marked_new.len + src.marked_dirty.len + src.marked_turfs.len + last_completed = 0 + + write_time() + if(src.del_list.len) + var/s = "del [jointext(src.del_list, ",")]\n" // if I don't do it like this I get "incorrect number of macro arguments" because byond is stupid and sucks + WRITE_LOG_NO_FORMAT(GLOB.demo_log, s) + src.del_list.Cut() + + var/canceled = FALSE + + var/list/marked_dirty = src.marked_dirty + var/list/dirty_updates = list() + while(marked_dirty.len) + last_completed++ + var/atom/movable/M = marked_dirty[marked_dirty.len] + marked_dirty.len-- + if(M.gc_destroyed || !M) + continue + if(M.loc == M.demo_last_loc && M.appearance == M.demo_last_appearance) + continue + var/loc_string = "=" + if(M.loc != M.demo_last_loc) + loc_string = "null" + if(isturf(M.loc)) + loc_string = "[M.x],[M.y],[M.z]" + else if(ismovable(M.loc)) + loc_string = "\ref[M.loc]" + M.demo_last_loc = M.loc + var/appearance_string = "=" + if(M.appearance != M.demo_last_appearance) + appearance_string = encode_appearance(M.appearance, M.demo_last_appearance) + M.demo_last_appearance = M.appearance + dirty_updates += "\ref[M] [loc_string] [appearance_string]" + if(MC_TICK_CHECK) + canceled = TRUE + break + if(dirty_updates.len) + var/s = "update [jointext(dirty_updates, ",")]\n" + WRITE_LOG_NO_FORMAT(GLOB.demo_log, s) + if(canceled) + return + + + var/list/marked_new = src.marked_new + var/list/new_updates = list() + while(marked_new.len) + last_completed++ + var/atom/movable/M = marked_new[marked_new.len] + marked_new.len-- + if(M.gc_destroyed || !M) + continue + var/loc_string = "null" + if(isturf(M.loc)) + loc_string = "[M.x],[M.y],[M.z]" + else if(ismovable(M.loc)) + loc_string = "\ref[M.loc]" + M.demo_last_appearance = M.appearance + new_updates += "\ref[M] [loc_string] [encode_appearance(M.appearance)]" + if(MC_TICK_CHECK) + canceled = TRUE + break + if(new_updates.len) + var/s = "new [jointext(new_updates, ",")]\n" + WRITE_LOG_NO_FORMAT(GLOB.demo_log, s) + if(canceled) + return + + + var/list/marked_turfs = src.marked_turfs + var/list/turf_updates = list() + while(marked_turfs.len) + last_completed++ + var/turf/T = marked_turfs[marked_turfs.len] + marked_turfs.len-- + if(T && T.appearance != T.demo_last_appearance) + turf_updates += "([T.x],[T.y],[T.z])=[encode_appearance(T.appearance, T.demo_last_appearance)]" + T.demo_last_appearance = T.appearance + if(MC_TICK_CHECK) + canceled = TRUE + break + if(turf_updates.len) + var/s = "turf [jointext(turf_updates, ",")]\n" + WRITE_LOG_NO_FORMAT(GLOB.demo_log, s) + if(canceled) + return -/datum/controller/subsystem/demo/proc/flush() - if(demo_started) - last_size = text2num(call(DEMO_WRITER, "demo_flush")()) +/datum/controller/subsystem/demo/proc/encode_init_obj(atom/movable/M) + M.demo_last_loc = M.loc + M.demo_last_appearance = M.appearance + var/encoded_appearance = encode_appearance(M.appearance) + var/list/encoded_contents = list() + for(var/C in M.contents) + if(isobj(C) || ismob(C)) + encoded_contents += encode_init_obj(C) + return "\ref[M]=[encoded_appearance][(encoded_contents.len ? "([jointext(encoded_contents, ",")])" : "")]" -/datum/controller/subsystem/demo/Shutdown() - call(DEMO_WRITER, "demo_end")() +// please make sure the order you call this function in is the same as the order you write +/datum/controller/subsystem/demo/proc/encode_appearance(image/appearance, image/diff_appearance, diff_remove_overlays = FALSE) + if(appearance == null) + return "n" + if(appearance == diff_appearance) + return "=" + + var/icon_txt = "[appearance.icon]" + var/cached_icon = icon_cache[icon_txt] || icon_txt + var/list/icon_state_cache + if(!isnum(cached_icon)) + icon_cache[icon_txt] = icon_cache.len + 1 + icon_state_cache = (icon_state_caches[++icon_state_caches.len] = list()) + else + icon_state_cache = icon_state_caches[cached_icon] + + var/list/cached_icon_state = icon_state_cache[appearance.icon_state] || appearance.icon_state + if(!isnum(cached_icon_state)) + icon_state_cache[appearance.icon_state] = icon_state_cache.len + 1 + + var/cached_name = name_cache[appearance.name] || appearance.name + if(!isnum(cached_name)) + name_cache[appearance.name] = name_cache.len + 1 + + var/color_string = appearance.color || "w" + if(islist(color_string)) + var/list/old_list = appearance.color + var/list/inted = list() + inted.len = old_list.len + for(var/i in 1 to old_list.len) + inted[i] += round(old_list[i] * 255) + color_string = jointext(inted, ",") + var/overlays_string = "\[]" + if(appearance.overlays.len) + var/list/overlays_list = list() + for(var/i in 1 to appearance.overlays.len) + var/image/overlay = appearance.overlays[i] + overlays_list += encode_appearance(overlay, appearance, TRUE) + overlays_string = "\[[jointext(overlays_list, ",")]]" + + var/underlays_string = "\[]" + if(appearance.underlays.len) + var/list/underlays_list = list() + for(var/i in 1 to appearance.underlays.len) + var/image/underlay = appearance.underlays[i] + underlays_list += encode_appearance(underlay, appearance, TRUE) + underlays_string = "\[[jointext(underlays_list, ",")]]" + + var/appearance_transform_string = "i" + if(appearance.transform) + var/matrix/M = appearance.transform + appearance_transform_string = "[M.a],[M.b],[M.c],[M.d],[M.e],[M.f]" + if(appearance_transform_string == "1,0,0,0,1,0") + appearance_transform_string = "i" + var/list/appearance_list = list( + json_encode(cached_icon), + json_encode(cached_icon_state), + json_encode(cached_name), + appearance.appearance_flags, + appearance.layer, + appearance.plane == -32767 ? "" : appearance.plane, + appearance.dir == 2 ? "" : appearance.dir, + appearance.color ? color_string : "", + appearance.alpha == 255 ? "" : appearance.alpha, + appearance.pixel_x == 0 ? "" : appearance.pixel_x, + appearance.pixel_y == 0 ? "" : appearance.pixel_y, + appearance.blend_mode <= 1 ? "" : appearance.blend_mode, + appearance_transform_string != "i" ? appearance_transform_string : "", + appearance:invisibility == 0 ? "" : appearance:invisibility, // colon because dreamchecker is dumb + appearance.pixel_w == 0 ? "" : appearance.pixel_w, + appearance.pixel_z == 0 ? "" : appearance.pixel_z, + appearance.overlays.len ? overlays_string : "", + appearance.underlays.len ? underlays_string : "" + ) + while(appearance_list[appearance_list.len] == "" && appearance_list.len > 0) + appearance_list.len-- + + var/undiffed_string = "{[jointext(appearance_list, ";")]}" + + if(diff_appearance) + var/overlays_identical = TRUE + if(diff_remove_overlays) + overlays_identical = (appearance.overlays.len == 0) + else if(appearance.overlays.len != diff_appearance.overlays.len) + overlays_identical = FALSE + else + for(var/i in 1 to appearance.overlays.len) + if(appearance.overlays[i] != diff_appearance.overlays[i]) + overlays_identical = FALSE + break + + var/underlays_identical = TRUE + if(diff_remove_overlays) + underlays_identical = (appearance.underlays.len == 0) + else if(appearance.underlays.len != diff_appearance.underlays.len) + underlays_identical = FALSE + else + for(var/i in 1 to appearance.underlays.len) + if(appearance.underlays[i] != diff_appearance.underlays[i]) + underlays_identical = FALSE + break + + var/diff_transform_string = "i" + if(diff_appearance.transform) + var/matrix/M = diff_appearance.transform + diff_transform_string = "[M.a],[M.b],[M.c],[M.d],[M.e],[M.f]" + if(diff_transform_string == "1,0,0,0,1,0") + diff_transform_string = "i" + + var/list/diffed_appearance_list = list( + json_encode(cached_icon), + json_encode(cached_icon_state), + json_encode(cached_name), + appearance.appearance_flags == diff_appearance.appearance_flags ? "" : appearance.appearance_flags, + appearance.layer == diff_appearance.layer ? "" : appearance.layer, + appearance.plane == diff_appearance.plane ? "" : appearance.plane, + appearance.dir == diff_appearance.dir ? "" : appearance.dir, + appearance.color == diff_appearance.color ? "" : color_string, + appearance.alpha == diff_appearance.alpha ? "" : appearance.alpha, + appearance.pixel_x == diff_appearance.pixel_x ? "" : appearance.pixel_x, + appearance.pixel_y == diff_appearance.pixel_y ? "" : appearance.pixel_y, + appearance.blend_mode == diff_appearance.blend_mode ? "" : appearance.blend_mode, + appearance_transform_string == diff_transform_string ? "" : appearance_transform_string, + appearance:invisibility == diff_appearance:invisibility ? "" : appearance:invisibility, // colon because dreamchecker is too dumb + appearance.pixel_w == diff_appearance.pixel_w ? "" : appearance.pixel_w, + appearance.pixel_z == diff_appearance.pixel_z ? "" : appearance.pixel_z, + overlays_identical ? "" : overlays_string, + underlays_identical ? "" :underlays_string + ) + while(diffed_appearance_list[diffed_appearance_list.len] == "" && diffed_appearance_list.len > 0) + diffed_appearance_list.len-- + + var/diffed_string = "~{[jointext(diffed_appearance_list, ";")]}" + if(length(diffed_string) < length(undiffed_string)) + return diffed_string + return undiffed_string /datum/controller/subsystem/demo/stat_entry(msg) - msg += "ALL: [format_size(last_size)] | RSC: [format_size(last_embedded_size)]" + msg += "Remaining: {" + msg += "Trf:[marked_turfs.len]|" + msg += "New:[marked_new.len]|" + msg += "Upd:[marked_dirty.len]|" + msg += "Del:[del_list.len]" + msg += "}" return ..(msg) -/datum/controller/subsystem/demo/proc/format_size(size) - if(size < 1000000) - return "[round(size / 1000, 0.01)]kB" - return "[round(size / 1000000, 0.01)]MB" - -/datum/controller/subsystem/demo/proc/embed_resource(res, path) - res = fcopy_rsc(res) - if(!demo_started) - if(embed_list) - embed_list += list(list(res, path)) - return res - if(!res || embedded_list[res]) - return res - var/do_del = FALSE - if(!istext(path)) - path = "tmp/rsc_[ckey("\ref[res]")]_[rand(0, 100000)]" - fcopy(res, path) - do_del = TRUE - var/size = length(file(path)) - last_embedded_size += size - log_world("Embedding \ref[res] [res] from [path] ([size] bytes)") - if(call(DEMO_WRITER, "demo_embed_resource")("\ref[res]", path) != "SUCCESS") - log_world("Failed to copy \ref[res] [res] from [path]!") - embedded_list[res] = 1 - if(do_del) - fdel(path) - return res +/datum/controller/subsystem/demo/proc/mark_turf(turf/T) + if(!isturf(T)) + return + marked_turfs[T] = TRUE + +/datum/controller/subsystem/demo/proc/mark_new(atom/movable/M) + if(!isobj(M) && !ismob(M)) + return + if(M.gc_destroyed) + return + marked_new[M] = TRUE + if(marked_dirty[M]) + marked_dirty -= M + +// I can't wait for when TG ports this and they make this a #define macro. +/datum/controller/subsystem/demo/proc/mark_dirty(atom/movable/M) + if(!isobj(M) && !ismob(M)) + return + if(M.gc_destroyed) + return + if(!marked_new[M]) + marked_dirty[M] = TRUE + +/datum/controller/subsystem/demo/proc/mark_destroyed(atom/movable/M) + if(!isobj(M) && !ismob(M)) + return + if(marked_new[M]) + marked_new -= M + if(marked_dirty[M]) + marked_dirty -= M + if(initialized) + del_list["\ref[M]"] = 1 diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 588b28f10eec..e635b71a9734 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -281,6 +281,7 @@ SUBSYSTEM_DEF(garbage) SSgarbage.Queue(D) if (QDEL_HINT_IWILLGC) D.gc_destroyed = world.time + SSdemo.mark_destroyed(D) return if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. if(!force) @@ -300,8 +301,10 @@ SUBSYSTEM_DEF(garbage) SSgarbage.Queue(D) if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete + SSdemo.mark_destroyed(D) SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. + SSdemo.mark_destroyed(D) SSgarbage.HardDelete(D) if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. SSgarbage.Queue(D) @@ -320,6 +323,8 @@ SUBSYSTEM_DEF(garbage) #endif I.no_hint++ SSgarbage.Queue(D) + if(D) + SSdemo.mark_destroyed(D) else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index 222791464068..0b7e1b0d27ee 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -57,7 +57,6 @@ SUBSYSTEM_DEF(title) continue var/atom/movable/screen/splash/S = new(thing, FALSE) S.Fade(FALSE,FALSE) - SSdemo.flush() /datum/controller/subsystem/title/Shutdown() if(file_path) diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index 41e6a901c2df..0378b747de92 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -122,7 +122,6 @@ sentmsg = "[span_prefix("RELAY: [input["source"]]")] " + sentmsg //no pinging across servers, thats intentional to_chat(C,sentmsg) - to_chat(SSdemo, "[span_prefix("RELAY: [input["source"]]")] " + oocmsg) /datum/world_topic/server_hop keyword = "server_hop" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d0beb04eda80..11e9c8fed0af 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -106,6 +106,7 @@ if(SSatoms.InitAtom(src, args)) //we were deleted return + SSdemo.mark_new(src) /** * The primary method that objects are setup in SS13 with diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index b411a72b3d7e..255766e1e7b8 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -427,6 +427,7 @@ if (length(client_mobs_in_contents)) update_parallax_contents() + SSdemo.mark_dirty(src) return TRUE /atom/movable/Destroy(force) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index cc682e741f09..5e57453c0125 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -602,6 +602,7 @@ if(AIRLOCK_DENY, AIRLOCK_OPENING, AIRLOCK_CLOSING, AIRLOCK_EMAG) icon_state = "nonexistenticonstate" //MADNESS set_airlock_overlays(state) + SSdemo.mark_dirty(src) /obj/machinery/door/airlock/proc/set_side_overlays(obj/effect/overlay/airlock_part/base, show_lights = FALSE) var/side = base.side_id diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 7e9bcf8a49f4..443b71a7accc 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -224,6 +224,7 @@ icon_state = "door_open" if(welded) add_overlay("welded_open") + SSdemo.mark_dirty(src) /obj/machinery/door/firedoor/open() . = ..() diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 5a9744dcad5c..7daa543a4a88 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -94,6 +94,7 @@ icon_state = "closed" else icon_state = "open" + SSdemo.mark_dirty(src) /obj/machinery/door/poddoor/try_to_activate_door(mob/user) return diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index b772f95d0c88..6f28785e0b4f 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -53,6 +53,7 @@ icon_state = base_state else icon_state = "[base_state]open" + SSdemo.mark_dirty(src) /obj/machinery/door/window/proc/open_and_close() if(!open()) diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index 603d292880fb..7c320f600d01 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -186,8 +186,6 @@ for(var/mob/dead/observer/M in GLOB.player_list) if(M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTRADIO)) receive |= M - if(SSdemo.dummy_observer) - receive |= SSdemo.dummy_observer // Render the message and have everybody hear it. // Always call this on the virtualspeaker to avoid issues. diff --git a/code/game/objects/effects/wanted_poster.dm b/code/game/objects/effects/wanted_poster.dm index b94db671463b..5cc2923f5ae7 100644 --- a/code/game/objects/effects/wanted_poster.dm +++ b/code/game/objects/effects/wanted_poster.dm @@ -63,7 +63,6 @@ the_icon.Insert(icon('icons/obj/contraband.dmi', "poster_ripped"), "poster_ripped") icon = the_icon - SSdemo.embed_resource(icon) /* This proc will write "WANTED" or MISSING" at the top of the poster. diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 951801a60d2d..5ddd7dee933f 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -795,7 +795,6 @@ GLOBAL_LIST_EMPTY(PDAs) for(var/mob/M in GLOB.player_list) if(isobserver(M) && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTPDA)) to_chat(M, "[FOLLOW_LINK(M, user)] [ghost_message]") - to_chat(SSdemo, "[FOLLOW_LINK(SSdemo, user)] [ghost_message]") // Log in the talk log user.log_talk(message, LOG_PDA, tag="PDA: [initial(name)] to [target_text]") to_chat(user, span_info("Message sent to [target_text]: \"[message]\"")) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 42db6df56708..2aeca9a435fc 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -135,6 +135,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( for(var/turf/open/space/S in RANGE_TURFS(1, src)) //RANGE_TURFS is in code\__HELPERS\game.dm S.update_starlight() + SSdemo.mark_turf(W) return W diff --git a/code/game/world.dm b/code/game/world.dm index 1ff9c863d9ce..a8dcd7f57255 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -277,7 +277,6 @@ GLOBAL_VAR(restart_counter) log_world("Deallocated [num_deleted] gas mixtures") if(fexists(EXTOOLS)) call(EXTOOLS, "cleanup")() - SSdemo?.Shutdown() ..() /world/proc/update_status() //yogs -- Mirrored in the Yogs folder in March 2019. Do not edit, swallow, or submerge in acid diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index adb2953cefe3..ed433033fe5b 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -33,7 +33,6 @@ continue if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above to_chat(M, rendered) - to_chat(SSdemo, rendered) SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 8cc94dfaf4cd..31c9a9532e0a 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -141,7 +141,6 @@ GLOBAL_VAR_INIT(mentor_ooc_colour, YOGS_MENTOR_OOC_COLOUR) // yogs - mentor ooc SEND_SOUND(C,pingsound) sentmsg = "" + sentmsg + "" to_chat(C,sentmsg) - to_chat(SSdemo, oocmsg); //YOGS END var/data = list() data["normal"] = oocmsg diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 632e4426682f..b42a3b6afeb0 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -343,13 +343,13 @@ BLIND // can't see anything var/icon/female_clothing_icon = icon(icon, t_color) // and make the uniform the "female" shape. female_s is either the top-only one (for jumpskirts and the like) or the full one (for jumpsuits) var/icon/female_s = icon('icons/effects/clothing.dmi', "[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]") female_clothing_icon.Blend(female_s, ICON_MULTIPLY) - GLOB.female_clothing_icons[index] = SSdemo.embed_resource(fcopy_rsc(female_clothing_icon)) //Then it saves the icon in a global list so it doesn't have to make it again + GLOB.female_clothing_icons[index] = fcopy_rsc(female_clothing_icon) //Then it saves the icon in a global list so it doesn't have to make it again /proc/generate_skinny_clothing(index,t_color,icon,type) //Works the exact same as above but for skinny people var/icon/skinny_clothing_icon = icon(icon, t_color) var/icon/skinny_s = icon('icons/effects/clothing.dmi', "[(type == FEMALE_UNIFORM_FULL) ? "skinny_full" : "skinny_top"]") //Hooks into same check to see if it's eligible skinny_clothing_icon.Blend(skinny_s, ICON_MULTIPLY) - GLOB.skinny_clothing_icons[index] = SSdemo.embed_resource(fcopy_rsc(skinny_clothing_icon)) + GLOB.skinny_clothing_icons[index] = fcopy_rsc(skinny_clothing_icon) /obj/item/clothing/under/verb/toggle() set name = "Adjust Suit Sensors" diff --git a/code/modules/demo/hooks.dm b/code/modules/demo/hooks.dm new file mode 100644 index 000000000000..ebf82f2bbcbd --- /dev/null +++ b/code/modules/demo/hooks.dm @@ -0,0 +1,24 @@ +/atom + var/image/demo_last_appearance +/atom/movable + var/atom/demo_last_loc + +/mob/Login() + . = ..() + SSdemo.write_event_line("setmob [client.ckey] \ref[src]") + +/client/New() + SSdemo.write_event_line("login [ckey]") + . = ..() + +/client/Del() + . = ..() + SSdemo.write_event_line("logout [ckey]") + +/turf/setDir() + . = ..() + SSdemo.mark_turf(src) + +/atom/movable/setDir() + . = ..() + SSdemo.mark_dirty(src) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index e524265076ea..36f2c821c977 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -104,6 +104,8 @@ All ShuttleMove procs go here loc = newT + SSdemo.mark_dirty(src) + return TRUE // Called on atoms after everything has been moved diff --git a/tools/deploy.sh b/tools/deploy.sh index 5d31f485333c..a83f1cb5756b 100755 --- a/tools/deploy.sh +++ b/tools/deploy.sh @@ -37,5 +37,4 @@ cp -r strings/* $1/strings/ #dlls on windows cp rust_g* $1/ || true -cp *byond-extools.* $1/ || true -cp *demo-writer.* $1/ || true +cp *byond-extools.* $1/ || true \ No newline at end of file diff --git a/yogstation.dme b/yogstation.dme index 72b5d1aeb43b..43c647aac530 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -1908,6 +1908,7 @@ #include "code\modules\clothing\under\jobs\Plasmaman\medsci.dm" #include "code\modules\clothing\under\jobs\Plasmaman\security.dm" #include "code\modules\corporations\corporation.dm" +#include "code\modules\demo\hooks.dm" #include "code\modules\detectivework\detective_work.dm" #include "code\modules\detectivework\evidence.dm" #include "code\modules\detectivework\footprints_and_rag.dm"