From bbead93c1a00a1c31956e12c94717f179ac5b84b Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Tue, 31 May 2011 20:02:55 +0300
Subject: [PATCH] Reduced server CPU usage on NodeMetadata step()s. Also
 furnace now cooks while no players are near it.

---
 src/environment.cpp  |  52 ++++++++++++++-
 src/environment.h    |   1 +
 src/main.cpp         |   3 +-
 src/map.h            |   6 ++
 src/nodemetadata.cpp | 155 +++++++++++++++++++++++--------------------
 src/server.cpp       |  22 +++++-
 src/server.h         |   4 +-
 7 files changed, 163 insertions(+), 80 deletions(-)

diff --git a/src/environment.cpp b/src/environment.cpp
index 36c754d57..f5f20d0e5 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -729,6 +729,16 @@ void ServerEnvironment::step(float dtime)
 			// Activate stored objects
 			activateObjects(block);
 
+			// Run node metadata
+			bool changed = block->m_node_metadata.step((float)dtime_s);
+			if(changed)
+			{
+				MapEditEvent event;
+				event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
+				event.p = p;
+				m_map->dispatchEvent(&event);
+			}
+
 			// TODO: Do something
 			// TODO: Implement usage of ActiveBlockModifier
 			
@@ -762,8 +772,10 @@ void ServerEnvironment::step(float dtime)
 	/*
 		Mess around in active blocks
 	*/
