Index: binary-improvements/7dtd-server-fixes/7dtd-server-fixes.csproj
===================================================================
--- binary-improvements/7dtd-server-fixes/7dtd-server-fixes.csproj	(revision 186)
+++ binary-improvements/7dtd-server-fixes/7dtd-server-fixes.csproj	(revision 187)
@@ -120,4 +120,7 @@
     <Compile Include="src\NetConnections\Servers\Web\API\GetLandClaims.cs" />
     <Compile Include="src\BlockingQueue.cs" />
+    <Compile Include="src\JSON\Parser.cs" />
+    <Compile Include="src\JSON\JSONNull.cs" />
+    <Compile Include="src\JSON\MalformedJSONException.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
@@ -132,4 +135,5 @@
     <Folder Include="src\PersistentData\" />
     <Folder Include="src\NetConnections\Servers\Web\API\" />
+    <Folder Include="src\JSON\Parser\" />
   </ItemGroup>
 </Project>
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONArray.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONArray.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONArray.cs	(revision 187)
@@ -9,20 +9,67 @@
 		private List<JSONNode> nodes = new List<JSONNode> ();
 
+		public JSONNode this [int index] {
+			get { return nodes [index]; }
+			set { nodes [index] = value; }
+		}
+
+		public int Count {
+			get { return nodes.Count; }
+		}
+
 		public void Add (JSONNode node)
 		{
-			nodes.Add(node);
+			nodes.Add (node);
 		}
 
-		public override string ToString ()
+		public override string ToString (bool prettyPrint = false, int currentLevel = 0)
 		{
 			StringBuilder sb = new StringBuilder ("[");
+			if (prettyPrint)
+				sb.Append ('\n');
 			foreach (JSONNode n in nodes) {
-				sb.Append (n.ToString ());
+				if (prettyPrint)
+					sb.Append (new String ('\t', currentLevel + 1));
+				sb.Append (n.ToString (prettyPrint, currentLevel + 1));
 				sb.Append (",");
+				if (prettyPrint)
+					sb.Append ('\n');
 			}
 			if (sb.Length > 1)
-				sb.Remove (sb.Length - 1, 1);
+				sb.Remove (sb.Length - (prettyPrint ? 2 : 1), 1);
+			if (prettyPrint)
+				sb.Append (new String ('\t', currentLevel));
 			sb.Append ("]");
 			return sb.ToString ();
+		}
+
+		public static JSONArray Parse (string json, ref int offset)
+		{
+			//Log.Out ("ParseArray enter (" + offset + ")");
+			JSONArray arr = new JSONArray ();
+
+			bool nextElemAllowed = true;
+			offset++;
+			while (true) {
+				Parser.SkipWhitespace (json, ref offset);
+
+				switch (json [offset]) {
+					case ',':
+						if (!nextElemAllowed) {
+							nextElemAllowed = true;
+							offset++;
+						} else
+							throw new MalformedJSONException ("Could not parse array, found a comma without a value first");
+						break;
+					case ']':
+						offset++;
+						//Log.Out ("JSON:Parsed Array: " + arr.ToString ());
+						return arr;
+					default:
+						arr.Add (Parser.ParseInternal (json, ref offset));
+						nextElemAllowed = false;
+						break;
+				}
+			}
 		}
 
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONBoolean.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONBoolean.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONBoolean.cs	(revision 187)
@@ -12,7 +12,29 @@
 		}
 
-		public override string ToString ()
+		public bool GetBool ()
+		{
+			return value;
+		}
+
+		public override string ToString (bool prettyPrint = false, int currentLevel = 0)
 		{
 			return value.ToString (System.Globalization.CultureInfo.InvariantCulture).ToLower ();
+		}
+
+		public static JSONBoolean Parse (string json, ref int offset)
+		{
+			//Log.Out ("ParseBool enter (" + offset + ")");
+
+			if (json.Substring (offset, 4).Equals ("true")) {
+				//Log.Out ("JSON:Parsed Bool: true");
+				offset += 4;
+				return new JSONBoolean (true);
+			} else if (json.Substring (offset, 5).Equals ("false")) {
+				//Log.Out ("JSON:Parsed Bool: false");
+				offset += 5;
+				return new JSONBoolean (false);
+			} else {
+				throw new MalformedJSONException ("No valid boolean found");
+			}
 		}
 
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONNode.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONNode.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONNode.cs	(revision 187)
@@ -5,5 +5,5 @@
 	public abstract class JSONNode
 	{
-		public abstract override string ToString();
+		public abstract string ToString(bool prettyPrint = false, int currentLevel = 0);
 	}
 }
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONNumber.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONNumber.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONNumber.cs	(revision 187)
@@ -1,3 +1,4 @@
 using System;
