Browse Source

Detect air-only blocks instead of day/night differences (#14264)

* Detect air-only blocks instead day/night differences

* Write !is_air into the former day-night-diff bit on disk, so that old server can still read maps written by new servers

* Only set is_air bit when reading from disk
lhofhansl 2 months ago
parent
commit
0d4b489545
5 changed files with 52 additions and 75 deletions
  1. 1 2
      builtin/settingtypes.txt
  2. 8 7
      src/map.cpp
  3. 29 45
      src/mapblock.cpp
  4. 11 12
      src/mapblock.h
  5. 3 9
      src/server/clientiface.cpp

+ 1 - 2
builtin/settingtypes.txt

@@ -2091,8 +2091,7 @@ liquid_update (Liquid update tick) float 1.0 0.001
 #    At this distance the server will aggressively optimize which blocks are sent to
 #    clients.
 #    Small values potentially improve performance a lot, at the expense of visible
-#    rendering glitches (some blocks will not be rendered under water and in caves,
-#    as well as sometimes on land).
+#    rendering glitches (some blocks might not be rendered correctly in caves).
 #    Setting this to a value greater than max_block_send_distance disables this
 #    optimization.
 #    Stated in MapBlocks (16 nodes).

+ 8 - 7
src/map.cpp

@@ -228,12 +228,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 		std::vector<std::pair<v3s16, MapNode> > oldnodes;
 		oldnodes.emplace_back(p, oldnode);
 		voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
-
-		for (auto &modified_block : modified_blocks) {
-			modified_block.second->expireDayNightDiff();
-		}
 	}
 
+	if (n.getContent() != oldnode.getContent() &&
+			(oldnode.getContent() == CONTENT_AIR || n.getContent() == CONTENT_AIR))
+		block->expireIsAirCache();
+
 	// Report for rollback
 	if(m_gamedef->rollback())
 	{
@@ -1462,14 +1462,14 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
 		if (!block)
 			continue;
 		/*
-			Update day/night difference cache of the MapBlocks
+			Update is air cache of the MapBlocks
 		*/
-		block->expireDayNightDiff();
+		block->expireIsAirCache();
 		/*
 			Set block as modified
 		*/
 		block->raiseModified(MOD_STATE_WRITE_NEEDED,
-			MOD_REASON_EXPIRE_DAYNIGHTDIFF);
+			MOD_REASON_EXPIRE_IS_AIR);
 	}
 
 	/*
@@ -2064,6 +2064,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
 
 		block->copyFrom(*this);
 		block->raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_VMANIP);
+		block->expireIsAirCache();
 
 		if(modified_blocks)
 			(*modified_blocks)[p] = block;

+ 29 - 45
src/mapblock.cpp

@@ -186,57 +186,27 @@ void MapBlock::copyFrom(VoxelManipulator &dst)
 			getPosRelative(), data_size);
 }
 
-void MapBlock::actuallyUpdateDayNightDiff()
+void MapBlock::actuallyUpdateIsAir()
 {
-	const NodeDefManager *nodemgr = m_gamedef->ndef();
+	// Running this function un-expires m_is_air
+	m_is_air_expired = false;
 
-	// Running this function un-expires m_day_night_differs
-	m_day_night_differs_expired = false;
-
-	bool differs = false;
-
-	/*
-		Check if any lighting value differs
-	*/
-
-	MapNode previous_n(CONTENT_IGNORE);
+	bool only_air = true;
 	for (u32 i = 0; i < nodecount; i++) {
-		MapNode n = data[i];
-
-		// If node is identical to previous node, don't verify if it differs
-		if (n == previous_n)
-			continue;
-
-		differs = !n.isLightDayNightEq(nodemgr->getLightingFlags(n));
-		if (differs)
+		MapNode &n = data[i];
+		if (n.getContent() != CONTENT_AIR) {
+			only_air = false;
 			break;
-		previous_n = n;
-	}
-
-	/*
-		If some lighting values differ, check if the whole thing is
-		just air. If it is just air, differs = false
-	*/
-	if (differs) {
-		bool only_air = true;
-		for (u32 i = 0; i < nodecount; i++) {
-			MapNode &n = data[i];
-			if (n.getContent() != CONTENT_AIR) {
-				only_air = false;
-				break;
-			}
 		}
-		if (only_air)
-			differs = false;
 	}
 
 	// Set member variable
-	m_day_night_differs = differs;
+	m_is_air = only_air;
 }
 