-	if(m_active_blocks_test_interval.step(dtime, 10.0))
+	if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
 	{
+		float dtime = 1.0;
+
 		for(core::map<v3s16, bool>::Iterator
 				i = m_active_blocks.m_list.getIterator();
 				i.atEnd()==false; i++)
@@ -779,7 +791,38 @@ void ServerEnvironment::step(float dtime)
 			
 			// Set current time as timestamp
 			block->setTimestamp(m_game_time);
+
+			// Run node metadata
+			bool changed = block->m_node_metadata.step(dtime);
+			if(changed)
+			{
+				MapEditEvent event;
+				event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
+				event.p = p;
+				m_map->dispatchEvent(&event);
+			}
+		}
+	}
+	if(m_active_blocks_test_interval.step(dtime, 10.0))
+	{
+		//float dtime = 10.0;
+
+		for(core::map<v3s16, bool>::Iterator
+				i = m_active_blocks.m_list.getIterator();
+				i.atEnd()==false; i++)
+		{
+			v3s16 p = i.getNode()->getKey();
 			
+			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
+					<<") being handled"<<std::endl;*/
+
+			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
+			if(block==NULL)
+				continue;
+			
+			// Set current time as timestamp
+			block->setTimestamp(m_game_time);
+
 			/*
 				Do stuff!
 
@@ -801,8 +844,11 @@ void ServerEnvironment::step(float dtime)
 			{
 				v3s16 p = p0 + block->getPosRelative();
 				MapNode n = block->getNodeNoEx(p0);
-				// Test something:
-				// Convert mud under proper lighting to grass
+
+				/*
+					Test something:
+					Convert mud under proper lighting to grass
+				*/
 				if(n.d == CONTENT_MUD)
 				{
 					if(myrand()%20 == 0)
diff --git a/src/environment.h b/src/environment.h
index f5cce5933..b4f2a64ca 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -246,6 +246,7 @@ class ServerEnvironment : public Environment
 	ActiveBlockList m_active_blocks;
 	IntervalLimiter m_active_blocks_management_interval;
 	IntervalLimiter m_active_blocks_test_interval;
+	IntervalLimiter m_active_blocks_nodemetadata_interval;
 	// Time from the beginning of the game in seconds.
 	// Incremented in step().
 	u32 m_game_time;
diff --git a/src/main.cpp b/src/main.cpp
index a739d71bf..e582569c5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -312,7 +312,8 @@ Stuff to do before release:
 
 Fixes to the current release:
 -----------------------------
-- Make AuthManager to save only when data has changed
+- Fix client password crash
+- Remember to release the fixes (some are already done)
 
 Stuff to do after release:
 ---------------------------
diff --git a/src/map.h b/src/map.h
index 09154547c..6f7ac0d3b 100644
--- a/src/map.h
+++ b/src/map.h
@@ -46,8 +46,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define MAPTYPE_CLIENT 2
 
 enum MapEditEventType{
+	// Node added (changed from air or something else to something)
 	MEET_ADDNODE,
+	// Node removed (changed to air)
 	MEET_REMOVENODE,
+	// Node metadata of block changed (not knowing which node exactly)
+	// p stores block coordinate
+	MEET_BLOCK_NODE_METADATA_CHANGED,
+	// Anything else
 	MEET_OTHER
 };
 
diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp
index 308a33854..f9468e4fa 100644
--- a/src/nodemetadata.cpp
+++ b/src/nodemetadata.cpp
@@ -268,91 +268,100 @@ void FurnaceNodeMetadata::inventoryModified()
 }
 bool FurnaceNodeMetadata::step(float dtime)
 {
+	if(dtime > 60.0)
+		dstream<<"Furnace stepping a long time ("<<dtime<<")"<<std::endl;
 	// Update at a fixed frequency
-	const float interval = 0.5;
+	const float interval = 2.0;
 	m_step_accumulator += dtime;
-	if(m_step_accumulator < interval)
-		return false;
-	m_step_accumulator -= interval;
-	dtime = interval;
-
-	//dstream<<"Furnace step dtime="<<dtime<<std::endl;
-	
-	InventoryList *dst_list = m_inventory->getList("dst");
-	assert(dst_list);
-
-	InventoryList *src_list = m_inventory->getList("src");
-	assert(src_list);
-	InventoryItem *src_item = src_list->getItem(0);
-	
-	// Start only if there are free slots in dst, so that it can
-	// accomodate any result item
-	if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
-	{
-		m_src_totaltime = 3;
-	}
-	else
+	bool changed = false;
+	while(m_step_accumulator > interval)
 	{
-		m_src_time = 0;
-		m_src_totaltime = 0;
-	}
+		m_step_accumulator -= interval;
+		dtime = interval;
 
-	if(m_fuel_time < m_fuel_totaltime)
-	{
-		//dstream<<"Furnace is active"<<std::endl;
-		m_fuel_time += dtime;
-		m_src_time += dtime;
-		if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
-				&& src_item)
+		//dstream<<"Furnace step dtime="<<dtime<<std::endl;
+		
+		InventoryList *dst_list = m_inventory->getList("dst");
+		assert(dst_list);
+
+		InventoryList *src_list = m_inventory->getList("src");
+		assert(src_list);
+		InventoryItem *src_item = src_list->getItem(0);
+		
+		// Start only if there are free slots in dst, so that it can
+		// accomodate any result item
+		if(dst_list->getFreeSlots() > 0 && src_item && src_item->isCookable())
+		{
+			m_src_totaltime = 3;
+		}
+		else
 		{
-			InventoryItem *cookresult = src_item->createCookResult();
-			dst_list->addItem(cookresult);
-			src_list->decrementMaterials(1);
 			m_src_time = 0;
 			m_src_totaltime = 0;
 		}
-		return true;
-	}
-	
-	if(src_item == NULL || m_src_totaltime < 0.001)
-	{
-		return false;
-	}
-	
-	bool changed = false;
 
-	//dstream<<"Furnace is out of fuel"<<std::endl;
+		if(m_fuel_time < m_fuel_totaltime)
+		{
+			//dstream<<"Furnace is active"<<std::endl;
+			m_fuel_time += dtime;
+			m_src_time += dtime;
+			if(m_src_time >= m_src_totaltime && m_src_totaltime > 0.001
+					&& src_item)
+			{
+				InventoryItem *cookresult = src_item->createCookResult();
+				dst_list->addItem(cookresult);
+				src_list->decrementMaterials(1);
+				m_src_time = 0;
+				m_src_totaltime = 0;
+			}
+			changed = true;
+			continue;
+		}
+		
+		if(src_item == NULL || m_src_totaltime < 0.001)
+		{
+			continue;
+		}
+		
+		//dstream<<"Furnace is out of fuel"<<std::endl;
 
-	InventoryList *fuel_list = m_inventory->getList("fuel");
-	assert(fuel_list);
-	InventoryItem *fuel_item = fuel_list->getItem(0);
+		InventoryList *fuel_list = m_inventory->getList("fuel");
+		assert(fuel_list);
+		InventoryItem *fuel_item = fuel_list->getItem(0);
 
-	if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
-	{
-		m_fuel_totaltime = 10;
-		m_fuel_time = 0;
-		fuel_list->decrementMaterials(1);
-		changed = true;
-	}
-	else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
-	{
-		m_fuel_totaltime = 5;
-		m_fuel_time = 0;
-		fuel_list->decrementMaterials(1);
-		changed = true;
-	}
-	else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
-	{
-		m_fuel_totaltime = 10;
-		m_fuel_time = 0;
-		fuel_list->decrementMaterials(1);
-		changed = true;
-	}
-	else
-	{
-		//dstream<<"No fuel found"<<std::endl;
+		if(ItemSpec(ITEM_MATERIAL, CONTENT_TREE).checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_MATERIAL, CONTENT_WOOD).checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30/4;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_CRAFT, "Stick").checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 30/4/4;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else if(ItemSpec(ITEM_CRAFT, "lump_of_coal").checkItem(fuel_item))
+		{
+			m_fuel_totaltime = 40;
+			m_fuel_time = 0;
+			fuel_list->decrementMaterials(1);
+			changed = true;
+		}
+		else
+		{
+			//dstream<<"No fuel found"<<std::endl;
+		}
 	}
-
 	return changed;
 }
 
