diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 637326acd0f86439ebb23eeaeed38a2a056985a8..1392f155b84238f19275bec15e77b667a2332fc9 100755
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -821,7 +821,13 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction)
 
 		LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
 		camera_offset_dir.normalize();
-		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
+// [RLVa:KB] - Checked: 2.0.0
+		const LLVector3d focus_offset_target = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
+		if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(focus_offset_target)) )
+			return;
+		mCameraFocusOffsetTarget = focus_offset_target;
+// [/RLVa:KB]
+//		mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
 	}
 	startCameraAnimation();
 }
@@ -946,6 +952,11 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction)
 		new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
 	}
 
+// [RLVa:KB] - Checked: 2.0.0
+	if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) )
+		return;
+// [/RLVa:KB]
+
 	mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
 }
 
@@ -1009,6 +1020,11 @@ void LLAgentCamera::cameraOrbitIn(const F32 meters)
 			new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
 		}
 
+// [RLVa:KB] - Checked: 2.0.0
+		if ( (RlvActions::isRlvEnabled()) && (!allowFocusOffsetChange(new_distance * camera_offset_unit)) )
+			return;
+// [/RLVa:KB]
+
 		// Compute new camera offset
 		mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
 		cameraZoomIn(1.f);
@@ -1931,6 +1947,44 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 //			}
 	}
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	if ( (CAMERA_MODE_THIRD_PERSON == mCameraMode) && (RlvActions::isRlvEnabled()) && (RlvActions::isCameraDistanceClamped()) )
+	{
+		m_fRlvMinDist = m_fRlvMaxDist = false;
+
+		// Av-locked | Focus-locked | Result
+		// ===================================================
+		//     T     |      T       | skip focus => slam av
+		//     T     |      F       | skip focus => slam av
+		//     F     |      T       | skip av    => slam focus
+		//     F     |      F       | clamp focus then av
+		bool fCamAvDistClamped, fCamAvDistLocked = false; float nCamAvDistLimitMin, nCamAvDistLimitMax;
+		if (fCamAvDistClamped = RlvActions::getCameraAvatarDistanceLimits(nCamAvDistLimitMin, nCamAvDistLimitMax))
+			fCamAvDistLocked = nCamAvDistLimitMin == nCamAvDistLimitMax;
+		bool fCamFocusDistClamped, fCamFocusDistLocked = false; float nCamFocusDistLimitMin, nCamFocusDistLimitMax;
+		if (fCamFocusDistClamped = RlvActions::getCameraFocusDistanceLimits(nCamFocusDistLimitMin, nCamFocusDistLimitMax))
+			fCamFocusDistLocked = nCamFocusDistLimitMin == nCamFocusDistLimitMax;
+
+		// Check focus distance limits
+		if ( (fCamFocusDistClamped) && (!fCamAvDistLocked) )
+		{
+			const LLVector3 offsetCameraLocal = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale");
+			const LLVector3d offsetCamera(gAgent.getFrameAgent().rotateToAbsolute(offsetCameraLocal));
+			const LLVector3d posFocusCam = frame_center_global + head_offset + offsetCamera;
+			if (clampCameraPosition(camera_position_global, posFocusCam, nCamFocusDistLimitMin, nCamFocusDistLimitMax))
+				isConstrained = TRUE;
+		}
+
+		// Check avatar distance limits
+		if ( (fCamAvDistClamped) && (fCamAvDistLocked || !fCamFocusDistClamped) )
+		{
+			const LLVector3d posAvatarCam = gAgent.getPosGlobalFromAgent( (isAgentAvatarValid()) ? gAgentAvatarp->mHeadp->getWorldPosition() : gAgent.getPositionAgent() );
+			if (clampCameraPosition(camera_position_global, posAvatarCam, nCamAvDistLimitMin, nCamAvDistLimitMax))
+				isConstrained = TRUE;
+		}
+	}
+// [/RLVa:KB]
+
 	// Don't let camera go underground
 	F32 camera_min_off_ground = getCameraMinOffGround();
 
