From ed52bd6aac7c02dfb1484c78fff6496040253e2f Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@alchemyviewer.org>
Date: Fri, 4 Mar 2022 21:57:03 -0500
Subject: [PATCH] Start to wire up var region support

---
 indra/llmessage/message_prehash.cpp          |   5 +
 indra/llmessage/message_prehash.h            |   4 +
 indra/newview/llstartup.cpp                  |  20 ++-
 indra/newview/llviewermessage.cpp            |  22 ++-
 indra/newview/llviewerregion.cpp             |  38 +++---
 indra/newview/llviewerregion.h               |   2 +
 indra/newview/llworld.cpp                    | 135 +++++++++++++------
 indra/newview/llworld.h                      |   6 +-
 scripts/messages/message_template.msg        |  59 ++++++--
 scripts/messages/message_template.msg.sha256 |   2 +-
 10 files changed, 210 insertions(+), 83 deletions(-)

diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 26e4a126d2d..d334aad3c1c 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -1445,3 +1445,8 @@ char const* const _PREHASH_AvatarNotesReply = LLMessageStringTable::getInstance(
 char const* const _PREHASH_CacheID = LLMessageStringTable::getInstance()->getString("CacheID");
 char const* const _PREHASH_OwnerMask = LLMessageStringTable::getInstance()->getString("OwnerMask");
 char const* const _PREHASH_TransferInventoryAck = LLMessageStringTable::getInstance()->getString("TransferInventoryAck");
+
+char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX");
+char const* const _PREHASH_RegionSizeY = LLMessageStringTable::getInstance()->getString("RegionSizey");
+char const* const _PREHASH_SizeX = LLMessageStringTable::getInstance()->getString("SizeX");
+char const* const _PREHASH_SizeY = LLMessageStringTable::getInstance()->getString("SizeY");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 020444738fa..a672a06e02d 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -1445,6 +1445,10 @@ extern char const* const _PREHASH_AvatarNotesReply;
 extern char const* const _PREHASH_CacheID;
 extern char const* const _PREHASH_OwnerMask;
 extern char const* const _PREHASH_TransferInventoryAck;
+extern char const* const _PREHASH_RegionSizeX;
+extern char const* const _PREHASH_RegionSizeY;
+extern char const* const _PREHASH_SizeX;
+extern char const* const _PREHASH_SizeY;
 
 
 #endif
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 76e03ca55f5..19e86f05f45 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -286,7 +286,7 @@ LLSD transform_cert_args(LLPointer<LLCertificate> cert);
 void general_cert_done(const LLSD& notification, const LLSD& response);
 void trust_cert_done(const LLSD& notification, const LLSD& response);
 void apply_udp_blacklist(const std::string& csv);
-bool process_login_success_response();
+bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y);
 void on_benefits_failed_callback(const LLSD& notification, const LLSD& response);
 void transition_back_to_login_panel(const std::string& emsg);
 // [SL:KB] - Patch: Chat-Alerts | Checked: 2012-09-22 (Catznip-3.3)
@@ -348,6 +348,9 @@ bool idle_startup()
 	static std::string auth_desc;
 	static std::string auth_message;
 
+	static U32 first_sim_size_x = 256;
+	static U32 first_sim_size_y = 256;
+
 	static LLVector3 agent_start_position_region(10.f, 10.f, 10.f);		// default for when no space server
 
 	// last location by default
@@ -1239,7 +1242,7 @@ bool idle_startup()
 		}
 		else if(LLLoginInstance::getInstance()->authSuccess())
 		{
-			if(process_login_success_response())
+			if(process_login_success_response(first_sim_size_x, first_sim_size_y))
 			{
 				// Pass the user information to the voice chat server interface.
 				LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID);
@@ -1334,6 +1337,7 @@ bool idle_startup()
 		gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
 		display_startup();
 
+		LLWorld::getInstance()->setRegionSize(first_sim_size_x, first_sim_size_y);
 		LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
 		display_startup();
 
@@ -3333,7 +3337,7 @@ bool init_benefits(LLSD& response)
 	return succ;
 }
 
