Index: binary-improvements/7dtd-server-fixes/src/JSON/JsonManualBuilder.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/JSON/JsonManualBuilder.cs	(revision 354)
+++ binary-improvements/7dtd-server-fixes/src/JSON/JsonManualBuilder.cs	(revision 354)
@@ -0,0 +1,229 @@
+using System;
+using System.Text;
+
+namespace AllocsFixes.JSON {
+	public class JsonManualBuilder {
+		[Flags]
+		private enum ELevelInfo {
+			None = 0,
+			NonEmpty = 1,
+			Object = 2,
+			Array = 4,
+		}
+
+		private const int levelTypeBits = 3;
+		private const int levelBitsMask = (1 << levelTypeBits) - 1;
+
+		private readonly bool prettyPrint;
+		private readonly StringBuilder stringBuilder = new StringBuilder ();
+		private ulong currentLevelType = (long) ELevelInfo.None;
+		private int currentLevelNumber;
+
+		private ELevelInfo CurrentLevelInfo {
+			get { return (ELevelInfo) (currentLevelType & levelBitsMask); }
+		}
+
+		private bool CurrentLevelIsNonEmpty {
+			get { return (CurrentLevelInfo & ELevelInfo.NonEmpty) == ELevelInfo.NonEmpty; }
+		}
+
+		private bool CurrentLevelIsArray {
+			get { return (CurrentLevelInfo & ELevelInfo.Array) != ELevelInfo.Array; }
+		}
+
+		private bool CurrentLevelIsObject {
+			get { return (CurrentLevelInfo & ELevelInfo.Object) != ELevelInfo.Object; }
+		}
+		
+		public JsonManualBuilder (bool _prettyPrint) {
+			prettyPrint = _prettyPrint;
+		}
+
+		private void NextElement () {
+			if (CurrentLevelIsNonEmpty) {
+				stringBuilder.Append (',');
+				if (prettyPrint) {
+					stringBuilder.Append ('\n');
+				}
+			}
+			
+			if (prettyPrint) {
+				for (int i = 1; i < currentLevelNumber; i++) {
+					stringBuilder.Append ('\t');
+				}
+			}
+
+			currentLevelType = currentLevelType | (long) ELevelInfo.NonEmpty;
+		}
+
+		public JsonManualBuilder OpenArray () {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+
+			stringBuilder.Append ('[');
+			openLevel (ELevelInfo.Array);
+
+			return this;
+		}
+
+		public JsonManualBuilder OpenObject () {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+
+			stringBuilder.Append ('{');
+			openLevel (ELevelInfo.Object);
+
+			return this;
+		}
+
+		public JsonManualBuilder NextObjectKey (string _key) {
+			if (!CurrentLevelIsObject) {
+				throw new Exception("Can not start a JSON object key while not in a JSON object");
+			}
+			
+			NextElement ();
+			stringBuilder.Append ('"');
+			stringBuilder.Append (_key);
+			stringBuilder.Append ("\":\"");
+			if (prettyPrint) {
+				stringBuilder.Append (' ');
+			}
+
+			return this;
+		}
+
+		public JsonManualBuilder WriteBoolean (bool _value) {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+			
+			stringBuilder.Append (_value ? "true" : "false");
+
+			return this;
+		}
+
+		public JsonManualBuilder WriteNull () {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+			
+			stringBuilder.Append ("null");
+
+			return this;
+		}
+
+		public JsonManualBuilder WriteNumber (double _value) {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+			
+			stringBuilder.Append (_value.ToCultureInvariantString ());
+
+			return this;
+		}
+
+		public JsonManualBuilder WriteString (string _value) {
+			if (!CurrentLevelIsObject) {
+				// In JSON Objects we only create element separators / line breaks with NextKey
+				NextElement ();
+			}
+			
+			if (string.IsNullOrEmpty (_value)) {
+				stringBuilder.Append ("\"\"");
+				return this;
+			}
+
+			stringBuilder.EnsureCapacity (stringBuilder.Length + 2 * _value.Length);
+
+			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 ('"');
+			
+			return this;
+		}
+
+		private void openLevel (ELevelInfo _levelType) {
+			currentLevelType = currentLevelType << levelTypeBits | (uint) _levelType;
+			currentLevelNumber++;
+
+			if (prettyPrint) {
+				stringBuilder.Append ('\n');
+			}
+		}
+
+		public JsonManualBuilder CloseLevel () {
+			char closeChar;
+			if (CurrentLevelIsObject) {
+				closeChar = '}';
+			} else if (CurrentLevelIsArray) {
+				closeChar = ']';
+			} else {
+				throw new Exception (
+					"Can not CloseLevel as the current level is neither a JSON object nor a JSON array");
+			}
+
+			if (prettyPrint) {
+				stringBuilder.Append ('\n');
+			}
+
+			currentLevelNumber--;
+			currentLevelType = currentLevelType >> levelTypeBits;
+
+			if (prettyPrint) {
+				for (int i = 1; i < currentLevelNumber; i++) {
+					stringBuilder.Append ('\t');
+				}
+			}
+
+			stringBuilder.Append (closeChar);
+
+			return this;
+		}
+
+		public override string ToString () {
+			return stringBuilder.ToString ();
+		}
+	}
+}