+using System.Text;
 
 namespace AllocsFixes.JSON
@@ -5,14 +6,103 @@
 	public class JSONNumber : JSONNode
 	{
-		private float value;
+		private double value;
 
-		public JSONNumber (float value)
+		public JSONNumber (double value)
 		{
 			this.value = value;
 		}
 
-		public override string ToString ()
+		public double GetDouble ()
+		{
+			return value;
+		}
+
+		public int GetInt ()
+		{
+			return (int)Math.Round(value);
+		}
+
+		public override string ToString (bool prettyPrint = false, int currentLevel = 0)
 		{
 			return value.ToString (System.Globalization.CultureInfo.InvariantCulture);
+		}
+
+		public static JSONNumber Parse (string json, ref int offset)
+		{
+			//Log.Out ("ParseNumber enter (" + offset + ")");
+			StringBuilder sbNum = new StringBuilder ();
+			StringBuilder sbExp = null;
+			bool hasDec = false;
+			bool hasExp = false;
+			while (offset < json.Length) {
+				if (json [offset] >= '0' && json [offset] <= '9') {
+					if (hasExp)
+						sbExp.Append (json [offset]);
+					else
+						sbNum.Append (json [offset]);
+				} else if (json [offset] == '.') {
+					if (hasExp) {
+						throw new MalformedJSONException ("Decimal separator in exponent");
+					} else {
+						if (hasDec)
+							throw new MalformedJSONException ("Multiple decimal separators in number found");
+						else if (sbNum.Length == 0) {
+							throw new MalformedJSONException ("No leading digits before decimal separator found");
+						} else {
+							sbNum.Append ('.');
+							hasDec = true;
+						}
+					}
+				} else	if (json [offset] == '-') {
+					if (hasExp) {
+						if (sbExp.Length > 0)
+							throw new MalformedJSONException ("Negative sign in exponent after digits");
+						else
+							sbExp.Append (json [offset]);
+					} else {
+						if (sbNum.Length > 0)
+							throw new MalformedJSONException ("Negative sign in mantissa after digits");
+						else
+							sbNum.Append (json [offset]);
+					}
+				} else if (json [offset] == 'e' || json [offset] == 'E') {
+					if (hasExp)
+						throw new MalformedJSONException ("Multiple exponential markers in number found");
+					else if (sbNum.Length == 0) {
+						throw new MalformedJSONException ("No leading digits before exponential marker found");
+					} else {
+						sbExp = new StringBuilder ();
+						hasExp = true;
+					}
+				} else if (json [offset] == '+') {
+					if (hasExp) {
+						if (sbExp.Length > 0)
+							throw new MalformedJSONException ("Positive sign in exponent after digits");
+						else
+							sbExp.Append (json [offset]);
+					} else {
+						throw new MalformedJSONException ("Positive sign in mantissa found");
+					}
+				} else {
+					double number;
+					if (!double.TryParse (sbNum.ToString (), out number)) {
+						throw new MalformedJSONException ("Mantissa is not a valid decimal (\"" + sbNum.ToString () + "\")");
+					}
+
+					if (hasExp) {
+						int exp;
+						if (!int.TryParse (sbExp.ToString (), out exp)) {
+							throw new MalformedJSONException ("Exponent is not a valid integer (\"" + sbExp.ToString () + "\")");
+						}
+
+						number = number * Math.Pow (10, exp);
+					}
+
+					//Log.Out ("JSON:Parsed Number: " + number.ToString ());
+					return new JSONNumber (number);
+				}
+				offset++;
+			}
+			throw new MalformedJSONException ("End of JSON reached before parsing number finished");
 		}
 
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONObject.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONObject.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONObject.cs	(revision 187)
@@ -9,4 +9,22 @@
 		private Dictionary<string, JSONNode> nodes = new Dictionary<string, JSONNode> ();
 
+		public JSONNode this [string name] {
+			get { return nodes [name]; }
+			set { nodes [name] = value; }
+		}
+
+		public int Count {
+			get { return nodes.Count; }
+		}
+
+		public List<string> Keys {
+			get { return new List<string> (nodes.Keys); }
+		}
+
+		public bool ContainsKey (string name)
+		{
+			return nodes.ContainsKey (name);
+		}
+
 		public void Add (string name, JSONNode node)
 		{
@@ -14,16 +32,66 @@
 		}
 
-		public override string ToString ()
+		public override string ToString (bool prettyPrint = false, int currentLevel = 0)
 		{
 			StringBuilder sb = new StringBuilder ("{");
+			if (prettyPrint)
+				sb.Append ('\n');
 			foreach (KeyValuePair<string, JSONNode> kvp in nodes) {
+				if (prettyPrint)
+					sb.Append (new String ('\t', currentLevel + 1));
 				sb.Append (String.Format ("\"{0}\":", kvp.Key));
-				sb.Append (kvp.Value.ToString ());
+				if (prettyPrint)
+					sb.Append (" ");
+				sb.Append (kvp.Value.ToString (prettyPrint, currentLevel + 1));
 				sb.Append (",");
+				if (prettyPrint)
+					sb.Append ('\n');
 			}
 			if (sb.Length > 1)
-				sb.Remove (sb.Length - 1, 1);
+				sb.Remove (sb.Length - (prettyPrint ? 2 : 1), 1);
+			if (prettyPrint)
+				sb.Append (new String ('\t', currentLevel));
 			sb.Append ("}");
 			return sb.ToString ();
+		}
+
+		public static JSONObject Parse (string json, ref int offset)
+		{
+			//Log.Out ("ParseObject enter (" + offset + ")");
+			JSONObject obj = new JSONObject ();
+
+			bool nextElemAllowed = true;
+			offset++;
+			while (true) {
+				Parser.SkipWhitespace (json, ref offset);
+				switch (json [offset]) {
+					case '"':
+						if (nextElemAllowed) {
+							JSONString key = JSONString.Parse (json, ref offset);
+							Parser.SkipWhitespace (json, ref offset);
+							if (json [offset] != ':') {
+								throw new MalformedJSONException ("Could not parse object, missing colon (\":\") after key");
+							}
+							offset++;
+							JSONNode val = Parser.ParseInternal (json, ref offset);
+							obj.Add (key.GetString (), val);
+							nextElemAllowed = false;
+						} else {
+							throw new MalformedJSONException ("Could not parse object, found new key without a separating comma");
+						}
+						break;
+					case ',':
+						if (!nextElemAllowed) {
+							nextElemAllowed = true;
+							offset++;
+						} else
+							throw new MalformedJSONException ("Could not parse object, found a comma without a key/value pair first");
+						break;
+					case '}':
+						offset++;
+						//Log.Out ("JSON:Parsed Object: " + obj.ToString ());
+						return obj;
+				}
+			}
 		}
 
Index: binary-improvements/7dtd-server-fixes/src/JSON/JSONString.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JSONString.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JSONString.cs	(revision 187)
@@ -13,5 +13,10 @@
 		}
 
