From 4c92c7b2d025b7cd85bf176287b86a3990959841 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 4 Dec 2018 17:52:46 +0200
Subject: [PATCH] SL-1481 Don't predict region crossings over a second

---
 indra/newview/app_settings/settings.xml | 11 +++++
 indra/newview/llviewerobject.cpp        | 58 ++++++++++++++++++-------
 indra/newview/llviewerobject.h          |  4 +-
 indra/newview/llviewerobjectlist.cpp    |  2 +
 4 files changed, 59 insertions(+), 16 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3ad8b6cdedd..0eef5120eb2 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -14068,6 +14068,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RegionCrossingInterpolationTime</key>
+    <map>
+      <key>Comment</key>
+      <string>How long to extrapolate object motion after crossing regions</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>VerboseLogs</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1e46a1cf9e4..079a9f0372e 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -127,6 +127,7 @@ BOOL		LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
 // sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime
 F64Seconds	LLViewerObject::sMaxUpdateInterpolationTime(3.0);		// For motion interpolation: after X seconds with no updates, don't predict object motion
 F64Seconds	LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0);	// For motion interpolation: after Y seconds with no updates, taper off motion prediction
+F64Seconds	LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing
 
 std::map<std::string, U32> LLViewerObject::sObjectDataMap;
 
@@ -2487,7 +2488,7 @@ void LLViewerObject::loadFlags(U32 flags)
 	return;
 }
 
-void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
+void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time)
 {
 	//static LLTrace::BlockTimerStatHandle ftm("Viewer Object");
 	//LL_RECORD_BLOCK_TIME(ftm);
@@ -2498,19 +2499,19 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
 		{
 			// calculate dt from last update
 			F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.0f;
-			F32 dt_raw = ((F64Seconds)time - mLastInterpUpdateSecs).value();
+			F32 dt_raw = ((F64Seconds)frame_time - mLastInterpUpdateSecs).value();
 			F32 dt = time_dilation * dt_raw;
 
 			applyAngularVelocity(dt);
 
 			if (isAttachment())
 			{
-				mLastInterpUpdateSecs = (F64Seconds)time;
+				mLastInterpUpdateSecs = (F64Seconds)frame_time;
 				return;
 			}
 			else
 			{	// Move object based on it's velocity and rotation
-				interpolateLinearMotion(time, dt);
+				interpolateLinearMotion(frame_time, dt);
 			}
 		}
 
@@ -2520,7 +2521,7 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time)
 
 
 // Move an object due to idle-time viewer side updates by interpolating motion
