From c7a7503b2ccebda39a48a1164bf07e4541fd8d2b Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 27 Nov 2018 18:51:53 +0200
Subject: [PATCH] SL-10096 ParcelPropertiesRequest is sent too often when
 terraforming or hover tooltips are On

---
 indra/newview/llviewerparcelmgr.cpp     | 121 +++++++++++++++++-------
 indra/newview/llviewerparceloverlay.cpp |  17 ++++
 indra/newview/llviewerparceloverlay.h   |   2 +
 3 files changed, 107 insertions(+), 33 deletions(-)

diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 5477d2d4445..416d5d8e2ef 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -1331,22 +1331,18 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag
 void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
 {
 	static U32 last_west, last_south;
-
+	static LLUUID last_region;
 
 	// only request parcel info if position has changed outside of the
 	// last parcel grid step
-	U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS );
-	U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS );
-	
+	const U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS );
+	const U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS );
+
 	if ((west_parcel_step == last_west) && (south_parcel_step == last_south))
 	{
+		// We are staying in same segment
 		return;
 	}
-	else 
-	{
-		last_west = west_parcel_step;
-		last_south = south_parcel_step;
-	}
 
 	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos );
 	if (!region)
@@ -1354,36 +1350,95 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
 		return;
 	}
 
-	LL_DEBUGS("ParcelMgr") << "Requesting parcel properties on hover, for " << pos << LL_ENDL;
+	LLUUID region_id = region->getRegionID();
+	LLVector3 pos_in_region = region->getPosRegionFromGlobal(pos);
+
+	bool request_properties = false;
+	if (region_id != last_region)
+	{
+		request_properties = true;
+	}
+	else
+	{
+		// Check if new position is in same parcel.
+		// This check is not ideal, since it checks by way of straight lines.
+		// So sometimes (small parcel in the middle of large one) it can
+		// decide that parcel actually changed, but it still allows to 
+		// reduce amount of requests significantly
+
+		S32 west_parcel_local = (S32)(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS);
+		S32 south_parcel_local = (S32)(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS);
+
+		LLViewerParcelOverlay* overlay = region->getParcelOverlay();
+		if (!overlay)
+		{
+			 request_properties = true;
+		}
+		while (!request_properties && west_parcel_step < last_west)
+		{
+			S32 segment_shift = last_west - west_parcel_step;
+			request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local + segment_shift) & PARCEL_WEST_LINE;
+			last_west--;
+		}
+		while (!request_properties && south_parcel_step < last_south)
+		{
+			S32 segment_shift = last_south - south_parcel_step;
+			request_properties = overlay->parcelLineFlags(south_parcel_local + segment_shift, west_parcel_local) & PARCEL_SOUTH_LINE;
+			last_south--;
+		}
+		// Note: could have just swapped values, reused first two 'while' and set last_south, last_west separately,
+		// but this looks to be easier to understand/straightforward/less bulky
+		while (!request_properties && west_parcel_step > last_west)
+		{
+			S32 segment_shift = west_parcel_step - last_west;
+			request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local - segment_shift + 1) & PARCEL_WEST_LINE;
+			last_west++;
+		}
+		while (!request_properties && south_parcel_step > last_south)
+		{
+			S32 segment_shift = south_parcel_step - last_south;
+			request_properties = overlay->parcelLineFlags(south_parcel_local - segment_shift + 1, west_parcel_local) & PARCEL_SOUTH_LINE;
+			last_south++;
+		}
+
+		// if (!request_properties) last_south and last_west will be equal to new values
+	}
+
+	if (request_properties)
+	{
+		last_west = west_parcel_step;
+		last_south = south_parcel_step;
+		last_region = region_id;
 
+		LL_DEBUGS("ParcelMgr") << "Requesting parcel properties on hover, for " << pos << LL_ENDL;
 
-	// Send a rectangle around the point.
-	// This means the parcel sent back is at least a rectangle around the point,
-	// which is more efficient for public land.  Fewer requests are sent.  JC
-	LLVector3 wsb_region = region->getPosRegionFromGlobal( pos );
 
-	F32 west  = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VX] / PARCEL_GRID_STEP_METERS );
-	F32 south = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VY] / PARCEL_GRID_STEP_METERS );
+		// Send a rectangle around the point.
+		// This means the parcel sent back is at least a rectangle around the point,
+		// which is more efficient for public land.  Fewer requests are sent.  JC
+		F32 west = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS);
+		F32 south = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS);
 