-		public override string ToString ()
+		public string GetString ()
+		{
+			return value;
+		}
+
+		public override string ToString (bool prettyPrint = false, int currentLevel = 0)
 		{
 			if (value == null || value.Length == 0) {
@@ -61,4 +66,53 @@
 		}
 
+		public static JSONString Parse (string json, ref int offset)
+		{
+			//Log.Out ("ParseString enter (" + offset + ")");
+			StringBuilder sb = new StringBuilder ();
+			offset++;
+			while (offset < json.Length) {
+				switch (json [offset]) {
+					case '\\':
+						offset++;
+						switch (json [offset]) {
+							case '\\':
+							case '"':
+							case '/':
+								sb.Append (json [offset]);
+								break;
+							case 'b':
+								sb.Append ('\b');
+								break;
+							case 't':
+								sb.Append ('\t');
+								break;
+							case 'n':
+								sb.Append ('\n');
+								break;
+							case 'f':
+								sb.Append ('\f');
+								break;
+							case 'r':
+								sb.Append ('\r');
+								break;
+							default:
+								sb.Append (json [offset]);
+								break;
+						}
+						offset++;
+						break;
+					case '"':
+						offset++;
+						//Log.Out ("JSON:Parsed String: " + sb.ToString ());
+						return new JSONString (sb.ToString ());
+					default:
+						sb.Append (json [offset]);
+						offset++;
+						break;
+				}
+			}
+			throw new MalformedJSONException ("End of JSON reached before parsing string finished");
+		}
+
 	}
 }
