Index: binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs	(revision 142)
+++ binary-improvements/7dtd-server-fixes/src/MapRendering/Constants.cs	(revision 143)
@@ -7,5 +7,7 @@
 		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 string MAP_DIRECTORY = string.Empty;
Index: binary-improvements/7dtd-server-fixes/src/MapRendering/MapRenderBlockBuffer.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/MapRendering/MapRenderBlockBuffer.cs	(revision 142)
+++ binary-improvements/7dtd-server-fixes/src/MapRendering/MapRenderBlockBuffer.cs	(revision 143)
@@ -29,6 +29,7 @@
 		}
 
-		public void LoadBlock (Vector2i block)
+		public bool LoadBlock (Vector2i block)
 		{
+			bool res = false;
 			Monitor.Enter (blockMap);
 			try {
@@ -37,4 +38,5 @@
 				Directory.CreateDirectory (folder);
 				if (!fileName.Equals (currentBlockMap)) {
+					res = true;
 					SaveBlock();
 					loadTextureFromFile (fileName);
@@ -44,4 +46,5 @@
 				Monitor.Exit (blockMap);
 			}
+			return res;
 		}
 
Index: binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs
===================================================================
--- binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs	(revision 142)
+++ binary-improvements/7dtd-server-fixes/src/MapRendering/MapRendering.cs	(revision 143)
@@ -20,11 +20,10 @@
 		}
 
-		private RegionFileManager rfm;
-		private Texture2D fullMapTexture = null;
 		private MapRenderBlockBuffer[] zoomLevelBuffers = new MapRenderBlockBuffer[Constants.ZOOMLEVELS];
-		private Color[] chunkColors = new Color[Constants.MAP_CHUNK_SIZE * Constants.MAP_CHUNK_SIZE];
+		private Dictionary<Vector2i, Color[]> dirtyChunks = new Dictionary<Vector2i, Color[]> ();
 		private System.Timers.Timer chunkSaveTimer = new System.Timers.Timer (500);
 		private bool renderingFullMap = false;
 		public static bool renderingEnabled = true;
+		private MicroStopwatch msw = new MicroStopwatch ();
 
 		private MapRendering ()
@@ -37,5 +36,5 @@
 
 			chunkSaveTimer.AutoReset = false;
-			chunkSaveTimer.Elapsed += new System.Timers.ElapsedEventHandler (SaveAllBlockMaps);
+			chunkSaveTimer.Elapsed += new System.Timers.ElapsedEventHandler (RenderDirtyChunks);
 		}
 
