Index: binary-improvements/MapRendering/API/GetPlayerList.cs
===================================================================
--- binary-improvements/MapRendering/API/GetPlayerList.cs	(revision 454)
+++ binary-improvements/MapRendering/API/GetPlayerList.cs	(revision 455)
@@ -2,7 +2,8 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 using System.Text.RegularExpressions;
-using AllocsFixes.JSON;
 using AllocsFixes.PersistentData;
+using JetBrains.Annotations;
 using Webserver;
 using Webserver.Permissions;
@@ -10,4 +11,5 @@
 
 namespace AllocsFixes.WebAPIs {
+	[UsedImplicitly]
 	public class GetPlayerList : AbsWebAPI {
 		private static readonly Regex numberFilterMatcher =
@@ -121,8 +123,10 @@
 			result.Add ("players", playersJsResult);
 
-			LegacyApiHelper.WriteJSON (_context.Response, result);
-		}
-
-		private IEnumerable<JSONObject> ExecuteFilter (IEnumerable<JSONObject> _list, string _filterCol,
+			StringBuilder sb = new StringBuilder ();
+			result.ToString (sb);
+			WebUtils.WriteText (_context.Response, sb.ToString(), _mimeType: WebUtils.MimeJson);
+		}
+
+		private static IEnumerable<JSONObject> ExecuteFilter (IEnumerable<JSONObject> _list, string _filterCol,
 			string _filterVal) {
 			if (!_list.Any()) {
@@ -144,5 +148,5 @@
 					// regex-match whole ^string$, replace * by .*, ? by .?, + by .+
 					_filterVal = _filterVal.Replace ("*", ".*").Replace ("?", ".?").Replace ("+", ".+");
-					_filterVal = "^" + _filterVal + "$";
+					_filterVal = $"^{_filterVal}$";
 
 					//Log.Out ("GetPlayerList: Filter on String with Regex '" + _filterVal + "'");
@@ -156,5 +160,5 @@
 
 
-		private IEnumerable<JSONObject> ExecuteNumberFilter (IEnumerable<JSONObject> _list, string _filterCol,
+		private static IEnumerable<JSONObject> ExecuteNumberFilter (IEnumerable<JSONObject> _list, string _filterCol,
 			string _filterVal) {
 			// allow value (exact match), =, ==, >=, >, <=, <
@@ -207,10 +211,10 @@
 			}
 
-			Log.Out ("GetPlayerList: ignoring invalid filter for number-column '{0}': '{1}'", _filterCol, _filterVal);
+			Log.Out ($"GetPlayerList: ignoring invalid filter for number-column '{_filterCol}': '{_filterVal}'");
 			return _list;
 		}
 
 
-		private IEnumerable<JSONObject> ExecuteSort (IEnumerable<JSONObject> _list, string _sortCol, bool _ascending) {
+		private static IEnumerable<JSONObject> ExecuteSort (IEnumerable<JSONObject> _list, string _sortCol, bool _ascending) {
 			if (_list.Count () == 0) {
 				return _list;
@@ -246,5 +250,5 @@
 
 
-		private bool NearlyEqual (double _a, double _b, double _epsilon) {
+		private static bool NearlyEqual (double _a, double _b, double _epsilon) {
 			double absA = Math.Abs (_a);
 			double absB = Math.Abs (_b);
@@ -267,6 +271,214 @@
 			GreaterEqual,
 			Lesser,
-			LesserEqual
-		}
+			LesserEqual,
+		}
+
+
+#region JSON encoder
+
+		private abstract class JSONNode {
+			public abstract void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0);
+
+			public override string ToString () {
+				StringBuilder sb = new StringBuilder ();
+				ToString (sb);
+				return sb.ToString ();
+			}
+		}
+
+		private abstract class JSONValue : JSONNode {
+		}
+
+		private class JSONNull : JSONValue {
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				_stringBuilder.Append ("null");
+			}
+		}
+
+		private class JSONBoolean : JSONValue {
+			private readonly bool value;
+
+			public JSONBoolean (bool _value) {
+				value = _value;
+			}
+
+			public bool GetBool () {
+				return value;
+			}
+
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				_stringBuilder.Append (value ? "true" : "false");
+			}
+		}
+
+		private class JSONNumber : JSONValue {
+			private readonly double value;
+
+			public JSONNumber (double _value) {
+				value = _value;
+			}
+
+			public double GetDouble () {
+				return value;
+			}
+
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				_stringBuilder.Append (value.ToCultureInvariantString ());
+			}
+		}
+
+		private class JSONString : JSONValue {
+			private readonly string value;
+
+			public JSONString (string _value) {
+				value = _value;
+			}
+
+			public string GetString () {
+				return value;
+			}
+
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				if (string.IsNullOrEmpty (value)) {
+					_stringBuilder.Append ("\"\"");
+					return;
+				}
+
+				int len = value.Length;
+
+				_stringBuilder.EnsureCapacity (_stringBuilder.Length + 2 * len);
+
+				_stringBuilder.Append ('"');
+
+				foreach (char c in value) {
+					switch (c) {
+						case '\\':
+						case '"':
+
+//					case '/':
+							_stringBuilder.Append ('\\');
+							_stringBuilder.Append (c);
+							break;
+						case '\b':
+							_stringBuilder.Append ("\\b");
+							break;
+						case '\t':
+							_stringBuilder.Append ("\\t");
+							break;
+						case '\n':
+							_stringBuilder.Append ("\\n");
+							break;
+						case '\f':
+							_stringBuilder.Append ("\\f");
+							break;
+						case '\r':
+							_stringBuilder.Append ("\\r");
+							break;
+						default:
+							if (c < ' ') {
+								_stringBuilder.Append ("\\u");
+								_stringBuilder.Append (((int) c).ToString ("X4"));
+							} else {
+								_stringBuilder.Append (c);
+							}
+
+							break;
+					}
+				}
+
+				_stringBuilder.Append ('"');
+			}
+
+		}
+
+		private class JSONArray : JSONNode {
+			private readonly List<JSONNode> nodes = new List<JSONNode> ();
+
+			public void Add (JSONNode _node) {
+				nodes.Add (_node);
+			}
+
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				_stringBuilder.Append ("[");
+				if (_prettyPrint) {
+					_stringBuilder.Append ('\n');
+				}
+
+				foreach (JSONNode n in nodes) {
+					if (_prettyPrint) {
+						_stringBuilder.Append (new string ('\t', _currentLevel + 1));
+					}
+
+					n.ToString (_stringBuilder, _prettyPrint, _currentLevel + 1);
+					_stringBuilder.Append (",");
+					if (_prettyPrint) {
+						_stringBuilder.Append ('\n');
+					}
+				}
+
+				if (nodes.Count > 0) {
+					_stringBuilder.Remove (_stringBuilder.Length - (_prettyPrint ? 2 : 1), 1);
+				}
+
+				if (_prettyPrint) {
+					_stringBuilder.Append (new string ('\t', _currentLevel));
+				}
+
+				_stringBuilder.Append ("]");
+			}
+
+		}
+
+		private class JSONObject : JSONNode {
+			private readonly Dictionary<string, JSONNode> nodes = new Dictionary<string, JSONNode> ();
+
+			public JSONNode this [string _name] => nodes [_name];
+
+			public bool ContainsKey (string _name) {
+				return nodes.ContainsKey (_name);
+			}
+
+			public void Add (string _name, JSONNode _node) {
+				nodes.Add (_name, _node);
+			}
+
+			public override void ToString (StringBuilder _stringBuilder, bool _prettyPrint = false, int _currentLevel = 0) {
+				_stringBuilder.Append ("{");
+				if (_prettyPrint) {
+					_stringBuilder.Append ('\n');
+				}
+
+				foreach (KeyValuePair<string, JSONNode> kvp in nodes) {
+					if (_prettyPrint) {
+						_stringBuilder.Append (new string ('\t', _currentLevel + 1));
+					}
+
+					_stringBuilder.Append ($"\"{kvp.Key}\":");
+					if (_prettyPrint) {
+						_stringBuilder.Append (" ");
+					}
+
+					kvp.Value.ToString (_stringBuilder, _prettyPrint, _currentLevel + 1);
+					_stringBuilder.Append (",");
+					if (_prettyPrint) {
+						_stringBuilder.Append ('\n');
+					}
+				}
+
+				if (nodes.Count > 0) {
+					_stringBuilder.Remove (_stringBuilder.Length - (_prettyPrint ? 2 : 1), 1);
+				}
+
+				if (_prettyPrint) {
+					_stringBuilder.Append (new string ('\t', _currentLevel));
+				}
+
+				_stringBuilder.Append ("}");
+			}
+
+		}
+		
+#endregion
+
 	}
 }
