diff --git a/code/__HELPERS/510.dm b/code/__HELPERS/510.dm
index cc7b2fe13a0..8c3a26053e7 100644
--- a/code/__HELPERS/510.dm
+++ b/code/__HELPERS/510.dm
@@ -1,27 +1,33 @@
// Helpers for running 510 code on older versions of BYOND.
#if DM_VERSION < 510
-
#define BYGEX "code/__HELPERS/bygex.dll"
-/proc/replacetext(str, exp, fmt)
- return call(BYGEX, "regex_replaceallliteral")(str, exp, fmt)
+/proc/replacetext(text, replace, replacement)
+ return call(BYGEX, "regex_replaceallliteral")(text, replace, replacement)
-/proc/replacetextEx(str, exp, fmt)
- return call(BYGEX, "regEx_replaceallliteral")(str, exp, fmt)
+/proc/replacetextEx(text, replace, replacement)
+ return call(BYGEX, "regEx_replaceallliteral")(text, replace, replacement)
-/proc/regex(pattern)
- return new /regex(pattern)
+/proc/regex(pattern, flags)
+ return new /regex(pattern, flags)
/regex
var/pattern
+ var/list/flags
var/list/group
-/regex/New(pattern) // Does not support Flags.
+/regex/New(pattern, flags)
src.pattern = pattern
+ src.flags = splittext(flags, "")
group = list()
/regex/proc/Find(text) // Does not support Start/End.
- var/results = call(BYGEX, "regex_find")(text, pattern)
+ var/method
+ if("i" in flags)
+ method = "regex_find"
+ else
+ method = "regEx_find"
+ var/results = call(BYGEX, method)(text, pattern)
var/list/L = params2list(results)
var/list/M
var/i
@@ -34,9 +40,21 @@
var/len = text2num(M[j])
group += copytext(text, pos, pos + len)
+/regex/proc/Replace(text, replacement)
+ var/method
+ if("g" in flags)
+ if("i" in flags)
+ method = "regex_replaceall"
+ else
+ method = "regEx_replaceall"
+ else
+ if("i" in flags)
+ method = "regex_replace"
+ else
+ method = "regEx_replace"
+ return call(BYGEX, method)(text, pattern, replacement)
#undef BYGEX
-
// Formerly list2text
/proc/jointext(list/ls, sep)
if(ls.len <= 1) // Early-out code for empty or singleton lists.
@@ -228,4 +246,8 @@
#undef CannotBeFlat
#undef CannotBeAssoc
#undef BadList
+#else
+/regex/Replace()
+ ..()
+ return text
#endif
\ No newline at end of file
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 7d1ea89c53a..1dff0ee6ceb 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -176,6 +176,8 @@
var/reactionary_explosions = 0 //If we use reactionary explosions, explosions that react to walls and doors
+ var/autoconvert_notes = 0 //if all connecting player's notes should attempt to be converted to the database
+
var/announce_admin_logout = 0
var/announce_admin_login = 0
@@ -369,6 +371,8 @@
if (world.log != newlog)
world.log << "Now logging runtimes to data/logs/runtimes/runtime-[time2text(world.realtime, "YYYY-MM-DD")].log"
world.log = newlog
+ if("autoconvert_notes")
+ config.autoconvert_notes = 1
if("allow_webclient")
config.allowwebclient = 1
if("webclient_only_byond_members")
diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm
index 3a0a90b719f..c38ed7d242b 100644
--- a/code/modules/admin/sql_notes.dm
+++ b/code/modules/admin/sql_notes.dm
@@ -168,3 +168,50 @@
output += "
\[Add Note\]"
output += ruler
usr << browse(output, "window=show_notes;size=900x500")
+
+#define NOTESFILE "data/player_notes.sav"
+//if the AUTOCONVERT_NOTES is turned on, anytime a player connects this will be run to try and add all their notes to the databas
+/proc/convert_notes_sql(ckey)
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile)
+ log_game("Error: Cannot access [NOTESFILE]")
+ return
+ notesfile.cd = "/[ckey]"
+ while(!notesfile.eof)
+ var/notetext
+ notesfile >> notetext
+ var/server
+ if(config && config.server_name)
+ server = config.server_name
+ var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i")
+ note.Find(notetext)
+ var/timestamp = note.group[2]
+ notetext = note.group[3]
+ var/adminckey = note.group[4]
+ var/DBQuery/query_convert_time = dbcon.NewQuery("SELECT ADDTIME(STR_TO_DATE('[timestamp]','%d-%b-%Y'), '0')")
+ if(!query_convert_time.Execute())
+ var/err = query_convert_time.ErrorMsg()
+ log_game("SQL ERROR converting timestamp. Error : \[[err]\]\n")
+ return
+ if(query_convert_time.NextRow())
+ timestamp = query_convert_time.item[1]
+ if(ckey && notetext && timestamp && adminckey && server)
+ add_note(ckey, notetext, timestamp, adminckey, 0, server)
+ notesfile.cd = "/"
+ notesfile.dir.Remove(ckey)
+
+/*alternatively this proc can be run once to pass through every note and attempt to convert it before deleting the file, if done then AUTOCONVERT_NOTES should be turned off
+this proc can take several minutes to execute fully if converting and cause DD to hang if converting a lot of notes; it's not advised to do so while a server is live
+/proc/mass_convert_notes()
+ world << "Beginning mass note conversion"
+ var/savefile/notesfile = new(NOTESFILE)
+ if(!notesfile)
+ log_game("Error: Cannot access [NOTESFILE]")
+ return
+ notesfile.cd = "/"
+ for(var/ckey in notesfile.dir)
+ convert_notes_sql(ckey)
+ world << "Deleting NOTESFILE"
+ fdel(NOTESFILE)
+ world << "Finished mass note conversion, remember to turn off AUTOCONVERT_NOTES"*/
+#undef NOTESFILE
\ No newline at end of file
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index ba21a347c95..452e6077172 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -206,6 +206,9 @@ var/next_external_rsc = 0
src << message
clientmessages.Remove(ckey)
+ if(config && config.autoconvert_notes)
+ convert_notes_sql(ckey)
+
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
src << "Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you."
diff --git a/config/config.txt b/config/config.txt
index a398d26f5f8..c7ad64e5a6e 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -206,23 +206,26 @@ NOTIFY_NEW_PLAYER_AGE 0
## Uncomment to have the game log runtimes to the log folder. (Note: this disables normal output in dd/ds, so it should be left off for testing.
#LOG_RUNTIMES
-##Comment this out to stop admin messages sent anytime an admin disconnects from a round in play, you can edit the messages in admin.dm
+## Comment this out if you've used the mass conversion sql proc for notes or want to stop converting notes
+AUTOCONVERT_NOTES
+
+## Comment this out to stop admin messages sent anytime an admin disconnects from a round in play, you can edit the messages in admin.dm
ANNOUNCE_ADMIN_LOGOUT
-##Uncomment to have an admin message sent anytime an admin connects to a round in play, you can edit the messages in admin.dm
+## Uncomment to have an admin message sent anytime an admin connects to a round in play, you can edit the messages in admin.dm
#ANNOUNCE_ADMIN_LOGIN
-##Map rotation
-##This feature requires you are running a Windows OS (or can other wise run .bat files) and that you are using the tgstation-server toolset in tools/
-##You should edit maps.txt to match your configuration when you enable this.
+## Map rotation
+## This feature requires you are running a Windows OS (or can other wise run .bat files) and that you are using the tgstation-server toolset in tools/
+## You should edit maps.txt to match your configuration when you enable this.
#MAPROTATION
-##Map rotate chance delta
-##This is the chance of map rotation factored to the round length.
-##A value of 1 would mean the map rotation chance is the round length in minutes (hour long round == 60% rotation chance)
-##A value of 0.5 would mean the map rotation chance is half of the round length in minutes (hour long round == 30% rotation chance)
+## Map rotate chance delta
+## This is the chance of map rotation factored to the round length.
+## A value of 1 would mean the map rotation chance is the round length in minutes (hour long round == 60% rotation chance)
+## A value of 0.5 would mean the map rotation chance is half of the round length in minutes (hour long round == 30% rotation chance)
#MAPROTATIONCHANCEDELTA 0.75
-##AUTOADMIN
-##Uncomment to automatically give that admin rank to all players
+## AUTOADMIN
+## Uncomment to automatically give that admin rank to all players
#AUTOADMIN Game Admin