From 575d0989449ca3eb6eb003a2b7297c2332c42622 Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Tue, 8 May 2018 22:33:07 -0400 Subject: [PATCH] Update DMAPI to version 3.2.1.0 (#37429) This is primarily a compatibility layer that enables both forward and backward compatibility for all past and future APIs based on the detected running TGS version. It also bundles all it's includes to make future upgrades not have to modify the dme, heck, could even use a submodule if it wanted (not happening). No other changes necessary. There's an upcoming event system and new chat management functions. Check them out here: https://github.com/tgstation/tgstation-server/blob/303448457e1529c900fa183a8b3c7f2e5459acf1/DMAPI/tgs.dm Also added /datum/proc/CanProcCall() --- code/__DEFINES/server_tools.config.dm | 8 - code/__DEFINES/server_tools.dm | 128 --------- code/__DEFINES/tgs.config.dm | 19 ++ code/__DEFINES/tgs.dm | 202 ++++++++++++++ code/_globalvars/configuration.dm | 2 +- code/controllers/master.dm | 7 +- code/controllers/subsystem/server_maint.dm | 6 +- code/controllers/subsystem/ticker.dm | 2 +- code/datums/datumvars.dm | 3 + code/datums/helper_datums/getrev.dm | 17 +- code/datums/world_topic.dm | 8 +- code/game/world.dm | 14 +- code/modules/admin/admin.dm | 4 +- code/modules/admin/chat_commands.dm | 57 ++-- code/modules/admin/verbs/adminhelp.dm | 2 +- code/modules/admin/verbs/debug.dm | 8 +- code/modules/server_tools/st_commands.dm | 76 ------ code/modules/server_tools/st_interface.dm | 135 ---------- code/modules/tgs/core/_definitions.dm | 2 + code/modules/tgs/core/core.dm | 144 ++++++++++ code/modules/tgs/core/datum.dm | 74 ++++++ .../modules/tgs/core/default_event_handler.dm | 30 +++ code/modules/tgs/includes.dm | 6 + code/modules/tgs/v3210/api.dm | 248 ++++++++++++++++++ code/modules/tgs/v3210/commands.dm | 78 ++++++ tgstation.dme | 7 +- 26 files changed, 881 insertions(+), 406 deletions(-) delete mode 100644 code/__DEFINES/server_tools.config.dm delete mode 100644 code/__DEFINES/server_tools.dm create mode 100644 code/__DEFINES/tgs.config.dm create mode 100644 code/__DEFINES/tgs.dm delete mode 100644 code/modules/server_tools/st_commands.dm delete mode 100644 code/modules/server_tools/st_interface.dm create mode 100644 code/modules/tgs/core/_definitions.dm create mode 100644 code/modules/tgs/core/core.dm create mode 100644 code/modules/tgs/core/datum.dm create mode 100644 code/modules/tgs/core/default_event_handler.dm create mode 100644 code/modules/tgs/includes.dm create mode 100644 code/modules/tgs/v3210/api.dm create mode 100644 code/modules/tgs/v3210/commands.dm diff --git a/code/__DEFINES/server_tools.config.dm b/code/__DEFINES/server_tools.config.dm deleted file mode 100644 index 4cc082bbe48..00000000000 --- a/code/__DEFINES/server_tools.config.dm +++ /dev/null @@ -1,8 +0,0 @@ -#define SERVER_TOOLS_EXTERNAL_CONFIGURATION -#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name) -#define SERVER_TOOLS_READ_GLOBAL(Name) GLOB.##Name -#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value -#define SERVER_TOOLS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]") -#define SERVER_TOOLS_LOG(message) log_world("SERVICE: [##message]") -#define SERVER_TOOLS_NOTIFY_ADMINS(event) message_admins(##event) -#define SERVER_TOOLS_CLIENT_COUNT GLOB.clients.len diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm deleted file mode 100644 index a1764880c34..00000000000 --- a/code/__DEFINES/server_tools.dm +++ /dev/null @@ -1,128 +0,0 @@ -// /tg/station 13 server tools API -#define SERVICE_API_VERSION_STRING "3.2.0.2" - -//CONFIGURATION -//use this define if you want to do configuration outside of this file -#ifndef SERVER_TOOLS_EXTERNAL_CONFIGURATION -//Comment this out once you've filled in the below -#error /tg/station server tools interface unconfigured - -//Required interfaces (fill in with your codebase equivalent): - -//create a global variable named `Name` and set it to `Value` -//These globals must not be modifiable from anywhere outside of the server tools -#define SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(Name, Value) -//Read the value in the global variable `Name` -#define SERVER_TOOLS_READ_GLOBAL(Name) -//Set the value in the global variable `Name` to `Value` -#define SERVER_TOOLS_WRITE_GLOBAL(Name, Value) -//display an announcement `message` from the server to all players -#define SERVER_TOOLS_WORLD_ANNOUNCE(message) -//Write a string `message` to a server log -#define SERVER_TOOLS_LOG(message) -//Notify current in-game administrators of a string `event` -#define SERVER_TOOLS_NOTIFY_ADMINS(event) -//The current amount of connected clients -#define SERVER_TOOLS_CLIENT_COUNT -#endif - -//Required hooks: - -//Put this somewhere in /world/New() that is always run -#define SERVER_TOOLS_ON_NEW ServiceInit() -//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified -#define SERVER_TOOLS_ON_TOPIC var/service_topic_return = ServiceCommand(params2list(T)); if(service_topic_return) return service_topic_return -//Put at the beginning of world/Reboot(reason) -#define SERVER_TOOLS_ON_REBOOT ServiceReboot() - -//Optional callable functions: - -//Returns the string version of the API -#define SERVER_TOOLS_API_VERSION ServiceAPIVersion() -//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise -//No function below this succeed if this is FALSE -#define SERVER_TOOLS_PRESENT RunningService() -//Gets the current version of the service running the server -#define SERVER_TOOLS_VERSION ServiceVersion() -//Forces a hard reboot of BYOND by ending the process -//unlike del(world) clients will try to reconnect -//If the service has not requested a shutdown, the world will reboot shortly after -#define SERVER_TOOLS_REBOOT_BYOND world.ServiceEndProcess() -/* - Gets the list of any testmerged github pull requests - - "[PR Number]" => list( - "title" -> PR title - "commit" -> Full hash of commit merged - "author" -> Github username of the author of the PR - ) -*/ -#define SERVER_TOOLS_PR_LIST GetTestMerges() -//Sends a message to connected game chats -#define SERVER_TOOLS_CHAT_BROADCAST(message) world.ChatBroadcast(message) -//Sends a message to connected admin chats -#define SERVER_TOOLS_RELAY_BROADCAST(message) world.AdminBroadcast(message) - -//IMPLEMENTATION - -#define REBOOT_MODE_NORMAL 0 -#define REBOOT_MODE_HARD 1 -#define REBOOT_MODE_SHUTDOWN 2 - -#define SERVICE_WORLD_PARAM "server_service" -#define SERVICE_VERSION_PARAM "server_service_version" -#define SERVICE_INSTANCE_PARAM "server_instance" -#define SERVICE_PR_TEST_JSON "prtestjob.json" -#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll" -#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint" - -#define SERVICE_CMD_HARD_REBOOT "hard_reboot" -#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown" -#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce" -#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands" -#define SERVICE_CMD_API_COMPATIBLE "api_compat" -#define SERVICE_CMD_PLAYER_COUNT "client_count" - -#define SERVICE_CMD_PARAM_KEY "serviceCommsKey" -#define SERVICE_CMD_PARAM_COMMAND "command" -#define SERVICE_CMD_PARAM_SENDER "sender" -#define SERVICE_CMD_PARAM_CUSTOM "custom" - -#define SERVICE_JSON_PARAM_HELPTEXT "help_text" -#define SERVICE_JSON_PARAM_ADMINONLY "admin_only" -#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters" - -#define SERVICE_REQUEST_KILL_PROCESS "killme" -#define SERVICE_REQUEST_IRC_BROADCAST "irc" -#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc" -#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot" -#define SERVICE_REQUEST_API_VERSION "api_ver" - -#define SERVICE_RETURN_SUCCESS "SUCCESS" - -/* -The MIT License - -Copyright (c) 2017 Jordan Brown - -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ diff --git a/code/__DEFINES/tgs.config.dm b/code/__DEFINES/tgs.config.dm new file mode 100644 index 00000000000..00cbae7629a --- /dev/null +++ b/code/__DEFINES/tgs.config.dm @@ -0,0 +1,19 @@ +#define TGS_EXTERNAL_CONFIGURATION +#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) GLOBAL_VAR_INIT(##Name, ##Value); GLOBAL_PROTECT(##Name) +#define TGS_READ_GLOBAL(Name) GLOB.##Name +#define TGS_WRITE_GLOBAL(Name, Value) GLOB.##Name = ##Value +#define TGS_WORLD_ANNOUNCE(message) to_chat(world, "[html_encode(##message)]") +#define TGS_INFO_LOG(message) log_world("TGS: Info: [##message]") +#define TGS_ERROR_LOG(message) log_world("TGS: Error: [##message]") +#define TGS_NOTIFY_ADMINS(event) message_admins(##event) +#define TGS_CLIENT_COUNT GLOB.clients.len +#define TGS_PROTECT_DATUM(Path)\ +##Path/can_vv_get(var_name){\ + return FALSE;\ +}\ +##Path/vv_edit_var(var_name, var_value){\ + return FALSE;\ +}\ +##Path/CanProcCall(procname){\ + return FALSE;\ +} diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm new file mode 100644 index 00000000000..651be685c55 --- /dev/null +++ b/code/__DEFINES/tgs.dm @@ -0,0 +1,202 @@ +//tgstation-server DMAPI + +//All functions and datums outside this document are subject to change with any version and should not be relied on + +//CONFIGURATION + +//create this define if you want to do configuration outside of this file +#ifndef TGS_EXTERNAL_CONFIGURATION + +//Comment this out once you've filled in the below +#error TGS API unconfigured + +//Required interfaces (fill in with your codebase equivalent): + +//create a global variable named `Name` and set it to `Value` +//These globals must not be modifiable from anywhere outside of the server tools +#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) + +//Read the value in the global variable `Name` +#define TGS_READ_GLOBAL(Name) + +//Set the value in the global variable `Name` to `Value` +#define TGS_WRITE_GLOBAL(Name, Value) + +//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game priveledge escalation +#define TGS_PROTECT_DATUM(Path) + +//display an announcement `message` from the server to all players +#define TGS_WORLD_ANNOUNCE(message) + +//Notify current in-game administrators of a string `event` +#define TGS_NOTIFY_ADMINS(event) + +//Write an info `message` to a server log +#define TGS_INFO_LOG(message) + +//Write an error `message` to a server log +#define TGS_ERROR_LOG(message) + +//Get the number of connected /clients +#define TGS_CLIENT_COUNT + +#endif + +//EVENT CODES + +//TODO + +//REQUIRED HOOKS + +//Call this somewhere in /world/New() that is always run +//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels +/world/proc/TgsNew(datum/tgs_event_handler/event_handler) + return + +//Call this when your initializations are complete and your game is ready to play before any player interactions happen +//This may use world.sleep_offline to make this happen so ensure no changes are made to it while this call is running +/world/proc/TgsInitializationComplete() + return + +//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified +#define TGS_TOPIC var/tgs_topic_return = TgsTopic(T); if(tgs_topic_return) return tgs_topic_return + +//Call this at the beginning of world/Reboot(reason) +/world/proc/TgsReboot() + return + +//DATUM DEFINITIONS +//unless otherwise specified all datums defined here should be considered read-only, warranty void if written + +//represents git revision information about the current world build +/datum/tgs_revision_information + var/commit //full sha of compiled commit + var/origin_commit //full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch + +//represents a merge of a GitHub pull request +/datum/tgs_revision_information/test_merge + var/number //pull request number + var/title //pull request title + var/body //pull request body + var/author //pull request github author + var/url //link to pull request html + var/pull_request_commit //commit of the pull request when it was merged + var/time_merged //timestamp of when the merge commit for the pull request was created + var/comment //optional comment left by the one who initiated the test merge + +//represents a connected chat channel +/datum/tgs_chat_channel + var/id //internal channel representation + var/friendly_name //user friendly channel name + var/server_name //server name the channel resides on + var/provider_name //chat provider for the channel + var/is_admin_channel //if the server operator has marked this channel for game admins only + var/is_private_channel //if this is a private chat channel + +//represents a chat user +/datum/tgs_chat_user + var/id //Internal user representation + var/friendly_name //The user's public name + var/mention //The text to use to ping this user in a message + var/datum/tgs_chat_channel/channel //The /datum/tgs_chat_channel this user was from + +//user definable callback for handling events +/datum/tgs_event_handler/proc/HandleEvent(event_code) + return + +//user definable chat command +/datum/tgs_chat_command + var/name = "" //the string to trigger this command on a chat bot. e.g. TGS3_BOT: do_this_command + var/help_text = "" //help text for this command + var/admin_only = FALSE //set to TRUE if this command should only be usable by registered chat admins + +//override to implement command +//sender: The tgs_chat_user who send to command +//params: The trimmed string following the command name +//The return value will be stringified and sent to the appropriate chat +/datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params) + CRASH("[type] has no implementation for Run()") + +//FUNCTIONS + +//Returns the respective string version of the API +/world/proc/TgsMaximumAPIVersion() + return + +/world/proc/TgsMinimumAPIVersion() + return + +//Gets the current version of the server tools running the server +/world/proc/TgsVersion() + return + +//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise +//No function below this succeeds if it returns FALSE +/world/proc/TgsAvailable() + return + +/world/proc/TgsInstanceName() + return + +//Get the current `/datum/tgs_revision_information` +/world/proc/TgsRevision() + return + +//Gets a list of active `/datum/tgs_revision_information/test_merge`s +/world/proc/TgsTestMerges() + return + +//Forces a hard reboot of BYOND by ending the process +//unlike del(world) clients will try to reconnect +//If the service has not requested a shutdown, the next server will take over +/world/proc/TgsEndProcess() + return + +//Gets a list of connected tgs_chat_channel +/world/proc/TgsChatChannelInfo() + return + +//Sends a message to connected game chats +//message: The message to send +//channels: optional channels to limit the broadcast to +/world/proc/TgsChatBroadcast(message, list/channels) + return + +//Send a message to non-admin connected chats +//message: The message to send +//admin_only: If TRUE, message will instead be sent to only admin connected chats +/world/proc/TgsTargetedChatBroadcast(message, admin_only) + return + +//Send a private message to a specific user +//message: The message to send +//user: The /datum/tgs_chat_user to send to +/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user) + return + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index f580eab3d55..7c5715e1bb7 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -1,6 +1,6 @@ GLOBAL_REAL(config, /datum/controller/configuration) -GLOBAL_DATUM_INIT(revdata, /datum/getrev, new) +GLOBAL_DATUM(revdata, /datum/getrev) GLOBAL_VAR(host) GLOBAL_VAR(station_name) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 2b1e9bcda99..0cc0c622d7b 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -199,11 +199,14 @@ GLOBAL_REAL(Master, /datum/controller/master) = new // Sort subsystems by display setting for easy access. sortTim(subsystems, /proc/cmp_subsystem_display) // Set world options. - if(sleep_offline_after_initializations) - world.sleep_offline = TRUE world.fps = CONFIG_GET(number/fps) var/initialized_tod = REALTIMEOFDAY + + world.TgsInitializationComplete() + if(sleep_offline_after_initializations) + world.sleep_offline = TRUE sleep(1) + if(sleep_offline_after_initializations && CONFIG_GET(flag/resume_after_initializations)) world.sleep_offline = FALSE initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index dd68443bd72..dd45f9146f2 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -55,8 +55,8 @@ SUBSYSTEM_DEF(server_maint) co.ehjax_send(data = "roundrestart") if(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://[server]") - if(SERVER_TOOLS_PRESENT) - SSblackbox.record_feedback("text", "server_tools", 1, SERVER_TOOLS_VERSION) - SSblackbox.record_feedback("text", "server_tools_api", 1, SERVER_TOOLS_API_VERSION) + var/tgsversion = world.TgsVersion() + if(tgsversion) + SSblackbox.record_feedback("text", "server_tools", 1, tgsversion) #undef PING_BUFFER_TIME diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index b0d9787fe32..2966ae7d7c7 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -144,7 +144,7 @@ SUBSYSTEM_DEF(ticker) window_flash(C, ignorepref = TRUE) //let them know lobby has opened up. to_chat(world, "Welcome to [station_name()]!") if(CONFIG_GET(flag/irc_announce_new_game)) - SERVER_TOOLS_CHAT_BROADCAST("New round starting on [SSmapping.config.map_name]!") + world.TgsTargetedChatBroadcast("New round starting on [SSmapping.config.map_name]!", FALSE) current_state = GAME_STATE_PREGAME //Everyone who wants to be an observer is now spawned create_observers() diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index c6c0f2353a8..59953a4ce1a 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1,3 +1,6 @@ +/datum/proc/CanProcCall(procname) + return TRUE + /datum/proc/can_vv_get(var_name) return TRUE diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index a9fa7e4e10f..b459b31fcb9 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -5,7 +5,7 @@ var/date /datum/getrev/New() - testmerge = SERVER_TOOLS_PR_LIST + testmerge = world.TgsTestMerges() log_world("Running /tg/ revision:") var/list/logs = world.file2list(".git/logs/HEAD") if(logs) @@ -21,7 +21,8 @@ log_world(commit) for(var/line in testmerge) if(line) - var/tmcommit = testmerge[line]["commit"] + var/datum/tgs_revision_information/test_merge/tm = line + var/tmcommit = tm.commit log_world("Test merge active of PR #[line] commit [tmcommit]") SSblackbox.record_feedback("nested tally", "testmerged_prs", 1, list("[line]", "[tmcommit]")) if(originmastercommit) @@ -34,11 +35,12 @@ return "" . = header ? "The following pull requests are currently test merged:
" : "" for(var/line in testmerge) - var/cm = testmerge[line]["commit"] - var/details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11))) + var/datum/tgs_revision_information/test_merge/tm = line + var/cm = tm.pull_request_commit + var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11))) if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder)) continue - . += "#[line][details]
" + . += "#[tm.number][details]
" /client/verb/showrevinfo() set category = "OOC" @@ -58,9 +60,8 @@ else to_chat(src, "Master revision unknown") to_chat(src, "Revision: [GLOB.revdata.commit]") - if(SERVER_TOOLS_PRESENT) - to_chat(src, "Server tools version: [SERVER_TOOLS_VERSION]") - to_chat(src, "Server tools API version: [SERVER_TOOLS_API_VERSION]") + if(world.TgsAvailable()) + to_chat(src, "Server tools version: [world.TgsVersion()]") to_chat(src, "Current Informational Settings:") to_chat(src, "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]") to_chat(src, "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]") diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm index 93193f964aa..46326ce4cfb 100644 --- a/code/datums/world_topic.dm +++ b/code/datums/world_topic.dm @@ -120,8 +120,12 @@ require_comms_key = TRUE /datum/world_topic/namecheck/Run(list/input) - var/datum/server_tools_command/namecheck/NC = new - return NC.Run(input["sender"], input["namecheck"]) + //Oh this is a hack, someone refactor the functionality out of the chat command PLS + var/datum/tgs_chat_command/namecheck/NC = new + var/datum/tgs_chat_user/user = new + user.friendly_name = input["sender"] + user.mention = user.friendly_name + return NC.Run(user, input["namecheck"]) /datum/world_topic/adminwho keyword = "adminwho" diff --git a/code/game/world.dm b/code/game/world.dm index 64eace7f70a..9ea419bb3ba 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -17,6 +17,10 @@ GLOBAL_PROTECT(security_mode) make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once) + TgsNew() + + GLOB.revdata = new + config.Load() //SetupLogs depends on the RoundID, so lets check @@ -25,8 +29,6 @@ GLOBAL_PROTECT(security_mode) SSdbcore.SetRoundID() SetupLogs() - SERVER_TOOLS_ON_NEW - load_admins() LoadVerbs(/datum/verbs/menu) if(CONFIG_GET(flag/usewhitelist)) @@ -126,7 +128,7 @@ GLOBAL_PROTECT(security_mode) warning("/tg/station 13 uses many file operations, a few shell()s, and some external call()s. Trusted mode is recommended. You can download our source code for your own browsing and compilation at https://github.com/tgstation/tgstation") /world/Topic(T, addr, master, key) - SERVER_TOOLS_ON_TOPIC //redirect to server tools if necessary + TGS_TOPIC //redirect to server tools if necessary var/static/list/topic_handlers = TopicHandlers() @@ -182,7 +184,7 @@ GLOBAL_PROTECT(security_mode) qdel(src) //shut it down /world/Reboot(reason = 0, fast_track = FALSE) - SERVER_TOOLS_ON_REBOOT + TgsReboot() 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") @@ -196,7 +198,7 @@ GLOBAL_PROTECT(security_mode) FinishTestRun() return - if(SERVER_TOOLS_PRESENT) + if(TgsAvailable()) var/do_hard_reboot // check the hard reboot counter var/ruhr = CONFIG_GET(number/rounds_until_hard_restart) @@ -215,7 +217,7 @@ GLOBAL_PROTECT(security_mode) if(do_hard_reboot) log_world("World hard rebooted at [time_stamp()]") shutdown_logging() // See comment below. - SERVER_TOOLS_REBOOT_BYOND + TgsEndProcess() log_world("World rebooted at [time_stamp()]") shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss. diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index e9e5fb6be4b..9bf40344811 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -432,7 +432,7 @@ return var/list/options = list("Regular Restart", "Hard Restart (No Delay/Feeback Reason)", "Hardest Restart (No actions, just reboot)") - if(SERVER_TOOLS_PRESENT) + if(world.TgsAvailable()) options += "Server Restart (Kill and restart DD)"; var/rebootconfirm @@ -457,7 +457,7 @@ world.Reboot(fast_track = TRUE) if("Server Restart (Kill and restart DD)") to_chat(world, "Server restart - [init_by]") - SERVER_TOOLS_REBOOT_BYOND + world.TgsEndProcess() /datum/admins/proc/end_round() set category = "Server" diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index bc41b489c05..aec7dfb41dc 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -1,12 +1,12 @@ #define IRC_STATUS_THROTTLE 5 -/datum/server_tools_command/ircstatus +/datum/tgs_chat_command/ircstatus name = "status" help_text = "Gets the admincount, playercount, gamemode, and true game mode of the server" admin_only = TRUE - var/static/last_irc_status = 0 + var/last_irc_status = 0 -/datum/server_tools_command/ircstatus/Run(sender, params) +/datum/tgs_chat_command/ircstatus/Run(datum/tgs_chat_user/sender, params) var/rtod = REALTIMEOFDAY if(rtod - last_irc_status < IRC_STATUS_THROTTLE) return @@ -17,12 +17,12 @@ status += "Players: [GLOB.clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [SSticker.mode ? SSticker.mode.name : "Not started"]." return status -/datum/server_tools_command/irccheck +/datum/tgs_chat_command/irccheck name = "check" help_text = "Gets the playercount, gamemode, and address of the server" - var/static/last_irc_check = 0 + var/last_irc_check = 0 -/datum/server_tools_command/irccheck/Run(sender, params) +/datum/tgs_chat_command/irccheck/Run(datum/tgs_chat_user/sender, params) var/rtod = REALTIMEOFDAY if(rtod - last_irc_check < IRC_STATUS_THROTTLE) return @@ -30,14 +30,15 @@ var/server = CONFIG_GET(string/server) return "[GLOB.round_id ? "Round #[GLOB.round_id]: " : ""][GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [server ? server : "[world.internet_address]:[world.port]"]" -/datum/server_tools_command/ahelp +/datum/tgs_chat_command/ahelp name = "ahelp" help_text = " |list>>" - required_parameters = 2 admin_only = TRUE -/datum/server_tools_command/ahelp/Run(sender, params) +/datum/tgs_chat_command/ahelp/Run(datum/tgs_chat_user/sender, params) var/list/all_params = splittext(params, " ") + if(all_params.len < 2) + return "Insufficient parameters" var/target = all_params[1] all_params.Cut(1, 2) var/id = text2num(target) @@ -47,52 +48,54 @@ target = AH.initiator_ckey else return "Ticket #[id] not found!" - var/res = IrcPm(target, all_params.Join(" "), sender) + var/res = IrcPm(target, all_params.Join(" "), sender.friendly_name) if(res != "Message Successful") return res -/datum/server_tools_command/namecheck +/datum/tgs_chat_command/namecheck name = "namecheck" help_text = "Returns info on the specified target" - required_parameters = 1 admin_only = TRUE -/datum/server_tools_command/namecheck/Run(sender, params) - log_admin("Chat Name Check: [sender] on [params]") - message_admins("Name checking [params] from [sender]") +/datum/tgs_chat_command/namecheck/Run(datum/tgs_chat_user/sender, params) + params = trim(params) + if(!params) + return "Insufficient parameters" + log_admin("Chat Name Check: [sender.friendly_name] on [params]") + message_admins("Name checking [params] from [sender.friendly_name]") return keywords_lookup(params, 1) -/datum/server_tools_command/adminwho +/datum/tgs_chat_command/adminwho name = "adminwho" help_text = "Lists administrators currently on the server" admin_only = TRUE -/datum/server_tools_command/adminwho/Run(sender, params) +/datum/tgs_chat_command/adminwho/Run(datum/tgs_chat_user/sender, params) return ircadminwho() GLOBAL_LIST(round_end_notifiees) -/datum/server_tools_command/notify +/datum/tgs_chat_command/notify name = "notify" help_text = "Pings the invoker when the round ends" admin_only = TRUE -/datum/server_tools_command/notify/Run(sender, params) +/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params) if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted()) - return "[sender], the round has already ended!" + return "[sender.mention], the round has already ended!" LAZYINITLIST(GLOB.round_end_notifiees) GLOB.round_end_notifiees[sender] = TRUE - return "I will notify [sender] when the round ends." + return "I will notify [sender.mention] when the round ends." -/datum/server_tools_command/sdql +/datum/tgs_chat_command/sdql name = "sdql" help_text = "Runs an SDQL query" admin_only = TRUE -/datum/server_tools_command/sdql/Run(sender, params) +/datum/tgs_chat_command/sdql/Run(datum/tgs_chat_user/sender, params) if(GLOB.AdminProcCaller) return "Unable to run query, another admin proc call is in progress. Try again later." - GLOB.AdminProcCaller = "CHAT_[sender]" //_ won't show up in ckeys so it'll never match with a real admin + GLOB.AdminProcCaller = "CHAT_[sender.friendly_name]" //_ won't show up in ckeys so it'll never match with a real admin var/list/results = world.SDQL2_query(params, GLOB.AdminProcCaller, GLOB.AdminProcCaller) GLOB.AdminProcCaller = null if(!results) @@ -101,12 +104,12 @@ GLOBAL_LIST(round_end_notifiees) var/list/refs = results.len > 3 ? results.Copy(4) : null . = "[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]" -/datum/server_tools_command/reload_admins +/datum/tgs_chat_command/reload_admins name = "reload_admins" help_text = "Forces the server to reload admins." admin_only = TRUE -/datum/server_tools_command/reload_admins/Run(sender, params) +/datum/tgs_chat_command/reload_admins/Run(datum/tgs_chat_user/sender, params) load_admins() - log_admin("[sender] reloaded admins via chat command.") + log_admin("[sender.friendly_name] reloaded admins via chat command.") return "Admins reloaded." diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 6622d2f1d65..319a79a59da 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -575,7 +575,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) /proc/send2irc(msg,msg2) msg = replacetext(replacetext(msg, "\proper", ""), "\improper", "") msg2 = replacetext(replacetext(msg2, "\proper", ""), "\improper", "") - SERVER_TOOLS_RELAY_BROADCAST("[msg] | [msg2]") + world.TgsTargetedChatBroadcast("[msg] | [msg2]", TRUE) /proc/send2otherserver(source,msg,type = "Ahelp") var/comms_key = CONFIG_GET(string/comms_key) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 66eca3a5422..28fb4a485df 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -110,10 +110,14 @@ GLOBAL_PROTECT(LastAdminCalledProc) GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention) GLOBAL_PROTECT(AdminProcCallSpamPrevention) -/proc/WrapAdminProcCall(target, procname, list/arguments) +/proc/WrapAdminProcCall(datum/target, procname, list/arguments) if(target && procname == "Del") to_chat(usr, "Calling Del() is not allowed") return + + if(!target.CanProcCall(procname)) + to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!") + return var/current_caller = GLOB.AdminProcCaller var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller if(!ckey) @@ -137,7 +141,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) GLOB.AdminProcCaller = null //adv proc call this, ya nerds -/world/proc/WrapAdminProcCall(target, procname, list/arguments) +/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments) if(target == GLOBAL_PROC) return call(procname)(arglist(arguments)) else if(target != world) diff --git a/code/modules/server_tools/st_commands.dm b/code/modules/server_tools/st_commands.dm deleted file mode 100644 index 1e071550e0f..00000000000 --- a/code/modules/server_tools/st_commands.dm +++ /dev/null @@ -1,76 +0,0 @@ -/datum/server_tools_command - var/name = "" //the string to trigger this command on a chat bot. e.g. TGS3_BOT: do_this_command - var/help_text = "" //help text for this command - var/required_parameters = 0 //number of parameters required for this command - var/admin_only = FALSE //set to TRUE if this command should only be usable by registered chat admins - -//override to implement command -//sender is the display name of who sent the command -//params is the trimmed string following the command name -/datum/server_tools_command/proc/Run(sender, params) - CRASH("[type] has no implementation for Run()") - -/world/proc/ListServiceCustomCommands(warnings_only) - if(!warnings_only) - . = list() - var/list/command_name_types = list() - var/list/warned_command_names = warnings_only ? list() : null - for(var/I in typesof(/datum/server_tools_command) - /datum/server_tools_command) - var/datum/server_tools_command/stc = I - var/command_name = initial(stc.name) - var/static/list/warned_server_tools_names = list() - if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\"")) - if(warnings_only && !warned_command_names[command_name]) - SERVER_TOOLS_LOG("WARNING: Custom command [command_name] can't be used as it is empty or contains illegal characters!") - warned_command_names[command_name] = TRUE - continue - - if(command_name_types[command_name]) - if(warnings_only) - SERVER_TOOLS_LOG("WARNING: Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!") - continue - command_name_types[stc] = command_name - - if(!warnings_only) - .[command_name] = list(SERVICE_JSON_PARAM_HELPTEXT = initial(stc.help_text), SERVICE_JSON_PARAM_ADMINONLY = initial(stc.admin_only), SERVICE_JSON_PARAM_REQUIREDPARAMETERS = initial(stc.required_parameters)) - -/world/proc/HandleServiceCustomCommand(command, sender, params) - var/static/list/cached_custom_server_tools_commands - if(!cached_custom_server_tools_commands) - cached_custom_server_tools_commands = list() - for(var/I in typesof(/datum/server_tools_command) - /datum/server_tools_command) - var/datum/server_tools_command/stc = I - cached_custom_server_tools_commands[lowertext(initial(stc.name))] = stc - - var/command_type = cached_custom_server_tools_commands[command] - if(!command_type) - return FALSE - var/datum/server_tools_command/stc = new command_type - return stc.Run(sender, params) || TRUE - -/* -The MIT License - -Copyright (c) 2017 Jordan Brown - -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ diff --git a/code/modules/server_tools/st_interface.dm b/code/modules/server_tools/st_interface.dm deleted file mode 100644 index ca7d54695b9..00000000000 --- a/code/modules/server_tools/st_interface.dm +++ /dev/null @@ -1,135 +0,0 @@ -SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(reboot_mode, REBOOT_MODE_NORMAL) -SERVER_TOOLS_DEFINE_AND_SET_GLOBAL(server_tools_api_compatible, FALSE) - -/proc/GetTestMerges() - if(RunningService(TRUE) && fexists(SERVICE_PR_TEST_JSON)) - . = json_decode(file2text(SERVICE_PR_TEST_JSON)) - if(.) - return - return list() - -/world/proc/ServiceInit() - if(!RunningService(TRUE)) - return - ListServiceCustomCommands(TRUE) - ExportService("[SERVICE_REQUEST_API_VERSION] [SERVER_TOOLS_API_VERSION]", TRUE) - -/proc/RunningService(skip_compat_check = FALSE) - if(!skip_compat_check && !SERVER_TOOLS_READ_GLOBAL(server_tools_api_compatible)) - return FALSE - . = world.params[SERVICE_WORLD_PARAM] != null - if(. && world.system_type != MS_WINDOWS) - SERVER_TOOLS_LOG("Warning: Server tools world parameter detected but not running on Windows. Aborting initialization!") - return FALSE - -/proc/ServiceVersion() - if(RunningService(TRUE)) - return world.params[SERVICE_VERSION_PARAM] - -/proc/ServiceAPIVersion() - return SERVICE_API_VERSION_STRING - -/world/proc/ExportService(command, skip_compat_check = FALSE) - . = FALSE - if(!RunningService(skip_compat_check)) - return - if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL)) - CRASH("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.") - var/instance = params[SERVICE_INSTANCE_PARAM] - if(!instance) - instance = "TG Station Server" //maybe just upgraded - call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance, command) //trust no retval - return TRUE - -/world/proc/ChatBroadcast(message) - ExportService("[SERVICE_REQUEST_IRC_BROADCAST] [message]") - -/world/proc/AdminBroadcast(message) - ExportService("[SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE] [message]") - -/world/proc/ServiceEndProcess() - SERVER_TOOLS_LOG("Sending shutdown request!"); - sleep(world.tick_lag) //flush the buffers - ExportService(SERVICE_REQUEST_KILL_PROCESS) - -//called at the exact moment the world is supposed to reboot -/world/proc/ServiceReboot() - switch(SERVER_TOOLS_READ_GLOBAL(reboot_mode)) - if(REBOOT_MODE_HARD) - SERVER_TOOLS_WORLD_ANNOUNCE("Hard reboot triggered, you will automatically reconnect...") - ServiceEndProcess() - if(REBOOT_MODE_SHUTDOWN) - SERVER_TOOLS_WORLD_ANNOUNCE("The server is shutting down...") - ServiceEndProcess() - else - ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know - -/world/proc/ServiceCommand(list/params) - var/their_sCK = params[SERVICE_CMD_PARAM_KEY] - if(!their_sCK || !RunningService(TRUE)) - return FALSE //continue world/Topic - - var/sCK = world.params[SERVICE_WORLD_PARAM] - if(their_sCK != sCK) - return "Invalid comms key!"; - - var/command = params[SERVICE_CMD_PARAM_COMMAND] - if(!command) - return "No command!" - - switch(command) - if(SERVICE_CMD_API_COMPATIBLE) - SERVER_TOOLS_WRITE_GLOBAL(server_tools_api_compatible, TRUE) - return SERVICE_RETURN_SUCCESS - if(SERVICE_CMD_HARD_REBOOT) - if(SERVER_TOOLS_READ_GLOBAL(reboot_mode) != REBOOT_MODE_HARD) - SERVER_TOOLS_WRITE_GLOBAL(reboot_mode, REBOOT_MODE_HARD) - SERVER_TOOLS_LOG("Hard reboot requested by service") - SERVER_TOOLS_NOTIFY_ADMINS("The world will hard reboot at the end of the game. Requested by service.") - if(SERVICE_CMD_GRACEFUL_SHUTDOWN) - if(SERVER_TOOLS_READ_GLOBAL(reboot_mode) != REBOOT_MODE_SHUTDOWN) - SERVER_TOOLS_WRITE_GLOBAL(reboot_mode, REBOOT_MODE_SHUTDOWN) - SERVER_TOOLS_LOG("Shutdown requested by service") - message_admins("The world will shutdown at the end of the game. Requested by service.") - if(SERVICE_CMD_WORLD_ANNOUNCE) - var/msg = params["message"] - if(!istext(msg) || !msg) - return "No message set!" - SERVER_TOOLS_WORLD_ANNOUNCE(msg) - return SERVICE_RETURN_SUCCESS - if(SERVICE_CMD_PLAYER_COUNT) - return "[SERVER_TOOLS_CLIENT_COUNT]" - if(SERVICE_CMD_LIST_CUSTOM) - return json_encode(ListServiceCustomCommands(FALSE)) - else - var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM]) - if(custom_command_result) - return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS - return "Unknown command: [command]" - -/* -The MIT License - -Copyright (c) 2017 Jordan Brown - -Permission is hereby granted, free of charge, -to any person obtaining a copy of this software and -associated documentation files (the "Software"), to -deal in the Software without restriction, including -without limitation the rights to use, copy, modify, -merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom -the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ diff --git a/code/modules/tgs/core/_definitions.dm b/code/modules/tgs/core/_definitions.dm new file mode 100644 index 00000000000..d5e1a0075ba --- /dev/null +++ b/code/modules/tgs/core/_definitions.dm @@ -0,0 +1,2 @@ +#define TGS_UNIMPLEMENTED "___unimplemented" +#define TGS_VERSION_PARAMETER "server_service_version" diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm new file mode 100644 index 00000000000..79c42ed37b5 --- /dev/null +++ b/code/modules/tgs/core/core.dm @@ -0,0 +1,144 @@ +/world/TgsNew(datum/tgs_event_handler/event_handler) + var/tgs_version = world.params[TGS_VERSION_PARAMETER] + if(!tgs_version) + return + + var/path = SelectTgsApi(tgs_version) + if(!path) + TGS_ERROR_LOG("Found unsupported API version: [tgs_version]. If this is a valid version please report this, backporting is done on demand.") + + TGS_INFO_LOG("Activating API for version [tgs_version]") + var/datum/tgs_api/new_api = new path + + var/result = new_api.OnWorldNew(event_handler ? event_handler : new /datum/tgs_event_handler/tgs_default) + if(result && result != TGS_UNIMPLEMENTED) + TGS_WRITE_GLOBAL(tgs, new_api) + else + TGS_ERROR_LOG("Failed to activate API!") + +/world/proc/SelectTgsApi(tgs_version) + //remove the old 3.0 header + tgs_version = replacetext(tgs_version, "/tg/station 13 Server v", "") + + var/list/version_bits = splittext(tgs_version, ".") + + var/super = text2num(version_bits[1]) + var/major = text2num(version_bits[2]) + var/minor = text2num(version_bits[3]) + var/patch = text2num(version_bits[4]) + + switch(super) + if(3) + switch(major) + if(2) + return /datum/tgs_api/v3210 + + if(super != null && major != null && minor != null && patch != null && tgs_version > TgsMaximumAPIVersion()) + TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.") + return /datum/tgs_api/latest + +/world/TgsMaximumAPIVersion() + return "4.0.0.0" + +/world/TgsMinimumAPIVersion() + return "3.2.0.0" + +/world/TgsInitializationComplete() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.OnInitializationComplete() + +/world/proc/TgsTopic(T) + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + var/result = api.OnTopic(T) + if(result != TGS_UNIMPLEMENTED) + return result + +/world/TgsRevision() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + var/result = api.Revision() + if(result != TGS_UNIMPLEMENTED) + return result + +/world/TgsReboot() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.OnReboot() + +/world/TgsAvailable() + return TGS_READ_GLOBAL(tgs) != null + +/world/TgsVersion() + return world.params[TGS_VERSION_PARAMETER] + +/world/TgsInstanceName() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + var/result = api.InstanceName() + if(result != TGS_UNIMPLEMENTED) + return result + +/world/TgsTestMerges() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + var/result = api.TestMerges() + if(result != TGS_UNIMPLEMENTED) + return result + return list() + +/world/TgsEndProcess() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.EndProcess() + +/world/TgsChatChannelInfo() + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + var/result = api.ChatChannelInfo() + if(result != TGS_UNIMPLEMENTED) + return result + return list() + +/world/TgsChatBroadcast(message, list/channels) + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.ChatBroadcast(message, channels) + +/world/TgsTargetedChatBroadcast(message, admin_only) + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.ChatTargetedBroadcast(message, admin_only) + +/world/TgsChatPrivateMessage(message, datum/tgs_chat_user/user) + var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs) + if(api) + api.ChatPrivateMessage(message, user) + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm new file mode 100644 index 00000000000..5da73bfdc5c --- /dev/null +++ b/code/modules/tgs/core/datum.dm @@ -0,0 +1,74 @@ +TGS_DEFINE_AND_SET_GLOBAL(tgs, null) + +/datum/tgs_api + +/datum/tgs_api/latest + parent_type = /datum/tgs_api/v3210 + +TGS_PROTECT_DATUM(/datum/tgs_api) + +/datum/tgs_api/proc/ApiVersion() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/OnWorldNew(datum/tgs_event_handler/event_handler) + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/OnInitializationComplete() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/OnTopic(T) + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/OnReboot() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/InstanceName() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/TestMerges() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/EndProcess() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/Revision() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/ChatChannelInfo() + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/ChatBroadcast(message, list/channels) + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/ChatTargetedBroadcast(message, admin_only) + return TGS_UNIMPLEMENTED + +/datum/tgs_api/proc/ChatPrivateMessage(message, admin_only) + return TGS_UNIMPLEMENTED + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/core/default_event_handler.dm b/code/modules/tgs/core/default_event_handler.dm new file mode 100644 index 00000000000..c0ea8eec469 --- /dev/null +++ b/code/modules/tgs/core/default_event_handler.dm @@ -0,0 +1,30 @@ +/datum/tgs_event_handler/tgs_default/HandleEvent(event_code) + //TODO + return + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm new file mode 100644 index 00000000000..586cbbe427c --- /dev/null +++ b/code/modules/tgs/includes.dm @@ -0,0 +1,6 @@ +#include "core\_definitions.dm" +#include "core\core.dm" +#include "core\datum.dm" +#include "core\default_event_handler.dm" +#include "v3210\api.dm" +#include "v3210\commands.dm" diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm new file mode 100644 index 00000000000..f9b32471de9 --- /dev/null +++ b/code/modules/tgs/v3210/api.dm @@ -0,0 +1,248 @@ +#define REBOOT_MODE_NORMAL 0 +#define REBOOT_MODE_HARD 1 +#define REBOOT_MODE_SHUTDOWN 2 + +#define SERVICE_WORLD_PARAM "server_service" +#define SERVICE_INSTANCE_PARAM "server_instance" +#define SERVICE_PR_TEST_JSON "prtestjob.json" +#define SERVICE_INTERFACE_DLL "TGDreamDaemonBridge.dll" +#define SERVICE_INTERFACE_FUNCTION "DDEntryPoint" + +#define SERVICE_CMD_HARD_REBOOT "hard_reboot" +#define SERVICE_CMD_GRACEFUL_SHUTDOWN "graceful_shutdown" +#define SERVICE_CMD_WORLD_ANNOUNCE "world_announce" +#define SERVICE_CMD_LIST_CUSTOM "list_custom_commands" +#define SERVICE_CMD_API_COMPATIBLE "api_compat" +#define SERVICE_CMD_PLAYER_COUNT "client_count" + +#define SERVICE_CMD_PARAM_KEY "serviceCommsKey" +#define SERVICE_CMD_PARAM_COMMAND "command" +#define SERVICE_CMD_PARAM_SENDER "sender" +#define SERVICE_CMD_PARAM_CUSTOM "custom" + +#define SERVICE_REQUEST_KILL_PROCESS "killme" +#define SERVICE_REQUEST_IRC_BROADCAST "irc" +#define SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE "send2irc" +#define SERVICE_REQUEST_WORLD_REBOOT "worldreboot" +#define SERVICE_REQUEST_API_VERSION "api_ver" + +#define SERVICE_RETURN_SUCCESS "SUCCESS" + +/datum/tgs_api/v3210 + var/reboot_mode = REBOOT_MODE_NORMAL + var/comms_key + var/instance_name + var/originmastercommit + var/commit + var/list/cached_custom_tgs_chat_commands + var/warned_revison = FALSE + var/warned_custom_commands = FALSE + +/datum/tgs_api/v3210/ApiVersion() + return "3.2.1.0" + +/datum/tgs_api/v3210/proc/trim_left(text) + for (var/i = 1 to length(text)) + if (text2ascii(text, i) > 32) + return copytext(text, i) + return "" + +/datum/tgs_api/v3210/proc/trim_right(text) + for (var/i = length(text), i > 0, i--) + if (text2ascii(text, i) > 32) + return copytext(text, 1, i + 1) + return "" + +/datum/tgs_api/v3210/proc/file2list(filename) + return splittext(trim_left(trim_right(file2text(filename))), "\n") + +/datum/tgs_api/v3210/OnWorldNew(datum/tgs_event_handler/event_handler) //don't use event handling in this version + . = FALSE + comms_key = world.params[SERVICE_WORLD_PARAM] + instance_name = world.params[SERVICE_INSTANCE_PARAM] + if(!instance_name) + instance_name = "TG Station Server" //maybe just upgraded + + var/list/logs = file2list(".git/logs/HEAD") + if(logs.len) + logs = splittext(logs[logs.len - 1], " ") + commit = logs[2] + logs = file2list(".git/logs/refs/remotes/origin/master") + if(logs.len) + originmastercommit = splittext(logs[logs.len - 1], " ")[2] + + if(world.system_type != MS_WINDOWS) + TGS_ERROR_LOG("This API version is only supported on Windows. Not running on Windows. Aborting initialization!") + return + ListServiceCustomCommands(TRUE) + ExportService("[SERVICE_REQUEST_API_VERSION] [ApiVersion()]", TRUE) + return TRUE + +//nothing to do for v3 +/datum/tgs_api/v3210/OnInitializationComplete() + return + +/datum/tgs_api/v3210/InstanceName() + return world.params[SERVICE_INSTANCE_PARAM] + +/datum/tgs_api/v3210/proc/ExportService(command, skip_compat_check = FALSE) + . = FALSE + if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL)) + TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.") + return + call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval + return TRUE + +/datum/tgs_api/v3210/OnTopic(T) + var/list/params = params2list(T) + var/their_sCK = params[SERVICE_CMD_PARAM_KEY] + if(!their_sCK) + return FALSE //continue world/Topic + + if(their_sCK != comms_key) + return "Invalid comms key!"; + + var/command = params[SERVICE_CMD_PARAM_COMMAND] + if(!command) + return "No command!" + + switch(command) + if(SERVICE_CMD_API_COMPATIBLE) + return SERVICE_RETURN_SUCCESS + if(SERVICE_CMD_HARD_REBOOT) + if(reboot_mode != REBOOT_MODE_HARD) + reboot_mode = REBOOT_MODE_HARD + TGS_INFO_LOG("Hard reboot requested by service") + TGS_NOTIFY_ADMINS("The world will hard reboot at the end of the game. Requested by TGS.") + if(SERVICE_CMD_GRACEFUL_SHUTDOWN) + if(reboot_mode != REBOOT_MODE_SHUTDOWN) + reboot_mode = REBOOT_MODE_SHUTDOWN + TGS_INFO_LOG("Shutdown requested by service") + TGS_NOTIFY_ADMINS("The world will shutdown at the end of the game. Requested by TGS.") + if(SERVICE_CMD_WORLD_ANNOUNCE) + var/msg = params["message"] + if(!istext(msg) || !msg) + return "No message set!" + TGS_WORLD_ANNOUNCE(msg) + return SERVICE_RETURN_SUCCESS + if(SERVICE_CMD_PLAYER_COUNT) + return "[TGS_CLIENT_COUNT]" + if(SERVICE_CMD_LIST_CUSTOM) + return json_encode(ListServiceCustomCommands(FALSE)) + else + var/custom_command_result = HandleServiceCustomCommand(lowertext(command), params[SERVICE_CMD_PARAM_SENDER], params[SERVICE_CMD_PARAM_CUSTOM]) + if(custom_command_result) + return istext(custom_command_result) ? custom_command_result : SERVICE_RETURN_SUCCESS + return "Unknown command: [command]" + +/datum/tgs_api/v3210/OnReboot() + switch(reboot_mode) + if(REBOOT_MODE_HARD) + TGS_WORLD_ANNOUNCE("Hard reboot triggered, you will automatically reconnect...") + EndProcess() + if(REBOOT_MODE_SHUTDOWN) + TGS_WORLD_ANNOUNCE("The server is shutting down...") + EndProcess() + else + ExportService(SERVICE_REQUEST_WORLD_REBOOT) //just let em know + +/datum/tgs_api/v3210/TestMerges() + //do the best we can here as the datum can't be completed using the v3 api + . = list() + if(!fexists(SERVICE_PR_TEST_JSON)) + return + var/list/json = json_decode(file2text(SERVICE_PR_TEST_JSON)) + if(!json) + return + for(var/I in json) + var/datum/tgs_revision_information/test_merge/tm = new + tm.number = text2num(I) + var/list/entry = json[I] + tm.pull_request_commit = entry["commit"] + tm.author = entry["author"] + tm.title = entry["title"] + . += tm + +/datum/tgs_api/v3210/Revision() + if(!warned_revison) + TGS_ERROR_LOG("Use of TgsRevision on [ApiVersion()] origin_commit only points to master!") + warned_revison = TRUE + var/datum/tgs_revision_information/ri = new + ri.commit = commit + ri.origin_commit = originmastercommit + +/datum/tgs_api/v3210/EndProcess() + sleep(world.tick_lag) //flush the buffers + ExportService(SERVICE_REQUEST_KILL_PROCESS) + +/datum/tgs_api/v3210/ChatChannelInfo() + return list() + +/datum/tgs_api/v3210/ChatBroadcast(message, list/channels) + if(channels) + return TGS_UNIMPLEMENTED + ChatTargetedBroadcast(message, TRUE) + ChatTargetedBroadcast(message, FALSE) + +/datum/tgs_api/v3210/ChatTargetedBroadcast(message, admin_only) + ExportService("[admin_only ? SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE : SERVICE_REQUEST_IRC_BROADCAST] [message]") + +/datum/tgs_api/v3210/ChatPrivateMessage(message, admin_only) + return TGS_UNIMPLEMENTED + +#undef REBOOT_MODE_NORMAL +#undef REBOOT_MODE_HARD +#undef REBOOT_MODE_SHUTDOWN + +#undef SERVICE_WORLD_PARAM +#undef SERVICE_INSTANCE_PARAM +#undef SERVICE_PR_TEST_JSON +#undef SERVICE_INTERFACE_DLL +#undef SERVICE_INTERFACE_FUNCTION + +#undef SERVICE_CMD_HARD_REBOOT +#undef SERVICE_CMD_GRACEFUL_SHUTDOWN +#undef SERVICE_CMD_WORLD_ANNOUNCE +#undef SERVICE_CMD_LIST_CUSTOM +#undef SERVICE_CMD_API_COMPATIBLE +#undef SERVICE_CMD_PLAYER_COUNT + +#undef SERVICE_CMD_PARAM_KEY +#undef SERVICE_CMD_PARAM_COMMAND +#undef SERVICE_CMD_PARAM_SENDER +#undef SERVICE_CMD_PARAM_CUSTOM + +#undef SERVICE_REQUEST_KILL_PROCESS +#undef SERVICE_REQUEST_IRC_BROADCAST +#undef SERVICE_REQUEST_IRC_ADMIN_CHANNEL_MESSAGE +#undef SERVICE_REQUEST_WORLD_REBOOT +#undef SERVICE_REQUEST_API_VERSION + +#undef SERVICE_RETURN_SUCCESS + +/* +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/code/modules/tgs/v3210/commands.dm b/code/modules/tgs/v3210/commands.dm new file mode 100644 index 00000000000..71d7e323661 --- /dev/null +++ b/code/modules/tgs/v3210/commands.dm @@ -0,0 +1,78 @@ +#define SERVICE_JSON_PARAM_HELPTEXT "help_text" +#define SERVICE_JSON_PARAM_ADMINONLY "admin_only" +#define SERVICE_JSON_PARAM_REQUIREDPARAMETERS "required_parameters" + +/datum/tgs_api/v3210/proc/ListServiceCustomCommands(warnings_only) + if(!warnings_only) + . = list() + var/list/command_name_types = list() + var/list/warned_command_names = warnings_only ? list() : null + var/warned_about_the_dangers_of_robutussin = !warnings_only + for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command) + if(!warned_about_the_dangers_of_robutussin) + TGS_ERROR_LOG("Custom chat commands in [ApiVersion()] lacks the /datum/tgs_chat_user/sender.channel field!") + warned_about_the_dangers_of_robutussin = TRUE + var/datum/tgs_chat_command/stc = I + var/command_name = initial(stc.name) + if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\"")) + if(warnings_only && !warned_command_names[command_name]) + TGS_ERROR_LOG("Custom command [command_name] can't be used as it is empty or contains illegal characters!") + warned_command_names[command_name] = TRUE + continue + + if(command_name_types[command_name]) + if(warnings_only) + TGS_ERROR_LOG("Custom commands [command_name_types[command_name]] and [stc] have the same name, only [command_name_types[command_name]] will be available!") + continue + command_name_types[stc] = command_name + + if(!warnings_only) + .[command_name] = list(SERVICE_JSON_PARAM_HELPTEXT = initial(stc.help_text), SERVICE_JSON_PARAM_ADMINONLY = initial(stc.admin_only), SERVICE_JSON_PARAM_REQUIREDPARAMETERS = 0) + +/datum/tgs_api/v3210/proc/HandleServiceCustomCommand(command, sender, params) + if(!cached_custom_tgs_chat_commands) + cached_custom_tgs_chat_commands = list() + for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command) + var/datum/tgs_chat_command/stc = I + cached_custom_tgs_chat_commands[lowertext(initial(stc.name))] = stc + + var/command_type = cached_custom_tgs_chat_commands[command] + if(!command_type) + return FALSE + var/datum/tgs_chat_command/stc = new command_type + var/datum/tgs_chat_user/user = new + user.friendly_name = sender + user.mention = sender + return stc.Run(user, params) || TRUE + +/* + +#undef SERVICE_JSON_PARAM_HELPTEXT +#undef SERVICE_JSON_PARAM_ADMINONLY +#undef SERVICE_JSON_PARAM_REQUIREDPARAMETERS + +The MIT License + +Copyright (c) 2017 Jordan Brown + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ diff --git a/tgstation.dme b/tgstation.dme index bbc6ef2c23e..c58e30a160b 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -73,8 +73,6 @@ #include "code\__DEFINES\robots.dm" #include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\say.dm" -#include "code\__DEFINES\server_tools.config.dm" -#include "code\__DEFINES\server_tools.dm" #include "code\__DEFINES\shuttles.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\sound.dm" @@ -82,6 +80,8 @@ #include "code\__DEFINES\stat_tracking.dm" #include "code\__DEFINES\status_effects.dm" #include "code\__DEFINES\subsystems.dm" +#include "code\__DEFINES\tgs.config.dm" +#include "code\__DEFINES\tgs.dm" #include "code\__DEFINES\tgui.dm" #include "code\__DEFINES\time.dm" #include "code\__DEFINES\tools.dm" @@ -2417,8 +2417,6 @@ #include "code\modules\ruins\spaceruin_code\whiteshipruin_box.dm" #include "code\modules\security_levels\keycard_authentication.dm" #include "code\modules\security_levels\security_levels.dm" -#include "code\modules\server_tools\st_commands.dm" -#include "code\modules\server_tools\st_interface.dm" #include "code\modules\shuttle\arrivals.dm" #include "code\modules\shuttle\assault_pod.dm" #include "code\modules\shuttle\computer.dm" @@ -2531,6 +2529,7 @@ #include "code\modules\surgery\organs\tails.dm" #include "code\modules\surgery\organs\tongue.dm" #include "code\modules\surgery\organs\vocal_cords.dm" +#include "code\modules\tgs\includes.dm" #include "code\modules\tgui\external.dm" #include "code\modules\tgui\states.dm" #include "code\modules\tgui\subsystem.dm"