Index: binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs	(revision 187)
@@ -3,12 +3,12 @@
 namespace AllocsFixes.MapRendering
 {
-	public static class Constants
+	public class Constants
 	{
-		public const int MAP_BLOCK_SIZE = 128;
-		public const int MAP_CHUNK_SIZE = 16;
-		public const int MAP_REGION_SIZE = 512;
-		public const int MAP_BLOCK_TO_CHUNK_DIV = MAP_BLOCK_SIZE / MAP_CHUNK_SIZE;
-		public const int MAP_REGION_TO_CHUNK_DIV = MAP_REGION_SIZE / MAP_CHUNK_SIZE;
-		public const int ZOOMLEVELS = 5;
+		public static int MAP_BLOCK_SIZE = 128;
+		public static int MAP_CHUNK_SIZE = 16;
+		public static int MAP_REGION_SIZE = 512;
+		public static int MAP_BLOCK_TO_CHUNK_DIV { get { return MAP_BLOCK_SIZE / MAP_CHUNK_SIZE; } }
+		public static int MAP_REGION_TO_CHUNK_DIV { get { return MAP_REGION_SIZE / MAP_CHUNK_SIZE; } }
+		public static int ZOOMLEVELS = 5;
 		public static string MAP_DIRECTORY = string.Empty;
 	}
Index: binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs	(revision 187)
@@ -1,5 +1,7 @@
+using AllocsFixes.JSON;
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Text;
 using System.Threading;
 using UnityEngine;
@@ -20,5 +22,5 @@
 		}
 
-		private MapRenderBlockBuffer[] zoomLevelBuffers = new MapRenderBlockBuffer[Constants.ZOOMLEVELS];
+		private MapRenderBlockBuffer[] zoomLevelBuffers;
 		private Dictionary<Vector2i, Color[]> dirtyChunks = new Dictionary<Vector2i, Color[]> ();
 		private System.Timers.Timer chunkSaveTimer = new System.Timers.Timer (500);
@@ -31,4 +33,11 @@
 			Constants.MAP_DIRECTORY = StaticDirectories.GetSaveGameDir () + "/map";
 
+			if (File.Exists (Constants.MAP_DIRECTORY + "/mapinfo.json")) {
+				LoadMapInfo ();
+			} else {
+				WriteMapInfo ();
+			}
+
+			zoomLevelBuffers = new MapRenderBlockBuffer[Constants.ZOOMLEVELS];
 			for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
 				zoomLevelBuffers [i] = new MapRenderBlockBuffer (i);
@@ -100,6 +109,8 @@
 				}
 
-				if (Directory.Exists (Constants.MAP_DIRECTORY))
+				if (Directory.Exists (Constants.MAP_DIRECTORY)) {
 					Directory.Delete (Constants.MAP_DIRECTORY, true);
+				}
+				WriteMapInfo ();
 
 				renderingFullMap = true;
@@ -239,4 +250,29 @@
 		}
 
