From ee404b21701f71f84290d4f6f50e35b5c730c210 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Thu, 18 May 2017 07:53:46 -0400 Subject: [PATCH] World.dm Refactor (#27268) * Cleanup world/New * Moves some things from OnReboot SS Shutdowns * Move mode handling procs to ticker * Moves delayed reboot to ticker Cleans up round end sound setting Splits round end animation between SStitle and SSticker * Moves PR announcement to where it can use the define * Clean this bit up * Move out datacore Initialization * Fix some stuff * Fix this for * Different PR * Gives admins reboot options * Make it smaller --- code/__DEFINES/subsystems.dm | 1 + code/_globalvars/misc.dm | 2 +- code/controllers/master.dm | 1 + code/controllers/subsystem/blackbox.dm | 2 + code/controllers/subsystem/server_maint.dm | 8 ++ code/controllers/subsystem/ticker.dm | 72 +++++++++- code/controllers/subsystem/title.dm | 6 + code/controllers/subsystem/vote.dm | 4 +- code/game/gamemodes/nuclear/nuclearbomb.dm | 3 +- code/modules/admin/admin.dm | 17 ++- code/modules/admin/topic.dm | 2 +- code/modules/admin/verbs/playsound.dm | 5 +- code/modules/client/client_procs.dm | 4 + code/world.dm | 149 ++++++--------------- 14 files changed, 151 insertions(+), 125 deletions(-) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 9a0bf8d401e0..371bad418c15 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -40,6 +40,7 @@ // Subsystem init_order, from highest priority to lowest priority // The numbers just define the ordering, they are meaningless otherwise. +#define INIT_ORDER_SERVER_MAINT 16 #define INIT_ORDER_JOBS 15 #define INIT_ORDER_EVENTS 14 #define INIT_ORDER_TICKER 13 diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index ba50d63aae06..59326c5c1700 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -8,7 +8,7 @@ GLOBAL_VAR_INIT(fileaccess_timer, 0) GLOBAL_VAR_INIT(TAB, "    ") -GLOBAL_DATUM(data_core, /datum/datacore) +GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) GLOBAL_VAR_INIT(CELLRATE, 0.002) // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second) GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index a220c2530cdc..773f334b6731 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -83,6 +83,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING) sortTim(subsystems, /proc/cmp_subsystem_init) reverseRange(subsystems) for(var/datum/controller/subsystem/ss in subsystems) + testing("Shutdown [ss.name] subsystem") ss.Shutdown() // Returns 1 if we created a new mc, 0 if we couldn't due to a recent restart, diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 8f7c772f6a98..76daddcf6a4b 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -54,6 +54,8 @@ SUBSYSTEM_DEF(blackbox) return FALSE /datum/controller/subsystem/blackbox/Shutdown() + set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len) + var/pda_msg_amt = 0 var/rc_msg_amt = 0 diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index a24d952b9dc6..3400c6b95098 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -5,6 +5,7 @@ SUBSYSTEM_DEF(server_maint) wait = 6 flags = SS_POST_FIRE_TIMING priority = 10 + init_order = INIT_ORDER_SERVER_MAINT runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/list/currentrun @@ -37,4 +38,11 @@ SUBSYSTEM_DEF(server_maint) if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check return +/datum/controller/subsystem/server_maint/Shutdown() + kick_clients_in_lobby("The round came to an end with you in the lobby.", TRUE) //second parameter ensures only afk clients are kicked + for(var/thing in GLOB.clients) + var/client/C = thing + if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite + C << link("byond://[config.server]") + #undef PING_BUFFER_TIME diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index e3c8f47471e5..dab36e8e33ec 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -20,6 +20,7 @@ SUBSYSTEM_DEF(ticker) var/login_music //music played in pregame lobby var/round_end_sound //music/jingle played when the world reboots + var/round_end_sound_sent = TRUE //If all clients have loaded it var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking. @@ -61,6 +62,7 @@ SUBSYSTEM_DEF(ticker) var/list/round_start_events /datum/controller/subsystem/ticker/Initialize(timeofday) + load_mode() var/list/music = world.file2list(ROUND_START_MUSIC_LIST, "\n") login_music = pick(music) @@ -616,9 +618,9 @@ SUBSYSTEM_DEF(ticker) sleep(50) if(mode.station_was_nuked) - world.Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke") + Reboot("Station destroyed by Nuclear Device.", "end_proper", "nuke") else - world.Reboot("Round ended.", "end_proper", "proper completion") + Reboot("Round ended.", "end_proper", "proper completion") /datum/controller/subsystem/ticker/proc/send_tip_of_the_round() var/m @@ -779,3 +781,69 @@ SUBSYSTEM_DEF(ticker) start_at = world.time + newtime else timeLeft = newtime + +/datum/controller/subsystem/ticker/proc/load_mode() + var/mode = trim(file2text("data/mode.txt")) + if(mode) + GLOB.master_mode = mode + else + GLOB.master_mode = "extended" + log_game("Saved mode is '[GLOB.master_mode]'") + +/datum/controller/subsystem/ticker/proc/save_mode(the_mode) + var/F = file("data/mode.txt") + fdel(F) + F << the_mode + +/datum/controller/subsystem/ticker/proc/SetRoundEndSound(the_sound) + set waitfor = FALSE + round_end_sound_sent = FALSE + round_end_sound = fcopy_rsc(the_sound) + for(var/thing in GLOB.clients) + var/client/C = thing + if (!C) + continue + C.Export("##action=load_rsc", round_end_sound) + round_end_sound_sent = TRUE + +/datum/controller/subsystem/ticker/proc/Reboot(reason, feedback_c, feedback_r, delay) + set waitfor = FALSE + if(usr && !check_rights(R_SERVER, TRUE)) + return + + if(!delay) + delay = config.round_end_countdown * 10 + + if(delay_end) + to_chat(world, "An admin has delayed the round end.") + return + + to_chat(world, "Rebooting World in [delay/10] [(delay >= 10 && delay < 20) ? "second" : "seconds"]. [reason]") + + var/start_wait = world.time + UNTIL(round_end_sound_sent && (world.time - start_wait) > (delay * 2)) //don't wait forever + sleep(delay - (world.time - start_wait)) + + if(delay_end) + to_chat(world, "Reboot was cancelled by an admin.") + return + + SSblackbox.set_details("[feedback_c]","[feedback_r]") + + log_game("Rebooting World. [reason]") + + world.Reboot() + +/datum/controller/subsystem/ticker/Shutdown() + if(!round_end_sound) + round_end_sound = pick(\ + 'sound/roundend/newroundsexy.ogg', + 'sound/roundend/apcdestroyed.ogg', + 'sound/roundend/bangindonk.ogg', + 'sound/roundend/leavingtg.ogg', + 'sound/roundend/its_only_game.ogg', + 'sound/roundend/yeehaw.ogg', + 'sound/roundend/disappointed.ogg'\ + ) + + world << sound(round_end_sound) \ No newline at end of file diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index d9f4ef99386c..6c5466d8d9f4 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -55,6 +55,12 @@ SUBSYSTEM_DEF(title) var/F = file("data/previous_title.dat") F << file_path + for(var/thing in GLOB.clients) + if(!thing) + continue + var/obj/screen/splash/S = new(thing, FALSE) + S.Fade(FALSE,FALSE) + /datum/controller/subsystem/title/Recover() icon = SStitle.icon splash_turf = SStitle.splash_turf diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index a914074a418f..05c45988ca47 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -118,7 +118,7 @@ SUBSYSTEM_DEF(vote) restart = 1 if("gamemode") if(GLOB.master_mode != .) - world.save_mode(.) + SSticker.save_mode(.) if(SSticker.HasRoundStarted()) restart = 1 else @@ -130,7 +130,7 @@ SUBSYSTEM_DEF(vote) active_admins = 1 break if(!active_admins) - world.Reboot("Restart vote successful.", "end_error", "restart vote") + SSticker.Reboot("Restart vote successful.", "end_error", "restart vote") else to_chat(world, "Notice:Restart vote will not restart the server automatically because there are active admins on.") message_admins("A restart vote has passed, but there are active admins on with +server, so it has been canceled. If you wish, you may restart the server.") diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 1f01b38860d1..5964983b0950 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -459,8 +459,7 @@ var/datum/game_mode/nuclear/NM = SSticker.mode NM.nukes_left -- if(!SSticker.mode.check_finished())//If the mode does not deal with the nuke going off so just reboot because everyone is stuck as is - spawn() - world.Reboot("Station destroyed by Nuclear Device.", "end_error", "nuke - unhandled ending") + SSticker.Reboot("Station destroyed by Nuclear Device.", "end_error", "nuke - unhandled ending") /* diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 954283d1183c..3371914bb836 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -421,13 +421,18 @@ set desc="Restarts the world immediately" if (!usr.client.holder) return - var/confirm = alert("Restart the game world?", "Restart", "Yes", "Cancel") - if(confirm == "Cancel") - return - if(confirm == "Yes") - SSticker.delay_end = 0 + + var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") + var result = input(usr, "Select reboot method", "World Reboot", options[1]) as null|anything in options + if(result) SSblackbox.add_details("admin_verb","Reboot World") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - world.Reboot("Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key].", "end_error", "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) + switch(result) + if("Regular Restart") + SSticker.Reboot("Initiated by [usr.client.holder.fakekey ? "Admin" : usr.key].", "end_error", "admin reboot - by [usr.key] [usr.client.holder.fakekey ? "(stealth)" : ""]", 10) + if("Hard Restart (No Delay, No Feeback Reason)") + world.Reboot() + if("Hardest Restart (No actions, just reboot)") + world.Reboot(fast_track = TRUE) /datum/admins/proc/end_round() set category = "Server" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 98c26857a25f..eb6f03e7d0f4 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1206,7 +1206,7 @@ message_admins("[key_name_admin(usr)] set the mode as [GLOB.master_mode].") to_chat(world, "The mode is now: [GLOB.master_mode]") Game() // updates the main game menu - world.save_mode(GLOB.master_mode) + SSticker.save_mode(GLOB.master_mode) .(href, list("c_mode"=1)) else if(href_list["f_secret2"]) diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index e781473634c7..eb4c3a5f10fd 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -52,10 +52,7 @@ if(!check_rights(R_SOUNDS)) return - if(SSticker) - SSticker.round_end_sound = fcopy_rsc(S) - else - return + SSticker.SetRoundEndSound(S) log_admin("[key_name(src)] set the round end sound to [S]") message_admins("[key_name_admin(src)] set the round end sound to [S]") diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 32cb9dfaa77c..150c4b32eee3 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -636,3 +636,7 @@ GLOBAL_LIST(external_rsc_urls) CRASH("change_view called without argument.") view = new_size + +/client/proc/AnnouncePR(announcement) + if(prefs && prefs.chat_toggles & CHAT_PULLR) + to_chat(src, announcement) \ No newline at end of file diff --git a/code/world.dm b/code/world.dm index cef69c168089..6e3f4d79843c 100644 --- a/code/world.dm +++ b/code/world.dm @@ -16,6 +16,32 @@ /world/New() log_world("World loaded at [time_stamp()]") + SetupExternalRSC() + + GLOB.config_error_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl + + make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) + + config = new + + SetRoundID() + + SetupLogs() + + GLOB.revdata.DownloadPRDetails() + + load_motd() + load_admins() + load_menu() + if(config.usewhitelist) + load_whitelist() + LoadBans() + + GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 + + Master.Initialize(10, FALSE) + +/world/proc/SetupExternalRSC() #if (PRELOAD_RSC == 0) external_rsc_urls = world.file2list("config/external_rsc_urls.txt","\n") var/i=1 @@ -25,10 +51,8 @@ else external_rsc_urls.Cut(i,i+1) #endif - GLOB.config_error_log = file("data/logs/config_error.log") //temporary file used to record errors with loading config, moved to log directory once logging is set bl - make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) - config = new - GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" + +/world/proc/SetRoundID() if(config.sql_enabled) if(SSdbcore.Connect()) log_world("Database connection established.") @@ -38,10 +62,14 @@ query_feedback_max_id.Execute() if(query_feedback_max_id.NextRow()) GLOB.round_id = query_feedback_max_id.item[1] - GLOB.log_directory += "[GLOB.round_id]" else log_world("Your server failed to establish a connection with the database.") - if(!GLOB.round_id) + +/world/proc/SetupLogs() + GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-" + if(GLOB.round_id) + GLOB.log_directory += "[GLOB.round_id]" + else GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]" GLOB.world_game_log = file("[GLOB.log_directory]/game.log") GLOB.world_attack_log = file("[GLOB.log_directory]/attack.log") @@ -58,21 +86,6 @@ if(GLOB.round_id) log_game("Round ID: [GLOB.round_id]") - GLOB.revdata.DownloadPRDetails() - load_mode() - load_motd() - load_admins() - load_menu() - if(config.usewhitelist) - load_whitelist() - LoadBans() - - GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000 - - GLOB.data_core = new /datum/datacore() - - Master.Initialize(10, FALSE) - #define IRC_STATUS_THROTTLE 50 /world/Topic(T, addr, master, key) if(config && config.log_world_topic) @@ -198,99 +211,21 @@ if(PRcounts[id] > PR_ANNOUNCEMENTS_PER_ROUND) return -#define CHAT_PULLR 64 //defined in preferences.dm, but not available here at compilation time + var/final_composed = "PR: [announcement]" for(var/client/C in GLOB.clients) - if(C.prefs && (C.prefs.chat_toggles & CHAT_PULLR)) - C << "PR: [announcement]" -#undef CHAT_PULLR + C.AnnouncePR(final_composed) -#define WORLD_REBOOT(X) log_world("World rebooted at [time_stamp()]"); ..(X); return; - -/world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time) - if (reason == 1) //special reboot, do none of the normal stuff +/world/Reboot(reason = 0, fast_track = FALSE) + if (reason || fast_track) //special reboot, do none of the normal stuff if (usr) log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools") message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools") to_chat(world, "Rebooting World immediately due to host request") - WORLD_REBOOT(1) - var/delay - if(time) - delay = time else - delay = config.round_end_countdown * 10 - if(SSticker.delay_end) - to_chat(world, "An admin has delayed the round end.") - return - to_chat(world, "Rebooting World in [delay/10] [(delay >= 10 && delay < 20) ? "second" : "seconds"]. [reason]") - var/round_end_sound_sent = FALSE - if(SSticker.round_end_sound) - round_end_sound_sent = TRUE - for(var/thing in GLOB.clients) - var/client/C = thing - if (!C) - continue - C.Export("##action=load_rsc", SSticker.round_end_sound) - sleep(delay) - if(SSticker.delay_end) - to_chat(world, "Reboot was cancelled by an admin.") - return - OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent) - WORLD_REBOOT(0) -#undef WORLD_REBOOT - -/world/proc/OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent) - SSblackbox.set_details("[feedback_c]","[feedback_r]") - log_game("Rebooting World. [reason]") - SSblackbox.set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len) - Master.Shutdown() //run SS shutdowns - RoundEndAnimation(round_end_sound_sent) - kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) //second parameter ensures only afk clients are kicked - to_chat(world, "Rebooting world...") - for(var/thing in GLOB.clients) - var/client/C = thing - if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite - C << link("byond://[config.server]") - -/world/proc/RoundEndAnimation(round_end_sound_sent) - set waitfor = FALSE - var/round_end_sound - if(SSticker.round_end_sound) - round_end_sound = SSticker.round_end_sound - if (!round_end_sound_sent) - for(var/thing in GLOB.clients) - var/client/C = thing - if (!C) - continue - C.Export("##action=load_rsc", round_end_sound) - else - round_end_sound = pick(\ - 'sound/roundend/newroundsexy.ogg', - 'sound/roundend/apcdestroyed.ogg', - 'sound/roundend/bangindonk.ogg', - 'sound/roundend/leavingtg.ogg', - 'sound/roundend/its_only_game.ogg', - 'sound/roundend/yeehaw.ogg', - 'sound/roundend/disappointed.ogg'\ - ) - - for(var/thing in GLOB.clients) - var/obj/screen/splash/S = new(thing, FALSE) - S.Fade(FALSE,FALSE) - - world << sound(round_end_sound) - -/world/proc/load_mode() - var/mode = trim(file2text("data/mode.txt")) - if(mode) - GLOB.master_mode = mode - else - GLOB.master_mode = "extended" - log_game("Saved mode is '[GLOB.master_mode]'") - -/world/proc/save_mode(the_mode) - var/F = file("data/mode.txt") - fdel(F) - F << the_mode + to_chat(world, "Rebooting world...") + Master.Shutdown() //run SS shutdowns + log_world("World rebooted at [time_stamp()]"); + ..() /world/proc/load_motd() GLOB.join_motd = file2text("config/motd.txt") + "
" + GLOB.revdata.GetTestMergeInfo()