@@ -47,10 +46,24 @@
 					try {
 						if (!Instance.renderingFullMap) {
-							Chunk c = (Chunk)o;
-							Vector3i cPos = c.GetWorldPos ();
-							Vector2i cPos2 = new Vector2i (cPos.x / Constants.MAP_CHUNK_SIZE, cPos.z / Constants.MAP_CHUNK_SIZE);
-							Instance.RenderChunk (c, cPos2);
-							Instance.chunkSaveTimer.Stop ();
-							Instance.chunkSaveTimer.Start ();
+							Monitor.Enter (Instance.zoomLevelBuffers);
+							try {
+								Chunk c = (Chunk)o;
+								Vector3i cPos = c.GetWorldPos ();
+								Vector2i cPos2 = new Vector2i (cPos.x / Constants.MAP_CHUNK_SIZE, cPos.z / Constants.MAP_CHUNK_SIZE);
+
+								ushort[] mapColors = c.GetMapColors ();
+								if (mapColors != null) {
+									Color[] realColors = new Color[Constants.MAP_CHUNK_SIZE * Constants.MAP_CHUNK_SIZE];
+									for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
+										realColors [i_colors] = shortColorToColor (mapColors [i_colors]);
+									}
+									Instance.dirtyChunks [cPos2] = realColors;
+									Log.Out ("Add Dirty: " + cPos2);
+									Instance.chunkSaveTimer.Stop ();
+									Instance.chunkSaveTimer.Start ();
+								}
+							} finally {
+								Monitor.Exit (Instance.zoomLevelBuffers);
+							}
 						}
 					} catch (Exception e) {
@@ -66,5 +79,6 @@
 
 			string regionSaveDir = StaticDirectories.GetSaveGameRegionDir ();
-			rfm = new RegionFileManager (regionSaveDir, regionSaveDir, 1, false);
+			RegionFileManager rfm = new RegionFileManager (regionSaveDir, regionSaveDir, 0, false);
+			Texture2D fullMapTexture = null;
 
 			if (Directory.Exists (Constants.MAP_DIRECTORY))
@@ -76,5 +90,5 @@
 			Vector2i minPos, maxPos;
 			int widthChunks, heightChunks, widthPix, heightPix;
-			getWorldExtent (out minChunk, out maxChunk, out minPos, out maxPos, out widthChunks, out heightChunks, out widthPix, out heightPix);
+			getWorldExtent (rfm, out minChunk, out maxChunk, out minPos, out maxPos, out widthChunks, out heightChunks, out widthPix, out heightPix);
 
 			Log.Out (String.Format ("RenderMap: min: {0}, max: {1}, minPos: {2}, maxPos: {3}, w/h: {4}/{5}, wP/hP: {6}/{7}",
@@ -88,18 +102,43 @@
 				fullMapTexture = new Texture2D (widthPix, heightPix);
 
-			Vector2i curFullMapPos;
-			Vector2i curChunkPos;
-			for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
-				for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
-					curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
-					curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
-
-					RenderChunk (curChunkPos, curFullMapPos);
+			Monitor.Enter (Instance.zoomLevelBuffers);
+			try {
+				Vector2i curFullMapPos;
+				Vector2i curChunkPos;
+				for (curFullMapPos.x = 0; curFullMapPos.x < widthPix; curFullMapPos.x += Constants.MAP_CHUNK_SIZE) {
+					for (curFullMapPos.y = 0; curFullMapPos.y < heightPix; curFullMapPos.y += Constants.MAP_CHUNK_SIZE) {
+						curChunkPos.x = (curFullMapPos.x / Constants.MAP_CHUNK_SIZE) + minChunk.x;
+						curChunkPos.y = (curFullMapPos.y / Constants.MAP_CHUNK_SIZE) + minChunk.y;
+
+						try {
+							long chunkKey = WorldChunkCache.MakeChunkKey (curChunkPos.x, curChunkPos.y);
+							if (rfm.ContainsChunkSync (chunkKey)) {
+								Chunk c = rfm.GetChunkSync (chunkKey);
+								ushort[] mapColors = c.GetMapColors ();
+								if (mapColors != null) {
+									Color[] realColors = new Color[Constants.MAP_CHUNK_SIZE * Constants.MAP_CHUNK_SIZE];
+									for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
+										realColors [i_colors] = shortColorToColor (mapColors [i_colors]);
+									}
+									dirtyChunks [curChunkPos] = realColors;
+									if (fullMapTexture != null)
+										fullMapTexture.SetPixels (curFullMapPos.x, curFullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, realColors);
+								}
+							}
+						} catch (Exception e) {
+							Log.Out ("Exception: " + e);
+						}
+					}
+					Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
 				}
-				Log.Out (String.Format ("RenderMap: {0}/{1} ({2}%)", curFullMapPos.x, widthPix, (int)((float)curFullMapPos.x / widthPix * 100)));
-			}
-			SaveAllBlockMaps (null, null);
-
-			rfm = null;
+			} finally {
+				Monitor.Exit (Instance.zoomLevelBuffers);
+			}
+			int totalDirtyCount = dirtyChunks.Count;
+			Log.Out (String.Format ("Rendering chunks: {0}/{1} ({2}%)", totalDirtyCount - dirtyChunks.Count, totalDirtyCount, (int)((float)(totalDirtyCount - dirtyChunks.Count) / totalDirtyCount * 100)));
+			while (dirtyChunks.Count > 0) {
+				RenderDirtyChunks (null, null);
+				Log.Out (String.Format ("Rendering chunks: {0}/{1} ({2}%)", totalDirtyCount - dirtyChunks.Count, totalDirtyCount, (int)((float)(totalDirtyCount - dirtyChunks.Count) / totalDirtyCount * 100)));
+			}
 
 			if (fullMapTexture != null) {
@@ -116,55 +155,54 @@
 		}
 
-		private int saveCount = 0;
-		private long renderCount = 0;
-
 		private void SaveAllBlockMaps (object source, System.Timers.ElapsedEventArgs e)
+		{
+			for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
+				zoomLevelBuffers [i].SaveBlock ();
+			}
+		}
+
+		private void RenderDirtyChunks (object source, System.Timers.ElapsedEventArgs e)
 		{
 			Monitor.Enter (zoomLevelBuffers);
 			try {
-				Log.Out ("------- SaveAllBlockMaps " + ++saveCount + " - " + renderCount);
-				for (int i = 0; i < Constants.ZOOMLEVELS; i++) {
-					zoomLevelBuffers [i].SaveBlock ();
-				}
-			} finally {
-				Monitor.Exit (zoomLevelBuffers);
-			}
-		}
-
-		private bool RenderChunk (Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
-		{
-			long chunkKey = WorldChunkCache.MakeChunkKey (chunkPos.x, chunkPos.y);
-			if (rfm.ContainsChunkSync (chunkKey)) {
-				Chunk chunk = rfm.GetChunkSync (chunkKey);
-				return RenderChunk (chunk, chunkPos, fullMapPos);
-			}
-			return false;
-		}
-
-		private bool RenderChunk (Chunk chunk, Vector2i chunkPos, Vector2i fullMapPos = default(Vector2i))
-		{
-			Monitor.Enter (zoomLevelBuffers);
-			try {
-				renderCount++;
-				ushort[] mapColors = chunk.GetMapColors ();
-				if (mapColors != null) {
+				msw.ResetAndRestart ();
+
+				if (dirtyChunks.Count > 0) {
+					List<Vector2i> keys = new List<Vector2i> (dirtyChunks.Keys);
+					List<Vector2i> chunksDone = new List<Vector2i> ();
+
+					Vector2i chunkPos = keys [0];
+					chunksDone.Add (chunkPos);
+
+					//Log.Out ("Start Dirty: " + chunkPos);
+
 					Vector2i block, blockOffset;
 					getBlockNumber (chunkPos, out block, out blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
 
-					for (int i_colors = 0; i_colors < mapColors.Length; i_colors++) {
-						chunkColors [i_colors] = shortColorToColor (mapColors [i_colors]);
+					zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
+
+					Vector2i v_block, v_blockOffset;
+					foreach (Vector2i v in keys) {
+						getBlockNumber (v, out v_block, out v_blockOffset, Constants.MAP_BLOCK_TO_CHUNK_DIV, Constants.MAP_CHUNK_SIZE);
+						if (v_block.Equals (block)) {
+							//Log.Out ("Dirty: " + v + " render: true");
+							chunksDone.Add (v);
+							zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (v_blockOffset, Constants.MAP_CHUNK_SIZE, dirtyChunks [v]);
+						} else {
+							//Log.Out ("Dirty: " + v + " render: false");
+						}
 					}
 
-					zoomLevelBuffers [Constants.ZOOMLEVELS - 1].LoadBlock (block);
-					zoomLevelBuffers [Constants.ZOOMLEVELS - 1].SetPart (blockOffset, Constants.MAP_CHUNK_SIZE, chunkColors);
-
-					if (renderingFullMap && fullMapTexture != null)
-						fullMapTexture.SetPixels (fullMapPos.x, fullMapPos.y, Constants.MAP_CHUNK_SIZE, Constants.MAP_CHUNK_SIZE, chunkColors);
+					foreach (Vector2i v in chunksDone)
+						dirtyChunks.Remove (v);
 
 					RenderZoomLevel (Constants.ZOOMLEVELS - 1, block);
 
-					return true;
+					SaveAllBlockMaps (null, null);
 				}
-				return false;
+
+				if (e != null)
+				if (dirtyChunks.Count > 0)
+					Instance.chunkSaveTimer.Start ();
 			} finally {
 				Monitor.Exit (zoomLevelBuffers);
@@ -193,5 +231,5 @@
 		}
 
-		private void getWorldExtent (out Vector2i minChunk, out Vector2i maxChunk,
+		private void getWorldExtent (RegionFileManager rfm, out Vector2i minChunk, out Vector2i maxChunk,
 	                                    out Vector2i minPos, out Vector2i maxPos,
 	                                    out int widthChunks, out int heightChunks,
@@ -236,10 +274,5 @@
 		}
 
-		private Color32 shortColorToColor32 (ushort col)
-		{
-			return new Color32 ((byte)((float)(col >> 10 & 31) / 31f * 255f), (byte)((float)(col >> 5 & 31) / 31f * 255f), (byte)((float)(col & 31) / 31f * 255f), 255);
-		}
-
-		private Color shortColorToColor (ushort col)
+		private static Color shortColorToColor (ushort col)
 		{
 			return new Color (((float)(col >> 10 & 31) / 31f), ((float)(col >> 5 & 31) / 31f), ((float)(col & 31) / 31f), 255);
