From 582af0cb212a5bb522356657c89b643501935230 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sun, 26 Dec 2010 03:58:19 +0200
Subject: [PATCH] new viewing range updater algorithm

---
 src/client.cpp |   2 +-
 src/client.h   |   2 +-
 src/main.cpp   | 154 ++++++++++++++++++++++++++++++++++++++++++++++---
 src/map.cpp    |   4 +-
 src/map.h      |   4 +-
 5 files changed, 153 insertions(+), 13 deletions(-)

diff --git a/src/client.cpp b/src/client.cpp
index b0750cae6..d43b97a3c 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -67,7 +67,7 @@ Client::Client(
 		IrrlichtDevice *device,
 		const char *playername,
 		JMutex &range_mutex,
-		s16 &viewing_range_nodes,
+		float &viewing_range_nodes,
 		bool &viewing_range_all):
 	m_thread(this),
 	m_env(new ClientMap(this,
diff --git a/src/client.h b/src/client.h
index b29358d93..e48c8ec69 100644
--- a/src/client.h
+++ b/src/client.h
@@ -111,7 +111,7 @@ class Client : public con::PeerHandler
 			IrrlichtDevice *device,
 			const char *playername,
 			JMutex &range_mutex,
-			s16 &viewing_range_nodes,
+			float &viewing_range_nodes,
 			bool &viewing_range_all
 			);
 	
diff --git a/src/main.cpp b/src/main.cpp
index d22da3ff7..b7a1b6b32 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -257,7 +257,7 @@ IrrlichtWrapper *g_irrlicht;
 JMutex g_range_mutex;
 
 // Blocks are viewed in this range from the player
-s16 g_viewing_range_nodes = 60;
+float g_viewing_range_nodes = 60;
 //s16 g_viewing_range_nodes = 0;
 
 // This is updated by the client's fetchBlocks routine
@@ -849,6 +849,7 @@ class RandomInputHandler : public InputHandler
 	bool rightclicked;
 };
 
+#if 0
 void updateViewingRange(f32 frametime, Client *client)
 {
 	// Range_all messes up frametime_avg
@@ -860,6 +861,9 @@ void updateViewingRange(f32 frametime, Client *client)
 	// Initialize to the target value
 	static float frametime_avg = 1.0/wanted_fps;
 	//frametime_avg = frametime_avg * 0.9 + frametime * 0.1;
+	//frametime_avg = frametime_avg * 0.7 + frametime * 0.3;
+	//frametime_avg = frametime_avg * 0.5 + frametime * 0.5;
+	//frametime_avg = frametime_avg * 0.0 + frametime * 1.0;
 	frametime_avg = frametime_avg * 0.7 + frametime * 0.3;
 
 	static f32 counter = 0;
@@ -869,6 +873,8 @@ void updateViewingRange(f32 frametime, Client *client)
 	}
 	//counter = 1.0; //seconds
 	counter = 0.5; //seconds
+	//counter += 0.1; //seconds
+	//counter = 0.3; //seconds
 
 	//float freetime_ratio = 0.2;
 	//float freetime_ratio = 0.4;
@@ -876,7 +882,20 @@ void updateViewingRange(f32 frametime, Client *client)
 
 	float frametime_wanted = (1.0/(wanted_fps/(1.0-freetime_ratio)));
 
-	float fraction = sqrt(frametime_avg / frametime_wanted);
+	//float fraction = sqrt(frametime_avg / frametime_wanted);
+	//float fraction = pow(frametime_avg / frametime_wanted, 1./3);
+
+	float fraction_unbiased = frametime_avg / frametime_wanted;
+
+	float fraction = pow(fraction_unbiased, 20./(float)g_viewing_range_nodes);
+	
+	/*float fraction = 1.0;
+	// If frametime is too high
+	if(fraction_unbiased > 1.0)
+		fraction = pow(fraction_unbiased, 1./2);
+	// If frametime is too low
+	else
+		fraction = pow(fraction_unbiased, 1./5);*/
 
 	/*float fraction = sqrt(frametime_avg / frametime_wanted) / 2.0
 			+ frametime_avg / frametime_wanted / 2.0;*/