-void MapBlock::expireDayNightDiff()
+void MapBlock::expireIsAirCache()
 {
-	m_day_night_differs_expired = true;
+	m_is_air_expired = true;
 }
 
 /*
@@ -369,7 +339,12 @@ void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int
 	u8 flags = 0;
 	if(is_underground)
 		flags |= 0x01;
-	if(getDayNightDiff())
+	// This flag used to be day-night-differs, and it is no longer used.
+	// We write it anyway so that old servers can still use this.
+	// Above ground isAir implies !day-night-differs, !isAir is good enough for old servers
+	// to check whether above ground blocks should be sent.
+	// See RemoteClient::getNextBlocks(...)
+	if(!isAir())
 		flags |= 0x02;
 	if (!m_generated)
 		flags |= 0x08;
@@ -473,7 +448,7 @@ void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
 
 	TRACESTREAM(<<"MapBlock::deSerialize "<<getPos()<<std::endl);
 
-	m_day_night_differs_expired = false;
+	m_is_air_expired = true;
 
 	if(version <= 21)
 	{
@@ -489,7 +464,9 @@ void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
 
 	u8 flags = readU8(is);
 	is_underground = (flags & 0x01) != 0;
-	m_day_night_differs = (flags & 0x02) != 0;
+	// IMPORTANT: when the version is bumped to 30 we can read m_is_air from here
+	// m_is_air = (flags & 0x02) == 0;
+
 	if (version < 27)
 		m_lighting_complete = 0xFFFF;
 	else
@@ -599,6 +576,10 @@ void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk)
 					<<": Node timers (ver>=25)"<<std::endl);
 			m_node_timers.deSerialize(is, version);
 		}
+
+		u16 dummy;
+		m_is_air = nimap.size() == 1 && nimap.getId("air", dummy);
+		m_is_air_expired = false;
 	}
 
 	TRACESTREAM(<<"MapBlock::deSerialize "<<getPos()
@@ -647,7 +628,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
 {
 	// Initialize default flags
 	is_underground = false;
-	m_day_night_differs = false;
+	m_is_air = false;
 	m_lighting_complete = 0xFFFF;
 	m_generated = true;
 
@@ -713,7 +694,6 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
 		u8 flags;
 		is.read((char*)&flags, 1);
 		is_underground = (flags & 0x01) != 0;
-		m_day_night_differs = (flags & 0x02) != 0;
 		if (version >= 18)
 			m_generated = (flags & 0x08) == 0;
 
@@ -798,9 +778,13 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
 		// If supported, read node definition id mapping
 		if (version >= 21) {
 			nimap.deSerialize(is);
+			u16 dummy;
+			m_is_air = nimap.size() == 1 && nimap.getId("air", dummy);
 		// Else set the legacy mapping
 		} else {
 			content_mapnode_get_name_id_mapping(&nimap);
+			m_is_air = false;
+			m_is_air_expired = true;
 		}
 		correctBlockNodeIds(&nimap, data, m_gamedef);
 	}

+ 11 - 12
src/mapblock.h

@@ -60,7 +60,7 @@ enum ModReason : u32 {
 	MOD_REASON_STATIC_DATA_ADDED          = 1 << 13,
 	MOD_REASON_STATIC_DATA_REMOVED        = 1 << 14,
 	MOD_REASON_STATIC_DATA_CHANGED        = 1 << 15,
-	MOD_REASON_EXPIRE_DAYNIGHTDIFF        = 1 << 16,
+	MOD_REASON_EXPIRE_IS_AIR              = 1 << 16,
 	MOD_REASON_VMANIP                     = 1 << 17,
 	MOD_REASON_UNKNOWN                    = 1 << 18,
 };
@@ -310,20 +310,19 @@ public:
 	// Copies data from VoxelManipulator getPosRelative()
 	void copyFrom(VoxelManipulator &dst);
 
-	// Update day-night lighting difference flag.
-	// Sets m_day_night_differs to appropriate value.
-	// These methods don't care about neighboring blocks.
-	void actuallyUpdateDayNightDiff();
+	// Update is air flag.
+	// Sets m_is_air to appropriate value.
+	void actuallyUpdateIsAir();
 
 	// Call this to schedule what the previous function does to be done
 	// when the value is actually needed.
-	void expireDayNightDiff();
+	void expireIsAirCache();
 
-	inline bool getDayNightDiff()
+	inline bool isAir()
 	{
-		if (m_day_night_differs_expired)
-			actuallyUpdateDayNightDiff();
-		return m_day_night_differs;
+		if (m_is_air_expired)
+			actuallyUpdateIsAir();
+		return m_is_air;
 	}
 
 	bool onObjectsActivation();
@@ -517,8 +516,8 @@ public:
 
 private:
 	// Whether day and night lighting differs
-	bool m_day_night_differs = false;
-	bool m_day_night_differs_expired = true;
+	bool m_is_air = false;
+	bool m_is_air_expired = true;
 
 	/*
 		- On the server, this is used for telling whether the

+ 3 - 9
src/server/clientiface.cpp

@@ -354,18 +354,12 @@ void RemoteClient::GetNextBlocks (
 					continue;
 
 				/*
-					If block is not close, don't send it unless it is near
-					ground level.
-
-					Block is near ground level if night-time mesh
-					differs from day-time mesh.
+					If block is not close, don't send it if it
+					consists of air only.
 				*/
-				if (d >= d_opt) {
-					if (!block->getIsUnderground() && !block->getDayNightDiff())
+				if (d >= d_opt && block->isAir())
 						continue;
-				}
 			}
-
 			/*
 				Check occlusion cache first.
 			 */