-	F32 east  = west  + PARCEL_GRID_STEP_METERS;
-	F32 north = south + PARCEL_GRID_STEP_METERS;
+		F32 east = west + PARCEL_GRID_STEP_METERS;
+		F32 north = south + PARCEL_GRID_STEP_METERS;
 
-	// Send request message
-	LLMessageSystem *msg = gMessageSystem;
-	msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
-	msg->nextBlockFast(_PREHASH_ParcelData);
-	msg->addS32Fast(_PREHASH_SequenceID,	HOVERED_PARCEL_SEQ_ID );
-	msg->addF32Fast(_PREHASH_West,			west );
-	msg->addF32Fast(_PREHASH_South,			south );
-	msg->addF32Fast(_PREHASH_East,			east );
-	msg->addF32Fast(_PREHASH_North,			north );
-	msg->addBOOL("SnapSelection",			FALSE );
-	msg->sendReliable( region->getHost() );
+		// Send request message
+		LLMessageSystem *msg = gMessageSystem;
+		msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
+		msg->nextBlockFast(_PREHASH_AgentData);
+		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+		msg->nextBlockFast(_PREHASH_ParcelData);
+		msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID);
+		msg->addF32Fast(_PREHASH_West, west);
+		msg->addF32Fast(_PREHASH_South, south);
+		msg->addF32Fast(_PREHASH_East, east);
+		msg->addF32Fast(_PREHASH_North, north);
+		msg->addBOOL("SnapSelection", FALSE);
+		msg->sendReliable(region->getHost());
 
-	mHoverRequestResult = PARCEL_RESULT_NO_DATA;
+		mHoverRequestResult = PARCEL_RESULT_NO_DATA;
+	}
 }
 
 
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 4fd423b6f4e..7c3dd00e1a1 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -274,6 +274,23 @@ U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const
 	return ownership(row, column);
 }
 
+U8 LLViewerParcelOverlay::parcelLineFlags(const LLVector3& pos) const
+{
+    S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS);
+    S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS);
+    return parcelLineFlags(row, column);
+}
+U8 LLViewerParcelOverlay::parcelLineFlags(S32 row, S32 col) const
+{
+    U8 flags = PARCEL_WEST_LINE | PARCEL_SOUTH_LINE;
+    if (row > mParcelGridsPerEdge || col > mParcelGridsPerEdge)
+    {
+        LL_WARNS() << "Attempted to get ownership out of region's overlay, row: " << row << " col: " << col << LL_ENDL;
+        return flags;
+    }
+    return mOwnership[row * mParcelGridsPerEdge + col] & flags;
+}
+
 F32 LLViewerParcelOverlay::getOwnedRatio() const
 {
 	S32	size = mParcelGridsPerEdge * mParcelGridsPerEdge;
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index 14a2af53547..e30dbf17b3e 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -71,6 +71,8 @@ class LLViewerParcelOverlay : public LLGLUpdate
 	S32				renderPropertyLines();
 
 	U8				ownership( const LLVector3& pos) const;
+	U8				parcelLineFlags( const LLVector3& pos) const;
+	U8				parcelLineFlags(S32 row, S32 col) const;
 
 	// MANIPULATE
 	void	uncompressLandOverlay(S32 chunk, U8 *compressed_overlay);
-- 
GitLab