@@ -1951,6 +2005,49 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 	return camera_position_global;
 }
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+bool LLAgentCamera::allowFocusOffsetChange(const LLVector3d& offsetFocus)
+{
+	if (RlvActions::isCameraDistanceClamped())
+	{
+		if ( (CAMERA_MODE_THIRD_PERSON == getCameraMode()) && ((m_fRlvMinDist) || (m_fRlvMaxDist)) )
+		{
+			const LLVector3d posFocusGlobal = calcFocusPositionTargetGlobal();
+			// Don't allow moving the focus offset if at minimum and moving closer (or if at maximum and moving further) to prevent camera warping
+			F32 nCurDist = llabs((posFocusGlobal + mCameraFocusOffsetTarget - m_posRlvRefGlobal).magVec());
+			F32 nNewDist = llabs((posFocusGlobal + offsetFocus - m_posRlvRefGlobal).magVec());
+			if ( ((m_fRlvMaxDist) && (nNewDist > nCurDist)) || ((m_fRlvMinDist) && (nNewDist < nCurDist)) )
+				return false;
+		}
+	}
+	return true;
+}
+
+bool LLAgentCamera::clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax)
+{
+	const LLVector3d offsetCamera = posCamGlobal - posCamRefGlobal;
+
+	F32 nCamAvDist = llabs(offsetCamera.magVec()), nDistMult = NAN;
+	if (nCamAvDist > nDistMax)
+	{
+		nDistMult = nDistMax / nCamAvDist;
+		m_fRlvMaxDist = true;
+	}
+	else if (nCamAvDist < nDistMin)
+	{
+		nDistMult = nDistMin / nCamAvDist;
+		m_fRlvMinDist = true;
+	}
+
+	if (!isnan(nDistMult))
+	{
+		posCamGlobal = posCamRefGlobal + nDistMult * offsetCamera;
+		m_posRlvRefGlobal = posCamRefGlobal;
+		return true;
+	}
+	return false;
+}
+// [/RLVa:KB]
 
 LLVector3 LLAgentCamera::getCameraOffsetInitial()
 {
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index 3a448de7839eab0ff3fdb103b7f989b1adaaf549..969a86ab558ae3c0e01cabf47d176ba65e90145b 100755
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -305,6 +305,18 @@ public:
 	F32				mHUDTargetZoom;	// Target zoom level for HUD objects (used when editing)
 	F32				mHUDCurZoom; 	// Current animated zoom level for HUD objects
 
+// [RLVa:KB] - Checked: RLVa-2.0.0
+	//--------------------------------------------------------------------
+	// RLVa
+	//--------------------------------------------------------------------
+protected:
+	bool allowFocusOffsetChange(const LLVector3d& offsetFocus);
+	bool clampCameraPosition(LLVector3d& posCamGlobal, const LLVector3d posCamRefGlobal, float nDistMin, float nDistMax);
+
+	bool m_fRlvMaxDist;				// True if the camera is at max distance
+	bool m_fRlvMinDist;				// True if the camera is at min distance
+	LLVector3d m_posRlvRefGlobal;		// Current reference point for distance calculations
+// [/RLVa:KB]
 
 /********************************************************************************
  **                                                                            **
diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp
index 89bba202fdfa29dc8735dfda560ef2d6ecf94a66..f1c9ec27ab0a073b23d40880c0941cf2e1891cb0 100644
--- a/indra/newview/rlvactions.cpp
+++ b/indra/newview/rlvactions.cpp
@@ -27,6 +27,12 @@
 // Camera
 //
 
+bool RlvActions::canChangeCameraFOV(const LLUUID& idRlvObject)
+{
+	// NOTE: if an object has exclusive camera controls then all other objects are locked out
+	return (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM));
+}
+
 bool RlvActions::canChangeCameraPreset(const LLUUID& idRlvObject)
 {
 	// NOTE: if an object has exclusive camera controls then all other objects are locked out
@@ -35,10 +41,16 @@ bool RlvActions::canChangeCameraPreset(const LLUUID& idRlvObject)
 		(!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET));
 }
 
-bool RlvActions::canChangeCameraFOV(const LLUUID& idRlvObject)
+bool RlvActions::isCameraDistanceClamped()
 {
-	// NOTE: if an object has exclusive camera controls then all other objects are locked out
-	return (!gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(idRlvObject, RLV_BHVR_SETCAM));
+	return
+		(gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX)) ||
+		(gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSDISTMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSDISTMAX));
+}
+
+bool RlvActions::isCameraFOVClamped()
+{
+	return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX));
 }
 
 bool RlvActions::isCameraPresetLocked()
@@ -46,23 +58,49 @@ bool RlvActions::isCameraPresetLocked()
 	return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_EYEOFFSET)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSOFFSET));
 }
 
-bool RlvActions::isCameraFOVClamped()
+bool RlvActions::getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax)
 {
-	return (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX));
+	bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_AVDISTMAX);
+	if ( (fDistMin) || (fDistMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_AVDISTMIN);
+		static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_AVDISTMAX);
+
+		nDistMax = (fDistMax) ? sCamDistMax : F32_MAX;
+		nDistMin = (fDistMin) ? sCamDistMin : 0.0;
+		return true;
+	}
+	return false;
 }
 
-bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax)
+bool RlvActions::getCameraFocusDistanceLimits(float& nDistMin, float& nDistMax)
 {
-	static RlvCachedBehaviourModifier<float> sCamFovMin(RLV_MODIFIER_SETCAM_FOVMIN);
-	static RlvCachedBehaviourModifier<float> sCamFovMax(RLV_MODIFIER_SETCAM_FOVMAX);
-
-	bool fClampMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX);
-	nFOVMax = (fClampMax) ? sCamFovMax : LLViewerCamera::getInstance()->getMaxView();
+	bool fDistMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSDISTMIN), fDistMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOCUSDISTMAX);
+	if ( (fDistMin) || (fDistMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamDistMin(RLV_MODIFIER_SETCAM_FOCUSDISTMIN);
+		static RlvCachedBehaviourModifier<float> sCamDistMax(RLV_MODIFIER_SETCAM_FOCUSDISTMAX);
 
-	bool fClampMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN);
-	nFOVMin = (fClampMin) ? sCamFovMin : LLViewerCamera::getInstance()->getMinView();
+		nDistMax = (fDistMax) ? sCamDistMax : F32_MAX;
+		nDistMin = (fDistMin) ? sCamDistMin : 0.0;
+		return true;
+	}
+	return false;
+}
 
-	return (fClampMin) || (fClampMax);
+bool RlvActions::getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax)
+{
+	bool fClampMin = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMIN), fClampMax = gRlvHandler.hasBehaviour(RLV_BHVR_SETCAM_FOVMAX);
+	if ( (fClampMin) || (fClampMax) )
+	{
+		static RlvCachedBehaviourModifier<float> sCamFovMin(RLV_MODIFIER_SETCAM_FOVMIN);
+		static RlvCachedBehaviourModifier<float> sCamFovMax(RLV_MODIFIER_SETCAM_FOVMAX);
+
+		nFOVMin = (fClampMin) ? sCamFovMin : LLViewerCamera::getInstance()->getMinView();
+		nFOVMax = (fClampMax) ? sCamFovMax : LLViewerCamera::getInstance()->getMaxView();
+		return true;
+	}
+	return false;
 }
 
 // ============================================================================
diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h
index e93060f384584c37d6095ff44995493a550e6107..2fbe9e0acadf100815d9abbf5b23d813762f3da4 100644
--- a/indra/newview/rlvactions.h
+++ b/indra/newview/rlvactions.h
@@ -29,15 +29,25 @@ class RlvActions
 	// Camera
 	// ======
 public:
+	/*
+	 * Returns true if the specified object cannot manipulate the camera FOV
+	 */
+	static bool canChangeCameraFOV(const LLUUID& idRlvObject);
+
 	/*
 	 * Returns true if the specified object can manipulate the camera offset and/or focus offset values
 	 */
 	static bool canChangeCameraPreset(const LLUUID& idRlvObject);
 
 	/*
-	 * Returns true if the specified object cannot manipulate the camera FOV
+	 * Returns true if the camera's distance (from either the avatar of the focus) is currently restricted/clamped
 	 */
-	static bool canChangeCameraFOV(const LLUUID& idRlvObject);
+	static bool isCameraDistanceClamped();
+
+	/*
+	 * Returns true if the camera's FOV is currently restricted/clamped
+	 */
+	static bool isCameraFOVClamped();
 
 	/*
 	 * Returns true if the camera offset and focus offset are locked (prevents changing the current camera preset)
@@ -45,14 +55,15 @@ public:
 	static bool isCameraPresetLocked();
 
 	/*
-	 * Returns true if the camera's FOV is currently restricted/clamped
+	 * Retrieves the current (avatar or focus) camera distance limits
 	 */
-	static bool isCameraFOVClamped();
+	static bool getCameraAvatarDistanceLimits(float& nDistMin, float& nDistMax);
+	static bool getCameraFocusDistanceLimits(float& nDistMin, float& nDistMax);
 
 	/*
 	 * Retrieves the current camera FOV limits - returns isCameraFOVClamped()
 	 */
-	static bool getCameraFOVLimits(F32& nFOVMin, F32& nFOVMax);
+	static bool getCameraFOVLimits(float& nFOVMin, float& nFOVMax);
 
 	// ================================
 	// Communication/Avatar interaction
diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h
index 7814545bd096ab5bf98acaaaa0ce9a9978566489..847b86d743c67ea2666f6f5023b1ea62cf74f4b8 100644
--- a/indra/newview/rlvdefines.h
+++ b/indra/newview/rlvdefines.h
@@ -190,6 +190,10 @@ enum ERlvBehaviour {
 
 	// Camera
 	RLV_BHVR_SETCAM,                // Gives an object exclusive control of the user's camera
+	RLV_BHVR_SETCAM_AVDISTMIN,		// Enforces a minimum distance from the avatar
+	RLV_BHVR_SETCAM_AVDISTMAX,		// Enforces a maximum distance from the avatar
+	RLV_BHVR_SETCAM_FOCUSDISTMIN,	// Enforces a minimum distance from the camera focus
+	RLV_BHVR_SETCAM_FOCUSDISTMAX,	// Enforces a maximum distance from the camera focus
 	RLV_BHVR_SETCAM_EYEOFFSET,      // Changes the default camera offset
 	RLV_BHVR_SETCAM_FOCUSOFFSET,    // Changes the default camera focus offset
 	RLV_BHVR_SETCAM_FOCUS,			// Forces the camera focus and/or position to a specific object, avatar or position
@@ -204,6 +208,10 @@ enum ERlvBehaviour {
 
 enum ERlvBehaviourModifier
 {
+	RLV_MODIFIER_SETCAM_AVDISTMIN,
+	RLV_MODIFIER_SETCAM_AVDISTMAX,
+	RLV_MODIFIER_SETCAM_FOCUSDISTMIN,
+	RLV_MODIFIER_SETCAM_FOCUSDISTMAX,
 	RLV_MODIFIER_SETCAM_EYEOFFSET,
 	RLV_MODIFIER_SETCAM_FOCUSOFFSET,
 	RLV_MODIFIER_SETCAM_FOVMIN,
diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp
index 6237653cbeb21462535972dff67860648683fb6b..ffc95be74b786e141ce64eac6fef456cf477d995 100644
--- a/indra/newview/rlvhelper.cpp
+++ b/indra/newview/rlvhelper.cpp
@@ -161,6 +161,14 @@ RlvBehaviourDictionary::RlvBehaviourDictionary()
 	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_NONE>("viewtexture", RLV_BHVR_VIEWTEXTURE));
 	// Camera
 	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SETCAM, RLV_OPTION_NONE>("setcam"));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmin", RLV_BHVR_SETCAM_AVDISTMIN));
+	addModifier(RLV_BHVR_SETCAM_AVDISTMIN, RLV_MODIFIER_SETCAM_AVDISTMIN, new RlvBehaviourModifier(0.0f, true, new RlvBehaviourModifier_CompMax()));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_avdistmax", RLV_BHVR_SETCAM_AVDISTMAX));
+	addModifier(RLV_BHVR_SETCAM_AVDISTMAX, RLV_MODIFIER_SETCAM_AVDISTMAX, new RlvBehaviourModifier(F32_MAX, true, new RlvBehaviourModifier_CompMin()));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_focusdistmin", RLV_BHVR_SETCAM_FOCUSDISTMIN));
+	addModifier(RLV_BHVR_SETCAM_FOCUSDISTMIN, RLV_MODIFIER_SETCAM_FOCUSDISTMIN, new RlvBehaviourModifier(0.0f, true, new RlvBehaviourModifier_CompMax()));
+	addEntry(new RlvBehaviourGenericProcessor<RLV_OPTION_MODIFIER>("setcam_focusdistmax", RLV_BHVR_SETCAM_FOCUSDISTMAX));
+	addModifier(RLV_BHVR_SETCAM_FOCUSDISTMAX, RLV_MODIFIER_SETCAM_FOCUSDISTMAX, new RlvBehaviourModifier(F32_MAX, true, new RlvBehaviourModifier_CompMin()));
 	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SETCAM_EYEOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_eyeoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));
 	addModifier(RLV_BHVR_SETCAM_EYEOFFSET, RLV_MODIFIER_SETCAM_EYEOFFSET, new RlvBehaviourModifierHandler<RLV_MODIFIER_SETCAM_EYEOFFSET>(LLVector3::zero, true, nullptr));
 	addEntry(new RlvBehaviourToggleProcessor<RLV_BHVR_SETCAM_FOCUSOFFSET, RLV_OPTION_MODIFIER, RlvBehaviourCamEyeFocusOffsetHandler>("setcam_focusoffset", RlvBehaviourInfo::BHVR_EXPERIMENTAL));