mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 21:48:21 +01: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:
@@ -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`
|
||||
@@ -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>")
|
||||
*/
|
||||
@@ -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]")
|
||||
@@ -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"))
|
||||
@@ -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>")
|
||||
@@ -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>")
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user