diff --git a/CMakeLists.txt b/CMakeLists.txt
index e12b0d34532546595ea627329eba5e973567c671..25a44f01659a58dcd5b6fcd439b4778970b6b805 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,8 +1,12 @@
 cmake_minimum_required(VERSION 3.0)
+
+file(STRINGS src/version.h SRB2_VERSION)
+string(REGEX MATCH "[0-9]+\\.[0-9.]+" SRB2_VERSION ${SRB2_VERSION})
+
 # DO NOT CHANGE THIS SRB2 STRING! Some variable names depend on this string.
 # Version change is fine.
 project(SRB2
-	VERSION 2.2.6
+	VERSION ${SRB2_VERSION}
 	LANGUAGES C)
 
 if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index c7c5470ae75f3f996361468a6f21a90be219567a..71e2e947e63078719fa14f5515bc72d45541935d 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -2336,8 +2336,8 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
 		if (server_list)
 		{
 			char version[8] = "";
-#if VERSION > 0 || SUBVERSION > 0
-			snprintf(version, sizeof (version), "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
+#ifndef DEVELOP
+			strcpy(version, SRB2VERSION);
 #else
 			strcpy(version, GetRevisionString());
 #endif
diff --git a/src/d_main.c b/src/d_main.c
index 28570b90938eaea055bc24b1b058c0ee49b13c6e..96167ac0bb265f98a3e1c55b00f8c8b8b0d2db94 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -93,6 +93,10 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 
 #include "lua_script.h"
 
+// Version numbers for netplay :upside_down_face:
+int    VERSION;
+int SUBVERSION;
+
 // platform independant focus loss
 UINT8 window_notinfocus = false;
 
@@ -1142,6 +1146,21 @@ static inline void D_Titlebar(void)
 }
 #endif
 
+static void
+D_ConvertVersionNumbers (void)
+{
+	/* leave at defaults (0) under DEVELOP */
+#ifndef DEVELOP
+	int major;
+	int minor;
+
+	sscanf(SRB2VERSION, "%d.%d.%d", &major, &minor, &SUBVERSION);
+
+	/* this is stupid */
+	VERSION = ( major * 100 ) + minor;
+#endif
+}
+
 //
 // D_SRB2Main
 //
@@ -1152,6 +1171,9 @@ void D_SRB2Main(void)
 	INT32 pstartmap = 1;
 	boolean autostart = false;
 
+	/* break the version string into version numbers, for netplay */
+	D_ConvertVersionNumbers();
+
 	// Print GPL notice for our console users (Linux)
 	CONS_Printf(
 	"\n\nSonic Robo Blast 2\n"
diff --git a/src/dehacked.c b/src/dehacked.c
index 99d4883f6de75ebec0e3275a7d19e0c04a4f248a..d02dc3d24ae797a5fe628bab54570e186d55bc79 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -9484,8 +9484,6 @@ struct {
 	{"PUSHACCEL",PUSHACCEL},
 	{"MODID",MODID}, // I don't know, I just thought it would be cool for a wad to potentially know what mod it was loaded into.
 	{"CODEBASE",CODEBASE}, // or what release of SRB2 this is.
-	{"VERSION",VERSION}, // Grab the game's version!
-	{"SUBVERSION",SUBVERSION}, // more precise version number
 	{"NEWTICRATE",NEWTICRATE}, // TICRATE*NEWTICRATERATIO
 	{"NEWTICRATERATIO",NEWTICRATERATIO},
 
diff --git a/src/doomdef.h b/src/doomdef.h
index 380adf781e047b7b40d58f7f14fadbeb4a102547..249bd5128c4a0751f12a498eecfff5098d00916c 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -86,6 +86,7 @@
 // warning C4213: nonstandard extension used : cast on l-value
 
 
+#include "version.h"
 #include "doomtype.h"
 
 #include <stdarg.h>
@@ -135,21 +136,17 @@ extern char logfilename[1024];
 
 //#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
 #ifdef DEVELOP
-#define VERSION    0 // Game version
-#define SUBVERSION 0 // more precise version number
 #define VERSIONSTRING "Development EXE"
-#define VERSIONSTRINGW L"Development EXE"
 // most interface strings are ignored in development mode.
 // we use comprevision and compbranch instead.
 #else
-#define VERSION    202 // Game version
-#define SUBVERSION 6  // more precise version number
-#define VERSIONSTRING "v2.2.6"
-#define VERSIONSTRINGW L"v2.2.6"
+#define VERSIONSTRING "v"SRB2VERSION
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
 
+#define VERSIONSTRINGW WSTRING (VERSIONSTRING)
+
 /* A custom URL protocol for server links. */
 #define SERVER_URL_PROTOCOL "srb2://"
 
@@ -204,17 +201,6 @@ extern char logfilename[1024];
 // Will always resemble the versionstring, 205 = 2.0.5, 210 = 2.1, etc.
 #define CODEBASE 220
 
-// The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ).
-// DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
-// "18" is the default mod ID for version 2.2
-#define MODID 18
-
-// The Modification Version, starting from 1. Do not follow your version string for this,
-// it's only for detection of the version the player is using so the MS can alert them of an update.
-// Only set it higher, not lower, obviously.
-// Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1".
-#define MODVERSION 47
-
 // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically.
 // Increment MINOREXECVERSION whenever a config change is needed that does not correspond
 // to an increment in MODVERSION. This might never happen in practice.
@@ -503,6 +489,8 @@ char *sizeu4(size_t num);
 char *sizeu5(size_t num);
 
 // d_main.c
+extern int    VERSION;
+extern int SUBVERSION;
 extern boolean devparm; // development mode (-debug)
 // d_netcmd.c
 extern INT32 cv_debug;
diff --git a/src/doomtype.h b/src/doomtype.h
index 571e930e0b540f08a923fb033a9d7c4951cae54c..0aa3e23e05b74613b690993450e87b5dad6e800d 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -367,4 +367,8 @@ typedef UINT32 tic_t;
 #define UINT2RGBA(a) (UINT32)((a&0xff)<<24)|((a&0xff00)<<8)|((a&0xff0000)>>8)|(((UINT32)a&0xff000000)>>24)
 #endif
 
+/* preprocessor dumb and needs second macro to expand input */
+#define WSTRING2(s) L ## s
+#define WSTRING(s) WSTRING2 (s)
+
 #endif //__DOOMTYPE__
diff --git a/src/lua_script.c b/src/lua_script.c
index 5fb153c0efec3064eefdad29284be901ebfc2216..9d7d536b971a45da3f45ee7022e06daf636e4edf 100644
--- a/src/lua_script.c
+++ b/src/lua_script.c
@@ -344,6 +344,12 @@ int LUA_PushGlobals(lua_State *L, const char *word)
 	} else if (fastcmp(word,"gravity")) {
 		lua_pushinteger(L, gravity);
 		return 1;
+	} else if (fastcmp(word,"VERSION")) {
+		lua_pushinteger(L, VERSION);
+		return 1;
+	} else if (fastcmp(word,"SUBVERSION")) {
+		lua_pushinteger(L, SUBVERSION);
+		return 1;
 	} else if (fastcmp(word,"VERSIONSTRING")) {
 		lua_pushstring(L, VERSIONSTRING);
 		return 1;
diff --git a/src/mserv.c b/src/mserv.c
index 05a5344bac1ee38b2b249b245615ba0dd300a49d..af56907885cc7575069cd4c649ec456ff690b04e 100644
--- a/src/mserv.c
+++ b/src/mserv.c
@@ -754,8 +754,8 @@ static INT32 AddToMasterServer(boolean firstadd)
 	strcpy(info->port, int2str(current_port));
 	strcpy(info->name, cv_servername.string);
 	M_Memcpy(&info->room, & room, sizeof (INT32));
-#if VERSION > 0 || SUBVERSION > 0
-	sprintf(info->version, "%d.%d.%d", VERSION/100, VERSION%100, SUBVERSION);
+#ifndef DEVELOP
+	strcpy(info->version, SRB2VERSION);
 #else // Trunk build, send revision info
 	strcpy(info->version, GetRevisionString());
 #endif
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000000000000000000000000000000000000..31cf85bdcdfae7d462bc1786f752bf3bd673eb82
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,12 @@
+#define SRB2VERSION "2.2.6"/* this must be the first line, for cmake !! */
+
+// The Modification ID; must be obtained from a Master Server Admin ( https://mb.srb2.org/showgroups.php ).
+// DO NOT try to set this otherwise, or your modification will be unplayable through the Master Server.
+// "18" is the default mod ID for version 2.2
+#define MODID 18
+
+// The Modification Version, starting from 1. Do not follow your version string for this,
+// it's only for detection of the version the player is using so the MS can alert them of an update.
+// Only set it higher, not lower, obviously.
+// Note that we use this to help keep internal testing in check; this is why v2.2.0 is not version "1".
+#define MODVERSION 47