diff --git a/.travis.yml b/.travis.yml index 6c9841d87b..60a2a7e7b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ env: - BYOND_MAJOR="512" - BYOND_MINOR="1418" - NODE_VERSION="4" + - RUST_G_VERSION="0.2.0" - BUILD_TOOLS=false - BUILD_TESTING=false - DM_MAPFILE="loadallmaps" @@ -18,8 +19,10 @@ env: cache: directories: - - tgui/node_modules - $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR} + - tgui/node_modules + - $HOME/.rustup + - $HOME/.cargo addons: @@ -28,6 +31,7 @@ addons: - libc6-i386 - libgcc1:i386 - libstdc++6:i386 + - gcc-multilib - python3 - python3-pip @@ -41,5 +45,6 @@ before_script: script: - tools/travis/check_filedirs.sh tgstation.dme - tools/travis/build_tools.sh + - tools/travis/build_dependencies.sh - tools/travis/build_byond.sh diff --git a/README.md b/README.md index 159cab53cd..3e123280a2 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ byondkey = Rank where the admin rank must be properly capitalised. +This codebase also depends on a native library called rust-g. A precompiled +Windows DLL is included in this repository, but Linux users will need to build +and install it themselves. Directions can be found at the [rust-g +repo](https://github.com/tgstation13/rust-g). + Finally, to start the server, run Dream Daemon and enter the path to your compiled tgstation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Safe'. Then press GO diff --git a/TGS3.json b/TGS3.json index d6dc6c9d9e..9b7aef9599 100644 --- a/TGS3.json +++ b/TGS3.json @@ -17,6 +17,7 @@ "data" ], "dlls": [ - "libmariadb.dll" + "libmariadb.dll", + "rust_g.dll" ] - } \ No newline at end of file + } diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index 18dd85fa5b..6585aebd36 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -1,9 +1,13 @@ +//location of the rust-g library +#define RUST_G "rust_g" + //wrapper macros for easier grepping #define DIRECT_OUTPUT(A, B) A << B #define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image) #define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound) #define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text) #define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text) +#define WRITE_LOG(log, text) call(RUST_G, "log_write")(log, text) //print a warning message to world.log #define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].") @@ -26,99 +30,129 @@ #ifdef UNIT_TESTS /proc/log_test(text) - WRITE_FILE(GLOB.test_log, "\[[time_stamp()]]: [text]") + WRITE_LOG(GLOB.test_log, text) SEND_TEXT(world.log, text) #endif + +/* Items with ADMINPRIVATE prefixed are stripped from public logs. */ /proc/log_admin(text) GLOB.admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMIN: [text]") + WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]") -//Items using this proc are stripped from public logs - use with caution /proc/log_admin_private(text) GLOB.admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]") + WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: [text]") /proc/log_adminsay(text) if (CONFIG_GET(flag/log_adminchat)) - log_admin_private("ASAY: [text]") + WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: ASAY: [text]") /proc/log_dsay(text) if (CONFIG_GET(flag/log_adminchat)) - log_admin("DSAY: [text]") + WRITE_LOG(GLOB.world_game_log, "ADMIN: DSAY: [text]") + +/* All other items are public. */ /proc/log_game(text) if (CONFIG_GET(flag/log_game)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]") - -/proc/log_vote(text) - if (CONFIG_GET(flag/log_vote)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]") + WRITE_LOG(GLOB.world_game_log, "GAME: [text]") /proc/log_access(text) if (CONFIG_GET(flag/log_access)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]") - -/proc/log_say(text) - if (CONFIG_GET(flag/log_say)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]") - -/proc/log_prayer(text) - if (CONFIG_GET(flag/log_prayer)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]") + WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]") /proc/log_law(text) if (CONFIG_GET(flag/log_law)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]") - -/proc/log_ooc(text) - if (CONFIG_GET(flag/log_ooc)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]") - -/proc/log_whisper(text) - if (CONFIG_GET(flag/log_whisper)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]") - -/proc/log_emote(text) - if (CONFIG_GET(flag/log_emote)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]") + WRITE_LOG(GLOB.world_game_log, "LAW: [text]") /proc/log_attack(text) if (CONFIG_GET(flag/log_attack)) - WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]") + WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]") + +/proc/log_manifest(ckey, datum/mind/mind,mob/body, latejoin = FALSE) + if (CONFIG_GET(flag/log_manifest)) + WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]") + + +/proc/log_say(text) + if (CONFIG_GET(flag/log_say)) + WRITE_LOG(GLOB.world_game_log, "SAY: [text]") + +/proc/log_ooc(text) + if (CONFIG_GET(flag/log_ooc)) + WRITE_LOG(GLOB.world_game_log, "OOC: [text]") + +/proc/log_whisper(text) + if (CONFIG_GET(flag/log_whisper)) + WRITE_LOG(GLOB.world_game_log, "WHISPER: [text]") + +/proc/log_emote(text) + if (CONFIG_GET(flag/log_emote)) + WRITE_LOG(GLOB.world_game_log, "EMOTE: [text]") + +/proc/log_prayer(text) + if (CONFIG_GET(flag/log_prayer)) + WRITE_LOG(GLOB.world_game_log, "PRAY: [text]") /proc/log_pda(text) if (CONFIG_GET(flag/log_pda)) - WRITE_FILE(GLOB.world_pda_log, "\[[time_stamp()]]PDA: [text]") + WRITE_LOG(GLOB.world_pda_log, "PDA: [text]") /proc/log_comment(text) if (CONFIG_GET(flag/log_pda)) //reusing the PDA option because I really don't think news comments are worth a config option - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]") + WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]") /proc/log_chat(text) if (CONFIG_GET(flag/log_pda)) - WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]") + //same thing here + WRITE_LOG(GLOB.world_pda_log, "CHAT: [text]") -/proc/log_qdel(text) - WRITE_FILE(GLOB.world_qdel_log, "\[[time_stamp()]]QDEL: [text]") +/proc/log_vote(text) + if (CONFIG_GET(flag/log_vote)) + WRITE_LOG(GLOB.world_game_log, "VOTE: [text]") + + +/proc/log_topic(text) + WRITE_LOG(GLOB.world_game_log, "TOPIC: [text]") + +/proc/log_href(text) + WRITE_LOG(GLOB.world_href_log, "HREF: [text]") /proc/log_sql(text) - WRITE_FILE(GLOB.sql_error_log, "\[[time_stamp()]]SQL: [text]") + WRITE_LOG(GLOB.sql_error_log, "SQL: [text]") -/proc/log_config(text) - WRITE_FILE(GLOB.config_error_log, text) - SEND_TEXT(world.log, text) +/proc/log_qdel(text) + WRITE_LOG(GLOB.world_qdel_log, "QDEL: [text]") -//This replaces world.log so it displays both in DD and the file +/* Log to both DD and the logfile. */ /proc/log_world(text) - WRITE_FILE(GLOB.world_runtime_log, text) + WRITE_LOG(GLOB.world_runtime_log, text) SEND_TEXT(world.log, text) -// Helper procs for building detailed log lines +/* Log to the logfile only. */ +/proc/log_runtime(text) + WRITE_LOG(GLOB.world_runtime_log, text) +/* Rarely gets called; just here in case the config breaks. */ +/proc/log_config(text) + WRITE_LOG(GLOB.config_error_log, text) + SEND_TEXT(world.log, text) + + +/* For logging round startup. */ +/proc/start_log(log) + WRITE_LOG(log, "Starting up round ID [GLOB.round_id].\n-------------------------") + +/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */ +/proc/shutdown_logging() + call(RUST_G, "log_close_all")() + + +/* Helper procs for building detailed log lines */ /proc/datum_info_line(datum/D) if(!istype(D)) return @@ -136,7 +170,5 @@ else if(A.loc) return "[A.loc] (0, 0, 0) ([A.loc.type])" - -/proc/log_manifest(key,datum/mind/mind,mob/body,latejoin = FALSE) - if (CONFIG_GET(flag/log_manifest)) - WRITE_FILE(GLOB.manifest_log, "[key] \\ [body.real_name] \\ [mind.assigned_role] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]") \ No newline at end of file +//this is only used here (for now) +#undef RUST_G diff --git a/code/_globalvars/logging.dm b/code/_globalvars/logging.dm index 5df8ab5ee9..ff397785d8 100644 --- a/code/_globalvars/logging.dm +++ b/code/_globalvars/logging.dm @@ -18,8 +18,8 @@ GLOBAL_VAR(sql_error_log) GLOBAL_PROTECT(sql_error_log) GLOBAL_VAR(world_pda_log) GLOBAL_PROTECT(world_pda_log) -GLOBAL_VAR(manifest_log) -GLOBAL_PROTECT(manifest_log) +GLOBAL_VAR(world_manifest_log) +GLOBAL_PROTECT(world_manifest_log) GLOBAL_LIST_EMPTY(bombers) GLOBAL_PROTECT(bombers) @@ -41,4 +41,4 @@ GLOBAL_PROTECT(adminlog) GLOBAL_LIST_EMPTY(individual_log_list) // Logs each mob individual logs, a global so it doesn't get lost on cloning/changing mobs -GLOBAL_LIST_EMPTY(active_turfs_startlist) \ No newline at end of file +GLOBAL_LIST_EMPTY(active_turfs_startlist) diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 403ad06784..0f662ad97d 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -258,7 +258,7 @@ if ("disabled") currentmap = null else - WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'") + log_config("Unknown command in map vote config: '[command]'") /datum/controller/configuration/proc/pick_mode(mode_name) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 8cefa66005..4d3b19177e 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -257,9 +257,9 @@ GLOBAL_LIST_EMPTY(crematoriums) M.emote("scream") if(user) user.log_message("Cremated [M]/[M.ckey]", INDIVIDUAL_ATTACK_LOG) - log_attack("\[[time_stamp()]\] [user]/[user.ckey] cremated [M]/[M.ckey]") + log_attack("[user]/[user.ckey] cremated [M]/[M.ckey]") else - log_attack("\[[time_stamp()]\] UNKNOWN cremated [M]/[M.ckey]") + log_attack("UNKNOWN cremated [M]/[M.ckey]") M.death(1) if(M) //some animals get automatically deleted on death. M.ghostize() diff --git a/code/game/world.dm b/code/game/world.dm index 177d9ede22..edb08d4573 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -4,14 +4,14 @@ GLOBAL_VAR(security_mode) GLOBAL_VAR(restart_counter) GLOBAL_PROTECT(security_mode) -//This happens after the Master subsystem news (it's a global datum) +//This happens after the Master subsystem new(s) (it's a global datum) //So subsystems globals exist, but are not initialised /world/New() - log_world("World loaded at [time_stamp()]") + log_world("World loaded at [time_stamp()]!") SetupExternalRSC() - GLOB.config_error_log = GLOB.manifest_log = GLOB.world_pda_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl + GLOB.config_error_log = GLOB.world_manifest_log = GLOB.world_pda_log = GLOB.sql_error_log = GLOB.world_href_log = GLOB.world_runtime_log = GLOB.world_attack_log = GLOB.world_game_log = "data/logs/config_error.log" //temporary file used to record errors with loading config, moved to log directory once logging is set bl CheckSecurityMode() @@ -84,24 +84,30 @@ GLOBAL_PROTECT(security_mode) GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" else GLOB.log_directory = "data/logs/[override_dir]" - GLOB.world_game_log = file("[GLOB.log_directory]/game.log") - GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log") - GLOB.world_runtime_log = file("[GLOB.log_directory]/runtime.log") - GLOB.world_qdel_log = file("[GLOB.log_directory]/qdel.log") - GLOB.world_href_log = file("[GLOB.log_directory]/hrefs.html") - GLOB.world_pda_log = file("[GLOB.log_directory]/pda.log") - GLOB.sql_error_log = file("[GLOB.log_directory]/sql.log") - GLOB.manifest_log = file("[GLOB.log_directory]/manifest.log") + + GLOB.world_game_log = "[GLOB.log_directory]/game.log" + GLOB.world_attack_log = "[GLOB.log_directory]/attack.log" + GLOB.world_pda_log = "[GLOB.log_directory]/pda.log" + GLOB.world_manifest_log = "[GLOB.log_directory]/manifest.log" + GLOB.world_href_log = "[GLOB.log_directory]/hrefs.log" + GLOB.sql_error_log = "[GLOB.log_directory]/sql.log" + GLOB.world_qdel_log = "[GLOB.log_directory]/qdel.log" + GLOB.world_runtime_log = "[GLOB.log_directory]/runtime.log" + #ifdef UNIT_TESTS GLOB.test_log = file("[GLOB.log_directory]/tests.log") - WRITE_FILE(GLOB.test_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") + start_log(GLOB.test_log) #endif - WRITE_FILE(GLOB.world_game_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") - WRITE_FILE(GLOB.world_attack_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") - WRITE_FILE(GLOB.world_runtime_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") - WRITE_FILE(GLOB.world_pda_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") - WRITE_FILE(GLOB.manifest_log, "\n\nStarting up round ID [GLOB.round_id]. [time_stamp()]\n---------------------") - GLOB.changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently + start_log(GLOB.world_game_log) + start_log(GLOB.world_attack_log) + start_log(GLOB.world_pda_log) + start_log(GLOB.world_manifest_log) + start_log(GLOB.world_href_log) + start_log(GLOB.sql_error_log) + start_log(GLOB.world_qdel_log) + start_log(GLOB.world_runtime_log) + + GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently if(fexists(GLOB.config_error_log)) fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log") fdel(GLOB.config_error_log) @@ -124,7 +130,6 @@ GLOBAL_PROTECT(security_mode) warning("/tg/station 13 uses many file operations, a few shell()s, and some external call()s. Trusted mode is recommended. You can download our source code for your own browsing and compilation at https://github.com/tgstation/tgstation") /world/Topic(T, addr, master, key) - SERVER_TOOLS_ON_TOPIC //redirect to server tools if necessary var/static/list/topic_handlers = TopicHandlers() @@ -137,7 +142,7 @@ GLOBAL_PROTECT(security_mode) break if((!handler || initial(handler.log)) && config && CONFIG_GET(flag/log_world_topic)) - WRITE_FILE(GLOB.world_game_log, "TOPIC: \"[T]\", from:[addr], master:[master], key:[key]") + log_topic("\"[T]\", from:[addr], master:[master], key:[key]") if(!handler) return @@ -213,9 +218,11 @@ GLOBAL_PROTECT(security_mode) if(do_hard_reboot) log_world("World hard rebooted at [time_stamp()]") + shutdown_logging() // See comment below. SERVER_TOOLS_REBOOT_BYOND log_world("World rebooted at [time_stamp()]") + shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss. ..() /world/proc/update_status() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 61b3d1408a..c99f568086 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -32,14 +32,12 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin()) /datum/admins/proc/set_admin_notice, /*announcement all clients see when joining the server.*/ /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ /client/proc/toggle_view_range, /*changes how far we can see*/ - /datum/admins/proc/view_txt_log, /*shows the server log (world_game_log) for today*/ - /datum/admins/proc/view_atk_log, /*shows the server combat-log, doesn't do anything presently*/ + /client/proc/getserverlogs, /*for accessing server logs*/ /client/proc/cmd_admin_subtle_message, /*send an message to somebody as a 'voice in their head'*/ /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_admin_check_contents, /*displays the contents of an instance*/ /client/proc/check_antagonists, /*shows all antags*/ /datum/admins/proc/access_news_network, /*allows access of newscasters*/ - /client/proc/getserverlog, /*allows us to fetch server logs (world_game_log) for other days*/ /client/proc/jumptocoord, /*we ghost and jump to a coordinate*/ /client/proc/Getmob, /*teleports a mob to our location*/ /client/proc/Getkey, /*teleports a mob with a certain ckey to our location*/ @@ -182,8 +180,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( /datum/admins/proc/set_admin_notice, /client/proc/admin_ghost, /client/proc/toggle_view_range, - /datum/admins/proc/view_txt_log, - /datum/admins/proc/view_atk_log, /client/proc/cmd_admin_subtle_message, /client/proc/cmd_admin_check_contents, /datum/admins/proc/access_news_network, diff --git a/code/modules/admin/verbs/getlogs.dm b/code/modules/admin/verbs/getlogs.dm index 95f6d1166b..062d045862 100644 --- a/code/modules/admin/verbs/getlogs.dm +++ b/code/modules/admin/verbs/getlogs.dm @@ -1,9 +1,8 @@ //This proc allows download of past server logs saved within the data/logs/ folder. -//It works similarly to show-server-log. -/client/proc/getserverlog() - set name = ".getserverlog" - set desc = "Fetch logfiles from data/logs" - set category = null +/client/proc/getserverlogs() + set name = "Get Server Logs" + set desc = "View/retrieve logfiles." + set category = "Admin" var/path = browse_files("data/logs/") if(!path) @@ -13,9 +12,7 @@ return message_admins("[key_name_admin(src)] accessed file: [path]") - //this is copypasta because making it a proc would mean locking out adminproccalls, - // and that system is buggy enough with false positives that I don't want to risk locking admins out of legit calls. - switch(alert("View (in game), Open (in your system's text editor), or Download file [path]?", "Log File Opening", "View", "Open", "Download")) + switch(alert("View (in game), Open (in your system's text editor), or Download?", path, "View", "Open", "Download")) if ("View") src << browse("
[html_encode(file2text(file(path)))]", list2params(list("window" = "viewfile.[path]"))) if ("Open") @@ -24,52 +21,5 @@ src << ftp(file(path)) else return - to_chat(src, "Attempting to send file, this may take a fair few minutes if the file is very large.") - return - - -//Other log stuff put here for the sake of organisation - -//Shows today's server log -/datum/admins/proc/view_txt_log() - set category = "Admin" - set name = "Show Server Log" - set desc = "Shows server log for this round." - - if(fexists("[GLOB.world_game_log]")) - switch(alert("View (in game), Open (in your system's text editor), or Download file [GLOB.world_game_log]?", "Log File Opening", "View", "Open", "Download")) - if ("View") - src << browse("
[html_encode(file2text(GLOB.world_game_log))]", list2params(list("window" = "viewfile.[GLOB.world_game_log]"))) - if ("Open") - src << run(GLOB.world_game_log) - if ("Download") - src << ftp(GLOB.world_game_log) - else - return - else - to_chat(src, "Server log not found, try using .getserverlog.") - return - SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Server Log") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - return - -//Shows today's attack log -/datum/admins/proc/view_atk_log() - set category = "Admin" - set name = "Show Server Attack Log" - set desc = "Shows server attack log for this round." - - if(fexists("[GLOB.world_attack_log]")) - switch(alert("View (in game), Open (in your system's text editor), or Download file [GLOB.world_attack_log]?", "Log File Opening", "View", "Open", "Download")) - if ("View") - src << browse("
[html_encode(file2text(GLOB.world_attack_log))]", list2params(list("window" = "viewfile.[GLOB.world_attack_log]"))) - if ("Open") - src << run(GLOB.world_attack_log) - if ("Download") - src << ftp(GLOB.world_attack_log) - else - return - else - to_chat(src, "Server attack log not found, try using .getserverlog.") - return - SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Server Attack log") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + to_chat(src, "Attempting to send [path], this may take a fair few minutes if the file is very large.") return diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 035bd2f4b3..42c92908e7 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -81,7 +81,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( //Logs all hrefs, except chat pings if(!(href_list["_src_"] == "chat" && href_list["proc"] == "ping" && LAZYLEN(href_list) == 2)) - WRITE_FILE(GLOB.world_href_log, "[time_stamp(show_ds = TRUE)] [src] (usr:[usr]\[[COORD(usr)]\]) || [hsrc ? "[hsrc] " : ""][href]