diff --git a/src/server.cpp b/src/server.cpp
index 1b471fd09..acfc7446f 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -1637,6 +1637,11 @@ void Server::AsyncRunStep()
 				dstream<<"Server: MEET_REMOVENODE"<<std::endl;
 				sendRemoveNode(event->p, event->already_known_by_peer);
 			}
+			else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
+			{
+				dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
+				setBlockNotSent(event->p);
+			}
 			else if(event->type == MEET_OTHER)
 			{
 				dstream<<"WARNING: Server: MEET_OTHER not implemented"
@@ -1676,7 +1681,7 @@ void Server::AsyncRunStep()
 		Step node metadata
 		TODO: Move to ServerEnvironment and utilize active block stuff
 	*/
-	{
+	/*{
 		//TimeTaker timer("Step node metadata");
 
 		JMutexAutoLock envlock(m_env_mutex);
@@ -1686,6 +1691,8 @@ void Server::AsyncRunStep()
 
 		core::map<v3s16, MapBlock*> changed_blocks;
 		m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
+		
+		// Use setBlockNotSent
 
 		for(core::map<v3s16, MapBlock*>::Iterator
 				i = changed_blocks.getIterator();
@@ -1701,7 +1708,7 @@ void Server::AsyncRunStep()
 				client->SetBlockNotSent(block->getPos());
 			}
 		}
-	}
+	}*/
 		
 	/*
 		Trigger emergethread (it somehow gets to a non-triggered but
@@ -3655,6 +3662,17 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
 	}
 }
 
+void Server::setBlockNotSent(v3s16 p)
+{
+	for(core::map<u16, RemoteClient*>::Iterator
+		i = m_clients.getIterator();
+		i.atEnd()==false; i++)
+	{
+		RemoteClient *client = i.getNode()->getValue();
+		client->SetBlockNotSent(p);
+	}
+}
+
 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
 {
 	DSTACK(__FUNCTION_NAME);
diff --git a/src/server.h b/src/server.h
index 6bee10685..791ecdec7 100644
--- a/src/server.h
+++ b/src/server.h
@@ -480,15 +480,17 @@ class Server : public con::PeerHandler, public MapEventReceiver,
 		Additionally, if far_players!=NULL, players further away than
 		far_d_nodes are ignored and their peer_ids are added to far_players
 	*/
+	// Envlock and conlock should be locked when calling these
 	void sendRemoveNode(v3s16 p, u16 ignore_id=0,
 			core::list<u16> *far_players=NULL, float far_d_nodes=100);
 	void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
 			core::list<u16> *far_players=NULL, float far_d_nodes=100);
+	void setBlockNotSent(v3s16 p);
 	
 	// Environment and Connection must be locked when called
 	void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
 	
-	// Sends blocks to clients
+	// Sends blocks to clients (locks env and con on its own)
 	void SendBlocks(float dtime);
 
 	/*
-- 
GitLab