mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 02:32:10 +00:00
* Fixes an issue with tags for mobs not properly being handled correctly and adds logging to admin circuits (#64821) Tags would bug out due to how the 'Save Shell' component would copy all the variables on an object except a few restricted ones, though this proved to be very buggy. The duplicator part has been removed and more proper logging has been added. To compensate for the duplicator part being removed, admin circuit display names will now replace the entire name of the shell. * Fixes an issue with tags for mobs not properly being handled correctly and adds logging to admin circuits Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
436 lines
13 KiB
Plaintext
436 lines
13 KiB
Plaintext
//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 += "<nobody>"
|
|
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)
|
|
. += "<a href='?priv_msg=[C.findStealthKey()]'>"
|
|
. += "Administrator"
|
|
else
|
|
if(include_link)
|
|
. += "<a href='?priv_msg=[ckey]'>"
|
|
. += key
|
|
if(!C)
|
|
. += "\[DC\]"
|
|
|
|
if(include_link)
|
|
. += "</a>"
|
|
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 (?, ?, ?))"
|