@@ -887,8 +906,19 @@ void updateViewingRange(f32 frametime, Client *client)
 	
 	//float fraction_good_threshold = 0.1;
 	//float fraction_bad_threshold = 0.25;
-	float fraction_good_threshold = 0.075;
-	float fraction_bad_threshold = 0.125;
+
+	/*float fraction_good_threshold = 0.075;
+	float fraction_bad_threshold = 0.125;*/
+	// If frametime is too low
+	/*if(fraction < 1.0)
+	{
+		fraction_good_threshold = pow(fraction_good_threshold, 4);
+		fraction_bad_threshold = pow(fraction_bad_threshold, 4);
+	}*/
+
+	float fraction_good_threshold = 0.23;
+	float fraction_bad_threshold = 0.33;
+	
 	float fraction_limit;
 	// Use high limit if fraction is good AND the fraction would
 	// lower the range. We want to keep the range fairly high.
@@ -897,7 +927,8 @@ void updateViewingRange(f32 frametime, Client *client)
 	else
 		fraction_limit = fraction_good_threshold;
 
-	if(fabs(fraction - 1.0) < fraction_limit)
+	//if(fabs(fraction - 1.0) < fraction_limit)
+	if(fabs(fraction_unbiased - 1.0) < fraction_limit)
 	{
 		fraction_is_good = true;
 		return;
@@ -934,6 +965,113 @@ void updateViewingRange(f32 frametime, Client *client)
 	/*dstream<<"g_viewing_range_nodes = "
 			<<g_viewing_range_nodes<<std::endl;*/
 }
