diff --git a/.travis.yml b/.travis.yml index 6c9841d87bb..60a2a7e7b44 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 c8ede1a3d45..0b1baf0841d 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,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 d6dc6c9d9ef..9b7aef9599c 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 18dd85fa5bb..6585aebd36a 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 5df8ab5ee9e..ff397785d89 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 403ad067849..0f662ad97d9 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 8cefa660054..4d3b19177ed 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 1aa727e873a..79d287da00a 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() @@ -81,24 +81,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) @@ -121,7 +127,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() @@ -134,7 +139,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 @@ -210,9 +215,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 d25f257ba24..7ccfa950a77 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -38,14 +38,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*/ @@ -181,8 +179,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 95f6d1166b2..062d0458629 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 4a4a36157e7..73cb11cae8d 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]