diff --git a/src/light.cpp b/src/light.cpp
index fec800874b717f20e8017ec63e7012cf089ec7a0..c0255f7fbb1b8b01b23d4aadb2841606ffd03aa8 100644
--- a/src/light.cpp
+++ b/src/light.cpp
@@ -29,6 +29,24 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 u8 light_decode_table[LIGHT_MAX+1] = 
 {
 0,
+7,
+11,
+15,
+21,
+29,
+42,
+53,
+69,
+85,
+109,
+135,
+167,
+205,
+255,
+};
+/*u8 light_decode_table[LIGHT_MAX+1] = 
+{
+0,
 6,
 8,
 11,
@@ -43,7 +61,7 @@ u8 light_decode_table[LIGHT_MAX+1] =
 143,
 191,
 255,
-};
+};*/
 /*u8 light_decode_table[LIGHT_MAX+1] = 
 {
 0,
diff --git a/src/main.cpp b/src/main.cpp
index ef720789427db392f0830f81b9183ec26a4a0f75..e6b55e1bf15e20f2a0930e6e727d29aeeff96a46 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -348,6 +348,8 @@ Doing now:
 * Add some kind of erosion and other stuff that now is possible
 * Make client to fetch stuff asynchronously
   - Needs method SyncProcessData
+* What is the problem with the server constantly saving one or a few
+  blocks? List the first saved block, maybe it explains.
 
 ======================================================================
 
diff --git a/src/map.cpp b/src/map.cpp
index 7c0d19dbb5dbe834dd5068bf0e42e90975b6a69f..80210ceadcc3836b2abab7622e502c305bb9d907 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -2145,7 +2145,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 	
 	TimeTaker timer("generateChunkRaw()");
 	
-	// The distance how far into the neighbors the generator is allowed to go
+	// The distance how far into the neighbors the generator is allowed to go.
 	s16 max_spread_amount_sectors = 2;
 	assert(max_spread_amount_sectors <= m_chunksize);
 	s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
@@ -2190,6 +2190,12 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 			*(u32)sectorpos_base_size*MAP_BLOCKSIZE
 			*(u32)h_blocks*MAP_BLOCKSIZE;
 		
+	/*
+		The limiting edges of the lighting update, inclusive.
+	*/
+	s16 lighting_min_d = 0-max_spread_amount;
+	s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+
 	/*
 		Create the whole area of this and the neighboring chunks
 	*/
@@ -2226,6 +2232,12 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 			}
 		}
 	}
+	
+	/*
+		Clear all light emitted 
+	*/
+
+	core::map<v3s16, u8> unlight_from;
 
 	/*
 		Now we have a big empty area.
@@ -2310,7 +2322,8 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 	*/
 
 	u32 stone_obstacle_amount =
-			myrand_range(0, myrand_range(20, myrand_range(80,150)));
+			myrand_range(0, myrand_range(20, 150));
+			//myrand_range(0, myrand_range(20, myrand_range(80,150)));
 
 	/*
 		Loop this part, it will make stuff look older and newer nicely
@@ -2346,9 +2359,19 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 			myrand_range(0, maxheight_randomized),
 			myrand_range(5, stone_obstacle_max_size)
 		);
-		v2s16 ob_place(
+		/*v2s16 ob_place(
 			myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1),
 			myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1)
+		);*/
+		/*
+			Limit by 1 to not obstruct sunlight at borders, because
+			it would fuck up lighting in some places because we're
+			leaving out removing light from the borders for optimization
+			and simplicity.
+		*/
+		v2s16 ob_place(
+			myrand_range(1, sectorpos_base_size*MAP_BLOCKSIZE-1-1),
+			myrand_range(1, sectorpos_base_size*MAP_BLOCKSIZE-1-1)
 		);
 		
 		// Minimum space left on top of the obstacle
@@ -2450,20 +2473,20 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 		Make dungeons
 	*/
 	u32 dungeons_count = relative_volume / 200000;
