mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2025-12-20 15:21:29 +00:00
world/Topic Refactor (#14850)
* world/Topic Refactor * These arent needed anymore * How could I forget this * Biggest edit ever * Forgot this * Mini refactor
This commit is contained in:
@@ -117,6 +117,17 @@
|
|||||||
if(R.selectable)
|
if(R.selectable)
|
||||||
GLOB.selectable_robolimbs[R.company] = R
|
GLOB.selectable_robolimbs[R.company] = R
|
||||||
|
|
||||||
|
// Setup world topic handlers
|
||||||
|
for(var/topic_handler_type in subtypesof(/datum/world_topic_handler))
|
||||||
|
var/datum/world_topic_handler/wth = new topic_handler_type()
|
||||||
|
if(!wth.topic_key)
|
||||||
|
stack_trace("[wth.type] has no topic key!")
|
||||||
|
continue
|
||||||
|
if(GLOB.world_topic_handlers[wth.topic_key])
|
||||||
|
stack_trace("[wth.type] has the same topic key as [GLOB.world_topic_handlers[wth.topic_key]]! ([wth.topic_key])")
|
||||||
|
continue
|
||||||
|
GLOB.world_topic_handlers[wth.topic_key] = topic_handler_type
|
||||||
|
|
||||||
/* // Uncomment to debug chemical reaction list.
|
/* // Uncomment to debug chemical reaction list.
|
||||||
/client/verb/debug_chemical_list()
|
/client/verb/debug_chemical_list()
|
||||||
|
|
||||||
|
|||||||
@@ -55,242 +55,41 @@ GLOBAL_LIST_INIT(map_transition_config, MAP_TRANSITION_CONFIG)
|
|||||||
investigate_reset() // This is part of the admin investigate system. PLEASE DONT SS THIS EITHER
|
investigate_reset() // This is part of the admin investigate system. PLEASE DONT SS THIS EITHER
|
||||||
makeDatumRefLists() // Setups up lists of datums and their subtypes
|
makeDatumRefLists() // Setups up lists of datums and their subtypes
|
||||||
|
|
||||||
//world/Topic(href, href_list[])
|
/// List of all world topic spam prevention handlers. See code/modules/world_topic/_spam_prevention_handler.dm
|
||||||
// to_chat(world, "Received a Topic() call!")
|
GLOBAL_LIST_EMPTY(world_topic_spam_prevention_handlers)
|
||||||
// to_chat(world, "[href]")
|
/// List of all world topic handler datums. Populated inside makeDatumRefLists()
|
||||||
// for(var/a in href_list)
|
GLOBAL_LIST_EMPTY(world_topic_handlers)
|
||||||
// to_chat(world, "[a]")
|
|
||||||
// if(href_list["hello"])
|
|
||||||
// to_chat(world, "Hello world!")
|
|
||||||
// return "Hello world!"
|
|
||||||
// to_chat(world, "End of Topic() call.")
|
|
||||||
// ..()
|
|
||||||
|
|
||||||
GLOBAL_VAR_INIT(world_topic_spam_protect_ip, "0.0.0.0")
|
|
||||||
GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday)
|
|
||||||
|
|
||||||
/world/Topic(T, addr, master, key)
|
/world/Topic(T, addr, master, key)
|
||||||
TGS_TOPIC
|
TGS_TOPIC
|
||||||
log_misc("WORLD/TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
|
log_misc("WORLD/TOPIC: \"[T]\", from:[addr], master:[master], key:[key]")
|
||||||
|
|
||||||
|
// Handle spam prevention
|
||||||
|
if(!GLOB.world_topic_spam_prevention_handlers[address])
|
||||||
|
GLOB.world_topic_spam_prevention_handlers[address] = new /datum/world_topic_spam_prevention_handler
|
||||||
|
|
||||||
|
var/datum/world_topic_spam_prevention_handler/sph = GLOB.world_topic_spam_prevention_handlers[address]
|
||||||
|
|
||||||
|
// Lock the user out and cancel their topic if needed
|
||||||
|
if(sph.check_lockout())
|
||||||
|
return
|
||||||
|
|
||||||
var/list/input = params2list(T)
|
var/list/input = params2list(T)
|
||||||
var/key_valid = (config.comms_password && input["key"] == config.comms_password) //no password means no comms, not any password
|
|
||||||
|
|
||||||
if("ping" in input)
|
var/datum/world_topic_handler/wth
|
||||||
var/x = 1
|
|
||||||
for(var/client/C)
|
|
||||||
x++
|
|
||||||
return x
|
|
||||||
|
|
||||||
else if("players" in input)
|
for(var/H in GLOB.world_topic_handlers)
|
||||||
var/n = 0
|
if(H in input)
|
||||||
for(var/mob/M in GLOB.player_list)
|
wth = GLOB.world_topic_handlers[H]
|
||||||
if(M.client)
|
|
||||||
n++
|
|
||||||
return n
|
|
||||||
|
|
||||||
else if("status" in input)
|
|
||||||
var/list/s = list()
|
|
||||||
var/list/admins = list()
|
|
||||||
s["version"] = GLOB.game_version
|
|
||||||
s["mode"] = GLOB.master_mode
|
|
||||||
s["respawn"] = config ? GLOB.abandon_allowed : 0
|
|
||||||
s["enter"] = GLOB.enter_allowed
|
|
||||||
s["vote"] = config.allow_vote_mode
|
|
||||||
s["ai"] = config.allow_ai
|
|
||||||
s["host"] = host ? host : null
|
|
||||||
s["players"] = list()
|
|
||||||
s["roundtime"] = worldtime2text()
|
|
||||||
s["stationtime"] = station_time_timestamp()
|
|
||||||
s["oldstationtime"] = classic_worldtime2text() // more "consistent" indication of the round's running time
|
|
||||||
s["listed"] = "Public"
|
|
||||||
if(!hub_password)
|
|
||||||
s["listed"] = "Invisible"
|
|
||||||
var/player_count = 0
|
|
||||||
var/admin_count = 0
|
|
||||||
|
|
||||||
for(var/client/C in GLOB.clients)
|
|
||||||
if(C.holder)
|
|
||||||
if(C.holder.fakekey)
|
|
||||||
continue //so stealthmins aren't revealed by the hub
|
|
||||||
admin_count++
|
|
||||||
admins += list(list(C.key, C.holder.rank))
|
|
||||||
s["player[player_count]"] = C.key
|
|
||||||
player_count++
|
|
||||||
s["players"] = player_count
|
|
||||||
s["admins"] = admin_count
|
|
||||||
s["map_name"] = GLOB.map_name ? GLOB.map_name : "Unknown"
|
|
||||||
|
|
||||||
if(key_valid)
|
|
||||||
if(SSticker && SSticker.mode)
|
|
||||||
s["real_mode"] = SSticker.mode.name
|
|
||||||
s["security_level"] = get_security_level()
|
|
||||||
s["ticker_state"] = SSticker.current_state
|
|
||||||
|
|
||||||
if(SSshuttle && SSshuttle.emergency)
|
|
||||||
// Shuttle status, see /__DEFINES/stat.dm
|
|
||||||
s["shuttle_mode"] = SSshuttle.emergency.mode
|
|
||||||
// Shuttle timer, in seconds
|
|
||||||
s["shuttle_timer"] = SSshuttle.emergency.timeLeft()
|
|
||||||
|
|
||||||
for(var/i in 1 to admins.len)
|
|
||||||
var/list/A = admins[i]
|
|
||||||
s["admin[i - 1]"] = A[1]
|
|
||||||
s["adminrank[i - 1]"] = A[2]
|
|
||||||
|
|
||||||
return list2params(s)
|
|
||||||
|
|
||||||
else if("manifest" in input)
|
|
||||||
var/list/positions = list()
|
|
||||||
var/list/set_names = list(
|
|
||||||
"heads" = GLOB.command_positions,
|
|
||||||
"sec" = GLOB.security_positions,
|
|
||||||
"eng" = GLOB.engineering_positions,
|
|
||||||
"med" = GLOB.medical_positions,
|
|
||||||
"sci" = GLOB.science_positions,
|
|
||||||
"car" = GLOB.supply_positions,
|
|
||||||
"srv" = GLOB.service_positions,
|
|
||||||
"civ" = GLOB.civilian_positions,
|
|
||||||
"bot" = GLOB.nonhuman_positions
|
|
||||||
)
|
|
||||||
|
|
||||||
for(var/datum/data/record/t in GLOB.data_core.general)
|
|
||||||
var/name = t.fields["name"]
|
|
||||||
var/rank = t.fields["rank"]
|
|
||||||
var/real_rank = t.fields["real_rank"]
|
|
||||||
|
|
||||||
var/department = 0
|
|
||||||
for(var/k in set_names)
|
|
||||||
if(real_rank in set_names[k])
|
|
||||||
if(!positions[k])
|
|
||||||
positions[k] = list()
|
|
||||||
positions[k][name] = rank
|
|
||||||
department = 1
|
|
||||||
if(!department)
|
|
||||||
if(!positions["misc"])
|
|
||||||
positions["misc"] = list()
|
|
||||||
positions["misc"][name] = rank
|
|
||||||
|
|
||||||
return json_encode(positions)
|
|
||||||
|
|
||||||
else if("adminmsg" in input)
|
|
||||||
/*
|
|
||||||
We got an adminmsg from IRC bot lets split the input then validate the input.
|
|
||||||
expected output:
|
|
||||||
1. adminmsg = ckey of person the message is to
|
|
||||||
2. msg = contents of message, parems2list requires
|
|
||||||
3. validatationkey = the key the bot has, it should match the gameservers commspassword in it's configuration.
|
|
||||||
4. sender = the ircnick that send the message.
|
|
||||||
*/
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
|
|
||||||
var/client/C
|
|
||||||
|
|
||||||
for(var/client/K in GLOB.clients)
|
|
||||||
if(K.ckey == input["adminmsg"])
|
|
||||||
C = K
|
|
||||||
break
|
break
|
||||||
if(!C)
|
|
||||||
return "No client with that name on server"
|
|
||||||
|
|
||||||
var/message = "<font color='red'>Discord PM from <b><a href='?discord_msg=1'>[input["sender"]]</a></b>: [input["msg"]]</font>"
|
if(!wth)
|
||||||
var/amessage = "<font color='blue'>Discord PM from <a href='?discord_msg=1'>[input["sender"]]</a> to <b>[key_name(C)]</b>: [input["msg"]]</font>"
|
return
|
||||||
|
|
||||||
// THESE TWO VARS DO VERY DIFFERENT THINGS. DO NOT ATTEMPT TO COMBINE THEM
|
// If we are here, the handler exists, so it needs to be invoked
|
||||||
C.received_discord_pm = world.time
|
wth = new wth()
|
||||||
C.last_discord_pm_time = 0
|
return wth.invoke(input)
|
||||||
|
|
||||||
SEND_SOUND(C, 'sound/effects/adminhelp.ogg')
|
|
||||||
to_chat(C, message)
|
|
||||||
|
|
||||||
for(var/client/A in GLOB.admins)
|
|
||||||
if(A != C)
|
|
||||||
to_chat(A, amessage)
|
|
||||||
|
|
||||||
return "Message Successful"
|
|
||||||
|
|
||||||
else if("notes" in input)
|
|
||||||
/*
|
|
||||||
We got a request for notes from the IRC Bot
|
|
||||||
expected output:
|
|
||||||
1. notes = ckey of person the notes lookup is for
|
|
||||||
2. validationkey = the key the bot has, it should match the gameservers commspassword in it's configuration.
|
|
||||||
*/
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
|
|
||||||
return show_player_info_irc(input["notes"])
|
|
||||||
|
|
||||||
else if("announce" in input)
|
|
||||||
if(config.comms_password)
|
|
||||||
if(input["key"] != config.comms_password)
|
|
||||||
return "Bad Key"
|
|
||||||
else
|
|
||||||
var/prtext = input["announce"]
|
|
||||||
var/pr_substring = copytext(prtext, 1, 23)
|
|
||||||
if(pr_substring == "Pull Request merged by")
|
|
||||||
GLOB.pending_server_update = TRUE
|
|
||||||
for(var/client/C in GLOB.clients)
|
|
||||||
to_chat(C, "<span class='announce'>PR: [prtext]</span>")
|
|
||||||
|
|
||||||
else if("kick" in input)
|
|
||||||
/*
|
|
||||||
We have a kick request over coms.
|
|
||||||
Only needed portion is the ckey
|
|
||||||
*/
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
|
|
||||||
var/client/C
|
|
||||||
|
|
||||||
for(var/client/K in GLOB.clients)
|
|
||||||
if(K.ckey == input["kick"])
|
|
||||||
C = K
|
|
||||||
break
|
|
||||||
if(!C)
|
|
||||||
return "No client with that name on server"
|
|
||||||
|
|
||||||
qdel(C)
|
|
||||||
|
|
||||||
return "Kick Successful"
|
|
||||||
|
|
||||||
else if("setlog" in input)
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
|
|
||||||
SetupLogs()
|
|
||||||
|
|
||||||
return "Logs set to current date"
|
|
||||||
|
|
||||||
else if("setlist" in input)
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
if(input["req"] == "public")
|
|
||||||
hub_password = initial(hub_password)
|
|
||||||
update_status()
|
|
||||||
return "Set listed status to public."
|
|
||||||
else
|
|
||||||
hub_password = ""
|
|
||||||
update_status()
|
|
||||||
return "Set listed status to invisible."
|
|
||||||
|
|
||||||
|
|
||||||
else if("hostannounce" in input)
|
|
||||||
if(!key_valid)
|
|
||||||
return keySpamProtect(addr)
|
|
||||||
GLOB.pending_server_update = TRUE
|
|
||||||
to_chat(world, "<hr><span style='color: #12A5F4'><b>Server Announcement:</b> [input["message"]]</span><hr>")
|
|
||||||
|
|
||||||
/proc/keySpamProtect(var/addr)
|
|
||||||
if(GLOB.world_topic_spam_protect_ip == addr && abs(GLOB.world_topic_spam_protect_time - world.time) < 50)
|
|
||||||
spawn(50)
|
|
||||||
GLOB.world_topic_spam_protect_time = world.time
|
|
||||||
return "Bad Key (Throttled)"
|
|
||||||
|
|
||||||
GLOB.world_topic_spam_protect_time = world.time
|
|
||||||
GLOB.world_topic_spam_protect_ip = addr
|
|
||||||
return "Bad Key"
|
|
||||||
|
|
||||||
/world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time)
|
/world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time)
|
||||||
TgsReboot()
|
TgsReboot()
|
||||||
|
|||||||
@@ -202,18 +202,3 @@
|
|||||||
output += ruler
|
output += ruler
|
||||||
usr << browse(output, "window=show_notes;size=900x500")
|
usr << browse(output, "window=show_notes;size=900x500")
|
||||||
|
|
||||||
/proc/show_player_info_irc(var/key as text)
|
|
||||||
var/target_sql_ckey = ckey(key)
|
|
||||||
var/DBQuery/query_get_notes = GLOB.dbcon.NewQuery("SELECT timestamp, notetext, adminckey, server, crew_playtime FROM [format_table_name("notes")] WHERE ckey = '[target_sql_ckey]' ORDER BY timestamp")
|
|
||||||
if(!query_get_notes.Execute())
|
|
||||||
var/err = query_get_notes.ErrorMsg()
|
|
||||||
log_game("SQL ERROR obtaining timestamp, notetext, adminckey, server, crew_playtime from notes table. Error : \[[err]\]\n")
|
|
||||||
return
|
|
||||||
var/output = " Info on [key]%0D%0A"
|
|
||||||
while(query_get_notes.NextRow())
|
|
||||||
var/timestamp = query_get_notes.item[1]
|
|
||||||
var/notetext = query_get_notes.item[2]
|
|
||||||
var/adminckey = query_get_notes.item[3]
|
|
||||||
var/server = query_get_notes.item[4]
|
|
||||||
output += "[notetext]%0D%0Aby [adminckey] on [timestamp] (Server: [server])%0D%0A%0D%0A"
|
|
||||||
return output
|
|
||||||
|
|||||||
5
code/modules/world_topic/README.MD
Normal file
5
code/modules/world_topic/README.MD
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# NOTE
|
||||||
|
|
||||||
|
Please keep things in this directory standardised!
|
||||||
|
|
||||||
|
This means one topic handler per DM file, and the filename being the key. For an example, see `ping.dm`
|
||||||
63
code/modules/world_topic/_spam_prevention_handler.dm
Normal file
63
code/modules/world_topic/_spam_prevention_handler.dm
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#define WORLD_TOPIC_STRIKES_THRESHOLD 5
|
||||||
|
#define WORLD_TOPIC_LOCKOUT_TIME 1 MINUTES
|
||||||
|
|
||||||
|
/datum/world_topic_spam_prevention_handler
|
||||||
|
/// Amount of strikes. [WORLD_TOPIC_STRIKES_THRESHOLD] strikes is a lockout of [WORLD_TOPIC_LOCKOUT_TIME]
|
||||||
|
var/strikes = 0
|
||||||
|
/// Time of last request
|
||||||
|
var/last_request = 0
|
||||||
|
/// Is this IP currently locked out
|
||||||
|
var/locked_out = FALSE
|
||||||
|
/// Unlock time
|
||||||
|
var/unlock_time = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lockout handler
|
||||||
|
*
|
||||||
|
* Updates strikes and timers of the most recent client to topic the server
|
||||||
|
* including any relevant detail
|
||||||
|
*/
|
||||||
|
/datum/world_topic_spam_prevention_handler/proc/check_lockout()
|
||||||
|
// Check if they are already locked out
|
||||||
|
if(locked_out && (unlock_time >= world.time))
|
||||||
|
// Relock out for another minute if youre spamming
|
||||||
|
unlock_time = world.time + WORLD_TOPIC_LOCKOUT_TIME
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
// If they were locked out and are now allowed, unlock them
|
||||||
|
if(locked_out && (unlock_time < world.time))
|
||||||
|
strikes = 0
|
||||||
|
locked_out = FALSE
|
||||||
|
|
||||||
|
// Allow a grace period of 0.5 seconds per topic, or you get a strike
|
||||||
|
if(last_request + 5 > world.time)
|
||||||
|
strikes++
|
||||||
|
if(strikes >= WORLD_TOPIC_STRIKES_THRESHOLD)
|
||||||
|
locked_out = TRUE
|
||||||
|
unlock_time = world.time + WORLD_TOPIC_LOCKOUT_TIME
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
// If we got here, assume they arent locked out
|
||||||
|
last_request = world.time
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Uncomment this if you modify the topic limiter, trust me, youll need to test it
|
||||||
|
|
||||||
|
/client/verb/debug_limiter()
|
||||||
|
if(!GLOB.world_topic_spam_prevention_handlers[address])
|
||||||
|
GLOB.world_topic_spam_prevention_handlers[address] = new /datum/world_topic_spam_prevention_handler
|
||||||
|
|
||||||
|
var/datum/world_topic_spam_prevention_handler/sph = GLOB.world_topic_spam_prevention_handlers[address]
|
||||||
|
var/result = sph.check_lockout()
|
||||||
|
to_chat(usr, "Strikes: [sph.strikes]")
|
||||||
|
to_chat(usr, "Last request: [sph.last_request]")
|
||||||
|
to_chat(usr, "Locked out: [sph.locked_out]")
|
||||||
|
to_chat(usr, "Unlock time: [sph.unlock_time]")
|
||||||
|
to_chat(usr, "SPH Result: [result]")
|
||||||
|
to_chat(usr, "World.time: [world.time]")
|
||||||
|
to_chat(usr, "LR DIFF: [(sph.last_request - world.time)/10]s")
|
||||||
|
to_chat(usr, "LO DIFF: [(sph.unlock_time - world.time)/10]s")
|
||||||
|
to_chat(usr, "<hr>")
|
||||||
|
*/
|
||||||
36
code/modules/world_topic/_topic_base.dm
Normal file
36
code/modules/world_topic/_topic_base.dm
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/datum/world_topic_handler
|
||||||
|
/// Key which invokes this topic
|
||||||
|
var/topic_key
|
||||||
|
/// Set this to TRUE if the topic handler needs an authorised comms key
|
||||||
|
var/requires_commskey = FALSE
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the world/Topic handler
|
||||||
|
*
|
||||||
|
* This includes sanity checking for if the key is required, as well as other sanity checks
|
||||||
|
* DO NOT OVERRIDE
|
||||||
|
* Arguments:
|
||||||
|
* * input - The list of topic data, sent from [world/Topic]
|
||||||
|
*/
|
||||||
|
/datum/world_topic_handler/proc/invoke(list/input)
|
||||||
|
SHOULD_NOT_OVERRIDE(TRUE)
|
||||||
|
var/authorised = (config.comms_password && input["key"] == config.comms_password) // No password means no comms, not any password
|
||||||
|
if(requires_commskey && !authorised)
|
||||||
|
// Try keep all returns in JSON unless absolutely necessary (?ping for example)
|
||||||
|
return(json_encode(list("error" = "Invalid Key")))
|
||||||
|
|
||||||
|
return execute(input, authorised)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actually executes the user's topic
|
||||||
|
*
|
||||||
|
* Override this to do your work in subtypes of this topic
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* * input - The list of topic data, sent from [world/Topic]
|
||||||
|
* * key_valid - Has the user entered the correct auth key
|
||||||
|
*/
|
||||||
|
/datum/world_topic_handler/proc/execute(list/input, key_valid = FALSE)
|
||||||
|
PRIVATE_PROC(TRUE) // Ensures no one can call this arbitrarily without checking key auth
|
||||||
|
CRASH("execute() not implemented/overridden for [type]")
|
||||||
38
code/modules/world_topic/adminmsg.dm
Normal file
38
code/modules/world_topic/adminmsg.dm
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/datum/world_topic_handler/adminmsg
|
||||||
|
topic_key = "adminmsg"
|
||||||
|
requires_commskey = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic_handler/adminmsg/execute(list/input, key_valid)
|
||||||
|
/*
|
||||||
|
We got an adminmsg from the Discord bot, so lets split the input then validate the input. Expected output:
|
||||||
|
1. adminmsg = ckey of person the message is to
|
||||||
|
2. msg = contents of message, params2list requires
|
||||||
|
3. sender = the discord name that send the message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var/client/C
|
||||||
|
|
||||||
|
for(var/client/K in GLOB.clients)
|
||||||
|
if(K.ckey == input["adminmsg"])
|
||||||
|
C = K
|
||||||
|
break
|
||||||
|
if(!C)
|
||||||
|
return json_encode(list("error" = "No client with that name on server"))
|
||||||
|
|
||||||
|
var/message = "<font color='red'>Discord PM from <b><a href='?discord_msg=1'>[input["sender"]]</a></b>: [input["msg"]]</font>"
|
||||||
|
var/amessage = "<font color='blue'>Discord PM from <a href='?discord_msg=1'>[input["sender"]]</a> to <b>[key_name_admin(C)]</b>: [input["msg"]]</font>"
|
||||||
|
|
||||||
|
// THESE TWO VARS DO VERY DIFFERENT THINGS. DO NOT ATTEMPT TO COMBINE THEM
|
||||||
|
C.received_discord_pm = world.time
|
||||||
|
C.last_discord_pm_time = 0
|
||||||
|
|
||||||
|
SEND_SOUND(C, 'sound/effects/adminhelp.ogg')
|
||||||
|
to_chat(C, message)
|
||||||
|
|
||||||
|
for(var/client/A in GLOB.admins)
|
||||||
|
// GLOB.admins includes anyone with a holder datum (mentors too). This makes sure only admins see ahelps
|
||||||
|
if(check_rights(R_ADMIN, FALSE, A.mob))
|
||||||
|
if(A != C)
|
||||||
|
to_chat(A, amessage)
|
||||||
|
|
||||||
|
return json_encode(list("success" = "Message Successful"))
|
||||||
11
code/modules/world_topic/announce.dm
Normal file
11
code/modules/world_topic/announce.dm
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/datum/world_topic_handler/announce
|
||||||
|
topic_key = "announce"
|
||||||
|
requires_commskey = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic_handler/announce/execute(list/input, key_valid)
|
||||||
|
var/prtext = input["announce"]
|
||||||
|
var/pr_substring = copytext(prtext, 1, 23)
|
||||||
|
if(pr_substring == "Pull Request merged by")
|
||||||
|
GLOB.pending_server_update = TRUE
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
to_chat(C, "<span class='announce'>PR: [prtext]</span>")
|
||||||
7
code/modules/world_topic/hostannounce.dm
Normal file
7
code/modules/world_topic/hostannounce.dm
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/datum/world_topic_handler/hostannounce
|
||||||
|
topic_key = "hostannounce"
|
||||||
|
requires_commskey = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic_handler/hostannounce/execute(list/input, key_valid)
|
||||||
|
GLOB.pending_server_update = TRUE
|
||||||
|
to_chat(world, "<hr><span style='color: #12A5F4'><b>Server Announcement:</b> [input["message"]]</span><hr>")
|
||||||
35
code/modules/world_topic/manifest.dm
Normal file
35
code/modules/world_topic/manifest.dm
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/datum/world_topic_handler/manifest
|
||||||
|
topic_key = "manifest"
|
||||||
|
|
||||||
|
/datum/world_topic_handler/manifest/execute(list/input, key_valid)
|
||||||
|
var/list/positions = list()
|
||||||
|
var/list/set_names = list(
|
||||||
|
"heads" = GLOB.command_positions,
|
||||||
|
"sec" = GLOB.security_positions,
|
||||||
|
"eng" = GLOB.engineering_positions,
|
||||||
|
"med" = GLOB.medical_positions,
|
||||||
|
"sci" = GLOB.science_positions,
|
||||||
|
"car" = GLOB.supply_positions,
|
||||||
|
"srv" = GLOB.service_positions,
|
||||||
|
"civ" = GLOB.civilian_positions,
|
||||||
|
"bot" = GLOB.nonhuman_positions
|
||||||
|
)
|
||||||
|
|
||||||
|
for(var/datum/data/record/t in GLOB.data_core.general)
|
||||||
|
var/name = t.fields["name"]
|
||||||
|
var/rank = t.fields["rank"]
|
||||||
|
var/real_rank = t.fields["real_rank"]
|
||||||
|
|
||||||
|
var/department = FALSE
|
||||||
|
for(var/k in set_names)
|
||||||
|
if(real_rank in set_names[k])
|
||||||
|
if(!positions[k])
|
||||||
|
positions[k] = list()
|
||||||
|
positions[k][name] = rank
|
||||||
|
department = TRUE
|
||||||
|
if(!department)
|
||||||
|
if(!positions["misc"])
|
||||||
|
positions["misc"] = list()
|
||||||
|
positions["misc"][name] = rank
|
||||||
|
|
||||||
|
return json_encode(positions)
|
||||||
14
code/modules/world_topic/ping.dm
Normal file
14
code/modules/world_topic/ping.dm
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/datum/world_topic_handler/ping
|
||||||
|
topic_key = "ping"
|
||||||
|
|
||||||
|
/datum/world_topic_handler/ping/execute(list/input, key_valid)
|
||||||
|
/*
|
||||||
|
Basically a more efficient version of
|
||||||
|
|
||||||
|
if("ping" in input)
|
||||||
|
var/x = 1
|
||||||
|
for(var/client/C)
|
||||||
|
x++
|
||||||
|
return x
|
||||||
|
*/
|
||||||
|
return length(GLOB.clients) + 1
|
||||||
10
code/modules/world_topic/players.dm
Normal file
10
code/modules/world_topic/players.dm
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/datum/world_topic_handler/playerlist
|
||||||
|
topic_key = "playerlist"
|
||||||
|
|
||||||
|
/datum/world_topic_handler/playerlist/execute(list/input, key_valid)
|
||||||
|
var/list/keys = list()
|
||||||
|
for(var/I in GLOB.clients)
|
||||||
|
var/client/C = I
|
||||||
|
keys += C.key
|
||||||
|
|
||||||
|
return json_encode(keys)
|
||||||
53
code/modules/world_topic/status.dm
Normal file
53
code/modules/world_topic/status.dm
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/datum/world_topic_handler/status
|
||||||
|
topic_key = "status"
|
||||||
|
|
||||||
|
/datum/world_topic_handler/status/execute(list/input, key_valid)
|
||||||
|
var/list/status_info = list()
|
||||||
|
var/list/admins = list()
|
||||||
|
status_info["version"] = GLOB.revision_info.commit_hash
|
||||||
|
status_info["mode"] = GLOB.master_mode
|
||||||
|
status_info["respawn"] = GLOB.abandon_allowed
|
||||||
|
status_info["enter"] = GLOB.enter_allowed
|
||||||
|
status_info["vote"] = config.allow_vote_mode
|
||||||
|
status_info["ai"] = config.allow_ai
|
||||||
|
status_info["host"] = world.host ? world.host : null
|
||||||
|
status_info["players"] = list()
|
||||||
|
status_info["roundtime"] = worldtime2text()
|
||||||
|
status_info["stationtime"] = station_time_timestamp()
|
||||||
|
status_info["oldstationtime"] = classic_worldtime2text() // more "consistent" indication of the round's running time
|
||||||
|
status_info["listed"] = "Public"
|
||||||
|
if(!world.hub_password)
|
||||||
|
status_info["listed"] = "Invisible"
|
||||||
|
var/player_count = 0
|
||||||
|
var/admin_count = 0
|
||||||
|
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
if(C.holder)
|
||||||
|
if(C.holder.fakekey)
|
||||||
|
continue //so stealthmins aren't revealed by the hub
|
||||||
|
admin_count++
|
||||||
|
admins += list(list(C.key, C.holder.rank))
|
||||||
|
player_count++
|
||||||
|
status_info["players"] = player_count
|
||||||
|
status_info["admins"] = admin_count
|
||||||
|
status_info["map_name"] = GLOB.map_name ? GLOB.map_name : "Unknown"
|
||||||
|
|
||||||
|
// Add more info if we are authed
|
||||||
|
if(key_valid)
|
||||||
|
if(SSticker && SSticker.mode)
|
||||||
|
status_info["real_mode"] = SSticker.mode.name
|
||||||
|
status_info["security_level"] = get_security_level()
|
||||||
|
status_info["ticker_state"] = SSticker.current_state
|
||||||
|
|
||||||
|
if(SSshuttle && SSshuttle.emergency)
|
||||||
|
// Shuttle status, see /__DEFINES/stat.dm
|
||||||
|
status_info["shuttle_mode"] = SSshuttle.emergency.mode
|
||||||
|
// Shuttle timer, in seconds
|
||||||
|
status_info["shuttle_timer"] = SSshuttle.emergency.timeLeft()
|
||||||
|
|
||||||
|
for(var/i in 1 to admins.len)
|
||||||
|
var/list/A = admins[i]
|
||||||
|
status_info["admin[i - 1]"] = A[1]
|
||||||
|
status_info["adminrank[i - 1]"] = A[2]
|
||||||
|
|
||||||
|
return json_encode(status_info)
|
||||||
@@ -2470,6 +2470,15 @@
|
|||||||
#include "code\modules\vehicle\speedbike.dm"
|
#include "code\modules\vehicle\speedbike.dm"
|
||||||
#include "code\modules\vehicle\sportscar.dm"
|
#include "code\modules\vehicle\sportscar.dm"
|
||||||
#include "code\modules\vehicle\vehicle.dm"
|
#include "code\modules\vehicle\vehicle.dm"
|
||||||
|
#include "code\modules\world_topic\_spam_prevention_handler.dm"
|
||||||
|
#include "code\modules\world_topic\_topic_base.dm"
|
||||||
|
#include "code\modules\world_topic\adminmsg.dm"
|
||||||
|
#include "code\modules\world_topic\announce.dm"
|
||||||
|
#include "code\modules\world_topic\hostannounce.dm"
|
||||||
|
#include "code\modules\world_topic\manifest.dm"
|
||||||
|
#include "code\modules\world_topic\ping.dm"
|
||||||
|
#include "code\modules\world_topic\players.dm"
|
||||||
|
#include "code\modules\world_topic\status.dm"
|
||||||
#include "goon\code\datums\browserOutput.dm"
|
#include "goon\code\datums\browserOutput.dm"
|
||||||
#include "interface\interface.dm"
|
#include "interface\interface.dm"
|
||||||
#include "interface\skin.dmf"
|
#include "interface\skin.dmf"
|
||||||
|
|||||||
Reference in New Issue
Block a user