-void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, const F32SecondsImplicit& dt_seconds)
+void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& frame_time, const F32SecondsImplicit& dt_seconds)
 {
 	// linear motion
 	// PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object
@@ -2532,7 +2533,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
 	// zeroing it out	
 
 	F32 dt = dt_seconds;
-	F64Seconds time_since_last_update = time - mLastMessageUpdateSecs;
+	F64Seconds time_since_last_update = frame_time - mLastMessageUpdateSecs;
 	if (time_since_last_update <= (F64Seconds)0.0 || dt <= 0.f)
 	{
 		return;
@@ -2580,7 +2581,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
 						 (time_since_last_packet > sPhaseOutUpdateInterpolationTime))
 					{
 						// Start to reduce motion interpolation since we haven't seen a server update in a while
-						F64Seconds time_since_last_interpolation = time - mLastInterpUpdateSecs;
+						F64Seconds time_since_last_interpolation = frame_time - mLastInterpUpdateSecs;
 						F64 phase_out = 1.0;
 						if (time_since_last_update > sMaxUpdateInterpolationTime)
 						{	// Past the time limit, so stop the object
@@ -2636,6 +2637,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
 
 		// Check to see if it's going off the region
 		LLVector3 temp(new_pos);
+		static F64SecondsImplicit region_cross_expire = 0; // frame time we detected region crossing in + wait time
 		if (temp.clamp(0.f, mRegionp->getWidth()))
 		{	// Going off this region, so see if we might end up on another region
 			LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());
@@ -2644,21 +2646,47 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
 			// Clip the positions to known regions
 			LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global);
 			if (clip_pos_global != new_pos_global)
-			{	// Was clipped, so this means we hit a edge where there is no region to enter
-				
-				//LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global)
-				//	<< " from " << new_pos << LL_ENDL;
-				new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
+			{
+				// Was clipped, so this means we hit a edge where there is no region to enter
+				LLVector3 clip_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global);
+				LL_DEBUGS("Interpolate") << "Hit empty region edge, clipped predicted position to "
+										 << clip_pos
+										 << " from " << new_pos << LL_ENDL;
+				new_pos = clip_pos;
 				
 				// Stop motion and get server update for bouncing on the edge
 				new_v.clear();
 				setAcceleration(LLVector3::zero);
 			}
 			else
-			{	// Let predicted movement cross into another region
-				//LL_INFOS() << "Predicting region crossing to " << new_pos << LL_ENDL;
+			{
+				// Check for how long we are crossing.
+				// Note: theoretically we can find time from velocity, acceleration and
+				// distance from border to new position, but it is not going to work
+				// if 'phase_out' activates
+				if (region_cross_expire == 0)
+				{
+					// Workaround: we can't accurately figure out time when we cross border
+					// so just write down time 'after the fact', it is far from optimal in
+					// case of lags, but for lags sMaxUpdateInterpolationTime will kick in first
+					LL_DEBUGS("Interpolate") << "Predicted region crossing, new position " << new_pos << LL_ENDL;
+					region_cross_expire = frame_time + sMaxRegionCrossingInterpolationTime;
+				}
+				else if (frame_time > region_cross_expire)
+				{
+					// Predicting crossing over 1s, stop motion
+					// Stop motion
+					LL_DEBUGS("Interpolate") << "Predicting region crossing for too long, stopping at " << new_pos << LL_ENDL;
+					new_v.clear();
+					setAcceleration(LLVector3::zero);
+					region_cross_expire = 0;
+				}
 			}
 		}
+		else
+		{
+			region_cross_expire = 0;
+		}
 
 		// Set new position and velocity
 		setPositionRegion(new_pos);
@@ -2669,7 +2697,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con
 	}		
 
 	// Update the last time we did anything
-	mLastInterpUpdateSecs = time;
+	mLastInterpUpdateSecs = frame_time;
 }
 
 
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index d6c8b761479..990c392531d 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -615,7 +615,7 @@ class LLViewerObject
     U32 checkMediaURL(const std::string &media_url);
 	
 	// Motion prediction between updates
-	void interpolateLinearMotion(const F64SecondsImplicit & time, const F32SecondsImplicit & dt);
+	void interpolateLinearMotion(const F64SecondsImplicit & frame_time, const F32SecondsImplicit & dt);
 
 	static void initObjectDataMap();
 
@@ -851,6 +851,7 @@ class LLViewerObject
 
 	static void setPhaseOutUpdateInterpolationTime(F32 value)	{ sPhaseOutUpdateInterpolationTime = (F64Seconds) value;	}
 	static void setMaxUpdateInterpolationTime(F32 value)		{ sMaxUpdateInterpolationTime = (F64Seconds) value;	}
+	static void setMaxRegionCrossingInterpolationTime(F32 value)		{ sMaxRegionCrossingInterpolationTime = (F64Seconds) value; }
 
 	static void	setVelocityInterpolate(BOOL value)		{ sVelocityInterpolate = value;	}
 	static void	setPingInterpolate(BOOL value)			{ sPingInterpolate = value;	}
@@ -860,6 +861,7 @@ class LLViewerObject
 
 	static F64Seconds sPhaseOutUpdateInterpolationTime;	// For motion interpolation
 	static F64Seconds sMaxUpdateInterpolationTime;			// For motion interpolation
+	static F64Seconds sMaxRegionCrossingInterpolationTime;			// For motion interpolation
 
 	static BOOL sVelocityInterpolate;
 	static BOOL sPingInterpolate;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 2aff71367ef..932759c86d3 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -854,6 +854,7 @@ void LLViewerObjectList::update(LLAgent &agent)
 	
 	F32 interp_time = gSavedSettings.getF32("InterpolationTime");
 	F32 phase_out_time = gSavedSettings.getF32("InterpolationPhaseOut");
+	F32 region_interp_time = llclamp(gSavedSettings.getF32("RegionCrossingInterpolationTime"), 0.5f, 5.f);
 	if (interp_time < 0.0 || 
 		phase_out_time < 0.0 ||
 		phase_out_time > interp_time)
@@ -864,6 +865,7 @@ void LLViewerObjectList::update(LLAgent &agent)
 	}
 	LLViewerObject::setPhaseOutUpdateInterpolationTime( interp_time );
 	LLViewerObject::setMaxUpdateInterpolationTime( phase_out_time );
+	LLViewerObject::setMaxRegionCrossingInterpolationTime(region_interp_time);
 
 	gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures");
 
-- 
GitLab