+		private void WriteMapInfo ()
+		{
+			JSONObject mapInfo = new JSONObject ();
+			mapInfo.Add ("blockSize", new JSONNumber (Constants.MAP_BLOCK_SIZE));
+			mapInfo.Add ("maxZoom", new JSONNumber (Constants.ZOOMLEVELS - 1));
+
+			Directory.CreateDirectory (Constants.MAP_DIRECTORY);
+			File.WriteAllText (Constants.MAP_DIRECTORY + "/mapinfo.json", mapInfo.ToString (), Encoding.UTF8);
+		}
+
+		private void LoadMapInfo ()
+		{
+			if (File.Exists (Constants.MAP_DIRECTORY + "/mapinfo.json")) {
+				string json = File.ReadAllText (Constants.MAP_DIRECTORY + "/mapinfo.json", Encoding.UTF8);
+				JSONNode node = Parser.Parse (json);
+				if (node is JSONObject) {
+					JSONObject jo = (JSONObject)node;
+					if (jo.ContainsKey ("blockSize"))
+						Constants.MAP_BLOCK_SIZE = ((JSONNumber)jo ["blockSize"]).GetInt ();
+					if (jo.ContainsKey ("maxZoom"))
+						Constants.ZOOMLEVELS = ((JSONNumber)jo ["maxZoom"]).GetInt () + 1;
+				}
+			}
+		}
+
 		private void getWorldExtent (RegionFileManager rfm, out Vector2i minChunk, out Vector2i maxChunk,
 	                                    out Vector2i minPos, out Vector2i maxPos,
Index: binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/Telnet.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/Telnet.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/Telnet.cs	(revision 187)
@@ -9,7 +9,31 @@
 	public class Telnet : IServer
 	{
+		private const int MAX_LOGIN_ATTEMPTS = 10;
+		private const int BLOCK_TIME_SECONDS = 10;
+
+		private class LoginAttempts
+		{
+			private int count = 0;
+			private DateTime lastAttempt = new DateTime (0);
+
+			public bool LogAttempt ()
+			{
+				lastAttempt = DateTime.Now;
+				count++;
+				return count < MAX_LOGIN_ATTEMPTS;
+			}
+
+			public bool IsBanned ()
+			{
+				if ((DateTime.Now - lastAttempt).TotalSeconds > BLOCK_TIME_SECONDS)
+					count = 0;
+				return count >= MAX_LOGIN_ATTEMPTS;
+			}
+		}
+
 		private TcpListener listener = null;
 		private bool authEnabled = false;
 		private List<TelnetConnection> connections = new List<TelnetConnection> ();
+		private Dictionary<int, LoginAttempts> loginAttemptsPerIP = new Dictionary<int, LoginAttempts> ();
 
 		public Telnet ()
@@ -39,6 +63,10 @@
 		}
 
-		public void FailedLogins ()
+		public bool RegisterFailedLogin (int addressHash)
 		{
+			lock (loginAttemptsPerIP) {
+				LoginAttempts la = loginAttemptsPerIP [addressHash];
+				return la.LogAttempt ();
+			}
 		}
 
@@ -46,6 +74,31 @@
 		{
 			if (listener.Server.IsBound) {
-				TelnetConnection c = new TelnetConnection (this, listener.EndAcceptTcpClient (asyncResult), authEnabled);
-				connections.Add (c);
+				TcpClient client = listener.EndAcceptTcpClient (asyncResult);
+
+				EndPoint endpoint = client.Client.RemoteEndPoint;
+				int addressHash = -1;
+				if (endpoint is IPEndPoint) {
+					addressHash = ((IPEndPoint)endpoint).Address.GetHashCode ();
+					//Log.Out ("Hash: " + endpointAddressHash);
+				} else {
+					Log.Out ("EndPoint is not an IPEndPoint but: " + endpoint.GetType ().ToString ());
+				}
+
+				lock (loginAttemptsPerIP) {
+					LoginAttempts la = null;
+					if (loginAttemptsPerIP.ContainsKey(addressHash))
+						la = loginAttemptsPerIP [addressHash];
+					if (la == null) {
+						la = new LoginAttempts ();
+						loginAttemptsPerIP [addressHash] = la;
+					}
+					if (!la.IsBanned ()) {
+						TelnetConnection con = new TelnetConnection (this, client, authEnabled);
+						connections.Add (con);
+					} else {
+						client.Close ();
+						Log.Out ("Telnet connection not accepted for too many login attempts: " + endpoint);
+					}
+				}
 				listener.BeginAcceptTcpClient (new AsyncCallback (AcceptClient), null);
 			}
Index: binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/TelnetConnection.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/TelnetConnection.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Telnet/TelnetConnection.cs	(revision 187)
@@ -15,5 +15,4 @@
 		private readonly Thread receiveThread = null;
 		private readonly Thread sendThread = null;
-		private int authTries = 0;
 		private bool authenticated = false;
 		private readonly bool authEnabled;
@@ -91,12 +90,9 @@
 									LoginMessage ();
 								} else {
-									authTries++;
-									// TODO: check if IP has more login attempts by now
-									if (authTries < 3) {
+									if (owner.RegisterFailedLogin(endpointAddressHash)) {
 										WriteLine ("Password incorrect, please enter password:");
 									} else {
 										WriteLine ("Too many failed login attempts!");
 										Thread.Sleep(100);
-										//TODO: owner.FailedLogins();
 										Close ();
 										Log.Out ("Telnet connection closed for too many login attempts: " + endpoint);
Index: binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Web/MimeType.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Web/MimeType.cs	(revision 186)
+++ binary-improvements/7dtd-server-fixes/src/NetConnections/Servers/Web/MimeType.cs	(revision 187)
@@ -209,4 +209,5 @@
         {".jpg", "image/jpeg"},
         {".js", "application/x-javascript"},
+		{".json", "application/json"},
         {".jsx", "text/jscript"},
         {".jsxbin", "text/plain"},
Index: binary-improvements/bin/Release/7dtd-server-fixes_version.txt
===================================================================
--- binary-improvements/bin/Release/7dtd-server-fixes_version.txt	(revision 186)
+++ binary-improvements/bin/Release/7dtd-server-fixes_version.txt	(revision 187)
@@ -1,1 +1,1 @@
-Version:       0.93.5365.39558
+Version:       0.93.5366.36263