-bool process_login_success_response()
+bool process_login_success_response(U32& first_sim_size_x, U32& first_sim_size_y)
 {
 	LLSD response = LLLoginInstance::getInstance()->getResponse();
 
@@ -3376,7 +3380,7 @@ bool process_login_success_response()
 	// otherwise if the response contains a first and/or last name,
 	// use those.  Otherwise use the credential identifier
 
-	gDisplayName = "";
+	gDisplayName.clear();
 	if (response.has("display_name"))
 	{
 		gDisplayName.assign(response["display_name"].asString());
@@ -3482,7 +3486,13 @@ bool process_login_success_response()
 		U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
 		gFirstSimHandle = to_region_handle(region_x, region_y);
 	}
-	
+
+	text = response["region_size_x"].asString();
+	if (!text.empty()) LLViewerParcelMgr::getInstance()->init(first_sim_size_x = atoi(text.c_str()));
+	//region Y size is currently unused, major refactoring required. - Patrick Sapinski (2/10/2011)
+	text = response["region_size_y"].asString();
+	if (!text.empty()) first_sim_size_y = atoi(text.c_str());
+
 	const std::string look_at_str = response["look_at"];
 	if (!look_at_str.empty())
 	{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ef581fb3e43..d3c9120523d 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3240,7 +3240,15 @@ void process_teleport_finish(LLMessageSystem* msg, void**)
 
 	// Viewer trusts the simulator.
 	gMessageSystem->enableCircuit(sim_host, TRUE);
-	LLViewerRegion* regionp =  LLWorld::getInstanceFast()->addRegion(region_handle, sim_host);
+	if (LLGridManager::getInstance()->isInOpenSim())
+	{
+		U32 region_size_x = 256;
+		msg->getU32Fast(_PREHASH_Info, _PREHASH_RegionSizeX, region_size_x);
+		U32 region_size_y = 256;
+		msg->getU32Fast(_PREHASH_Info, _PREHASH_RegionSizeY, region_size_y);
+		LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y);
+	}
+	LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
 
 /*
 	// send camera update to new region
@@ -3548,10 +3556,18 @@ void process_crossed_region(LLMessageSystem* msg, void**)
 
 	send_complete_agent_movement(sim_host);
 
-	LLViewerRegion* regionp = LLWorld::getInstanceFast()->addRegion(region_handle, sim_host);
+	if (LLGridManager::getInstance()->isInOpenSim())
+	{
+		U32 region_size_x = 256;
+		msg->getU32(_PREHASH_RegionData, _PREHASH_RegionSizeX, region_size_x);
+		U32 region_size_y = 256;
+		msg->getU32(_PREHASH_RegionData, _PREHASH_RegionSizeY, region_size_y);
+		LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y);
+	}
+	LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
 
 	LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == "
-			<< seedCap << LL_ENDL;
+		<< seedCap << LL_ENDL;
 	regionp->setSeedCapability(seedCap);
 }
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index fa98d715256..2bb8001537a 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -578,8 +578,10 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 							   const U32 grids_per_patch_edge, 
 							   const F32 region_width_meters)
 :	mImpl(new LLViewerRegionImpl(this, host)),
+	mWidth(region_width_meters),
 	mHandle(handle),
 	mTimeDilation(1.0f),
+	mWidthScaleFactor(region_width_meters / REGION_WIDTH_METERS),
 	mMaxBakes(LLGridManager::getInstance()->isInSecondlife()?
 		LLAvatarAppearanceDefines::EBakedTextureIndex::BAKED_NUM_INDICES:
 		LLAvatarAppearanceDefines::EBakedTextureIndex::BAKED_LEFT_ARM),
@@ -616,8 +618,6 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mRegionCacheHitCount(0),
 	mRegionCacheMissCount(0)
 {
-	mWidth = region_width_meters;
-
 	mRenderMatrix.setIdentity();
 
 	mImpl->mOriginGlobal = from_region_handle(handle); 
@@ -629,7 +629,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mImpl->mCompositionp =
 		new LLVLComposition(mImpl->mLandp,
 							grids_per_region_edge,
-							region_width_meters / grids_per_region_edge);
+							mWidth / grids_per_region_edge);
 	mImpl->mCompositionp->setSurface(mImpl->mLandp);
 
 	// Create the surfaces
@@ -1851,11 +1851,11 @@ LLVLComposition * LLViewerRegion::getComposition() const
 
 F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 {
-	if (x >= 256)
+	if (x >= mWidth)
 	{
-		if (y >= 256)
+		if (y >= mWidth)
 		{
-			LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 256.f, 0.f);
+			LLVector3d center = getCenterGlobal() + LLVector3d(mWidth, mWidth, 0.f);
 			LLViewerRegion *regionp = LLWorld::getInstanceFast()->getRegionFromPosGlobal(center);
 			if (regionp)
 			{
@@ -1864,8 +1864,8 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 				// If we're attempting to blend, then we want to make the fractional part of
 				// this region match the fractional of the adjacent.  For now, just minimize
 				// the delta.
-				F32 our_comp = getComposition()->getValueScaled(255, 255);
-				F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, y - 256.f);
+				F32 our_comp = getComposition()->getValueScaled(mWidth-1.f, mWidth-1.f);
+				F32 adj_comp = regionp->getComposition()->getValueScaled(x - regionp->getWidth(), y - regionp->getWidth());
 				while (llabs(our_comp - adj_comp) >= 1.f)
 				{
 					if (our_comp > adj_comp)
@@ -1882,7 +1882,7 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 		}
 		else
 		{
-			LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 0, 0.f);
+			LLVector3d center = getCenterGlobal() + LLVector3d(mWidth, 0, 0.f);
 			LLViewerRegion *regionp = LLWorld::getInstanceFast()->getRegionFromPosGlobal(center);
 			if (regionp)
 			{
@@ -1891,8 +1891,8 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 				// If we're attempting to blend, then we want to make the fractional part of
 				// this region match the fractional of the adjacent.  For now, just minimize
 				// the delta.
-				F32 our_comp = getComposition()->getValueScaled(255.f, (F32)y);
-				F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, (F32)y);
+				F32 our_comp = getComposition()->getValueScaled(mWidth-1.f, (F32)y);
+				F32 adj_comp = regionp->getComposition()->getValueScaled(x - regionp->getWidth(), (F32)y);
 				while (llabs(our_comp - adj_comp) >= 1.f)
 				{
 					if (our_comp > adj_comp)
@@ -1908,9 +1908,9 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 			}
 		}
 	}
-	else if (y >= 256)
+	else if (y >= mWidth)
 	{
-		LLVector3d center = getCenterGlobal() + LLVector3d(0.f, 256.f, 0.f);
+		LLVector3d center = getCenterGlobal() + LLVector3d(0.f, mWidth, 0.f);
 		LLViewerRegion *regionp = LLWorld::getInstanceFast()->getRegionFromPosGlobal(center);
 		if (regionp)
 		{
@@ -1919,8 +1919,8 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
 			// If we're attempting to blend, then we want to make the fractional part of
 			// this region match the fractional of the adjacent.  For now, just minimize
 			// the delta.
-			F32 our_comp = getComposition()->getValueScaled((F32)x, 255.f);
-			F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - 256.f);
+			F32 our_comp = getComposition()->getValueScaled((F32)x, mWidth-1.f);
+			F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - regionp->getWidth());
 			while (llabs(our_comp - adj_comp) >= 1.f)
 			{
 				if (our_comp > adj_comp)
@@ -2150,8 +2150,8 @@ class CoarseLocationUpdate : public LLHTTPNode
 			if(i == target_index)
 			{
 				LLVector3d global_pos(region->getOriginGlobal());
-				global_pos.mdV[VX] += (F64)x;
-				global_pos.mdV[VY] += (F64)y;
+				global_pos.mdV[VX] += (F64)x * region->getWidthScaleFactor();
+				global_pos.mdV[VY] += (F64)y * region->getWidthScaleFactor();
 				global_pos.mdV[VZ] += (F64)z * 4.0;
 				LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
 			}
@@ -2225,8 +2225,8 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
 		if(i == target_index)
 		{
 			LLVector3d global_pos(mImpl->mOriginGlobal);
-			global_pos.mdV[VX] += (F64)(x_pos);
-			global_pos.mdV[VY] += (F64)(y_pos);
+			global_pos.mdV[VX] += (F64)(x_pos) * mWidthScaleFactor;
+			global_pos.mdV[VY] += (F64)(y_pos) * mWidthScaleFactor;
 			global_pos.mdV[VZ] += (F64)(z_pos) * 4.0;
 			LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
 		}
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index ce62c20411f..73369d6065c 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -235,6 +235,7 @@ class LLViewerRegion final : public LLCapabilityProvider // implements this inte
 
 	// regions are expensive to release, this function gradually releases cache from memory
 	static void idleCleanup(F32 max_update_time);
+	F32 getWidthScaleFactor() const				{ return mWidthScaleFactor; } // Scaling for OpenSim VarRegions
 
 	S32 getRegionMaxBakes() const						{ return mMaxBakes; }
 	S32 getRegionMaxTEs() const							{ return mMaxTEs; }
@@ -525,6 +526,7 @@ class LLViewerRegion final : public LLCapabilityProvider // implements this inte
 	U64			mHandle;
 	F32			mTimeDilation;	// time dilation of physics simulation on simulator
 	S32         mLastUpdate; //last time called idleUpdate()
+	F32			mWidthScaleFactor; // Scaling for OpenSim VarRegions
 	S32			mMaxBakes; // store max bakes on the region
 	S32			mMaxTEs; // store max TEs on the region
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 9fbdaf22a7a..3b09ea1845f 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -74,12 +74,13 @@ const S32 WORLD_PATCH_SIZE = 16;
 
 extern LLColor4U MAX_WATER_COLOR;
 
-const U32 LLWorld::mWidth = 256;
+U32 LLWorld::mWidth = 256;
+U32 LLWorld::mLength = 256;
 
 // meters/point, therefore mWidth * mScale = meters per edge
 const F32 LLWorld::mScale = 1.f;
 
-const F32 LLWorld::mWidthInMeters = mWidth * mScale;
+F32 LLWorld::mWidthInMeters = mWidth * mScale;
 
 //
 // Functions
@@ -137,6 +138,12 @@ void LLWorld::destroyClass()
 	LLSceneMonitor::deleteSingleton();
 }
 
+void LLWorld::setRegionSize(const U32& width, const U32& length)
+{
+	mWidth = width ? width : 256; // Width of 0 is really 256
+	mLength = length ? length : 256; // Length of 0 is really 256
+	mWidthInMeters = mWidth * mScale;
+}
 
 LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
 {
@@ -180,8 +187,8 @@ LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
 	U32 iindex = 0;
 	U32 jindex = 0;
 	from_region_handle(region_handle, &iindex, &jindex);
-	S32 x = (S32)(iindex/mWidth);
-	S32 y = (S32)(jindex/mWidth);
+	S32 x = (S32)(iindex/256);
+	S32 y = (S32)(jindex/256);
 	LL_INFOS() << "Adding new region (" << x << ":" << y << ")" 
 		<< " on host: " << host << LL_ENDL;
 
@@ -229,13 +236,43 @@ LLViewerRegion* LLWorld::addRegion(const U64 &region_handle, const LLHost &host)
 	{
 		adj_x = region_x + width * gDirAxes[dir][0];
 		adj_y = region_y + width * gDirAxes[dir][1];
-		to_region_handle(adj_x, adj_y, &adj_handle);
 
-		neighborp = getRegionFromHandle(adj_handle);
-		if (neighborp)
+		if (mWidth == 256 && mLength == 256)
 		{
-			//LL_INFOS() << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << LL_ENDL;
-			regionp->connectNeighbor(neighborp, dir);
+			to_region_handle(adj_x, adj_y, &adj_handle);
+			neighborp = getRegionFromHandle(adj_handle);
+			if (neighborp)
+			{
+				//LL_INFOS() << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << LL_ENDL;
+				regionp->connectNeighbor(neighborp, dir);
+			}
+		}
+		else // Unconventional region size
+		{
+			LLViewerRegion* last_neighborp = nullptr;
+			if(gDirAxes[dir][0] < 0) adj_x = region_x - WORLD_PATCH_SIZE;
+			if(gDirAxes[dir][1] < 0) adj_y = region_y - WORLD_PATCH_SIZE;
+
+			for (S32 offset = 0; offset < width; offset += WORLD_PATCH_SIZE)
+			{
+				to_region_handle(adj_x, adj_y, &adj_handle);
+				neighborp = getRegionFromHandle(adj_handle);
+
+				if (neighborp && last_neighborp != neighborp)
+				{
+					//LL_INFOS() << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << LL_ENDL;
+					regionp->connectNeighbor(neighborp, dir);
+					last_neighborp = neighborp;
+				}
+
+				if (dir == NORTH || dir == SOUTH)
+					adj_x += WORLD_PATCH_SIZE;
+				else if (dir == EAST || dir == WEST)
+					adj_y += WORLD_PATCH_SIZE;
+				else if (dir == NORTHEAST || dir == NORTHWEST || dir == SOUTHWEST || dir == SOUTHEAST)
+					break;
+
+			}
 		}
 	}
 
@@ -402,9 +439,17 @@ LLVector3d	LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVe
 
 LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
 {
+	U32 x, y;
+	from_region_handle(handle, &x, &y);
+
 	for (LLViewerRegion* regionp : mRegionList)
 	{
-		if (regionp->getHandle() == handle)
+		U32 checkRegionX, checkRegionY;
+		F32 checkRegionWidth = regionp->getWidth();
+		from_region_handle(regionp->getHandle(), &checkRegionX, &checkRegionY);
+
+		if (x >= checkRegionX && x < (checkRegionX + checkRegionWidth) &&
+			y >= checkRegionY && y < (checkRegionY + checkRegionWidth))
 		{
 			return regionp;
 		}
@@ -836,7 +881,7 @@ F32 LLWorld::getLandFarClip() const
 
 void LLWorld::setLandFarClip(const F32 far_clip)
 {
-	static S32 const rwidth = (S32)REGION_WIDTH_U32;
+	S32 const rwidth = (S32)getRegionWidthInMeters();
 	S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
 	S32 const n2 = (llceil(far_clip) - 1) / rwidth;
 	bool need_water_objects_update = n1 != n2;
@@ -931,18 +976,20 @@ void LLWorld::updateWaterObjects()
 	S32 max_y = 0;
 	U32 region_x, region_y;
 
-	S32 rwidth = 256;
+	LLViewerRegion const* regionp = gAgent.getRegion();
+
+	// Region width in meters.
+	S32 const rwidth = (S32)regionp->getWidth();
 
 	// We only want to fill in water for stuff that's near us, say, within 256 or 512m
 	S32 range = LLViewerCamera::getInstanceFast()->getFar() > 256.f ? 512 : 256;
 
-	LLViewerRegion* regionp = gAgent.getRegion();
 	from_region_handle(regionp->getHandle(), &region_x, &region_y);
 
 	min_x = (S32)region_x - range;
 	min_y = (S32)region_y - range;
-	max_x = (S32)region_x + range;
-	max_y = (S32)region_y + range;
+	max_x = (S32)region_x + (rwidth-256) + range;
+	max_y = (S32)region_y + (rwidth-256) + range;
 
 	for (LLViewerRegion* regionp : mRegionList)
 	{
@@ -953,32 +1000,31 @@ void LLWorld::updateWaterObjects()
 		}
 	}
 
-	for (std::list<LLPointer<LLVOWater> >::iterator iter = mHoleWaterObjects.begin();
-		 iter != mHoleWaterObjects.end(); ++ iter)
+	for (LLVOWater* waterp : mHoleWaterObjects)
 	{
-		LLVOWater* waterp = (*iter).get();
 		gObjectList.killObject(waterp);
 	}
 	mHoleWaterObjects.clear();
 
 	// Use the water height of the region we're on for areas where there is no region
-	F32 water_height = gAgent.getRegion()->getWaterHeight();
+	F32 water_height = gAgent.getRegion()->getWaterHeight() + 256.f;
 
 	// Now, get a list of the holes
 	S32 x, y;
-	for (x = min_x; x <= max_x; x += rwidth)
+	const S32 step = 256;
+	for (x = min_x; x <= max_x; x += step)
 	{
-		for (y = min_y; y <= max_y; y += rwidth)
+		for (y = min_y; y <= max_y; y += step)
 		{
 			U64 region_handle = to_region_handle(x, y);
 			if (!getRegionFromHandle(region_handle))
 			{	// No region at that area, so make water
 				LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
 				waterp->setUseTexture(FALSE);
-				waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
-													 y + rwidth/2,
-													 256.f + water_height));
-				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
+				waterp->setPositionGlobal(LLVector3d(x + step/2,
+													 y + step/2,
+													 water_height));
+				waterp->setScale(LLVector3((F32)step, (F32)step, 512.f));
 				gPipeline.createObject(waterp);
 				mHoleWaterObjects.push_back(waterp);
 			}
@@ -988,16 +1034,16 @@ void LLWorld::updateWaterObjects()
 	// Update edge water objects
 	S32 wx, wy;
 	S32 center_x, center_y;
-	wx = (max_x - min_x) + rwidth;
-	wy = (max_y - min_y) + rwidth;
+	wx = (max_x - min_x) + step;
+	wy = (max_y - min_y) + step;
 	center_x = min_x + (wx >> 1);
 	center_y = min_y + (wy >> 1);
 
 	S32 add_boundary[4] = {
-		(S32)(512 - (max_x - region_x)),
-		(S32)(512 - (max_y - region_y)),
-		(S32)(512 - (region_x - min_x)),
-		(S32)(512 - (region_y - min_y)) };
+        static_cast<S32>(512 - (max_x - (rwidth - 256) - region_x)),
+        static_cast<S32>(512 - (max_y - (rwidth - 256) - region_y)),
+        512 - ((S32)region_x - min_x),
+        512 - ((S32)region_y - min_y) };
 		
 	S32 dir;
 	for (dir = 0; dir < 8; dir++)
@@ -1034,7 +1080,7 @@ void LLWorld::updateWaterObjects()
 		}
 
 		waterp->setRegion(gAgent.getRegion());
-		LLVector3d water_pos(water_center_x, water_center_y, 256.f + water_height) ;
+		LLVector3d water_pos(water_center_x, water_center_y, water_height) ;
 		LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
 
 		//stretch out to horizon
@@ -1137,7 +1183,15 @@ void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 
 	// Viewer trusts the simulator.
 	msg->enableCircuit(sim, TRUE);
-	LLWorld::getInstanceFast()->addRegion(handle, sim);
+	if (LLGridManager::getInstance()->isInOpenSim())
+	{
+		U32 region_size_x = 256;
+		msg->getU32Fast(_PREHASH_SimulatorInfo, _PREHASH_RegionSizeX, region_size_x);
+		U32 region_size_y = 256;
+		msg->getU32Fast(_PREHASH_SimulatorInfo, _PREHASH_RegionSizeY, region_size_y);
+		LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y);
+	}
+	LLWorld::getInstance()->addRegion(handle, sim);
 
 	// give the simulator a message it can use to get ip and port
 	LL_INFOS() << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << LL_ENDL;
@@ -1287,14 +1341,17 @@ void send_agent_resume()
 	LLAppViewer::instance()->resumeMainloopTimeout();
 }
 
-static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin)
+static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin, F32 width_scale_factor)
 {
 	LLVector3d pos_local;
 
-	pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4;
+	pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4U;
 	pos_local.mdV[VY] = (compact_local >> 8) & 0xFFU;
 	pos_local.mdV[VX] = (compact_local >> 16) & 0xFFU;
 
+	// Scaling for OpenSim VarRegions
+	pos_local.mdV[VX] *= width_scale_factor;
+	pos_local.mdV[VY] *= width_scale_factor;
 	return region_origin + pos_local;
 }
 
@@ -1345,7 +1402,7 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi
 		S32 count = regionp->mMapAvatars.size();
 		for (S32 i = 0; i < count; i++)
 		{
-			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global);
+			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global, regionp->getWidthScaleFactor());
 			if(dist_vec_squared(pos_global, relative_to) <= radius_squared)
 			{
 				LLUUID uuid = regionp->mMapAvatarIDs[i];
@@ -1400,7 +1457,7 @@ void LLWorld::getAvatars(pos_map_t* umap, const LLVector3d& relative_to, F32 rad
 			LLUUID uuid = regionp->mMapAvatarIDs[i];
 			if (uuid.isNull()) continue;
 
-			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global);
+			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global, regionp->getWidthScaleFactor());
 			if(dist_vec_squared(pos_global, relative_to) <= radius_squared && umap->find(uuid) == umap->end())
 			{
 				umap->emplace(std::move(uuid), std::move(pos_global));
@@ -1447,7 +1504,7 @@ void LLWorld::getAvatars(region_gpos_map_t* umap, const LLVector3d& relative_to,
 			LLUUID uuid = regionp->mMapAvatarIDs[i];
 			if (uuid.isNull()) continue;
 
-			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global);
+			LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars[i], origin_global, regionp->getWidthScaleFactor());
 			if (dist_vec_squared(pos_global, relative_to) <= radius_squared && umap->find(uuid) == umap->end())
 			{
 				umap->emplace(std::move(uuid), std::make_pair(regionp, std::move(pos_global)));
@@ -1475,7 +1532,7 @@ bool LLWorld::getAvatar(const LLUUID& idAvatar, LLVector3d& posAvatar) const
 		{
 			if (idAvatar == pRegion->mMapAvatarIDs[idxAgent])
 			{
-				posAvatar = unpackLocalToGlobalPosition(pRegion->mMapAvatars[idxAgent], pRegion->getOriginGlobal());
+				posAvatar = unpackLocalToGlobalPosition(pRegion->mMapAvatars[idxAgent], pRegion->getOriginGlobal(), pRegion->getWidthScaleFactor());
 				return true;
 			}
 		}
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index d9c35a58492..d79706a8561 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -108,6 +108,7 @@ class LLWorld final : public LLSingleton<LLWorld>
 	LLSurfacePatch *		resolveLandPatchGlobal(const LLVector3d &position);
 	LLVector3				resolveLandNormalGlobal(const LLVector3d &position);		// absolute frame
 
+	void					setRegionSize(const U32& width = 0, const U32& length = 0);
 	U32						getRegionWidthInPoints() const	{ return mWidth; }
 	F32						getRegionScale() const			{ return mScale; }
 
@@ -196,12 +197,13 @@ class LLWorld final : public LLSingleton<LLWorld>
 	region_remove_signal_t mRegionRemovedSignal;
 
 	// Number of points on edge
-	static const U32 mWidth;
+	static U32 mWidth;
+	static U32 mLength;
 
 	// meters/point, therefore mWidth * mScale = meters per edge
 	static const F32 mScale;
 
-	static const F32 mWidthInMeters;
+	static F32 mWidthInMeters;
 
 	F32 mLandFarClip;					// Far clip distance for land.
 	LLPatchVertexArray		mLandPatch;
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index a3ddc6d3364..714da02fe6e 100755
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -460,7 +460,7 @@ version 2.0
 // that a given simulator is present and valid for a set amount of
 // time
 {
-	SetSimPresenceInDatabase Low 23 Trusted Unencoded
+	SetSimPresenceInDatabase Low 23 Trusted Unencoded UDPDeprecated
 	{
 		SimData Single
 		{   RegionID 	LLUUID	}
@@ -2064,11 +2064,10 @@ version 2.0
     {
 		ExtraPhysics        Variable
 		{   PhysicsShapeType U8     }
-        {   Density          F32    }
-        {   Friction         F32    }
-        {   Restitution      F32    }
-        {   GravityMultiplier    F32    }
-
+		{	Density			 F32	}
+		{	Friction		 F32	}
+		{	Restitution 	 F32	}
+		{	GravityMultiplier	 F32	}
 	}
 }
 
@@ -2847,6 +2846,10 @@ version 2.0
 		{	Message			Variable	1	}
 		{	ExtraParams		Variable	1	}
 	}
+    {
+        AgentInfo           Variable
+        {   AgentID         LLUUID  }
+    }
 }
 
 // Send an AlertMessage to the named agent.
@@ -4255,7 +4258,7 @@ version 2.0
 		{	Questions		S32	}
 	}
 	{
-		Experience	Single
+	Experience	Single
 		{	ExperienceID	LLUUID	}
 	}
 }
@@ -4449,7 +4452,7 @@ version 2.0
 // WARNING: This packet is potentially large.  With max length name,
 // description, music URL and media URL, it is 1526 + sizeof ( LLUUID ) bytes.
 {
-	ParcelProperties High 23 Trusted Zerocoded
+	ParcelProperties High 23 Trusted Zerocoded UDPDeprecated
 	{
 		ParcelData			Single
 		{	RequestResult	S32				}
@@ -4503,15 +4506,16 @@ version 2.0
 		{	RegionDenyAnonymous	BOOL		}
 		{	RegionDenyIdentified	BOOL		}
 		{	RegionDenyTransacted	BOOL		}
+		// in llsd message, SeeAVs, GroupAVSounds and AnyAVSounds BOOLs are also sent
 	}
 	{
 		AgeVerificationBlock Single
 		{   RegionDenyAgeUnverified BOOL    }
 	}
-    {
-        RegionAllowAccessBlock Single
-        {   RegionAllowAccessOverride BOOL  }  
-    }
+	{
+		RegionAllowAccessBlock Single
+		{   RegionAllowAccessOverride BOOL    }
+	}
     {
         ParcelEnvironmentBlock Single
         {   ParcelEnvironmentVersion        S32  }
@@ -5280,6 +5284,10 @@ version 2.0
 		{	CanAcceptAgents		BOOL	}
 		{	CanAcceptTasks		BOOL	}
 	}
+	{
+		SimFlags				Single
+		{	Flags				U64 }
+	}
 }
 
 // Child Agent Update - agents send child agents to neighboring simulators.
@@ -5358,6 +5366,10 @@ version 2.0
 		AgentInfo				Variable
 		{	Flags					U32	}
 	}
+	{
+		AgentInventoryHost		Variable
+		{	InventoryHost		Variable	1	} //String
+	}
 }
 
 // ChildAgentAlive
@@ -5659,10 +5671,15 @@ version 2.0
 		{	Message			Variable	2	}
 		{	BinaryBucket	Variable	2	}
 	}
+	{
+		EstateBlock			Single
+		{	EstateID		U32	}
+	}
 }
 
 // RetrieveInstantMessages - used to get instant messages that
 // were persisted out to the database while the user was offline
+// Sent from viewer->simulator.   Also see RetrieveIMsExtended (back-end only)
 {
 	RetrieveInstantMessages Low 255 NotTrusted Unencoded
 	{
@@ -6576,6 +6593,11 @@ version 2.0
 		{	InventoryID		LLUUID	}
 		{	Type			S8	}
 	}
+	{
+		ValidationBlock		Single
+		{	NeedsValidation	BOOL	}
+		{	EstateID		U32	}
+	}
 }
 
 // dataserver -> sim
@@ -6921,7 +6943,7 @@ version 2.0
 // dataserver -> simulator -> spaceserver -> simulator -> viewer
 // reliable
 {
-	RoutedMoneyBalanceReply Low 315 Trusted Zerocoded
+	RoutedMoneyBalanceReply Low 315 Trusted Zerocoded UDPDeprecated
 	{
 		TargetBlock			Single
 		{	TargetIP		IPADDR	}	// U32 encoded IP
@@ -7655,10 +7677,14 @@ version 2.0
 		InviteData	Single
 		{	AgentID		LLUUID	}
 		{	InviteeID	LLUUID	}
-		{	GroupID			LLUUID	}
+		{	GroupID		LLUUID	}
 		{	RoleID		LLUUID	}
 		{	MembershipFee S32	}
 	}
+	{
+		GroupData	Single
+		{	GroupLimit    S32	}		// Extra block for the agent's group limit
+	}
 }
 
 // GroupProfileRequest
@@ -8778,6 +8804,11 @@ version 2.0
 		{	Agents		U8				}
 		{	MapImageID	LLUUID			}
 	}
+	{
+		Size			Variable
+		{	SizeX		U16				}
+		{	SizeY		U16				}
+	}
 }
 
 // viewer -> sim
diff --git a/scripts/messages/message_template.msg.sha256 b/scripts/messages/message_template.msg.sha256
index 22b227cb7fa..fd070287548 100644
--- a/scripts/messages/message_template.msg.sha256
+++ b/scripts/messages/message_template.msg.sha256
@@ -1 +1 @@
-6c29ee95a82a309046de26e1178cca385e2d5bff87eb9a5f6ff6dc9a6050f5ba
\ No newline at end of file
+1b3a27136052b532a0947ce7fb4339ffed1084f2ef8303d5b86eb6d176932803
\ No newline at end of file
-- 
GitLab