From 99afe463dc57aea90ec579b9cf400a91fadf8d08 Mon Sep 17 00:00:00 2001
From: CHOMPStation2StaffMirrorBot
<94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com>
Date: Thu, 19 Mar 2026 15:03:53 -0700
Subject: [PATCH] [MIRROR] reimplements attack and player logs (#12553)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
---
SQL/feedback_schema.sql | 37 ++--
code/__defines/logging.dm | 27 +++
code/_helpers/logging/attack.dm | 4 +-
code/_helpers/logging/log_to_db.dm | 13 ++
code/_helpers/logging/mob.dm | 52 ++----
code/_helpers/logging/talk.dm | 4 +-
code/_helpers/mobs.dm | 5 -
.../configuration/entries/general.dm | 7 +-
code/controllers/subsystems/dbcore.dm | 5 +
code/controllers/subsystems/mobs.dm | 1 -
code/controllers/subsystems/persist_vr.dm | 1 -
code/defines/procs/statistics.dm | 2 -
.../game/mecha/equipment/tools/armor_melee.dm | 2 +-
code/game/mecha/mecha.dm | 4 +-
code/game/mecha/mecha_actions.dm | 6 +-
code/game/world.dm | 71 -------
code/modules/admin/DB ban/functions.dm | 4 -
code/modules/admin/IsBanned.dm | 2 +-
code/modules/admin/admin_attack_log.dm | 29 ---
code/modules/admin/admin_tools.dm | 123 ++++++------
code/modules/admin/admin_verb_lists_vr.dm | 6 -
code/modules/admin/admin_verbs.dm | 1 -
code/modules/admin/banjob.dm | 2 +-
code/modules/admin/verbs/antag-ooc.dm | 2 +-
.../admin/verbs/check_customitem_activity.dm | 1 -
code/modules/admin/verbs/dbcon_fix.dm | 1 -
code/modules/client/client procs.dm | 2 -
code/modules/client/verbs/ooc.dm | 4 +-
.../food/kitchen/cooking_machines/fryer.dm | 3 +-
code/modules/library/lib_machines.dm | 6 -
code/modules/mob/dead/observer/observer.dm | 1 -
code/modules/mob/dead/observer/say.dm | 4 +-
code/modules/mob/living/say.dm | 4 +-
code/modules/mob/new_player/new_player.dm | 1 -
code/modules/mob/new_player/poll.dm | 6 -
code/modules/mob/say_vr.dm | 4 +-
.../nifsoft/software/13_soulcatcher.dm | 4 +-
code/modules/pda/messenger.dm | 2 +-
code/modules/recycling/packagewrap.dm | 2 +-
code/modules/research/message_server.dm | 1 -
code/modules/shieldgen/directional_shield.dm | 4 +-
code/modules/spells/spell_code.dm | 2 +-
code/modules/spells/spellbook.dm | 2 +-
code/modules/vehicles/vehicle.dm | 2 +-
code/modules/vore/eating/soulcatcher.dm | 4 +-
config/example/config.txt | 5 +
.../interfaces/PlayerLogViewer/function.ts | 11 ++
.../tgui/interfaces/PlayerLogViewer/index.tsx | 176 ++++++++++++++++++
.../tgui/interfaces/PlayerLogViewer/types.ts | 18 ++
vorestation.dme | 1 +
50 files changed, 411 insertions(+), 270 deletions(-)
create mode 100644 code/_helpers/logging/log_to_db.dm
create mode 100644 tgui/packages/tgui/interfaces/PlayerLogViewer/function.ts
create mode 100644 tgui/packages/tgui/interfaces/PlayerLogViewer/index.tsx
create mode 100644 tgui/packages/tgui/interfaces/PlayerLogViewer/types.ts
diff --git a/SQL/feedback_schema.sql b/SQL/feedback_schema.sql
index 62db2ea212..2e7bbb799a 100644
--- a/SQL/feedback_schema.sql
+++ b/SQL/feedback_schema.sql
@@ -76,7 +76,7 @@ CREATE TABLE IF NOT EXISTS `erro_feedback` (
`var_value` int(16) DEFAULT NULL,
`details` text,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_player`
CREATE TABLE IF NOT EXISTS `erro_player` (
@@ -93,7 +93,7 @@ CREATE TABLE IF NOT EXISTS `erro_player` (
KEY `discord_id` (`discord_id`),
KEY `computerid` (`computerid`),
KEY `ip` (`ip`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_poll_option`
CREATE TABLE IF NOT EXISTS `erro_poll_option` (
@@ -107,7 +107,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_option` (
`descmid` varchar(32) DEFAULT NULL,
`descmax` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_poll_question`
CREATE TABLE IF NOT EXISTS `erro_poll_question` (
@@ -118,7 +118,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_question` (
`question` varchar(255) NOT NULL,
`adminonly` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_poll_textreply`
CREATE TABLE IF NOT EXISTS `erro_poll_textreply` (
@@ -130,7 +130,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_textreply` (
`replytext` text NOT NULL,
`adminrank` varchar(32) NOT NULL DEFAULT 'Player',
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_poll_vote`
CREATE TABLE IF NOT EXISTS `erro_poll_vote` (
@@ -143,7 +143,7 @@ CREATE TABLE IF NOT EXISTS `erro_poll_vote` (
`adminrank` varchar(32) NOT NULL,
`rating` int(2) DEFAULT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `erro_privacy`
CREATE TABLE IF NOT EXISTS `erro_privacy` (
@@ -152,7 +152,20 @@ CREATE TABLE IF NOT EXISTS `erro_privacy` (
`ckey` varchar(32) NOT NULL,
`option` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+-- Dumping structure for table ss13.erro_dialog
+CREATE TABLE IF NOT EXISTS `erro_dialog` (
+ `mid` int(11) NOT NULL AUTO_INCREMENT,
+ `time` datetime NOT NULL,
+ `ckey` varchar(32) NOT NULL,
+ `color` varchar(16) DEFAULT NULL,
+ `mob` varchar(128) DEFAULT NULL,
+ `area` varchar(128) DEFAULT NULL,
+ `type` varchar(32) NOT NULL,
+ `message` text NOT NULL,
+ PRIMARY KEY (`mid`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `death`
CREATE TABLE IF NOT EXISTS `death` (
@@ -172,7 +185,7 @@ CREATE TABLE IF NOT EXISTS `death` (
`fireloss` INT(11) NOT NULL,
`oxyloss` INT(11) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `karma`
@@ -188,7 +201,7 @@ CREATE TABLE IF NOT EXISTS `karma` (
`spenderip` TEXT NOT NULL,
`time` DATETIME NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `karmatotals`
CREATE TABLE IF NOT EXISTS `karmatotals` (
@@ -196,7 +209,7 @@ CREATE TABLE IF NOT EXISTS `karmatotals` (
`byondkey` TEXT NOT NULL,
`karma` INT(11) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `library`
CREATE TABLE IF NOT EXISTS `library` (
@@ -206,7 +219,7 @@ CREATE TABLE IF NOT EXISTS `library` (
`content` TEXT NOT NULL,
`category` TEXT NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;
-- Table structure for table `population`
CREATE TABLE IF NOT EXISTS `population` (
@@ -215,7 +228,7 @@ CREATE TABLE IF NOT EXISTS `population` (
`admincount` INT(11) NULL DEFAULT NULL,
`time` DATETIME NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Table structure for table `vr_player_hours`
CREATE TABLE IF NOT EXISTS `vr_player_hours` (
diff --git a/code/__defines/logging.dm b/code/__defines/logging.dm
index f87ab3f428..4ebd600bcc 100644
--- a/code/__defines/logging.dm
+++ b/code/__defines/logging.dm
@@ -38,6 +38,33 @@
#define LOG_SPEECH_INDICATORS (1 << 22)
#define LOG_TRANSPORT (1 << 23)
+GLOBAL_ALIST_INIT(logtype_to_string, alist(
+ LOG_ATTACK = "ATTACK",
+ LOG_SAY = "SAY",
+ LOG_WHISPER = "WHISPER",
+ LOG_EMOTE = "EMOTE",
+ LOG_DSAY = "DEADSAY",
+ LOG_PDA = "PDA",
+ LOG_CHAT = "CHAT",
+ LOG_COMMENT = "COMMENT",
+ LOG_TELECOMMS = "RADIO",
+ LOG_OOC = "OOC",
+ LOG_LOOC = "LOOC",
+ LOG_ADMIN = "ADMIN",
+ LOG_OWNERSHIP = "OWNERSHIP",
+ LOG_GAME = "GAME",
+ LOG_ADMIN_PRIVATE = "ADMIN_PRIV",
+ LOG_ASAY = "ASAY",
+ LOG_MECHA = "MECH",
+ LOG_VIRUS = "VIRUS",
+ LOG_SHUTTLE = "SHUTTLE",
+ LOG_ECON = "ECON",
+ LOG_VICTIM = "VICTIM",
+ LOG_RADIO_EMOTE = "RADIO_EMOTE",
+ LOG_SPEECH_INDICATORS = "SPEECH_INDICATOR",
+ LOG_TRANSPORT = "TRANSPORT"
+))
+
//Individual logging panel pages
#define INDIVIDUAL_GAME_LOG (LOG_GAME)
#define INDIVIDUAL_ATTACK_LOG (LOG_ATTACK | LOG_VICTIM)
diff --git a/code/_helpers/logging/attack.dm b/code/_helpers/logging/attack.dm
index 69a843023b..60099bcebc 100644
--- a/code/_helpers/logging/attack.dm
+++ b/code/_helpers/logging/attack.dm
@@ -29,11 +29,11 @@
var/postfix = "[sobject][saddition][hp]"
var/message = "[what_done] [starget][postfix]"
- user.log_message(message, LOG_ATTACK, color="red")
+ user.log_message(message, LOG_ATTACK, color="#ff0000")
if(user != target)
var/reverse_message = "was [what_done] by [ssource][postfix]"
- target.log_message(reverse_message, LOG_VICTIM, color="orange", log_globally=FALSE)
+ target.log_message(reverse_message, LOG_VICTIM, color="#ffb300", log_globally=FALSE)
/// Log for vore interactions
/proc/log_vore(text, list/data)
diff --git a/code/_helpers/logging/log_to_db.dm b/code/_helpers/logging/log_to_db.dm
new file mode 100644
index 0000000000..0499f420cf
--- /dev/null
+++ b/code/_helpers/logging/log_to_db.dm
@@ -0,0 +1,13 @@
+/proc/db_log_insert(mob/log_target, message, type, color)
+ set waitfor = FALSE
+ if(!ismob(log_target))
+ return
+ if(!SSdbcore.IsConnected())
+ return
+ var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_dialog (mid, time, ckey, mob, area, type, color, message) VALUES (null, NOW(), :sender_ckey, :sender_mob, :message_area, :message_type, :message_color, :message_content)",
+ list("sender_ckey" = log_target.ckey, "sender_mob" = log_target.real_name, "message_area" = "[loc_name(log_target)]", "message_type" = "[type]", "message_color" = color, "message_content" = message))
+ if(!query_insert.Execute())
+ log_sql("Error during logging: "+query_insert.ErrorMsg())
+ qdel(query_insert)
+ return
+ qdel(query_insert)
diff --git a/code/_helpers/logging/mob.dm b/code/_helpers/logging/mob.dm
index 9db2f0f6db..37e94ddbb6 100644
--- a/code/_helpers/logging/mob.dm
+++ b/code/_helpers/logging/mob.dm
@@ -13,42 +13,30 @@
return
// Cannot use the list as a map if the key is a number, so we stringify it (thank you BYOND)
- var/smessage_type = num2text(message_type, MAX_BITFLAG_DIGITS)
-
- if(HAS_CONNECTED_PLAYER(src))
- if(!islist(persistent_client.logging[smessage_type]))
- persistent_client.logging[smessage_type] = list()
-
- if(!islist(logging[smessage_type]))
- logging[smessage_type] = list()
-
- var/colored_message = message
- if(color)
- if(color[1] == "#")
- colored_message = "[message]"
- else
- colored_message = "[message]"
+ var/smessage_type = GLOB.logtype_to_string[message_type]
//This makes readability a bit better for admins.
- switch(message_type)
- if(LOG_WHISPER)
- colored_message = "(WHISPER) [colored_message]"
- if(LOG_OOC)
- colored_message = "(OOC) [colored_message]"
- if(LOG_LOOC)
- colored_message = "(LOOC) [colored_message]"
- if(LOG_ASAY)
- colored_message = "(ASAY) [colored_message]"
- if(LOG_EMOTE)
- colored_message = "(EMOTE) [colored_message]"
- if(LOG_RADIO_EMOTE)
- colored_message = "(RADIOEMOTE) [colored_message]"
+ var/list/timestamped_message = list(
+ "time" = world.timeofday,
+ "name" = name,
+ "ckey" = ckey,
+ "loc" = loc_name(src),
+ "event_id" = LAZYLEN(logging[smessage_type]),
+ "message" = message,
+ "color" = color
+ )
- var/list/timestamped_message = list("\[[time_stamp(format = "YYYY-MM-DD hh:mm:ss")]\] [key_name_and_tag(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message)
-
- logging[smessage_type] += timestamped_message
+ if(!CONFIG_GET(flag/database_logging))
+ if(!islist(logging[smessage_type]))
+ logging[smessage_type] = list()
+ UNTYPED_LIST_ADD(logging[smessage_type], timestamped_message)
if(HAS_CONNECTED_PLAYER(src))
- persistent_client.logging[smessage_type] += timestamped_message
+ if(CONFIG_GET(flag/database_logging))
+ db_log_insert(src, message, smessage_type, color)
+ else
+ if(!islist(persistent_client.logging[smessage_type]))
+ persistent_client.logging[smessage_type] = list()
+ UNTYPED_LIST_ADD(persistent_client.logging[smessage_type], timestamped_message)
..()
diff --git a/code/_helpers/logging/talk.dm b/code/_helpers/logging/talk.dm
index 36e8dfb3d8..d90e69978c 100644
--- a/code/_helpers/logging/talk.dm
+++ b/code/_helpers/logging/talk.dm
@@ -11,10 +11,10 @@
* * log_globally - boolean checking whether or not we write this log to the log file
* * forced_by - source that forced the dialogue if any
*/
-/atom/proc/log_talk(message, message_type, tag = null, log_globally = TRUE, forced_by = null, custom_say_emote = null)
+/atom/proc/log_talk(message, message_type, tag = null, log_globally = TRUE, forced_by = null, custom_say_emote = null, color)
var/prefix = tag ? "([tag]) " : ""
var/suffix = forced_by ? " FORCED by [forced_by]" : ""
- log_message("[prefix][custom_say_emote ? "*[custom_say_emote]*, " : ""]\"[message]\"[suffix]", message_type, log_globally = log_globally)
+ log_message("[prefix][custom_say_emote ? "*[custom_say_emote]*, " : ""]\"[message]\"[suffix]", message_type, color, log_globally)
/// Logging for generic spoken messages
/proc/log_say(text, list/data)
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index d1d4808b6e..de3c98807a 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -151,13 +151,8 @@ Proc for attack log creation, because really why not
add_attack_logs(user,M,what_done,admin_notify)
return
- var/user_str = key_name(user)
var/target_str = key_name(target)
- if(ismob(user))
- user.attack_log += text("\[[time_stamp()]\] [span_red("Attacked [target_str]: [what_done]")]")
- if(ismob(target))
- target.attack_log += text("\[[time_stamp()]\] [span_orange("Attacked by [user_str]: [what_done]")]")
log_combat(user, target, what_done)
if(admin_notify)
msg_admin_attack("[key_name_admin(user)] vs [target_str]: [what_done]")
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index cefd6a5f67..6138c23edf 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -729,7 +729,7 @@
/datum/config_entry/flag/allow_simple_mob_recolor
/// Chatlogs are now saved by calling the chatlogging library instead of letting the clients handle it
-/// REQUIRES an database
+/// REQUIRES a database
/datum/config_entry/flag/chatlog_database_backend
default = FALSE
@@ -737,6 +737,11 @@
/// REQUIRES chatlog_database_backend to be enabled
/datum/config_entry/string/chatlog_database_api_endpoint
+/// Enables logging dialogue and attack logs to the database
+/// REQUIRES a database
+/datum/config_entry/flag/database_logging
+ default = FALSE
+
/datum/config_entry/flag/forbid_admin_profiling
/datum/config_entry/flag/pixel_size_limit
diff --git a/code/controllers/subsystems/dbcore.dm b/code/controllers/subsystems/dbcore.dm
index ed9dd2d82a..80381b6f86 100644
--- a/code/controllers/subsystems/dbcore.dm
+++ b/code/controllers/subsystems/dbcore.dm
@@ -44,6 +44,11 @@ SUBSYSTEM_DEF(dbcore)
/datum/controller/subsystem/dbcore/Initialize()
Connect()
+ if(IsConnected() && CONFIG_GET(flag/database_logging))
+ var/datum/db_query/query_truncate = NewQuery("TRUNCATE erro_dialog")
+ if(!query_truncate.Execute())
+ log_sql("ERROR TRYING TO CLEAR erro_dialog: "+query_truncate.ErrorMsg())
+ qdel(query_truncate)
return SS_INIT_SUCCESS
/datum/controller/subsystem/dbcore/stat_entry(msg)
diff --git a/code/controllers/subsystems/mobs.dm b/code/controllers/subsystems/mobs.dm
index 6883a69c1a..63e3d38f52 100644
--- a/code/controllers/subsystems/mobs.dm
+++ b/code/controllers/subsystems/mobs.dm
@@ -41,7 +41,6 @@ SUBSYSTEM_DEF(mobs)
// Lets handle all of these while we have time, should always remain extremely small...
if(length(death_list)) // Don't contact DB if this list is empty
if(CONFIG_GET(flag/sql_enabled))
- establish_db_connection()
if(!SSdbcore.IsConnected())
log_game("SQL ERROR during death reporting. Failed to connect.")
else
diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm
index 273bc0ea68..0637e217af 100644
--- a/code/controllers/subsystems/persist_vr.dm
+++ b/code/controllers/subsystems/persist_vr.dm
@@ -20,7 +20,6 @@ SUBSYSTEM_DEF(persist)
if(!CONFIG_GET(flag/time_off))
return
- establish_db_connection()
if(!SSdbcore.IsConnected())
src.currentrun.Cut()
return
diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm
index 9ac4c420cc..8e55f853de 100644
--- a/code/defines/procs/statistics.dm
+++ b/code/defines/procs/statistics.dm
@@ -6,7 +6,6 @@
for(var/mob/M in GLOB.player_list)
if(M.client)
playercount += 1
- establish_db_connection()
if(!SSdbcore.IsConnected())
log_game("SQL ERROR during population polling. Failed to connect.")
else
@@ -47,7 +46,6 @@
log_game("Round ended without any feedback being generated. No feedback was sent to the database.")
return
- establish_db_connection()
if(!SSdbcore.IsConnected())
log_game("SQL ERROR during feedback reporting. Failed to connect.")
else
diff --git a/code/game/mecha/equipment/tools/armor_melee.dm b/code/game/mecha/equipment/tools/armor_melee.dm
index 6232dcc0cd..33677ce9bd 100644
--- a/code/game/mecha/equipment/tools/armor_melee.dm
+++ b/code/game/mecha/equipment/tools/armor_melee.dm
@@ -20,7 +20,7 @@
/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/handle_melee_contact(var/obj/item/W, var/mob/living/user, var/inc_damage = null)
if(!action_checks(user))
return inc_damage
- chassis.log_message("Attacked by [W]. Attacker - [user]")
+ chassis.log_message("Attacked by [W]. Attacker - [user]", LOG_GAME)
if(prob(chassis.deflect_chance*deflect_coeff))
to_chat(user, span_danger("\The [W] bounces off \the [chassis]'s armor."))
chassis.log_append_to_last("Armor saved.")
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index dcb7660de3..2aa7b2ce40 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -2803,7 +2803,7 @@
src.log_append_to_last("Armor saved.")
src.occupant_message(span_notice("\The [user]'s attack is stopped by the armor."))
visible_message(span_infoplain(span_bold("\The [user]") + " rebounds off [src.name]'s armor!"))
- user.attack_log += text("\[[time_stamp()]\] [span_red("attacked [src.name]")]")
+ add_attack_logs(user, src, "attacked")
playsound(src, 'sound/weapons/slash.ogg', 50, 1, -1)
else if(damage < damage_minimum)//Pathetic damage levels just don't harm MECH. //CHOMPedit temp_damage_minimum -> damage_minimum
@@ -2818,7 +2818,7 @@
if(damage > internal_damage_minimum) //Only decently painful attacks trigger a chance of mech damage.
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
visible_message(span_danger("[user] [attack_message] [src]!"))
- user.attack_log += text("\[[time_stamp()]\] [span_red("attacked [src.name]")]")
+ add_attack_logs(user, src, "attacked")
return 1
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index b9e026df10..249896b322 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -285,7 +285,7 @@
else
deflect_chance = initial(deflect_chance)
src.occupant_message(span_red("You disable [src] defence mode."))
- src.log_message("Toggled defence mode.")
+ src.log_message("Toggled defence mode.", LOG_GAME)
return
@@ -363,7 +363,7 @@
return
if(src.occupant.client)
src.zoom = !src.zoom
- src.log_message("Toggled zoom mode.")
+ src.log_message("Toggled zoom mode.", LOG_GAME)
if(src.zoom)
src.occupant_message(span_blue("Zoom mode enabled."))
else
@@ -390,7 +390,7 @@
if(src.occupant)
if(get_charge() > 0)
thrusters = !thrusters
- src.log_message("Toggled thrusters.")
+ src.log_message("Toggled thrusters.", LOG_GAME)
if(src.thrusters)
src.occupant_message(span_blue("Thrusters enabled."))
else
diff --git a/code/game/world.dm b/code/game/world.dm
index 3942d3525f..daeb4e8139 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -645,75 +645,6 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
if (src.status != s)
src.status = s
-#define FAILED_DB_CONNECTION_CUTOFF 5
-GLOBAL_VAR_INIT(failed_db_connections, 0)
-
-/hook/startup/proc/connectDB()
- if(!CONFIG_GET(flag/sql_enabled))
- log_sql("SQL connection disabled in config.")
- else if(!setup_database_connection())
- log_sql("Your server failed to establish a connection with the feedback database.")
- else
- log_sql("Feedback database connection established.")
- return 1
-
-/proc/setup_database_connection()
- if(!CONFIG_GET(flag/sql_enabled))
- return 0
- if(GLOB.failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore.
- return 0
-
- if(!SSdbcore)
- SSdbcore = new()
-
- var/user = CONFIG_GET(string/feedback_login)
- var/pass = CONFIG_GET(string/feedback_password)
- var/db = CONFIG_GET(string/feedback_database)
- var/address = CONFIG_GET(string/address)
- var/port = CONFIG_GET(number/port)
-
- SSdbcore.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
- . = SSdbcore.IsConnected()
- if ( . )
- GLOB.failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter.
- return
- GLOB.failed_db_connections++ //If it failed, increase the failed connections counter.
- log_sql(SSdbcore.ErrorMsg())
- return
-
-//This proc ensures that the connection to the feedback database (global variable dbcon) is established
-/proc/establish_db_connection()
- if(GLOB.failed_db_connections > FAILED_DB_CONNECTION_CUTOFF)
- return 0
-
- if(!SSdbcore || !SSdbcore.IsConnected())
- return setup_database_connection()
- else
- return 1
-
-// Cleans up DB connections and recreates them
-/proc/reset_database_connections()
- var/list/results = list("-- Resetting DB connections --")
- GLOB.failed_db_connections = 0
-
- if(SSdbcore?.IsConnected())
- SSdbcore.Disconnect()
- results += "SSdbcore was connected and asked to disconnect"
- else
- results += "SSdbcore was not connected"
-
- if(!CONFIG_GET(flag/sql_enabled))
- results += "stopping because config.sql_enabled = false"
- else
- . = setup_database_connection()
- if(.)
- results += "SUCCESS: set up a connection successfully with setup_database_connection()"
- else
- results += "FAIL: failed to connect to the database with setup_database_connection()"
-
- results += "-- DB Reset End --"
- log_sql(results.Join("\n"))
-
// Things to do when a new z-level was just made.
/world/proc/max_z_changed()
if(!istype(GLOB.players_by_zlevel, /list))
@@ -784,8 +715,6 @@ GLOBAL_VAR_INIT(failed_db_connections, 0)
/world/proc/on_tickrate_change()
SStimer?.reset_buckets()
-#undef FAILED_DB_CONNECTION_CUTOFF
-
/proc/auxtools_stack_trace(msg)
CRASH(msg)
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 5ee62875e6..1a17c96d0a 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -4,7 +4,6 @@
if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return
- establish_db_connection()
if(!SSdbcore.IsConnected())
return
@@ -126,7 +125,6 @@
if(job)
sql += " AND job = '[job]'"
- establish_db_connection()
if(!SSdbcore.IsConnected())
return
@@ -224,7 +222,6 @@
var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]"
- establish_db_connection()
if(!SSdbcore.IsConnected())
return
@@ -276,7 +273,6 @@
if(!check_rights_for(user, R_BAN))
return
- establish_db_connection()
if(!SSdbcore.IsConnected())
to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]"))
return
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index 0d4cc98d02..a4800c875b 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -40,7 +40,7 @@
var/ckeytext = ckey(key)
- if(!establish_db_connection())
+ if(!SSdbcore.IsConnected())
var/msg = "Ban database connection failure. Key [ckeytext] not checked"
log_world(msg)
message_admins(msg)
diff --git a/code/modules/admin/admin_attack_log.dm b/code/modules/admin/admin_attack_log.dm
index c85616f301..6189a59480 100644
--- a/code/modules/admin/admin_attack_log.dm
+++ b/code/modules/admin/admin_attack_log.dm
@@ -1,7 +1,5 @@
/atom/var/lastattacker = null
/mob/var/lastattacked = null
-/mob/var/attack_log = list( )
-/mob/var/dialogue_log = list( )
/proc/log_and_message_admins(var/message as text, var/mob/user = usr)
log_admin(user ? "[key_name(user)] [message]" : "EVENT [message]")
@@ -17,30 +15,3 @@
log_admin("[english_list(user_keys)] [message]")
message_admins("[english_list(user_keys)] [message]")
-/* Old procs
-/proc/admin_attack_log(var/mob/attacker, var/mob/victim, var/attacker_message, var/victim_message, var/admin_message)
- if(victim)
- victim.attack_log += text("\[[time_stamp()]\]" + span_orange(" [key_name(attacker)] - [victim_message]"))
- if(attacker)
- attacker.attack_log += text("\[[time_stamp()]\]" + span_red(" [key_name(victim)] - [attacker_message]"))
-
- msg_admin_attack("[key_name(attacker)] [admin_message] [key_name(victim)] (INTENT: [attacker? uppertext(attacker.a_intent) : "N/A"]) (JMP)")
-
-/proc/admin_attacker_log_many_victims(var/mob/attacker, var/list/mob/victims, var/attacker_message, var/victim_message, var/admin_message)
- if(!victims || !victims.len)
- return
-
- for(var/mob/victim in victims)
- admin_attack_log(attacker, victim, attacker_message, victim_message, admin_message)
-
-/proc/admin_inject_log(mob/attacker, mob/victim, obj/item, reagents, amount_transferred, violent=0)
- if(violent)
- violent = "violently "
- else
- violent = ""
- admin_attack_log(attacker,
- victim,
- "used \the [weapon] to [violent]inject - [reagents] - [amount_transferred]u transferred",
- "was [violent]injected with \the [weapon] - [reagents] - [amount_transferred]u transferred",
- "used \the [weapon] to [violent]inject [reagents] ([amount_transferred]u transferred) into")
-*/
diff --git a/code/modules/admin/admin_tools.dm b/code/modules/admin/admin_tools.dm
index 61aa8dbaba..6284e6bd52 100644
--- a/code/modules/admin/admin_tools.dm
+++ b/code/modules/admin/admin_tools.dm
@@ -1,65 +1,84 @@
-/client/proc/cmd_admin_check_player_logs(mob/living/M as mob in GLOB.mob_list)
- set category = "Admin.Logs"
- set name = "Check Player Attack Logs"
- set desc = "Check a player's attack logs."
-
- show_cmd_admin_check_player_logs(M)
+ADMIN_VERB_ONLY_CONTEXT_MENU(cmd_admin_check_player_logs, R_ADMIN|R_MOD, "Check Mob Logs", mob/living/player in GLOB.mob_list)
+ user.show_cmd_admin_check_player_logs(player.logging, player.name, player.ckey, player.mind?.special_role)
//Views specific attack logs belonging to one player.
-/client/proc/show_cmd_admin_check_player_logs(mob/living/M)
- var/dat = span_bold("[M]'s Attack Log:
")
- dat += span_bold("Viewing attack logs of [M]") + " - (Played by ([key_name(M)]). "
- if(M.mind)
- dat += span_bold("Current Antag?:") + " [(M.mind.special_role)?"Yes":"No"] "
- dat += " " + span_bold("Note:") + " This is arranged from earliest to latest.
"
+/client/proc/show_cmd_admin_check_player_logs(list/mob_data, target_name, target_ckey, target_special)
+ if(CONFIG_GET(flag/database_logging))
+ var/datum/db_query/query = SSdbcore.NewQuery("SELECT mid,time,ckey,mob,area,color,type,message from erro_dialog WHERE ckey = :t_ckey", list("t_ckey" = ckey))
+ if(!query.Execute())
+ to_chat(src, span_admin("Database query error"))
+ qdel(query)
+ return
+ var/list/data = list()
+ while(query.NextRow())
+ var/list/timestamped_message = list(
+ "event_id" = query.item[1],
+ "time" = query.item[2],
+ "ckey" = query.item[3],
+ "name" = query.item[4],
+ "loc" = query.item[5],
+ "color" = query.item[6],
+ "message" = query.item[8]
+ )
+ var/entry_type = query.item[7]
+ if(!islist(data[entry_type]))
+ data[entry_type] = list()
+ UNTYPED_LIST_ADD(data[entry_type], timestamped_message)
+ qdel(query)
+ if(!length(data))
+ to_chat(src, span_admin("No data found."))
+ return
+ admin_log_view_target(data, target_name, target_ckey, target_special)
+ return
+ if(!length(mob_data))
+ to_chat(src, span_admin("No data found."))
+ return
+ admin_log_view_target(mob_data, target_name, target_ckey, target_special)
- if(!isemptylist(M.attack_log))
- dat += ""
+ var/datum/persistent_client/selected = GLOB.persistent_clients_by_ckey[selected_key]
- else
- dat += span_italics("No attack logs found for [M].")
+ user.show_cmd_admin_check_player_logs(selected.logging, selected.mob?.name, selected_key, selected.mob?.mind?.special_role)
- var/datum/browser/popup = new(usr, "admin_attack_log", "[src]", 650, 650, src)
- popup.set_content(jointext(dat,null))
- popup.open()
+/client/proc/admin_log_view_target(list/log_data, name, ckey, special, use_db)
+ var/datum/player_log_viwer/log_view = new(log_data, name, ckey, special)
+ log_view.tgui_interact(mob)
- onclose(usr, "admin_attack_log")
+/datum/player_log_viwer
+ var/list/log_data
+ var/target_name
+ var/target_ckey
+ var/special_role
- feedback_add_details("admin_verb","PL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/datum/player_log_viwer/tgui_close(mob/user)
+ . = ..()
+ log_data = null
-/client/proc/cmd_admin_check_dialogue_logs(mob/living/M as mob in GLOB.mob_list)
- set category = "Admin.Logs"
- set name = "Check Player Dialogue Logs"
- set desc = "Check a player's dialogue logs."
- show_cmd_admin_check_dialogue_logs(M)
+/datum/player_log_viwer/New(list/data, name, ckey, special)
+ . = ..()
+ log_data = data
+ target_name = name
+ target_ckey = ckey
+ special_role = special
-//Views specific dialogue logs belonging to one player.
-/client/proc/show_cmd_admin_check_dialogue_logs(mob/living/M)
- var/dat = span_bold("[M]'s Dialogue Log:")
- dat += span_bold("Viewing say and emote logs of [M]") + " - (Played by ([key_name(M)]). "
- if(M.mind)
- dat += span_bold("Current Antag?:") + " [(M.mind.special_role)?"Yes":"No"] "
- dat += " " + span_bold("Note:") + " This is arranged from earliest to latest.
"
+/datum/player_log_viwer/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "PlayerLogViewer")
+ ui.open()
- if(!isemptylist(M.dialogue_log))
- dat += ""
- else
- dat += span_italics("No dialogue logs found for [M].")
- var/datum/browser/popup = new(usr, "admin_dialogue_log", "[src]", 650, 650, src)
- popup.set_content(jointext(dat,null))
- popup.open()
-
- onclose(usr, "admin_dialogue_log")
-
-
- feedback_add_details("admin_verb","PDL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+/datum/player_log_viwer/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ return list(
+ "entries" = log_data,
+ "name" = target_name,
+ "ckey" = target_ckey,
+ "special" = special_role
+ )
diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm
index de6c1d79c2..98a4fb766f 100644
--- a/code/modules/admin/admin_verb_lists_vr.dm
+++ b/code/modules/admin/admin_verb_lists_vr.dm
@@ -20,8 +20,6 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list(
/client/proc/cmd_admin_pm_context, //right-click adminPM interface,
/client/proc/cmd_admin_pm_panel, //admin-pm list,
/client/proc/cmd_admin_subtle_message, //send an message to somebody as a 'voice in their head',
- /client/proc/cmd_admin_check_player_logs, //checks a player's attack logs,
- /client/proc/cmd_admin_check_dialogue_logs, //checks a player's dialogue logs,
/datum/admins/proc/access_news_network, //allows access of newscasters,
/client/proc/jumptocoord, //we ghost and jump to a coordinate,
/client/proc/Getmob, //teleports a mob to our location,
@@ -174,8 +172,6 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list(
/datum/admins/proc/toggleguests,
/datum/admins/proc/announce,
/client/proc/cmd_admin_subtle_message,
- /client/proc/cmd_admin_check_player_logs,
- /client/proc/cmd_admin_check_dialogue_logs,
/datum/admins/proc/access_news_network,
/client/proc/cmd_admin_direct_narrate,
/client/proc/cmd_admin_world_narrate,
@@ -277,8 +273,6 @@ GLOBAL_LIST_INIT(admin_verbs_event_manager, list(
/client/proc/cmd_admin_pm_context, //right-click adminPM interface,
/client/proc/cmd_admin_pm_panel, //admin-pm list,
/client/proc/cmd_admin_subtle_message, //send an message to somebody as a 'voice in their head',
- /client/proc/cmd_admin_check_player_logs, //checks a player's attack logs,
- /client/proc/cmd_admin_check_dialogue_logs, //checks a player's dialogue logs,
/datum/admins/proc/access_news_network, //allows access of newscasters,
/client/proc/jumptocoord, //we ghost and jump to a coordinate,
/client/proc/Getmob, //teleports a mob to our location,
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 124d722323..384156edd0 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -683,7 +683,6 @@ ADMIN_VERB(removetickets, R_ADMIN, "Security Tickets", "Allows one to remove tic
var/dat = "Book Inventory Management\n"
dat += "
ADMINISTRATIVE MANAGEMENT
"
- establish_db_connection()
if(!SSdbcore.IsConnected())
dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.")
diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm
index 28b6536332..b64a66cd6d 100644
--- a/code/modules/admin/banjob.dm
+++ b/code/modules/admin/banjob.dm
@@ -69,7 +69,7 @@ DEBUG
GLOB.jobban_keylist=list()
log_admin("jobban_keylist was empty")
else
- if(!establish_db_connection())
+ if(!SSdbcore.IsConnected())
log_sql("Database connection failed. Reverting to the legacy ban system.")
CONFIG_SET(flag/ban_legacy_system, TRUE)
jobban_loadbanfile()
diff --git a/code/modules/admin/verbs/antag-ooc.dm b/code/modules/admin/verbs/antag-ooc.dm
index 2405d5e6d8..a2b50be813 100644
--- a/code/modules/admin/verbs/antag-ooc.dm
+++ b/code/modules/admin/verbs/antag-ooc.dm
@@ -39,4 +39,4 @@
if((M.mind && M.mind.special_role && A && A.can_hear_aooc) || isobserver(M)) // Antags must have their type be allowed to AOOC to see AOOC. This prevents, say, ERT from seeing AOOC.
to_chat(M, span_ooc(span_aooc("[create_text_tag("aooc", "Antag-OOC:", M.client)] [player_display]: " + span_message("[msg]"))))
- src.mob.log_talk("(AOOC) [msg]", LOG_OOC)
+ src.mob.log_talk("(AOOC) [msg]", LOG_OOC, color="#ff0000")
diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm
index 0bc0e8dcd0..cadd8d5ae3 100644
--- a/code/modules/admin/verbs/check_customitem_activity.dm
+++ b/code/modules/admin/verbs/check_customitem_activity.dm
@@ -31,7 +31,6 @@ GLOBAL_VAR_INIT(inactive_keys, "None ")
if(GLOB.checked_for_inactives)
return
- establish_db_connection()
if(!SSdbcore.IsConnected())
return
diff --git a/code/modules/admin/verbs/dbcon_fix.dm b/code/modules/admin/verbs/dbcon_fix.dm
index 99deb034a7..cfc9233aff 100644
--- a/code/modules/admin/verbs/dbcon_fix.dm
+++ b/code/modules/admin/verbs/dbcon_fix.dm
@@ -15,7 +15,6 @@
else
log_admin("Database already disconnected")
- establish_db_connection()
var/errno = SSdbcore.ErrorMsg()
if(errno)
log_admin("Database connection returned error message `[errno]`. Aborting.")
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index af1daab44d..0f2dda9aef 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -437,7 +437,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
// Returns null if no DB connection can be established, or -1 if the requested key was not found in the database
/proc/get_player_age(key)
- establish_db_connection()
if(!SSdbcore.IsConnected())
return null
@@ -458,7 +457,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if ( IsGuestKey(src.key) )
return
- establish_db_connection()
if(!SSdbcore.IsConnected())
return
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index a8be59f005..b65bb906cf 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -42,7 +42,7 @@
message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]")
return
- src.mob.log_talk(msg, LOG_OOC)
+ src.mob.log_talk(msg, LOG_OOC, color="#0051ff")
if(msg)
handle_spam_prevention(MUTE_OOC)
@@ -125,7 +125,7 @@
message_admins("[key_name_admin(src)] has attempted to post a link in OOC: [msg]")
return
- src.mob.log_message(msg, LOG_LOOC)
+ src.mob.log_message(msg, LOG_LOOC, color="#53cbff")
if(msg)
handle_spam_prevention(MUTE_LOOC)
diff --git a/code/modules/food/kitchen/cooking_machines/fryer.dm b/code/modules/food/kitchen/cooking_machines/fryer.dm
index 0682468818..dc3f731535 100644
--- a/code/modules/food/kitchen/cooking_machines/fryer.dm
+++ b/code/modules/food/kitchen/cooking_machines/fryer.dm
@@ -235,8 +235,7 @@
else
to_chat(victim, span_danger("Searing hot oil scorches your [E ? E.name : "flesh"]!"))
- user.attack_log += text("\[[time_stamp()]\] [span_red("Has [cook_type] \the [victim] ([victim.ckey]) in \a [src]")]")
- victim.attack_log += text("\[[time_stamp()]\] [span_orange("Has been [cook_type] in \a [src] by [user.name] ([user.ckey])")]")
+ add_attack_logs(user, victim, "has been [cook_type] with [src]")
msg_admin_attack("[key_name_admin(user)] [cook_type] \the [victim] ([victim.ckey]) in \a [src]. (JMP)")
//Coat the victim in some oil
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 5540d0b6b0..debe48a02f 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -43,7 +43,6 @@
Filter by Author: [author] \[Start Search\] "}
if(1)
- establish_db_connection()
if(!SSdbcore.IsConnected())
dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.") + " "
else if(!SQLquery)
@@ -263,7 +262,6 @@
No. "}
if(8)
dat += "
" + span_red("arning: System Administrator has slated this archive for removal. Personal uploads should be taken to the NT board of internal literature.") + "