//wrapper macros for easier grepping #define DIRECT_OUTPUT(A, B) A << B #define DIRECT_INPUT(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 READ_FILE(file, text) DIRECT_INPUT(file, text) //This is an external call, "true" and "false" are how rust parses out booleans #define WRITE_LOG(log, text) rustg_log_write(log, text, "true") #define WRITE_LOG_NO_FORMAT(log, text) rustg_log_write(log, text, "false") //print a warning message to world.log #define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [UNLINT(src)] usr: [usr].") /proc/warning(msg) msg = "## WARNING: [msg]" log_world(msg) //not an error or a warning, but worth to mention on the world log, just in case. #define NOTICE(MSG) notice(MSG) /proc/notice(msg) msg = "## NOTICE: [msg]" log_world(msg) //print a testing-mode debug message to world.log and world #ifdef TESTING #define testing(msg) log_world("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]") GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) // we don't really check if a word or name is used twice, be aware of that #define testing_profile_start(NAME, LIST) LIST[NAME] = world.timeofday #define testing_profile_current(NAME, LIST) round((world.timeofday - LIST[NAME])/10,0.1) #define testing_profile_output(NAME, LIST) testing("[LIST["_PROFILE_NAME"]] profile of [NAME] is [testing_profile_current(NAME,LIST)]s") #define testing_profile_output_all(LIST) { for(var/_NAME in LIST) { testing_profile_current(,_NAME,LIST); }; }; #else #define testing(msg) #define testing_profile_start(NAME, LIST) #define testing_profile_current(NAME, LIST) #define testing_profile_output(NAME, LIST) #define testing_profile_output_all(LIST) #endif #define testing_profile_global_start(NAME) testing_profile_start(NAME,GLOB.testing_global_profiler) #define testing_profile_global_current(NAME) testing_profile_current(NAME, GLOB.testing_global_profiler) #define testing_profile_global_output(NAME) testing_profile_output(NAME, GLOB.testing_global_profiler) #define testing_profile_global_output_all testing_profile_output_all(GLOB.testing_global_profiler) #define testing_profile_local_init(PROFILE_NAME) var/list/_timer_system = list( "_PROFILE_NAME" = PROFILE_NAME, "_start_of_proc" = world.timeofday ) #define testing_profile_local_start(NAME) testing_profile_start(NAME, _timer_system) #define testing_profile_local_current(NAME) testing_profile_current(NAME, _timer_system) #define testing_profile_local_output(NAME) testing_profile_output(NAME, _timer_system) #define testing_profile_local_output_all testing_profile_output_all(_timer_system) #if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) /proc/log_test(text) WRITE_LOG(GLOB.test_log, text) SEND_TEXT(world.log, text) #endif #if defined(REFERENCE_DOING_IT_LIVE) #define log_reftracker(msg) log_harddel("## REF SEARCH [msg]") /proc/log_harddel(text) WRITE_LOG(GLOB.harddel_log, text) #elif defined(REFERENCE_TRACKING) // Doing it locally #define log_reftracker(msg) log_world("## REF SEARCH [msg]") #else //Not tracking at all #define log_reftracker(msg) #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_LOG(GLOB.world_game_log, "ADMIN: [text]") /proc/log_admin_circuit(text) GLOB.admin_log.Add(text) if(CONFIG_GET(flag/log_admin)) WRITE_LOG(GLOB.world_game_log, "ADMIN: CIRCUIT: [text]") /proc/log_admin_private(text) GLOB.admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: [text]") /proc/log_adminsay(text) GLOB.admin_log.Add(text) if (CONFIG_GET(flag/log_adminchat)) WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: ASAY: [text]") /proc/log_dsay(text) if (CONFIG_GET(flag/log_adminchat)) 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_LOG(GLOB.world_game_log, "GAME: [text]") /proc/log_mecha(text) if (CONFIG_GET(flag/log_mecha)) WRITE_LOG(GLOB.world_mecha_log, "MECHA: [text]") /proc/log_virus(text) if (CONFIG_GET(flag/log_virus)) WRITE_LOG(GLOB.world_virus_log, "VIRUS: [text]") /proc/log_cloning(text, mob/initiator) if(CONFIG_GET(flag/log_cloning)) WRITE_LOG(GLOB.world_cloning_log, "CLONING: [text]") /proc/log_paper(text) WRITE_LOG(GLOB.world_paper_log, "PAPER: [text]") /proc/log_asset(text) if(CONFIG_GET(flag/log_asset)) WRITE_LOG(GLOB.world_asset_log, "ASSET: [text]") /proc/log_access(text) if (CONFIG_GET(flag/log_access)) WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]") /proc/log_silicon(text) if (CONFIG_GET(flag/log_silicon)) WRITE_LOG(GLOB.world_silicon_log, "SILICON: [text]") /proc/log_tool(text, mob/initiator) if(CONFIG_GET(flag/log_tools)) WRITE_LOG(GLOB.world_tool_log, "TOOL: [text]") /** * Writes to a special log file if the log_suspicious_login config flag is set, * which is intended to contain all logins that failed under suspicious circumstances. * * Mirrors this log entry to log_access when access_log_mirror is TRUE, so this proc * doesn't need to be used alongside log_access and can replace it where appropriate. */ /proc/log_suspicious_login(text, access_log_mirror = TRUE) if (CONFIG_GET(flag/log_suspicious_login)) WRITE_LOG(GLOB.world_suspicious_login_log, "SUSPICIOUS_ACCESS: [text]") if(access_log_mirror) log_access(text) /proc/log_attack(text) if (CONFIG_GET(flag/log_attack)) WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]") /proc/log_econ(text) if (CONFIG_GET(flag/log_econ)) WRITE_LOG(GLOB.world_econ_log, "MONEY: [text]") /proc/log_traitor(text) if (CONFIG_GET(flag/log_econ)) WRITE_LOG(GLOB.world_game_log, "TRAITOR: [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.title] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]") /proc/log_bomber(atom/user, details, atom/bomb, additional_details, message_admins = TRUE) var/bomb_message = "[details][bomb ? " [bomb.name] at [AREACOORD(bomb)]": ""][additional_details ? " [additional_details]" : ""]." if(user) user.log_message(bomb_message, LOG_ATTACK) //let it go to individual logs as well as the game log bomb_message = "[key_name(user)] at [AREACOORD(user)] [bomb_message]" else log_game(bomb_message) GLOB.bombers += bomb_message if(message_admins) message_admins("[user ? "[ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(user)] " : ""][details][bomb ? " [bomb.name] at [ADMIN_VERBOSEJMP(bomb)]": ""][additional_details ? " [additional_details]" : ""].") /// Logs the contents of the gasmix to the game log, prefixed by text /proc/log_atmos(text, datum/gas_mixture/mix) var/message = text message += "TEMP=[mix.temperature],MOL=[mix.total_moles()],VOL=[mix.volume]" for(var/key in mix.gases) var/list/gaslist = mix.gases[key] message += "[gaslist[GAS_META][META_GAS_ID]]=[gaslist[MOLES]];" log_game(message) /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_radio_emote(text) if (CONFIG_GET(flag/log_emote)) WRITE_LOG(GLOB.world_game_log, "RADIOEMOTE: [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_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_LOG(GLOB.world_pda_log, "COMMENT: [text]") /proc/log_uplink(text) if (CONFIG_GET(flag/log_uplink)) WRITE_LOG(GLOB.world_uplink_log, "UPLINK: [text]") /proc/log_spellbook(text) if (CONFIG_GET(flag/log_uplink)) WRITE_LOG(GLOB.world_uplink_log, "SPELLBOOK: [text]") /proc/log_heretic_knowledge(text) if (CONFIG_GET(flag/log_uplink)) WRITE_LOG(GLOB.world_uplink_log, "HERETIC RESEARCH: [text]") /proc/log_telecomms(text) if (CONFIG_GET(flag/log_telecomms)) WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]") /proc/log_chat(text) if (CONFIG_GET(flag/log_pda)) //same thing here WRITE_LOG(GLOB.world_pda_log, "CHAT: [text]") /proc/log_vote(text) if (CONFIG_GET(flag/log_vote)) WRITE_LOG(GLOB.world_game_log, "VOTE: [text]") /proc/log_shuttle(text) if (CONFIG_GET(flag/log_shuttle)) WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [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_mob_tag(text) WRITE_LOG(GLOB.world_mob_tag_log, "TAG: [text]") /proc/log_sql(text) WRITE_LOG(GLOB.sql_error_log, "SQL: [text]") /proc/log_qdel(text) WRITE_LOG(GLOB.world_qdel_log, "QDEL: [text]") /proc/log_query_debug(text) WRITE_LOG(GLOB.query_debug_log, "SQL: [text]") /proc/log_job_debug(text) if (CONFIG_GET(flag/log_job_debug)) WRITE_LOG(GLOB.world_job_debug_log, "JOB: [text]") /* Log to both DD and the logfile. */ /proc/log_world(text) #ifdef USE_CUSTOM_ERROR_HANDLER WRITE_LOG(GLOB.world_runtime_log, text) #endif SEND_TEXT(world.log, text) /* 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) /proc/log_mapping(text, skip_world_log) WRITE_LOG(GLOB.world_map_error_log, text) if(skip_world_log) return SEND_TEXT(world.log, text) /proc/log_perf(list/perf_info) . = "[perf_info.Join(",")]\n" WRITE_LOG_NO_FORMAT(GLOB.perf_log, .) /** * Appends a tgui-related log entry. All arguments are optional. */ /proc/log_tgui(user, message, context, datum/tgui_window/window, datum/src_object) var/entry = "" // Insert user info if(!user) entry += "" else if(istype(user, /mob)) var/mob/mob = user entry += "[mob.ckey] (as [mob] at [mob.x],[mob.y],[mob.z])" else if(istype(user, /client)) var/client/client = user entry += "[client.ckey]" // Insert context if(context) entry += " in [context]" else if(window) entry += " in [window.id]" // Resolve src_object if(!src_object && window?.locked_by) src_object = window.locked_by.src_object // Insert src_object info if(src_object) entry += "\nUsing: [src_object.type] [REF(src_object)]" // Insert message if(message) entry += "\n[message]" WRITE_LOG(GLOB.tgui_log, entry) /* 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() rustg_log_close_all() /* Helper procs for building detailed log lines */ /proc/key_name(whom, include_link = null, include_name = TRUE) var/mob/M var/client/C var/key var/ckey var/fallback_name if(!whom) return "*null*" if(istype(whom, /client)) C = whom M = C.mob key = C.key ckey = C.ckey else if(ismob(whom)) M = whom C = M.client key = M.key ckey = M.ckey else if(istext(whom)) key = whom ckey = ckey(whom) C = GLOB.directory[ckey] if(C) M = C.mob else if(istype(whom,/datum/mind)) var/datum/mind/mind = whom key = mind.key ckey = ckey(key) if(mind.current) M = mind.current if(M.client) C = M.client else fallback_name = mind.name else // Catch-all cases if none of the types above match var/swhom = null if(istype(whom, /atom)) var/atom/A = whom swhom = "[A.name]" else if(istype(whom, /datum)) swhom = "[whom]" if(!swhom) swhom = "*invalid*" return "\[[swhom]\]" . = "" if(!ckey) include_link = FALSE if(key) if(C?.holder && C.holder.fakekey && !include_name) if(include_link) . += "" . += "Administrator" else if(include_link) . += "" . += key if(!C) . += "\[DC\]" if(include_link) . += "" else . += "*no key*" if(include_name) if(M) if(M.real_name) . += "/([M.real_name])" else if(M.name) . += "/([M.name])" else if(fallback_name) . += "/([fallback_name])" return . /proc/key_name_admin(whom, include_name = TRUE) return key_name(whom, TRUE, include_name) /proc/loc_name(atom/A) if(!istype(A)) return "(INVALID LOCATION)" var/turf/T = A if (!istype(T)) T = get_turf(A) if(istype(T)) return "([AREACOORD(T)])" else if(A.loc) return "(UNKNOWN (?, ?, ?))"