From 77848bd90f6f8b50b0370a82cc6b412319f06da3 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Fri, 8 May 2020 04:30:51 -0700
Subject: [PATCH 1/7] tgs folder
---
code/modules/tgs/core/core.dm | 17 +-
code/modules/tgs/core/datum.dm | 2 +-
code/modules/tgs/core/tgs_version.dm | 14 +-
code/modules/tgs/includes.dm | 34 +++
code/modules/tgs/v3210/api.dm | 8 +-
code/modules/tgs/v3210/commands.dm | 32 +--
code/modules/tgs/v4/api.dm | 2 +-
code/modules/tgs/v4/commands.dm | 30 +--
code/modules/tgs/v5/_defines.dm | 121 +++++++++
code/modules/tgs/v5/api.dm | 352 +++++++++++++++++++++++++++
code/modules/tgs/v5/commands.dm | 68 ++++++
code/modules/tgs/v5/undef.dm | 121 +++++++++
12 files changed, 756 insertions(+), 45 deletions(-)
create mode 100644 code/modules/tgs/v5/_defines.dm
create mode 100644 code/modules/tgs/v5/api.dm
create mode 100644 code/modules/tgs/v5/commands.dm
create mode 100644 code/modules/tgs/v5/undef.dm
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index 70252cfb49..144f33926f 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -22,17 +22,19 @@
#ifndef TGS_V3_API
TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!")
#else
- switch(version.major)
+ switch(version.minor)
if(2)
api_datum = /datum/tgs_api/v3210
#endif
if(4)
- switch(version.major)
+ switch(version.minor)
if(0)
api_datum = /datum/tgs_api/v4
+ if(5)
+ api_datum = /datum/tgs_api/v5
var/datum/tgs_version/max_api_version = TgsMaximumAPIVersion();
- if(version.suite != null && version.major != null && version.minor != null && version.patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
+ if(version.suite != null && version.minor != null && version.patch != null && version.deprecated_patch != null && version.deprefixed_parameter > max_api_version.deprefixed_parameter)
TGS_ERROR_LOG("Detected unknown API version! Defaulting to latest. Update the DMAPI to fix this problem.")
api_datum = /datum/tgs_api/latest
@@ -51,10 +53,10 @@
TGS_ERROR_LOG("Failed to activate API!")
/world/TgsMaximumAPIVersion()
- return new /datum/tgs_version("4.0.x.x")
+ return new /datum/tgs_version("5.x.x")
/world/TgsMinimumAPIVersion()
- return new /datum/tgs_version("3.2.0.0")
+ return new /datum/tgs_version("3.2.x")
/world/TgsInitializationComplete()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
@@ -88,6 +90,11 @@
if(api)
return api.version
+/world/TgsApiVersion()
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ return api.ApiVersion()
+
/world/TgsInstanceName()
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index fb2508059a..3adecbb556 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -8,7 +8,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
src.version = version
/datum/tgs_api/latest
- parent_type = /datum/tgs_api/v4
+ parent_type = /datum/tgs_api/v5
TGS_PROTECT_DATUM(/datum/tgs_api)
diff --git a/code/modules/tgs/core/tgs_version.dm b/code/modules/tgs/core/tgs_version.dm
index b97745611f..a5dae1241a 100644
--- a/code/modules/tgs/core/tgs_version.dm
+++ b/code/modules/tgs/core/tgs_version.dm
@@ -5,11 +5,11 @@
suite = text2num(version_bits[1])
if(version_bits.len > 1)
- major = text2num(version_bits[2])
+ minor = text2num(version_bits[2])
if(version_bits.len > 2)
- minor = text2num(version_bits[3])
+ patch = text2num(version_bits[3])
if(version_bits.len == 4)
- patch = text2num(version_bits[4])
+ deprecated_patch = text2num(version_bits[4])
/datum/tgs_version/proc/Valid(allow_wildcards = FALSE)
if(suite == null)
@@ -19,4 +19,10 @@
return !Wildcard()
/datum/tgs_version/Wildcard()
- return major == null || minor == null || patch == null
+ return minor == null || patch == null
+
+/datum/tgs_version/Equals(datum/tgs_version/other_version)
+ if(!istype(other_version))
+ return FALSE
+
+ return suite == other_version.suite && minor == other_version.minor && patch == other_version.patch && deprecated_patch == other_version.deprecated_patch
diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm
index 247f1fda5d..b3c1728f34 100644
--- a/code/modules/tgs/includes.dm
+++ b/code/modules/tgs/includes.dm
@@ -2,9 +2,43 @@
#include "core\core.dm"
#include "core\datum.dm"
#include "core\tgs_version.dm"
+
#ifdef TGS_V3_API
#include "v3210\api.dm"
#include "v3210\commands.dm"
#endif
+
#include "v4\api.dm"
#include "v4\commands.dm"
+
+#include "v5\_defines.dm"
+#include "v5\api.dm"
+#include "v5\commands.dm"
+#include "v5\undef.dm"
+
+/*
+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/api.dm b/code/modules/tgs/v3210/api.dm
index c536995b04..5327b9276b 100644
--- a/code/modules/tgs/v3210/api.dm
+++ b/code/modules/tgs/v3210/api.dm
@@ -39,7 +39,7 @@
var/warned_custom_commands = FALSE
/datum/tgs_api/v3210/ApiVersion()
- return "3.2.1.0"
+ return new /datum/tgs_version("3.2.1.0")
/datum/tgs_api/v3210/proc/trim_left(text)
for (var/i = 1 to length(text))
@@ -76,7 +76,8 @@
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)
+ var/datum/tgs_version/api_version = ApiVersion()
+ ExportService("[SERVICE_REQUEST_API_VERSION] [api_version.deprefixed_parameter]", TRUE)
return TRUE
//nothing to do for v3
@@ -166,7 +167,8 @@
/datum/tgs_api/v3210/Revision()
if(!warned_revison)
- TGS_ERROR_LOG("Use of TgsRevision on [ApiVersion()] origin_commit only points to master!")
+ var/datum/tgs_version/api_version = ApiVersion()
+ TGS_ERROR_LOG("Use of TgsRevision on [api_version.deprefixed_parameter] origin_commit only points to master!")
warned_revison = TRUE
var/datum/tgs_revision_information/ri = new
ri.commit = commit
diff --git a/code/modules/tgs/v3210/commands.dm b/code/modules/tgs/v3210/commands.dm
index e5bc6f4895..5046631981 100644
--- a/code/modules/tgs/v3210/commands.dm
+++ b/code/modules/tgs/v3210/commands.dm
@@ -19,7 +19,7 @@
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!")
@@ -55,24 +55,24 @@ 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,
+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
+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
+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/v4/api.dm b/code/modules/tgs/v4/api.dm
index b61cddbeba..5c98a1a7a7 100644
--- a/code/modules/tgs/v4/api.dm
+++ b/code/modules/tgs/v4/api.dm
@@ -49,7 +49,7 @@
var/list/last_interop_response
/datum/tgs_api/v4/ApiVersion()
- return "4.0.0.0"
+ return new /datum/tgs_version("4.0.0.0")
/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
json_path = world.params[TGS4_PARAM_INFO_JSON]
diff --git a/code/modules/tgs/v4/commands.dm b/code/modules/tgs/v4/commands.dm
index af21a86fb6..1d9951bc04 100644
--- a/code/modules/tgs/v4/commands.dm
+++ b/code/modules/tgs/v4/commands.dm
@@ -46,24 +46,24 @@ 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,
+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
+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
+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/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
new file mode 100644
index 0000000000..1117a1df50
--- /dev/null
+++ b/code/modules/tgs/v5/_defines.dm
@@ -0,0 +1,121 @@
+#define DMAPI5_PARAM_SERVER_PORT "tgs_port"
+#define DMAPI5_PARAM_ACCESS_IDENTIFIER "tgs_key"
+
+#define DMAPI5_BRIDGE_DATA "data"
+#define DMAPI5_TOPIC_DATA "tgs_data"
+
+#define DMAPI5_BRIDGE_COMMAND_PORT_UPDATE 0
+#define DMAPI5_BRIDGE_COMMAND_STARTUP 1
+#define DMAPI5_BRIDGE_COMMAND_PRIME 2
+#define DMAPI5_BRIDGE_COMMAND_REBOOT 3
+#define DMAPI5_BRIDGE_COMMAND_KILL 4
+#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
+
+#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RESPONSE_ERROR_MESSAGE "errorMessage"
+
+#define DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT "currentPort"
+#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
+#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
+#define DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS "customCommands"
+#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
+
+#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
+#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
+
+#define DMAPI5_CHAT_MESSAGE_TEXT "text"
+#define DMAPI5_CHAT_MESSAGE_CHANNEL_IDS "channelIds"
+
+#define DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER "accessIdentifier"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION "serverVersion"
+#define DMAPI5_RUNTIME_INFORMATION_SERVER_PORT "serverPort"
+#define DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY "apiValidateOnly"
+#define DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME "instanceName"
+#define DMAPI5_RUNTIME_INFORMATION_REVISION "revision"
+#define DMAPI5_RUNTIME_INFORMATION_TEST_MERGES "testMerges"
+#define DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL "securityLevel"
+
+#define DMAPI5_CHAT_UPDATE_CHANNELS "channels"
+
+#define DMAPI5_TEST_MERGE_TIME_MERGED "timeMerged"
+#define DMAPI5_TEST_MERGE_REVISION "revision"
+#define DMAPI5_TEST_MERGE_TITLE_AT_MERGE "titleAtMerge"
+#define DMAPI5_TEST_MERGE_BODY_AT_MERGE "bodyAtMerge"
+#define DMAPI5_TEST_MERGE_URL "url"
+#define DMAPI5_TEST_MERGE_AUTHOR "author"
+#define DMAPI5_TEST_MERGE_NUMBER "number"
+#define DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION "pullRequestRevision"
+#define DMAPI5_TEST_MERGE_COMMENT "comment"
+
+#define DMAPI5_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CHAT_COMMAND_PARAMS "params"
+#define DMAPI5_CHAT_COMMAND_USER "user"
+
+#define DMAPI5_EVENT_NOTIFICATION_TYPE "type"
+#define DMAPI5_EVENT_NOTIFICATION_PARAMETERS "parameters"
+
+#define DMAPI5_TOPIC_COMMAND_CHAT_COMMAND 0
+#define DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION 1
+#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2
+#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3
+#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4
+#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 4
+#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 5
+
+#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
+#define DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION "eventNotification"
+#define DMAPI5_TOPIC_PARAMETER_NEW_PORT "newPort"
+#define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState"
+#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName"
+#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
+
+#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
+#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses"
+
+#define DMAPI5_REVISION_INFORMATION_COMMIT_SHA "commitSha"
+#define DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA "originCommitSha"
+
+#define DMAPI5_CHAT_USER_ID "id"
+#define DMAPI5_CHAT_USER_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_USER_MENTION "mention"
+#define DMAPI5_CHAT_USER_CHANNEL "channel"
+
+#define DMAPI5_CHAT_CHANNEL_ID "id"
+#define DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME "friendlyName"
+#define DMAPI5_CHAT_CHANNEL_CONNECTION_NAME "connectionName"
+#define DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL "isAdminChannel"
+#define DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL "isPrivateChannel"
+#define DMAPI5_CHAT_CHANNEL_TAG "tag"
+
+#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
+#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"
+
+/*
+The MIT License
+
+Copyright (c) 2020 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/v5/api.dm b/code/modules/tgs/v5/api.dm
new file mode 100644
index 0000000000..32f80c0ae4
--- /dev/null
+++ b/code/modules/tgs/v5/api.dm
@@ -0,0 +1,352 @@
+/datum/tgs_api/v5
+ var/server_port
+ var/access_identifier
+
+ var/instance_name
+ var/security_level
+
+ var/reboot_mode = TGS_REBOOT_MODE_NORMAL
+
+ var/list/intercepted_message_queue
+
+ var/list/custom_commands
+
+ var/list/test_merges
+ var/datum/tgs_revision_information/revision
+ var/list/chat_channels
+
+ var/datum/tgs_event_handler/event_handler
+
+/datum/tgs_api/v5/ApiVersion()
+ return new /datum/tgs_version("5.0.0")
+
+/datum/tgs_api/v5/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
+ src.event_handler = event_handler
+
+ server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
+ access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER]
+
+ var/datum/tgs_version/api_version = ApiVersion()
+ var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
+ if(!istype(bridge_response))
+ TGS_ERROR_LOG("Failed initial bridge request!")
+ return FALSE
+
+ var/list/runtime_information = bridge_response[DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION]
+ if(!istype(runtime_information))
+ TGS_ERROR_LOG("Failed to decode runtime information from bridge response: [json_encode(bridge_response)]!")
+ return FALSE
+
+ if(runtime_information[DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY])
+ TGS_INFO_LOG("DMAPI validation, exiting...")
+ del(world)
+
+ security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL]
+ instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME]
+ version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
+
+ var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION]
+ if(istype(revisionData))
+ revision = new
+ revision.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ revision.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_ERROR_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_REVISION] from runtime information!")
+
+ test_merges = list()
+ var/list/test_merge_json = runtime_information[DMAPI5_RUNTIME_INFORMATION_TEST_MERGES]
+ if(istype(test_merge_json))
+ for(var/entry in test_merge_json)
+ var/datum/tgs_revision_information/test_merge/tm = new
+ tm.number = entry[DMAPI5_TEST_MERGE_NUMBER]
+
+ var/list/revInfo = entry[DMAPI5_TEST_MERGE_REVISION]
+ if(revInfo)
+ tm.commit = revisionData[DMAPI5_REVISION_INFORMATION_COMMIT_SHA]
+ tm.origin_commit = revisionData[DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA]
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_TEST_MERGE_REVISION] from test merge #[tm.number]!")
+
+ tm.time_merged = text2num(entry[DMAPI5_TEST_MERGE_TIME_MERGED])
+ tm.title = entry[DMAPI5_TEST_MERGE_TITLE_AT_MERGE]
+ tm.body = entry[DMAPI5_TEST_MERGE_BODY_AT_MERGE]
+ tm.url = entry[DMAPI5_TEST_MERGE_URL]
+ tm.author = entry[DMAPI5_TEST_MERGE_AUTHOR]
+ tm.pull_request_commit = entry[DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION]
+ tm.comment = entry[DMAPI5_TEST_MERGE_COMMENT]
+
+ test_merges += tm
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_RUNTIME_INFORMATION_TEST_MERGES] from runtime information!")
+
+ chat_channels = list()
+ DecodeChannels(runtime_information)
+
+ return TRUE
+
+/datum/tgs_api/v5/OnInitializationComplete()
+ Bridge(DMAPI5_BRIDGE_COMMAND_PRIME)
+
+ var/tgs4_secret_sleep_offline_sauce = 29051994
+ var/old_sleep_offline = world.sleep_offline
+ world.sleep_offline = tgs4_secret_sleep_offline_sauce
+ sleep(1)
+ if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
+ world.sleep_offline = old_sleep_offline
+
+/datum/tgs_api/v5/proc/TopicResponse(error_message = null)
+ var/list/response = list()
+ response[DMAPI5_RESPONSE_ERROR_MESSAGE] = error_message
+
+ return json_encode(response)
+
+/datum/tgs_api/v5/OnTopic(T)
+ var/list/params = params2list(T)
+ var/json = params[DMAPI5_TOPIC_DATA]
+ if(!json)
+ return FALSE //continue world/Topic
+
+ var/list/topic_parameters = json_decode(json)
+ if(!topic_parameters)
+ return TopicResponse("Invalid topic parameters json!");
+
+ var/their_sCK = topic_parameters[DMAPI5_PARAMETER_ACCESS_IDENTIFIER]
+ if(their_sCK != access_identifier)
+ return TopicResponse("Failed to decode [DMAPI5_PARAMETER_ACCESS_IDENTIFIER] from: [json]!");
+
+ var/command = topic_parameters[DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE]
+ if(!isnum(command))
+ return TopicResponse("Failed to decode [DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE] from: [json]!")
+
+ switch(command)
+ if(DMAPI5_TOPIC_COMMAND_CHAT_COMMAND)
+ var/result = HandleCustomCommand(topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND])
+ if(!result)
+ result = TopicResponse("Error running chat command!")
+ return result
+ if(DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION)
+ intercepted_message_queue = list()
+ var/list/event_notification = topic_parameters[DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]
+ if(!istype(event_notification))
+ return TopicResponse("Invalid [DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION]!")
+
+ var/event_type = event_notification[DMAPI5_EVENT_NOTIFICATION_TYPE]
+ if(!isnum(event_type))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_TYPE]!")
+
+ var/list/event_parameters = event_notification[DMAPI5_EVENT_NOTIFICATION_PARAMETERS]
+ if(event_parameters && !istype(event_parameters))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_NOTIFICATION_PARAMETERS]!")
+
+ var/list/event_call = list(event_type)
+ if(event_parameters)
+ event_call += event_parameters
+
+ if(event_handler != null)
+ event_handler.HandleEvent(arglist(event_call))
+
+ var/list/response = list()
+ response[DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES] = intercepted_message_queue
+ intercepted_message_queue = null
+ return json_encode(response)
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_PORT)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_PORT_SWAP, new_port)
+
+ //the topic still completes, miraculously
+ //I honestly didn't believe byond could do it without exploding
+ if(!world.OpenPort(new_port))
+ return TopicResponse("Port change failed!")
+
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE)
+ var/new_reboot_mode = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]
+ if(!isnum(new_reboot_mode))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_REBOOT_MODE_CHANGE, reboot_mode, new_reboot_mode)
+
+ reboot_mode = new_reboot_mode
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED)
+ var/new_instance_name = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]
+ if(!istext(new_instance_name))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME]!")
+
+ if(event_handler != null)
+ event_handler.HandleEvent(TGS_EVENT_INSTANCE_RENAMED, new_instance_name)
+
+ instance_name = new_instance_name
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE)
+ var/list/chat_update_json = topic_parameters[DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]
+ if(!istype(chat_update_json))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE]!")
+
+ DecodeChannels(chat_update_json)
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE)
+ var/new_port = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_PORT]
+ if (!isnum(new_port) || !(new_port > 0))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_PORT]]")
+
+ server_port = new_port
+ return TopicResponse()
+
+ return TopicResponse("Unknown command: [command]")
+
+/datum/tgs_api/v5/proc/Bridge(command, list/data)
+ if(!data)
+ data = list()
+
+ data[DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE] = command
+ data[DMAPI5_PARAMETER_ACCESS_IDENTIFIER] = access_identifier
+
+ var/json = json_encode(data)
+ var/encoded_json = url_encode(json)
+
+ // This is an infinite sleep until we get a response
+ var/export_response = world.Export("http://127.0.0.1:[server_port]/Bridge?[DMAPI5_BRIDGE_DATA]=[encoded_json]")
+ if(!export_response)
+ TGS_ERROR_LOG("Failed export request: [json]")
+ return
+
+ var/response_json = file2text(export_response["CONTENT"])
+ if(!response_json)
+ TGS_ERROR_LOG("Failed export request, missing content!")
+ return
+
+ var/list/bridge_response = json_decode(response_json)
+ if(!bridge_response)
+ TGS_ERROR_LOG("Failed export request, bad json: [response_json]")
+ return
+
+ var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE]
+ if(error)
+ TGS_ERROR_LOG("Failed export request, bad request: [error]")
+ return
+
+ return bridge_response
+
+/datum/tgs_api/v5/OnReboot()
+ var/list/result = Bridge(DMAPI5_BRIDGE_COMMAND_REBOOT)
+ if(!result)
+ return
+
+ //okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
+
+ var/port = result[DMAPI5_BRIDGE_RESPONSE_NEW_PORT]
+ if(!isnum(port))
+ return //this is valid, server may just want use to reboot
+
+ if(port == 0)
+ //to byond 0 means any port and "none" means close vOv
+ port = "none"
+
+ if(!world.OpenPort(port))
+ TGS_ERROR_LOG("Unable to set port to [port]!")
+
+/datum/tgs_api/v5/InstanceName()
+ return instance_name
+
+/datum/tgs_api/v5/TestMerges()
+ return test_merges
+
+/datum/tgs_api/v5/EndProcess()
+ Bridge(DMAPI5_BRIDGE_COMMAND_KILL)
+
+/datum/tgs_api/v5/Revision()
+ return revision
+
+/datum/tgs_api/v5/ChatBroadcast(message, list/channels)
+ if(!length(channels))
+ channels = ChatChannelInfo()
+
+ var/list/ids = list()
+ for(var/I in channels)
+ var/datum/tgs_chat_channel/channel = I
+ ids += channel.id
+
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = ids)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatTargetedBroadcast(message, admin_only)
+ var/list/channels = list()
+ for(var/I in ChatChannelInfo())
+ var/datum/tgs_chat_channel/channel = I
+ if (!channel.is_private_channel && ((channel.is_admin_channel && admin_only) || (!channel.is_admin_channel && !admin_only)))
+ channels += channel.id
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = channels)
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatPrivateMessage(message, datum/tgs_chat_user/user)
+ message = list(DMAPI5_CHAT_MESSAGE_TEXT = message, DMAPI5_CHAT_MESSAGE_CHANNEL_IDS = list(user.channel.id))
+ if(intercepted_message_queue)
+ intercepted_message_queue += list(message)
+ else
+ Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
+
+/datum/tgs_api/v5/ChatChannelInfo()
+ return chat_channels
+
+/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
+ var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
+ if(istype(chat_channels_json))
+ chat_channels.Cut()
+ for(var/channel_json in chat_channels_json)
+ var/datum/tgs_chat_channel/channel = DecodeChannel(channel_json)
+ if(channel)
+ chat_channels += channel
+ else
+ TGS_WARNING_LOG("Failed to decode [DMAPI5_CHAT_UPDATE_CHANNELS] from channel update!")
+
+/datum/tgs_api/v5/proc/DecodeChannel(channel_json)
+ var/datum/tgs_chat_channel/channel = new
+ channel.id = channel_json[DMAPI5_CHAT_CHANNEL_ID]
+ channel.friendly_name = channel_json[DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME]
+ channel.connection_name = channel_json[DMAPI5_CHAT_CHANNEL_CONNECTION_NAME]
+ channel.is_admin_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL]
+ channel.is_private_channel = channel_json[DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL]
+ channel.custom_tag = channel_json[DMAPI5_CHAT_CHANNEL_TAG]
+ return channel
+
+/datum/tgs_api/v5/SecurityLevel()
+ return security_level
+
+/*
+The MIT License
+
+Copyright (c) 2020 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/v5/commands.dm b/code/modules/tgs/v5/commands.dm
new file mode 100644
index 0000000000..2775157656
--- /dev/null
+++ b/code/modules/tgs/v5/commands.dm
@@ -0,0 +1,68 @@
+/datum/tgs_api/v5/proc/ListCustomCommands()
+ var/results = list()
+ custom_commands = list()
+ for(var/I in typesof(/datum/tgs_chat_command) - /datum/tgs_chat_command)
+ var/datum/tgs_chat_command/stc = new I
+ var/command_name = stc.name
+ if(!command_name || findtext(command_name, " ") || findtext(command_name, "'") || findtext(command_name, "\""))
+ TGS_WARNING_LOG("Custom command [command_name] ([I]) can't be used as it is empty or contains illegal characters!")
+ continue
+
+ if(results[command_name])
+ var/datum/other = custom_commands[command_name]
+ TGS_WARNING_LOG("Custom commands [other.type] and [I] have the same name (\"[command_name]\"), only [other.type] will be available!")
+ continue
+ results += list(list(DMAPI5_CUSTOM_CHAT_COMMAND_NAME = command_name, DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT = stc.help_text, DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY = stc.admin_only))
+ custom_commands[command_name] = stc
+
+ return results
+
+/datum/tgs_api/v5/proc/HandleCustomCommand(list/command_json)
+ var/command = command_json[DMAPI5_CHAT_COMMAND_NAME]
+ var/user = command_json[DMAPI5_CHAT_COMMAND_USER]
+ var/params = command_json[DMAPI5_CHAT_COMMAND_PARAMS]
+
+ var/datum/tgs_chat_user/u = new
+ u.id = user[DMAPI5_CHAT_USER_ID]
+ u.friendly_name = user[DMAPI5_CHAT_USER_FRIENDLY_NAME]
+ u.mention = user[DMAPI5_CHAT_USER_MENTION]
+ u.channel = DecodeChannel(user[DMAPI5_CHAT_USER_CHANNEL])
+
+ var/datum/tgs_chat_command/sc = custom_commands[command]
+ if(sc)
+ var/text_response = sc.Run(u, params)
+ var/list/topic_response = list()
+ if(!istext(text_response))
+ TGS_ERROR_LOG("Custom command [command] should return a string! Got: \"[text_response]\"")
+ text_response = null
+ topic_response[DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE] = text_response
+ return json_encode(topic_response)
+ return TopicResponse("Unknown custom chat command: [command]!")
+
+/*
+
+The MIT License
+
+Copyright (c) 2020 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/v5/undef.dm b/code/modules/tgs/v5/undef.dm
new file mode 100644
index 0000000000..72d673b9b1
--- /dev/null
+++ b/code/modules/tgs/v5/undef.dm
@@ -0,0 +1,121 @@
+#undef DMAPI5_PARAM_SERVER_PORT
+#undef DMAPI5_PARAM_ACCESS_IDENTIFIER
+
+#undef DMAPI5_BRIDGE_DATA
+#undef DMAPI5_TOPIC_DATA
+
+#undef DMAPI5_BRIDGE_COMMAND_PORT_UPDATE
+#undef DMAPI5_BRIDGE_COMMAND_STARTUP
+#undef DMAPI5_BRIDGE_COMMAND_PRIME
+#undef DMAPI5_BRIDGE_COMMAND_REBOOT
+#undef DMAPI5_BRIDGE_COMMAND_KILL
+#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
+
+#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
+#undef DMAPI5_RESPONSE_ERROR_MESSAGE
+
+#undef DMAPI5_BRIDGE_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_BRIDGE_PARAMETER_CURRENT_PORT
+#undef DMAPI5_BRIDGE_PARAMETER_VERSION
+#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
+#undef DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS
+#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
+
+#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
+#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
+
+#undef DMAPI5_CHAT_MESSAGE_TEXT
+#undef DMAPI5_CHAT_MESSAGE_CHANNEL_IDS
+
+#undef DMAPI5_RUNTIME_INFORMATION_ACCESS_IDENTIFIER
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION
+#undef DMAPI5_RUNTIME_INFORMATION_SERVER_PORT
+#undef DMAPI5_RUNTIME_INFORMATION_API_VALIDATE_ONLY
+#undef DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME
+#undef DMAPI5_RUNTIME_INFORMATION_REVISION
+#undef DMAPI5_RUNTIME_INFORMATION_TEST_MERGES
+#undef DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL
+
+#undef DMAPI5_CHAT_UPDATE_CHANNELS
+
+#undef DMAPI5_TEST_MERGE_TIME_MERGED
+#undef DMAPI5_TEST_MERGE_REVISION
+#undef DMAPI5_TEST_MERGE_TITLE_AT_MERGE
+#undef DMAPI5_TEST_MERGE_BODY_AT_MERGE
+#undef DMAPI5_TEST_MERGE_URL
+#undef DMAPI5_TEST_MERGE_AUTHOR
+#undef DMAPI5_TEST_MERGE_NUMBER
+#undef DMAPI5_TEST_MERGE_PULL_REQUEST_REVISION
+#undef DMAPI5_TEST_MERGE_COMMENT
+
+#undef DMAPI5_CHAT_COMMAND_NAME
+#undef DMAPI5_CHAT_COMMAND_PARAMS
+#undef DMAPI5_CHAT_COMMAND_USER
+
+#undef DMAPI5_EVENT_NOTIFICATION_TYPE
+#undef DMAPI5_EVENT_NOTIFICATION_PARAMETERS
+
+#undef DMAPI5_TOPIC_COMMAND_CHAT_COMMAND
+#undef DMAPI5_TOPIC_COMMAND_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_PORT
+#undef DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE
+#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED
+#undef DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE
+#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE
+
+#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
+#undef DMAPI5_TOPIC_PARAMETER_EVENT_NOTIFICATION
+#undef DMAPI5_TOPIC_PARAMETER_NEW_PORT
+#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE
+#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME
+#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE
+
+#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE
+#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES
+
+#undef DMAPI5_REVISION_INFORMATION_COMMIT_SHA
+#undef DMAPI5_REVISION_INFORMATION_ORIGIN_COMMIT_SHA
+
+#undef DMAPI5_CHAT_USER_ID
+#undef DMAPI5_CHAT_USER_FRIENDLY_NAME
+#undef DMAPI5_CHAT_USER_MENTION
+#undef DMAPI5_CHAT_USER_CHANNEL
+
+#undef DMAPI5_CHAT_CHANNEL_ID
+#undef DMAPI5_CHAT_CHANNEL_FRIENDLY_NAME
+#undef DMAPI5_CHAT_CHANNEL_CONNECTION_NAME
+#undef DMAPI5_CHAT_CHANNEL_IS_ADMIN_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_IS_PRIVATE_CHANNEL
+#undef DMAPI5_CHAT_CHANNEL_TAG
+
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
+#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY
+
+/*
+The MIT License
+
+Copyright (c) 2020 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.
+*/
From ee97ac81328e5408f7d238a9a57bffd8d473aeb8 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Fri, 8 May 2020 04:32:57 -0700
Subject: [PATCH 2/7] ok
---
code/__DEFINES/tgs.config.dm | 5 +++--
code/__DEFINES/tgs.dm | 39 +++++++++++++++++++++++++-----------
2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/code/__DEFINES/tgs.config.dm b/code/__DEFINES/tgs.config.dm
index 9f4f63a1fc..a2fcc7855a 100644
--- a/code/__DEFINES/tgs.config.dm
+++ b/code/__DEFINES/tgs.config.dm
@@ -4,8 +4,9 @@
#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_INFO_LOG(message) log_world("TGS Info: [##message]")
+#define TGS_WARNING_LOG(message) log_world("TGS Warn: [##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) GENERAL_PROTECT_DATUM(##Path)
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index dcccfc9295..4e152ad3cf 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,5 +1,7 @@
//tgstation-server DMAPI
+#define TGS_DMAPI_VERSION "5.0.0"
+
//All functions and datums outside this document are subject to change with any version and should not be relied on
//CONFIGURATION
@@ -17,7 +19,6 @@
//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`
@@ -26,10 +27,10 @@
//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
+//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities
#define TGS_PROTECT_DATUM(Path)
-//display an announcement `message` from the server to all players
+//Display an announcement `message` from the server to all players
#define TGS_WORLD_ANNOUNCE(message)
//Notify current in-game administrators of a string `event`
@@ -38,6 +39,9 @@
//Write an info `message` to a server log
#define TGS_INFO_LOG(message)
+//Write an warning `message` to a server log
+#define TGS_WARNING_LOG(message)
+
//Write an error `message` to a server log
#define TGS_ERROR_LOG(message)
@@ -48,10 +52,11 @@
//EVENT CODES
-#define TGS_EVENT_PORT_SWAP -2 //before a port change is about to happen, extra parameter is new port
-#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //before a reboot mode change, extras parameters are the current and new reboot mode enums
+#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums
+#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port
+#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra prameter is the new name
-//See the descriptions for these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
+//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
#define TGS_EVENT_REPO_RESET_ORIGIN 0
#define TGS_EVENT_REPO_CHECKOUT 1
#define TGS_EVENT_REPO_FETCH 2
@@ -63,9 +68,9 @@
#define TGS_EVENT_COMPILE_START 8
#define TGS_EVENT_COMPILE_CANCELLED 9
#define TGS_EVENT_COMPILE_FAILURE 10
-#define TGS_EVENT_COMPILE_COMPLETE 11
+#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead
#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
-#define TGS_EVENT_REPO_MERGE_CONFLICT 13
+#define TGS_EVENT_DEPLOYMENT_COMPLETE 13
//OTHER ENUMS
@@ -80,6 +85,7 @@
//REQUIRED HOOKS
//Call this somewhere in /world/New() that is always run
+//IMPORTANT: This function may sleep! Other TGS functions will not succeed until it completes
//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
//minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
@@ -109,12 +115,12 @@
//represents a version of tgstation-server
/datum/tgs_version
- var/suite //The suite version, can be >=3
+ var/suite //The suite/major version, can be >=3
//this group of variables can be null to represent a wild card
- var/major //The major version
var/minor //The minor version
var/patch //The patch version
+ var/deprecated_patch //The legacy version
var/raw_parameter //The unparsed parameter
var/deprefixed_parameter //The version only bit of raw_parameter
@@ -123,6 +129,10 @@
/datum/tgs_version/proc/Wildcard()
return
+//if the tgs_version equals some other_version
+/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
+ return
+
//represents a merge of a GitHub pull request
/datum/tgs_revision_information/test_merge
var/number //pull request number
@@ -179,7 +189,7 @@
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
+//No function below this succeeds if it returns FALSE or if TgsNew() has yet to be called
/world/proc/TgsAvailable()
return
@@ -187,6 +197,11 @@
/world/proc/TgsVersion()
return
+//Gets the current /datum/tgs_version of the DMAPI being used
+/world/proc/TgsApiVersion()
+ return
+
+//Gets the name of the TGS instance running the game
/world/proc/TgsInstanceName()
return
@@ -255,4 +270,4 @@ 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.
-*/
\ No newline at end of file
+*/
From 2b598c692c4f5f1e9f44c32c5ce5a077e995f51f Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 10 May 2020 15:01:30 -0700
Subject: [PATCH 3/7] ok
---
code/__HELPERS/unsorted.dm | 7 ++++++-
code/datums/tgs_event_handler.dm | 20 ++++++++++++++++++++
2 files changed, 26 insertions(+), 1 deletion(-)
create mode 100644 code/datums/tgs_event_handler.dm
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 13ac820778..830e933518 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1571,8 +1571,13 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
//empty string - use TgsTargetBroadcast with admin_only = FALSE
//other string - use TgsChatBroadcast with the tag that matches config_setting, only works with TGS4, if using TGS3 the above method is used
/proc/send2chat(message, config_setting)
- if(config_setting == null || !world.TgsAvailable())
+ if(config_setting == null)
return
+
+ UNTIL(GLOB.tgs_initialized)
+ if(!world.TgsAvailable())
+ return
+
var/datum/tgs_version/version = world.TgsVersion()
if(config_setting == "" || version.suite == 3)
world.TgsTargetedChatBroadcast(message, FALSE)
diff --git a/code/datums/tgs_event_handler.dm b/code/datums/tgs_event_handler.dm
new file mode 100644
index 0000000000..a3324121bf
--- /dev/null
+++ b/code/datums/tgs_event_handler.dm
@@ -0,0 +1,20 @@
+/datum/tgs_event_handler/impl/HandleEvent(event_code, ...)
+ switch(event_code)
+ if(TGS_EVENT_REBOOT_MODE_CHANGE)
+ var/list/reboot_mode_lookup = list ("[TGS_REBOOT_MODE_NORMAL]" = "be normal", "[TGS_REBOOT_MODE_SHUTDOWN]" = "shutdown the server", "[TGS_REBOOT_MODE_RESTART]" = "hard restart the server")
+ var old_reboot_mode = args[2]
+ var new_reboot_mode = args[3]
+ message_admins("TGS: Reboot will no longer [reboot_mode_lookup["[old_reboot_mode]"]], it will instead [reboot_mode_lookup["[new_reboot_mode]"]]")
+ if(TGS_EVENT_PORT_SWAP)
+ message_admins("TGS: Changing port from [world.port] to [args[2]]")
+ if(TGS_EVENT_INSTANCE_RENAMED)
+ message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]")
+ if(TGS_EVENT_COMPILE_START)
+ message_admins("TGS: Deployment started, new game version incoming...")
+ if(TGS_EVENT_COMPILE_CANCELLED)
+ message_admins("TGS: Deployment cancelled!")
+ if(TGS_EVENT_COMPILE_FAILURE)
+ message_admins("TGS: Deployment failed!")
+ if(TGS_EVENT_DEPLOYMENT_COMPLETE)
+ message_admins("TGS: Deployment complete!")
+ to_chat(world, "Server updated, changes will be applied on the next round...")
From 452b360450c991ba787b9c2991faf0da66da8c5d Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 10 May 2020 15:05:46 -0700
Subject: [PATCH 4/7] ok
---
code/datums/helper_datums/getrev.dm | 18 +++++++++++-------
code/game/world.dm | 15 ++++++++++++---
2 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 0b0fed407c..91b8e32566 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -5,16 +5,18 @@
var/list/testmerge = list()
/datum/getrev/New()
+ commit = rustg_git_revparse("HEAD")
+ if(commit)
+ date = rustg_git_commit_date(commit)
+ originmastercommit = rustg_git_revparse("origin/master")
+
+/datum/getrev/proc/load_tgs_info()
testmerge = world.TgsTestMerges()
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
- else
- commit = rustg_git_revparse("HEAD")
- if(commit)
- date = rustg_git_commit_date(commit)
- originmastercommit = rustg_git_revparse("origin/master")
+ date = rustg_git_commit_date(commit)
// goes to DD log and config_error.txt
log_world(get_log_message())
@@ -77,7 +79,9 @@
msg += "No commit information"
if(world.TgsAvailable())
var/datum/tgs_version/version = world.TgsVersion()
- msg += "Server tools version: [version.raw_parameter]"
+ msg += "TGS version: [version.raw_parameter]"
+ var/datum/tgs_version/api_version = world.TgsApiVersion()
+ msg += "DMAPI version: [api_version.raw_parameter]"
// Game mode odds
msg += "
Current Informational Settings:"
@@ -121,4 +125,4 @@
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
msg += "[ctag] [percentage]%"
- to_chat(src, msg.Join("
"))
\ No newline at end of file
+ to_chat(src, msg.Join("
"))
diff --git a/code/game/world.dm b/code/game/world.dm
index 10431e4af9..45ed035e58 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -23,10 +23,11 @@ GLOBAL_LIST(topic_status_cache)
make_datum_references_lists() //initialises global lists for referencing frequently used datums (so that we only ever do it once)
- TgsNew(minimum_required_security_level = TGS_SECURITY_TRUSTED)
GLOB.revdata = new
+ InitTgs()
+
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
//SetupLogs depends on the RoundID, so lets check
@@ -37,6 +38,9 @@ GLOBAL_LIST(topic_status_cache)
#ifndef USE_CUSTOM_ERROR_HANDLER
world.log = file("[GLOB.log_directory]/dd.log")
+#else
+ if (TgsAvailable())
+ world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them.
#endif
load_admins()
@@ -62,6 +66,10 @@ GLOBAL_LIST(topic_status_cache)
if(TEST_RUN_PARAMETER in params)
HandleTestRun()
+/world/proc/InitTgs()
+ TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED)
+ GLOB.revdata.load_tgs_info()
+
/world/proc/HandleTestRun()
//trigger things to run the whole process
Master.sleep_offline_after_initializations = FALSE
@@ -223,16 +231,17 @@ GLOBAL_LIST(topic_status_cache)
qdel(src) //shut it down
/world/Reboot(reason = 0, fast_track = FALSE)
- 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")
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")
+ to_chat(world, "Rebooting World immediately due to host request.")
else
to_chat(world, "Rebooting world...")
Master.Shutdown() //run SS shutdowns
+ TgsReboot()
+
if(TEST_RUN_PARAMETER in params)
FinishTestRun()
return
From 5aea034d881280eeef65d4268d5e856271fb1e04 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 10 May 2020 15:12:13 -0700
Subject: [PATCH 5/7] k
---
code/__HELPERS/unsorted.dm | 2 +-
code/game/world.dm | 9 ++++++---
tgstation.dme | 1 +
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 830e933518..e6663be5b9 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1573,7 +1573,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
/proc/send2chat(message, config_setting)
if(config_setting == null)
return
-
+
UNTIL(GLOB.tgs_initialized)
if(!world.TgsAvailable())
return
diff --git a/code/game/world.dm b/code/game/world.dm
index 45ed035e58..bd56ffdbf4 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -1,6 +1,7 @@
#define RESTART_COUNTER_PATH "data/round_counter.txt"
GLOBAL_VAR(restart_counter)
+GLOBAL_VAR_INIT(tgs_initialized, FALSE)
GLOBAL_VAR(topic_status_lastcache)
GLOBAL_LIST(topic_status_cache)
@@ -38,9 +39,6 @@ GLOBAL_LIST(topic_status_cache)
#ifndef USE_CUSTOM_ERROR_HANDLER
world.log = file("[GLOB.log_directory]/dd.log")
-#else
- if (TgsAvailable())
- world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them.
#endif
load_admins()
@@ -69,6 +67,11 @@ GLOBAL_LIST(topic_status_cache)
/world/proc/InitTgs()
TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_TRUSTED)
GLOB.revdata.load_tgs_info()
+#ifdef USE_CUSTOM_ERROR_HANDLER
+ if (TgsAvailable())
+ world.log = file("[GLOB.log_directory]/dd.log") //not all runtimes trigger world/Error, so this is the only way to ensure we can see all of them.
+#endif
+ GLOB.tgs_initialized = TRUE
/world/proc/HandleTestRun()
//trigger things to run the whole process
diff --git a/tgstation.dme b/tgstation.dme
index d61a1c4ef9..34cf0e354a 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -366,6 +366,7 @@
#include "code\datums\shuttles.dm"
#include "code\datums\soullink.dm"
#include "code\datums\spawners_menu.dm"
+#include "code\datums\tgs_event_handler.dm"
#include "code\datums\verbs.dm"
#include "code\datums\weakrefs.dm"
#include "code\datums\world_topic.dm"
From 7d75166b7bf680dadc5b98f5a84d134f5a32f1b5 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Fri, 15 May 2020 23:20:34 -0700
Subject: [PATCH 6/7] tgs 5.1.1
---
code/modules/tgs/core/core.dm | 22 ++++++++++++++++-----
code/modules/tgs/core/datum.dm | 4 +++-
code/modules/tgs/v3210/api.dm | 2 +-
code/modules/tgs/v4/api.dm | 5 +----
code/modules/tgs/v5/_defines.dm | 7 +++++--
code/modules/tgs/v5/api.dm | 34 ++++++++++++++++++++++++++-------
code/modules/tgs/v5/undef.dm | 3 +++
7 files changed, 57 insertions(+), 20 deletions(-)
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index 144f33926f..a74c9bbab2 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -1,11 +1,17 @@
/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
var/current_api = TGS_READ_GLOBAL(tgs)
if(current_api)
- TGS_ERROR_LOG("TgsNew(): TGS API datum already set ([current_api])! Was TgsNew() called more than once?")
+ TGS_ERROR_LOG("API datum already set (\ref[current_api] ([current_api]))! Was TgsNew() called more than once?")
+ return
+
+ if(!(minimum_required_security_level in list(TGS_SECURITY_ULTRASAFE, TGS_SECURITY_SAFE, TGS_SECURITY_TRUSTED)))
+ TGS_ERROR_LOG("Invalid minimum_required_security_level: [minimum_required_security_level]!")
return
#ifdef TGS_V3_API
- minimum_required_security_level = TGS_SECURITY_TRUSTED
+ if(minimum_required_security_level != TGS_SECURITY_TRUSTED)
+ TGS_WARNING_LOG("V3 DMAPI requires trusted security!")
+ minimum_required_security_level = TGS_SECURITY_TRUSTED
#endif
var/raw_parameter = world.params[TGS_VERSION_PARAMETER]
if(!raw_parameter)
@@ -13,7 +19,7 @@
var/datum/tgs_version/version = new(raw_parameter)
if(!version.Valid(FALSE))
- TGS_ERROR_LOG("Failed to validate TGS version parameter: [raw_parameter]!")
+ TGS_ERROR_LOG("Failed to validate DMAPI version parameter: [raw_parameter]!")
return
var/api_datum
@@ -21,6 +27,7 @@
if(3)
#ifndef TGS_V3_API
TGS_ERROR_LOG("Detected V3 API but TGS_V3_API isn't defined!")
+ return
#else
switch(version.minor)
if(2)
@@ -43,11 +50,16 @@
return
TGS_INFO_LOG("Activating API for version [version.deprefixed_parameter]")
- var/datum/tgs_api/new_api = new api_datum(version)
+
+ if(event_handler && !istype(event_handler))
+ TGS_ERROR_LOG("Invalid parameter for event_handler: [event_handler]")
+ event_handler = null
+
+ var/datum/tgs_api/new_api = new api_datum(event_handler, version)
TGS_WRITE_GLOBAL(tgs, new_api)
- var/result = new_api.OnWorldNew(event_handler, minimum_required_security_level)
+ var/result = new_api.OnWorldNew(minimum_required_security_level)
if(!result || result == TGS_UNIMPLEMENTED)
TGS_WRITE_GLOBAL(tgs, null)
TGS_ERROR_LOG("Failed to activate API!")
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index 3adecbb556..ccc75fe344 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -2,9 +2,11 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
/datum/tgs_api
var/datum/tgs_version/version
+ var/datum/tgs_event_handler/event_handler
-/datum/tgs_api/New(datum/tgs_version/version)
+/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version)
. = ..()
+ src.event_handler = event_handler
src.version = version
/datum/tgs_api/latest
diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm
index 5327b9276b..0fc0076c8b 100644
--- a/code/modules/tgs/v3210/api.dm
+++ b/code/modules/tgs/v3210/api.dm
@@ -56,7 +56,7 @@
/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, minimum_required_security_level) //don't use event handling in this version
+/datum/tgs_api/v3210/OnWorldNew(minimum_required_security_level)
. = FALSE
comms_key = world.params[SERVICE_WORLD_PARAM]
diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm
index 5c98a1a7a7..ba18aab688 100644
--- a/code/modules/tgs/v4/api.dm
+++ b/code/modules/tgs/v4/api.dm
@@ -43,15 +43,13 @@
var/list/cached_test_merges
var/datum/tgs_revision_information/cached_revision
- var/datum/tgs_event_handler/event_handler
-
var/export_lock = FALSE
var/list/last_interop_response
/datum/tgs_api/v4/ApiVersion()
return new /datum/tgs_version("4.0.0.0")
-/datum/tgs_api/v4/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
+/datum/tgs_api/v4/OnWorldNew(minimum_required_security_level)
json_path = world.params[TGS4_PARAM_INFO_JSON]
if(!json_path)
TGS_ERROR_LOG("Missing [TGS4_PARAM_INFO_JSON] world parameter!")
@@ -76,7 +74,6 @@
security_level = cached_json["securityLevel"]
chat_channels_json_path = cached_json["chatChannelsJson"]
chat_commands_json_path = cached_json["chatCommandsJson"]
- src.event_handler = event_handler
instance_name = cached_json["instanceName"]
ListCustomCommands()
diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
index 1117a1df50..2baf3e12d7 100644
--- a/code/modules/tgs/v5/_defines.dm
+++ b/code/modules/tgs/v5/_defines.dm
@@ -60,8 +60,10 @@
#define DMAPI5_TOPIC_COMMAND_CHANGE_PORT 2
#define DMAPI5_TOPIC_COMMAND_CHANGE_REBOOT_STATE 3
#define DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED 4
-#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 4
-#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 5
+#define DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE 5
+#define DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE 6
+#define DMAPI5_TOPIC_COMMAND_HEARTBEAT 7
+#define DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH 8
#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
@@ -70,6 +72,7 @@
#define DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE "newRebootState"
#define DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME "newInstanceName"
#define DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE "chatUpdate"
+#define DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION "newServerVersion"
#define DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE "commandResponseMessage"
#define DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES "chatResponses"
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
index 32f80c0ae4..eedefb2877 100644
--- a/code/modules/tgs/v5/api.dm
+++ b/code/modules/tgs/v5/api.dm
@@ -15,18 +15,15 @@
var/datum/tgs_revision_information/revision
var/list/chat_channels
- var/datum/tgs_event_handler/event_handler
-
/datum/tgs_api/v5/ApiVersion()
- return new /datum/tgs_version("5.0.0")
-
-/datum/tgs_api/v5/OnWorldNew(datum/tgs_event_handler/event_handler, minimum_required_security_level)
- src.event_handler = event_handler
+ return new /datum/tgs_version("5.1.1")
+/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
access_identifier = world.params[DMAPI5_PARAM_ACCESS_IDENTIFIER]
var/datum/tgs_version/api_version = ApiVersion()
+ version = null
var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_BRIDGE_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands()))
if(!istype(bridge_response))
TGS_ERROR_LOG("Failed initial bridge request!")
@@ -41,9 +38,9 @@
TGS_INFO_LOG("DMAPI validation, exiting...")
del(world)
+ version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
security_level = runtime_information[DMAPI5_RUNTIME_INFORMATION_SECURITY_LEVEL]
instance_name = runtime_information[DMAPI5_RUNTIME_INFORMATION_INSTANCE_NAME]
- version = new /datum/tgs_version(runtime_information[DMAPI5_RUNTIME_INFORMATION_SERVER_VERSION])
var/list/revisionData = runtime_information[DMAPI5_RUNTIME_INFORMATION_REVISION]
if(istype(revisionData))
@@ -84,6 +81,10 @@
return TRUE
+/datum/tgs_api/v5/proc/RequireInitialBridgeResponse()
+ while(!version)
+ sleep(1)
+
/datum/tgs_api/v5/OnInitializationComplete()
Bridge(DMAPI5_BRIDGE_COMMAND_PRIME)
@@ -197,6 +198,20 @@
server_port = new_port
return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_HEARTBEAT)
+ return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH)
+ var/new_version_string = topic_parameters[DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]
+ if (!istext(new_version_string))
+ return TopicResponse("Invalid or missing [DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION]]")
+
+ var/datum/tgs_version/new_version = new(new_version_string)
+ if (event_handler)
+ event_handler.HandleEvent(TGS_EVENT_WATCHDOG_REATTACH, new_version)
+
+ version = new_version
+
+ return TopicResponse()
return TopicResponse("Unknown command: [command]")
@@ -252,15 +267,18 @@
TGS_ERROR_LOG("Unable to set port to [port]!")
/datum/tgs_api/v5/InstanceName()
+ RequireInitialBridgeResponse()
return instance_name
/datum/tgs_api/v5/TestMerges()
+ RequireInitialBridgeResponse()
return test_merges
/datum/tgs_api/v5/EndProcess()
Bridge(DMAPI5_BRIDGE_COMMAND_KILL)
/datum/tgs_api/v5/Revision()
+ RequireInitialBridgeResponse()
return revision
/datum/tgs_api/v5/ChatBroadcast(message, list/channels)
@@ -298,6 +316,7 @@
Bridge(DMAPI5_BRIDGE_COMMAND_CHAT_SEND, list(DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE = message))
/datum/tgs_api/v5/ChatChannelInfo()
+ RequireInitialBridgeResponse()
return chat_channels
/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
@@ -322,6 +341,7 @@
return channel
/datum/tgs_api/v5/SecurityLevel()
+ RequireInitialBridgeResponse()
return security_level
/*
diff --git a/code/modules/tgs/v5/undef.dm b/code/modules/tgs/v5/undef.dm
index 72d673b9b1..b27e3abe95 100644
--- a/code/modules/tgs/v5/undef.dm
+++ b/code/modules/tgs/v5/undef.dm
@@ -62,6 +62,8 @@
#undef DMAPI5_TOPIC_COMMAND_INSTANCE_RENAMED
#undef DMAPI5_TOPIC_COMMAND_CHAT_CHANNELS_UPDATE
#undef DMAPI5_TOPIC_COMMAND_SERVER_PORT_UPDATE
+#undef DMAPI5_TOPIC_COMMAND_HEARTBEAT
+#undef DMAPI5_TOPIC_COMMAND_WATCHDOG_REATTACH
#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
@@ -70,6 +72,7 @@
#undef DMAPI5_TOPIC_PARAMETER_NEW_REBOOT_STATE
#undef DMAPI5_TOPIC_PARAMETER_NEW_INSTANCE_NAME
#undef DMAPI5_TOPIC_PARAMETER_CHAT_UPDATE
+#undef DMAPI5_TOPIC_PARAMETER_NEW_SERVER_VERSION
#undef DMAPI5_TOPIC_RESPONSE_COMMAND_RESPONSE_MESSAGE
#undef DMAPI5_TOPIC_RESPONSE_CHAT_RESPONSES
From 1d6ff8380f0d763eff3e030326a340051a5a0296 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Fri, 15 May 2020 23:22:13 -0700
Subject: [PATCH 7/7] update
---
code/__DEFINES/tgs.dm | 62 ++++++++++++++++++++++++-------------------
1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index 4e152ad3cf..e164a4ec96 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,6 +1,6 @@
//tgstation-server DMAPI
-#define TGS_DMAPI_VERSION "5.0.0"
+#define TGS_DMAPI_VERSION "5.1.1"
//All functions and datums outside this document are subject to change with any version and should not be relied on
@@ -54,7 +54,8 @@
#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //Before a reboot mode change, extras parameters are the current and new reboot mode enums
#define TGS_EVENT_PORT_SWAP -2 //Before a port change is about to happen, extra parameters is new port
-#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra prameter is the new name
+#define TGS_EVENT_INSTANCE_RENAMED -3 //Before the instance is renamed, extra parameter is the new name
+#define TGS_EVENT_WATCHDOG_REATTACH -4 //After the watchdog reattaches to DD, extra parameter is the new /datum/tgs_version of the server
//See the descriptions for the parameters of these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
#define TGS_EVENT_REPO_RESET_ORIGIN 0
@@ -70,7 +71,10 @@
#define TGS_EVENT_COMPILE_FAILURE 10
#define TGS_EVENT_COMPILE_COMPLETE 11 // Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the TGS_EVENT_DEPLOYMENT_COMPLETE instead
#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
-#define TGS_EVENT_DEPLOYMENT_COMPLETE 13
+#define TGS_EVENT_REPO_MERGE_CONFLICT 13
+#define TGS_EVENT_DEPLOYMENT_COMPLETE 14
+#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
+#define TGS_EVENT_WATCHDOG_DETACH 16
//OTHER ENUMS
@@ -85,7 +89,7 @@
//REQUIRED HOOKS
//Call this somewhere in /world/New() that is always run
-//IMPORTANT: This function may sleep! Other TGS functions will not succeed until it completes
+//IMPORTANT: This function may sleep!
//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
//minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
@@ -193,6 +197,32 @@
/world/proc/TgsAvailable()
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
+
+//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 following functions will sleep if a call to TgsNew() is sleeping
+
+//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
+
//Gets the current /datum/tgs_version of the server tools running the server
/world/proc/TgsVersion()
return
@@ -217,34 +247,10 @@
/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