-	u32 bruises_count = relative_volume * stone_surface_max_y / 15000000;
+	u32 bruises_count = relative_volume * stone_surface_max_y / 200000 / 50;
 	for(u32 jj=0; jj<dungeons_count+bruises_count; jj++)
 	{
-		s16 min_tunnel_diameter = 1;
-		s16 max_tunnel_diameter = 5;
-		u16 tunnel_routepoints = 10;
+		s16 min_tunnel_diameter = 3;
+		s16 max_tunnel_diameter = 6;
+		u16 tunnel_routepoints = 15;
 		
 		bool bruise_surface = (jj < bruises_count);
 
 		if(bruise_surface)
 		{
 			min_tunnel_diameter = 5;
-			max_tunnel_diameter = myrand_range(8, 20);
-			tunnel_routepoints = 7;
+			max_tunnel_diameter = myrand_range(10, 20);
+			tunnel_routepoints = 3;
 		}
 
 		// Allowed route area size in nodes
@@ -2801,11 +2824,25 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 	for(s16 k=0; k<4; k++)
 	{
 
-	for(s16 x=0-max_spread_amount+1;
+	/*for(s16 x=0-max_spread_amount+1;
 			x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
 			x++)
 	for(s16 z=0-max_spread_amount+1;
 			z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+			z++)*/
+	
+	/*
+		Firstly, limit area by 1 because mud is flown into neighbors.
+		Secondly, limit by 1 more to not obstruct sunlight at borders,
+		because it would fuck up lighting in some places because we're
+		leaving out removing light from the borders for optimization
+		and simplicity.
+	*/
+	for(s16 x=0-max_spread_amount+2;
+			x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
+			x++)
+	for(s16 z=0-max_spread_amount+2;
+			z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
 			z++)
 	{
 		// Node position in 2d
@@ -3070,13 +3107,76 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 	// 750ms @cs=8, can't optimize more
 	//TimeTaker timer1("initial lighting");
 
+#if 0
+	/*
+		Go through the edges and add all nodes that have light to light_sources
+	*/
+	
+	// Four edges
+	for(s16 i=0; i<4; i++)
+	// Edge length
+	for(s16 j=lighting_min_d;
+			j<=lighting_max_d;
+			j++)
+	{
+		s16 x;
+		s16 z;
+		// +-X
+		if(i == 0 || i == 1)
+		{
+			x = (i==0) ? lighting_min_d : lighting_max_d;
+			if(i == 0)
+				z = lighting_min_d;
+			else
+				z = lighting_max_d;
+		}
+		// +-Z
+		else
+		{
+			z = (i==0) ? lighting_min_d : lighting_max_d;
+			if(i == 0)
+				x = lighting_min_d;
+			else
+				x = lighting_max_d;
+		}
+		
+		// Node position in 2d
+		v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
+
+		{
+			v3s16 em = vmanip.m_area.getExtent();
+			s16 y_start = y_nodes_max;
+			u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
+			for(s16 y=y_start; y>=y_nodes_min; y--)
+			{
+				MapNode *n = &vmanip.m_data[i];
+				if(n->getLight(LIGHTBANK_DAY) != 0)
+				{
+					light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
+				}
+			}
+		}
+	}
+#endif
+
 	/*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
 	for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
-	for(s16 x=0-max_spread_amount+1;
+	/*for(s16 x=0-max_spread_amount+1;
 			x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
 			x++)
 	for(s16 z=0-max_spread_amount+1;
 			z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
+			z++)*/
+	
+	/*
+		This has to be 1 smaller than the actual area, because
+		neighboring nodes are checked.
+	*/
+	for(s16 x=lighting_min_d+1;
+			x<=lighting_max_d-1;
+			x++)
+	for(s16 z=lighting_min_d+1;
+			z<=lighting_max_d-1;
 			z++)
 	{
 		// Node position in 2d
@@ -3135,7 +3235,7 @@ MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
 						}
 					}
 				}
-
+				
 				n->setLight(LIGHTBANK_DAY, light);
 				n->setLight(LIGHTBANK_NIGHT, 0);
 				
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index f5ca0ca9ee1169076e8588168a0421b23d70541a..c5b252d8ee0fb100b83784015c941b0b4513d02e 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -140,7 +140,8 @@ void init_mapnode(IIrrlichtWrapper *irrlicht)
 	
 	i = CONTENT_WATERSOURCE;
 	f = &g_content_features[i];
-	f->setTexture(0, irrlicht->getTextureId("water.png"), WATER_ALPHA);
+	//f->setTexture(0, irrlicht->getTextureId("water.png"), WATER_ALPHA);
+	f->setAllTextures(irrlicht->getTextureId("water.png"), WATER_ALPHA);
 	f->setInventoryTexture(irrlicht->getTextureId("water.png"));
 	f->param_type = CPT_LIGHT;
 	f->light_propagates = true;
diff --git a/src/server.cpp b/src/server.cpp
index d71a6c05317f30e16b2e4e8c5ba0997bf45c161c..abf48df9aa2c1c721ce0fa3ba2a1e599c7d41455 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -510,9 +510,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
 			}
 			else
 			{
-				// Limit the generating area vertically to 2/3
+				/*// Limit the generating area vertically to 2/3
 				if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
-					generate = false;
+					generate = false;*/
+
+				// Limit the send area vertically to 2/3
+				if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
+					continue;
 			}
 
 #if 0