+#endif
+
+void updateViewingRange(f32 frametime_in, Client *client)
+{
+	if(g_viewing_range_all == true)
+		return;
+	
+	static f32 added_frametime = 0;
+	static s16 added_frames = 0;
+
+	added_frametime += frametime_in;
+	added_frames += 1;
+
+	// Actually this counter kind of sucks because frametime is busytime
+	static f32 counter = 0;
+	counter -= frametime_in;
+	if(counter > 0)
+		return;
+	//counter = 0.1;
+	counter = 0.2;
+
+	dstream<<__FUNCTION_NAME
+			<<": Collected "<<added_frames<<" frames, total of "
+			<<added_frametime<<"s."<<std::endl;
+	
+	f32 frametime = added_frametime / added_frames;
+	added_frametime = 0.0;
+	added_frames = 0;
+	
+	float wanted_fps = g_settings.getFloat("wanted_fps");
+	float wanted_frametime = 1.0 / wanted_fps;
+	
+	f32 wanted_frametime_change = wanted_frametime - frametime;
+	dstream<<"wanted_frametime_change="<<wanted_frametime_change<<std::endl;
+	
+	// If needed frametime change is very small, just return
+	if(fabs(wanted_frametime_change) < wanted_frametime*0.2)
+	{
+		dstream<<"ignoring small wanted_frametime_change"<<std::endl;
+		return;
+	}
+
+	float range = g_viewing_range_nodes;
+	float new_range = range;
+
+	static s16 range_old = 0;
+	static f32 frametime_old = 0;
+	
+	float d_range = range - range_old;
+	f32 d_frametime = frametime - frametime_old;
+	// A sane default of 30ms per 50 nodes of range
+	static f32 time_per_range = 30. / 50;
+	if(d_range != 0)
+	{
+		time_per_range = d_frametime / d_range;
+	}
+	
+	// The minimum allowed calculated frametime-range derivative:
+	// Practically this sets the maximum speed of changing the range.
+	// The lower this value, the higher the maximum changing speed.
+	// A low value here results in wobbly range (0.001)
+	// A high value here results in slow changing range (0.0025)
+	// SUGG: This could be dynamically adjusted so that when
+	//       the camera is turning, this is lower
+	float min_time_per_range = 0.001;
+	if(time_per_range < min_time_per_range)
+		time_per_range = min_time_per_range;
+	
+	dstream<<"time_per_range="<<time_per_range<<std::endl;
+
+	f32 wanted_range_change = wanted_frametime_change / time_per_range;
+	// Dampen the change a bit to kill oscillations
+	//wanted_range_change *= 0.9;
+	wanted_range_change *= 0.75;
+	dstream<<"wanted_range_change="<<wanted_range_change<<std::endl;
+
+	// If needed range change is very small, just return
+	if(fabs(wanted_range_change) < 0.001)
+	{
+		dstream<<"ignoring small wanted_range_change"<<std::endl;
+		return;
+	}
+
+	new_range += wanted_range_change;
+	dstream<<"new_range="<<new_range/*<<std::endl*/;
+	
+	float range_min = g_settings.getS16("viewing_range_nodes_min");
+	float range_max = g_settings.getS16("viewing_range_nodes_max");
+	
+	float new_range_unclamped = new_range;
+	if(new_range < range_min)
+		new_range = range_min;
+	if(new_range > range_max)
+		new_range = range_max;
+	
+	if(new_range != new_range_unclamped)
+		dstream<<", clamped to "<<new_range<<std::endl;
+	else
+		dstream<<std::endl;
+
+	JMutexAutoLock lock(g_range_mutex);
+
+	g_viewing_range_nodes = new_range;
+
+	range_old = new_range;
+	frametime_old = frametime;
+}
 
 class GUIQuickInventory : public IEventReceiver
 {
@@ -2326,13 +2464,15 @@ int main(int argc, char *argv[])
 			swprintf(temptext, 150,
 					L"(% .1f, % .1f, % .1f)"
 					L" (% .3f < btime_jitter < % .3f"
-					L", dtime_jitter = % .1f %%)",
+					L", dtime_jitter = % .1f %%"
+					L", v_range = %.1f)",
 					player_position.X/BS,
 					player_position.Y/BS,
 					player_position.Z/BS,
 					busytime_jitter1_min_sample,
 					busytime_jitter1_max_sample,
-					dtime_jitter1_max_fraction * 100.0
+					dtime_jitter1_max_fraction * 100.0,
+					g_viewing_range_nodes
 					);
 
 			guitext2->setText(temptext);
diff --git a/src/map.cpp b/src/map.cpp
index 59053f70c..d5a61d408 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -2890,7 +2890,7 @@ void ServerMap::PrintInfo(std::ostream &out)
 ClientMap::ClientMap(
 		Client *client,
 		JMutex &range_mutex,
-		s16 &viewing_range_nodes,
+		float &viewing_range_nodes,
 		bool &viewing_range_all,
 		scene::ISceneNode* parent,
 		scene::ISceneManager* mgr,
@@ -3013,7 +3013,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
 		all changed nodes in viewing range at the next step.
 	*/
 
-	s16 viewing_range_nodes;
+	float viewing_range_nodes;
 	bool viewing_range_all;
 	{
 		JMutexAutoLock lock(m_range_mutex);
diff --git a/src/map.h b/src/map.h
index 3c3fe9daf..8952bc110 100644
--- a/src/map.h
+++ b/src/map.h
@@ -551,7 +551,7 @@ class ClientMap : public Map, public scene::ISceneNode
 	ClientMap(
 			Client *client,
 			JMutex &range_mutex,
-			s16 &viewing_range_nodes,
+			float &viewing_range_nodes,
 			bool &viewing_range_all,
 			scene::ISceneNode* parent,
 			scene::ISceneManager* mgr,
@@ -620,7 +620,7 @@ class ClientMap : public Map, public scene::ISceneNode
 	JMutex mesh_mutex;
 
 	JMutex &m_range_mutex;
-	s16 &m_viewing_range_nodes;
+	float &m_viewing_range_nodes;
 	bool &m_viewing_range_all;
 };
 
-- 
GitLab