From f48882213e31c47660cf0c87df1e04e51db9b50a Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Mon, 4 Jun 2012 22:34:22 +0300
Subject: Add ignore_world_load_errors configuration option and provide better
 error messages

---
 src/defaultsettings.cpp |  1 +
 src/map.cpp             | 20 +++++++++++++-------
 src/mapblock.cpp        | 25 +++++++++++++++++++++++--
 src/server.cpp          | 23 +++++++++++++++++++++--
 4 files changed, 58 insertions(+), 11 deletions(-)

(limited to 'src')

diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index ab6866cec..d0ed22c2d 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -137,5 +137,6 @@ void set_default_settings(Settings *settings)
 	settings->setDefault("server_map_save_interval", "5.3");
 	settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
 	settings->setDefault("dedicated_server_step", "0.05");
+	settings->setDefault("ignore_world_load_errors", "false");
 }
 
diff --git a/src/map.cpp b/src/map.cpp
index 10dba3de9..647b9fe15 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -3378,14 +3378,20 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
 	}
 	catch(SerializationError &e)
 	{
-		infostream<<"WARNING: Invalid block data in database "
-				<<" (SerializationError). "
-				<<"what()="<<e.what()
-				<<std::endl;
-				//" Ignoring. A new one will be generated.
-		assert(0);
+		errorstream<<"Invalid block data in database"
+				<<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
+				<<" (SerializationError): "<<e.what()<<std::endl;
+		
+		// TODO: Block should be marked as invalid in memory so that it is
+		// not touched but the game can run
 
-		// TODO: Copy to a backup database.
+		if(g_settings->getBool("ignore_world_load_errors")){
+			errorstream<<"Ignoring block load error. Duck and cover! "
+					<<"(ignore_world_load_errors)"<<std::endl;
+		} else {
+			throw SerializationError("Invalid block data in database");
+			//assert(0);
+		}
 	}
 }
 
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index ed49f7b82..907be05eb 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -35,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock_mesh.h"
 #endif
 
+#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+
 /*
 	MapBlock
 */
@@ -634,6 +636,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 {
 	if(!ser_ver_supported(version))
 		throw VersionMismatchException("ERROR: MapBlock format not supported");
+	
+	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())<<std::endl);
 
 	m_day_night_differs_expired = false;
 
@@ -652,6 +656,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 	/*
 		Bulk node data
 	*/
+	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+			<<": Bulk node data"<<std::endl);
 	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
 	u8 content_width = readU8(is);
 	u8 params_width = readU8(is);
@@ -665,6 +671,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 	/*
 		NodeMetadata
 	*/
+	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+			<<": Node metadata"<<std::endl);
 	// Ignore errors
 	try{
 		std::ostringstream oss(std::ios_base::binary);
@@ -680,7 +688,8 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 	catch(SerializationError &e)
 	{
 		errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
-				<<" while deserializing node metadata: "<<e.what()<<std::endl;
+				<<" while deserializing node metadata at ("
+				<<PP(getPos())<<": "<<e.what()<<std::endl;
 	}
 
 	/*
@@ -689,21 +698,33 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 	if(disk)
 	{
 		// Node timers
-		if(version >= 23)
+		if(version >= 23){
+			TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+					<<": Node timers"<<std::endl);
 			m_node_timers.deSerialize(is);
+		}
 
 		// Static objects
+		TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+				<<": Static objects"<<std::endl);
 		m_static_objects.deSerialize(is);
 		
 		// Timestamp
+		TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+				<<": Timestamp"<<std::endl);
 		setTimestamp(readU32(is));
 		m_disk_timestamp = m_timestamp;
 		
 		// Dynamically re-set ids based on node names
+		TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+				<<": NameIdMapping"<<std::endl);
 		NameIdMapping nimap;
 		nimap.deSerialize(is);
 		correctBlockNodeIds(&nimap, data, m_gamedef);
 	}
+		
+	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
+			<<": Done."<<std::endl);
 }
 
 /*
diff --git a/src/server.cpp b/src/server.cpp
index fbeff83bf..f336fadc8 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -164,6 +164,8 @@ void * EmergeThread::Thread()
 	BEGIN_DEBUG_EXCEPTION_HANDLER
 
 	bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
+
+	v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
 	
 	/*
 		Get block info from queue, emerge them and send them
@@ -181,6 +183,8 @@ void * EmergeThread::Thread()
 
 		v3s16 &p = q->pos;
 		v2s16 p2d(p.X,p.Z);
+		
+		last_tried_pos = p;
 
 		/*
 			Do not generate over-limit
@@ -377,8 +381,23 @@ void * EmergeThread::Thread()
 	}
 	catch(VersionMismatchException &e)
 	{
-		m_server->setAsyncFatalError(std::string(
-				"World data version mismatch (server-side) (world probably saved by a newer version of Minetest): ")+e.what());
+		std::ostringstream err;
+		err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
+		err<<"----"<<std::endl;
+		err<<"\""<<e.what()<<"\""<<std::endl;
+		err<<"See debug.txt."<<std::endl;
+		err<<"World probably saved by a newer version of Minetest."<<std::endl;
+		m_server->setAsyncFatalError(err.str());
+	}
+	catch(SerializationError &e)
+	{
+		std::ostringstream err;
+		err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
+		err<<"----"<<std::endl;
+		err<<"\""<<e.what()<<"\""<<std::endl;
+		err<<"See debug.txt."<<std::endl;
+		err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
+		m_server->setAsyncFatalError(err.str());
 	}
 
 	END_DEBUG_EXCEPTION_HANDLER(errorstream)
-- 
cgit v1.2.3