diff options
Diffstat (limited to 'indra/newview/llviewerparcelmgr.cpp')
| -rw-r--r-- | indra/newview/llviewerparcelmgr.cpp | 5462 | 
1 files changed, 2734 insertions, 2728 deletions
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 8ed9d24c69..74b43976b8 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1,2728 +1,2734 @@ -/**  - * @file llviewerparcelmgr.cpp - * @brief Viewer-side representation of owned land - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerparcelmgr.h" - -// Library includes -#include "llaudioengine.h" -#include "indra_constants.h" -#include "llcachename.h" -#include "llgl.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llparcel.h" -#include "message.h" -#include "llfloaterreg.h" - -// Viewer includes -#include "llagent.h" -#include "llagentaccess.h" -#include "llviewerparcelaskplay.h" -#include "llviewerwindow.h" -#include "llviewercontrol.h" -//#include "llfirstuse.h" -#include "llfloaterbuyland.h" -#include "llfloatergroups.h" -#include "llpanelnearbymedia.h" -#include "llfloatersellland.h" -#include "llfloatertools.h" -#include "llparcelselection.h" -#include "llresmgr.h" -#include "llsdutil.h" -#include "llsdutil_math.h" -#include "llslurl.h" -#include "llstatusbar.h" -#include "llui.h" -#include "llviewertexture.h" -#include "llviewertexturelist.h" -#include "llviewermenu.h" -#include "llviewerparcelmedia.h" -#include "llviewerparceloverlay.h" -#include "llviewerregion.h" -#include "llworld.h" -#include "roles_constants.h" -#include "llweb.h" -#include "llvieweraudio.h" -#include "llcorehttputil.h" - -#include "llenvironment.h" - -const F32 PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION = 10.f; -const F32 PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY = 1.f; - - -// Globals - -U8* LLViewerParcelMgr::sPackedOverlay = NULL; -S32 LLViewerParcelMgr::PARCEL_BAN_LINES_HIDE = 0; -S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION = 1; -S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_PROXIMITY = 2; - -LLUUID gCurrentMovieID = LLUUID::null; - -LLPointer<LLViewerTexture> sBlockedImage; -LLPointer<LLViewerTexture> sPassImage; - -// Local functions -void callback_start_music(S32 option, void* data); -void optionally_prepare_video(const LLParcel *parcelp); -void callback_prepare_video(S32 option, void* data); -void prepare_video(const LLParcel *parcelp); -void start_video(const LLParcel *parcelp); -void stop_video(); -bool callback_god_force_owner(const LLSD&, const LLSD&); - -struct LLGodForceOwnerData -{ -	LLUUID mOwnerID; -	S32 mLocalID; -	LLHost mHost; - -	LLGodForceOwnerData( -		const LLUUID& owner_id, -		S32 local_parcel_id, -		const LLHost& host) : -		mOwnerID(owner_id), -		mLocalID(local_parcel_id), -		mHost(host) {} -}; - -// -// Methods -// -LLViewerParcelMgr::LLViewerParcelMgr() -:	mSelected(false), -	mRequestResult(0), -	mWestSouth(), -	mEastNorth(), -	mSelectedDwell(DWELL_NAN), -	mAgentParcelSequenceID(-1), -	mHoverRequestResult(0), -	mHoverWestSouth(), -	mHoverEastNorth(), -	mTeleportInProgressPosition(), -	mRenderCollision(false), -	mRenderSelection(true), -	mCollisionBanned(0), -	mCollisionTimer(), -	mMediaParcelId(0), -	mMediaRegionId(0) -{ -	mCurrentParcel = new LLParcel(); -	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); -	mFloatingParcelSelection = new LLParcelSelection(mCurrentParcel); - -	mAgentParcel = new LLParcel(); -	mHoverParcel = new LLParcel(); -	mCollisionParcel = new LLParcel(); - -	mParcelsPerEdge = S32(	REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS ); -	mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; -	resetSegments(mHighlightSegments); - -	mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; -	resetSegments(mCollisionSegments); - -	// JC: Resolved a merge conflict here, eliminated -	// mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP); -	// because it is done in llviewertexturelist.cpp -	mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI); -	mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI); - -	S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS; -	sPackedOverlay = new U8[overlay_size]; - -	mAgentParcelOverlay = new U8[mParcelsPerEdge * mParcelsPerEdge]; -	S32 i; -	for (i = 0; i < mParcelsPerEdge * mParcelsPerEdge; i++) -	{ -		mAgentParcelOverlay[i] = 0; -	} - -	mTeleportInProgress = true; // the initial parcel update is treated like teleport -} - - -LLViewerParcelMgr::~LLViewerParcelMgr() -{ -	mCurrentParcelSelection->setParcel(NULL); -	mCurrentParcelSelection = NULL; - -	mFloatingParcelSelection->setParcel(NULL); -	mFloatingParcelSelection = NULL; - -	delete mCurrentParcel; -	mCurrentParcel = NULL; - -	delete mAgentParcel; -	mAgentParcel = NULL; - -	delete mCollisionParcel; -	mCollisionParcel = NULL; - -	delete mHoverParcel; -	mHoverParcel = NULL; - -	delete[] mHighlightSegments; -	mHighlightSegments = NULL; - -	delete[] mCollisionSegments; -	mCollisionSegments = NULL; - -	delete[] sPackedOverlay; -	sPackedOverlay = NULL; - -	delete[] mAgentParcelOverlay; -	mAgentParcelOverlay = NULL; - -	sBlockedImage = NULL; -	sPassImage = NULL; -} - -void LLViewerParcelMgr::dump() -{ -	LL_INFOS() << "Parcel Manager Dump" << LL_ENDL; -	LL_INFOS() << "mSelected " << S32(mSelected) << LL_ENDL; -	LL_INFOS() << "Selected parcel: " << LL_ENDL; -	LL_INFOS() << mWestSouth << " to " << mEastNorth << LL_ENDL; -	mCurrentParcel->dump(); -	LL_INFOS() << "banning " << mCurrentParcel->mBanList.size() << LL_ENDL; -	 -	LLAccessEntry::map::const_iterator cit = mCurrentParcel->mBanList.begin(); -	LLAccessEntry::map::const_iterator end = mCurrentParcel->mBanList.end(); -	for ( ; cit != end; ++cit) -	{ -		LL_INFOS() << "ban id " << (*cit).first << LL_ENDL; -	} -	LL_INFOS() << "Hover parcel:" << LL_ENDL; -	mHoverParcel->dump(); -	LL_INFOS() << "Agent parcel:" << LL_ENDL; -	mAgentParcel->dump(); -} - - -LLViewerRegion* LLViewerParcelMgr::getSelectionRegion() -{ -	return LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -} - - -void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out, -									   S32* rent_out, -									   bool* for_sale_out, -									   F32* dwell_out) -{ -	S32 area = 0; -	S32 price = 0; -	S32 rent = 0; -	bool for_sale = false; -	F32 dwell = DWELL_NAN; - -	if (mSelected) -	{ -		if (mCurrentParcelSelection->mSelectedMultipleOwners) -		{ -			area = mCurrentParcelSelection->getClaimableArea(); -		} -		else -		{ -			area = getSelectedArea(); -		} - -		if (mCurrentParcel->getForSale()) -		{ -			price = mCurrentParcel->getSalePrice(); -			for_sale = true; -		} -		else -		{ -			price = area * mCurrentParcel->getClaimPricePerMeter(); -			for_sale = false; -		} - -		rent = mCurrentParcel->getTotalRent(); - -		dwell = mSelectedDwell; -	} - -	*area_out = area; -	*claim_out = price; -	*rent_out = rent; -	*for_sale_out = for_sale; -	*dwell_out = dwell; -} - -S32 LLViewerParcelMgr::getSelectedArea() const -{ -	S32 rv = 0; -	if(mSelected && mCurrentParcel && mCurrentParcelSelection->mWholeParcelSelected) -	{ -		rv = mCurrentParcel->getArea(); -	} -	else if(mSelected) -	{ -		F64 width = mEastNorth.mdV[VX] - mWestSouth.mdV[VX]; -		F64 height = mEastNorth.mdV[VY] - mWestSouth.mdV[VY]; -		F32 area = (F32)(width * height); -		rv = ll_round(area); -	} -	return rv; -} - -void LLViewerParcelMgr::resetSegments(U8* segments) -{ -	S32 i; -	S32 count = (mParcelsPerEdge+1)*(mParcelsPerEdge+1); -	for (i = 0; i < count; i++) -	{ -		segments[i] = 0x0; -	} -} - - -void LLViewerParcelMgr::writeHighlightSegments(F32 west, F32 south, F32 east, -											   F32 north) -{ -	S32 x, y; -	S32 min_x = ll_round( west / PARCEL_GRID_STEP_METERS ); -	S32 max_x = ll_round( east / PARCEL_GRID_STEP_METERS ); -	S32 min_y = ll_round( south / PARCEL_GRID_STEP_METERS ); -	S32 max_y = ll_round( north / PARCEL_GRID_STEP_METERS ); - -	const S32 STRIDE = mParcelsPerEdge+1; - -	// south edge -	y = min_y; -	for (x = min_x; x < max_x; x++) -	{ -		// exclusive OR means that writing to this segment twice -		// will turn it off -		mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK; -	} - -	// west edge -	x = min_x; -	for (y = min_y; y < max_y; y++) -	{ -		mHighlightSegments[x + y*STRIDE] ^= WEST_MASK; -	} - -	// north edge - draw the south border on the y+1'th cell, -	// which given C-style arrays, is item foo[max_y] -	y = max_y; -	for (x = min_x; x < max_x; x++) -	{ -		mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK; -	} - -	// east edge - draw west border on x+1'th cell -	x = max_x; -	for (y = min_y; y < max_y; y++) -	{ -		mHighlightSegments[x + y*STRIDE] ^= WEST_MASK; -	} -} - - -void LLViewerParcelMgr::writeSegmentsFromBitmap(U8* bitmap, U8* segments) -{ -	S32 x; -	S32 y; -	const S32 IN_STRIDE = mParcelsPerEdge; -	const S32 OUT_STRIDE = mParcelsPerEdge+1; - -	for (y = 0; y < IN_STRIDE; y++) -	{ -		x = 0; -		while( x < IN_STRIDE ) -		{ -			U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ]; - -			S32 bit; -			for (bit = 0; bit < 8; bit++) -			{ -				if (byte & (1 << bit) ) -				{ -					S32 out = x+y*OUT_STRIDE; - -					// This and one above it -					segments[out]            ^= SOUTH_MASK; -					segments[out+OUT_STRIDE] ^= SOUTH_MASK; - -					// This and one to the right -					segments[out]   ^= WEST_MASK; -					segments[out+1] ^= WEST_MASK; -				} -				x++; -			} -		} -	} -} - - -void LLViewerParcelMgr::writeAgentParcelFromBitmap(U8* bitmap) -{ -	S32 x; -	S32 y; -	const S32 IN_STRIDE = mParcelsPerEdge; - -	for (y = 0; y < IN_STRIDE; y++) -	{ -		x = 0; -		while( x < IN_STRIDE ) -		{ -			U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ]; - -			S32 bit; -			for (bit = 0; bit < 8; bit++) -			{ -				if (byte & (1 << bit) ) -				{ -					mAgentParcelOverlay[x+y*IN_STRIDE] = 1; -				} -				else -				{ -					mAgentParcelOverlay[x+y*IN_STRIDE] = 0; -				} -				x++; -			} -		} -	} -} - - -// Given a point, find the PARCEL_GRID_STEP x PARCEL_GRID_STEP block -// containing it and select that. -LLParcelSelectionHandle LLViewerParcelMgr::selectParcelAt(const LLVector3d& pos_global) -{ -	LLVector3d southwest = pos_global; -	LLVector3d northeast = pos_global; - -	southwest -= LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 ); -	southwest.mdV[VX] = ll_round( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); -	southwest.mdV[VY] = ll_round( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); - -	northeast += LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 ); -	northeast.mdV[VX] = ll_round( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); -	northeast.mdV[VY] = ll_round( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); - -	// Snap to parcel -	return selectLand( southwest, northeast, true ); -} - - -// Tries to select the parcel inside the rectangle -LLParcelSelectionHandle LLViewerParcelMgr::selectParcelInRectangle() -{ -	return selectLand(mWestSouth, mEastNorth, true); -} - - -void LLViewerParcelMgr::selectCollisionParcel() -{ -	// BUG: Claim to be in the agent's region -	mWestSouth = gAgent.getRegion()->getOriginGlobal(); -	mEastNorth = mWestSouth; -	mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0); - -	// BUG: must be in the sim you are in -	LLMessageSystem *msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_ParcelPropertiesRequestByID); -	msg->nextBlockFast(_PREHASH_AgentID); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); -	msg->nextBlockFast(_PREHASH_ParcelData); -	msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID ); -	msg->addS32Fast(_PREHASH_LocalID, mCollisionParcel->getLocalID() ); -	gAgent.sendReliableMessage(); - -	mRequestResult = PARCEL_RESULT_NO_DATA; - -	// Hack: Copy some data over temporarily -	mCurrentParcel->setName( mCollisionParcel->getName() ); -	mCurrentParcel->setDesc( mCollisionParcel->getDesc() ); -	mCurrentParcel->setPassPrice(mCollisionParcel->getPassPrice()); -	mCurrentParcel->setPassHours(mCollisionParcel->getPassHours()); - -	// clear the list of segments to prevent flashing -	resetSegments(mHighlightSegments); - -	mFloatingParcelSelection->setParcel(mCurrentParcel); -	mCurrentParcelSelection->setParcel(NULL); -	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); - -	mSelected = true; -	mCurrentParcelSelection->mWholeParcelSelected = true; -	notifyObservers(); -	return; -} - - -// snap_selection = auto-select the hit parcel, if there is exactly one -LLParcelSelectionHandle LLViewerParcelMgr::selectLand(const LLVector3d &corner1, const LLVector3d &corner2, -								   bool snap_selection) -{ -	sanitize_corners( corner1, corner2, mWestSouth, mEastNorth ); - -	// ...x isn't more than one meter away -	F32 delta_x = getSelectionWidth(); -	if (delta_x * delta_x <= 1.f * 1.f) -	{ -		mSelected = false; -		notifyObservers(); -		return NULL; -	} - -	// ...y isn't more than one meter away -	F32 delta_y = getSelectionHeight(); -	if (delta_y * delta_y <= 1.f * 1.f) -	{ -		mSelected = false; -		notifyObservers(); -		return NULL; -	} - -	// Can't select across region boundary -	// We need to pull in the upper right corner by a little bit to allow -	// selection up to the x = 256 or y = 256 edge. -	LLVector3d east_north_region_check( mEastNorth ); -	east_north_region_check.mdV[VX] -= 0.5; -	east_north_region_check.mdV[VY] -= 0.5; - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth); -	LLViewerRegion *region_other = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check ); - -	if(!region) -	{ -		// just in case they somehow selected no land. -		mSelected = false; -		return NULL; -	} - -	if (region != region_other) -	{ -		LLNotificationsUtil::add("CantSelectLandFromMultipleRegions"); -		mSelected = false; -		notifyObservers(); -		return NULL; -	} - -	// Build region global copies of corners -	LLVector3 wsb_region = region->getPosRegionFromGlobal( mWestSouth ); -	LLVector3 ent_region = region->getPosRegionFromGlobal( mEastNorth ); - -	// 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, SELECTED_PARCEL_SEQ_ID ); -	msg->addF32Fast(_PREHASH_West,  wsb_region.mV[VX] ); -	msg->addF32Fast(_PREHASH_South, wsb_region.mV[VY] ); -	msg->addF32Fast(_PREHASH_East,  ent_region.mV[VX] ); -	msg->addF32Fast(_PREHASH_North, ent_region.mV[VY] ); -	msg->addBOOL("SnapSelection", snap_selection); -	msg->sendReliable( region->getHost() ); - -	mRequestResult = PARCEL_RESULT_NO_DATA; - -	mFloatingParcelSelection->setParcel(mCurrentParcel); -	mCurrentParcelSelection->setParcel(NULL); -	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); - -	mSelected = true; -	mCurrentParcelSelection->mWholeParcelSelected = snap_selection; -	notifyObservers(); -	return mCurrentParcelSelection; -} - -void LLViewerParcelMgr::deselectUnused() -{ -	// no more outstanding references to this selection, other than our own -	if (mCurrentParcelSelection->getNumRefs() == 1 && mFloatingParcelSelection->getNumRefs() == 1) -	{ -		deselectLand(); -	} -} - -void LLViewerParcelMgr::deselectLand() -{ -	if (mSelected) -	{ -		mSelected = false; - -		// Invalidate the selected parcel -		mCurrentParcel->setLocalID(-1); -		mCurrentParcel->mAccessList.clear(); -		mCurrentParcel->mBanList.clear(); -		//mCurrentParcel->mRenterList.reset(); - -		mSelectedDwell = DWELL_NAN; - -		// invalidate parcel selection so that existing users of this selection can clean up -		mCurrentParcelSelection->setParcel(NULL); -		mFloatingParcelSelection->setParcel(NULL); -		// create new parcel selection -		mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); - -		notifyObservers(); // Notify observers *after* changing the parcel selection -	} -} - - -void LLViewerParcelMgr::addObserver(LLParcelObserver* observer) -{ -	mObservers.push_back(observer); -} - - -void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer) -{ -	vector_replace_with_last(mObservers, observer); -} - - -// Call this method when it's time to update everyone on a new state. -// Copy the list because an observer could respond by removing itself -// from the list. -void LLViewerParcelMgr::notifyObservers() -{ -	std::vector<LLParcelObserver*> observers; -	S32 count = mObservers.size(); -	S32 i; -	for(i = 0; i < count; ++i) -	{ -		observers.push_back(mObservers.at(i)); -	} -	for(i = 0; i < count; ++i) -	{ -		observers.at(i)->changed(); -	} -} - - -// -// ACCESSORS -// -bool LLViewerParcelMgr::selectionEmpty() const -{ -	return !mSelected; -} - - -LLParcelSelectionHandle LLViewerParcelMgr::getParcelSelection() const -{ -	return mCurrentParcelSelection; -} - -LLParcelSelectionHandle LLViewerParcelMgr::getFloatingParcelSelection() const -{ -	return mFloatingParcelSelection; -} - -LLParcel *LLViewerParcelMgr::getAgentParcel() const -{ -	return mAgentParcel; -} - - -LLParcel * LLViewerParcelMgr::getAgentOrSelectedParcel() const -{ -    LLParcel *parcel(nullptr); - -    LLParcelSelectionHandle sel_handle(getFloatingParcelSelection()); -    if (sel_handle) -    { -        LLParcelSelection *selection(sel_handle.get()); -        if (selection) -        { -            parcel = selection->getParcel(); -            if (parcel && (parcel->getLocalID() == INVALID_PARCEL_ID)) -            { -                parcel = NULL; -            } -        } -    } - -    if (!parcel) -        parcel = LLViewerParcelMgr::instance().getAgentParcel(); - -    return parcel; -} - -// Return whether the agent can build on the land they are on -bool LLViewerParcelMgr::allowAgentBuild() const -{ -	if (mAgentParcel) -	{ -		return (gAgent.isGodlike() || -				(mAgentParcel->allowModifyBy(gAgent.getID(), gAgent.getGroupID())) || -				(isParcelOwnedByAgent(mAgentParcel, GP_LAND_ALLOW_CREATE))); -	} -	else -	{ -		return gAgent.isGodlike(); -	} -} - -// Return whether anyone can build on the given parcel -bool LLViewerParcelMgr::allowAgentBuild(const LLParcel* parcel) const -{ -	return parcel->getAllowModify(); -} - -bool LLViewerParcelMgr::allowAgentVoice() const -{ -	return allowAgentVoice(gAgent.getRegion(), mAgentParcel); -} - -bool LLViewerParcelMgr::allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const -{ -	return region && region->isVoiceEnabled() -		&& parcel	&& parcel->getParcelFlagAllowVoice(); -} - -bool LLViewerParcelMgr::allowAgentFly(const LLViewerRegion* region, const LLParcel* parcel) const -{ -	return region && !region->getBlockFly() -		&& parcel && parcel->getAllowFly(); -} - -// Can the agent be pushed around by LLPushObject? -bool LLViewerParcelMgr::allowAgentPush(const LLViewerRegion* region, const LLParcel* parcel) const -{ -	return region && !region->getRestrictPushObject() -		&& parcel && !parcel->getRestrictPushObject(); -} - -bool LLViewerParcelMgr::allowAgentScripts(const LLViewerRegion* region, const LLParcel* parcel) const -{ -	// *NOTE: This code does not take into account group-owned parcels -	// and the flag to allow group-owned scripted objects to run. -	// This mirrors the traditional menu bar parcel icon code, but is not -	// technically correct. -	return region -		&& !region->getRegionFlag(REGION_FLAGS_SKIP_SCRIPTS) -		&& !region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS) -		&& parcel -		&& parcel->getAllowOtherScripts(); -} - -bool LLViewerParcelMgr::allowAgentDamage(const LLViewerRegion* region, const LLParcel* parcel) const -{ -	return (region && region->getAllowDamage()) -		|| (parcel && parcel->getAllowDamage()); -} - -bool LLViewerParcelMgr::isOwnedAt(const LLVector3d& pos_global) const -{ -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global ); -	if (!region) return false; - -	LLViewerParcelOverlay* overlay = region->getParcelOverlay(); -	if (!overlay) return false; - -	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global ); - -	return overlay->isOwned( pos_region ); -} - -bool LLViewerParcelMgr::isOwnedSelfAt(const LLVector3d& pos_global) const -{ -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global ); -	if (!region) return false; - -	LLViewerParcelOverlay* overlay = region->getParcelOverlay(); -	if (!overlay) return false; - -	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global ); - -	return overlay->isOwnedSelf( pos_region ); -} - -bool LLViewerParcelMgr::isOwnedOtherAt(const LLVector3d& pos_global) const -{ -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global ); -	if (!region) return false; - -	LLViewerParcelOverlay* overlay = region->getParcelOverlay(); -	if (!overlay) return false; - -	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global ); - -	return overlay->isOwnedOther( pos_region ); -} - -bool LLViewerParcelMgr::isSoundLocal(const LLVector3d& pos_global) const -{ -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global ); -	if (!region) return false; - -	LLViewerParcelOverlay* overlay = region->getParcelOverlay(); -	if (!overlay) return false; - -	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global ); - -	return overlay->isSoundLocal( pos_region ); -} - -bool LLViewerParcelMgr::canHearSound(const LLVector3d &pos_global) const -{ -	bool in_agent_parcel = inAgentParcel(pos_global); - -	if (in_agent_parcel) -	{ -		// In same parcel as the agent -		return true; -	} -	else -	{ -		if (LLViewerParcelMgr::getInstance()->getAgentParcel()->getSoundLocal()) -		{ -			// Not in same parcel, and agent parcel only has local sound -			return false; -		} -		else if (LLViewerParcelMgr::getInstance()->isSoundLocal(pos_global)) -		{ -			// Not in same parcel, and target parcel only has local sound -			return false; -		} -		else -		{ -			// Not in same parcel, but neither are local sound -			return true; -		} -	} -} - - -bool LLViewerParcelMgr::inAgentParcel(const LLVector3d &pos_global) const -{ -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(pos_global); -	LLViewerRegion* agent_region = gAgent.getRegion(); -	if (!region || !agent_region) -		return false; - -	if (region != agent_region) -	{ -		// Can't be in the agent parcel if you're not in the same region. -		return false; -	} - -	LLVector3 pos_region = agent_region->getPosRegionFromGlobal(pos_global); -	S32 row =    S32(pos_region.mV[VY] / PARCEL_GRID_STEP_METERS); -	S32 column = S32(pos_region.mV[VX] / PARCEL_GRID_STEP_METERS); - -	if (mAgentParcelOverlay[row*mParcelsPerEdge + column]) -	{ -		return true; -	} -	else -	{ -		return false; -	} -} - -// Returns NULL when there is no valid data. -LLParcel* LLViewerParcelMgr::getHoverParcel() const -{ -	if (mHoverRequestResult == PARCEL_RESULT_SUCCESS) -	{ -		return mHoverParcel; -	} -	else -	{ -		return NULL; -	} -} - -// Returns NULL when there is no valid data. -LLParcel* LLViewerParcelMgr::getCollisionParcel() const -{ -	if (mRenderCollision) -	{ -		return mCollisionParcel; -	} -	else -	{ -		return NULL; -	} -} - -// -// UTILITIES -// - -void LLViewerParcelMgr::render() -{ -	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected) -	{ -		// Rendering is done in agent-coordinates, so need to supply -		// an appropriate offset to the render code. -		LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth); -		if (!regionp) return; - -		renderHighlightSegments(mHighlightSegments, regionp); -	} -} - - -void LLViewerParcelMgr::renderParcelCollision() -{ -    static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION); - -	// check for expiration -    F32 expiration = (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY) -        ? PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY -        : PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION; -	if (mCollisionTimer.getElapsedTimeF32() > expiration) -	{ -		mRenderCollision = false; -	} - -	if (mRenderCollision && ban_lines_mode != PARCEL_BAN_LINES_HIDE) -	{ -		LLViewerRegion* regionp = gAgent.getRegion(); -		if (regionp) -		{ -			bool use_pass = mCollisionParcel->getParcelFlag(PF_USE_PASS_LIST); -			renderCollisionSegments(mCollisionSegments, use_pass, regionp); -		} -	} -} - - -void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags) -{ -	if (!mSelected) -	{ -		return; -	} - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) return; - -	LLMessageSystem *msg = gMessageSystem; - - -	if (flags & AL_BAN)  -	{ -		mCurrentParcel->mBanList.clear(); -	} -	if (flags & AL_ACCESS)  -	{ -		mCurrentParcel->mAccessList.clear(); -	}		 -	if (flags & AL_ALLOW_EXPERIENCE)  -	{ -		mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED); -	} -	if (flags & AL_BLOCK_EXPERIENCE)  -	{ -		mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED); -	}		 - -	// Only the headers differ -	msg->newMessageFast(_PREHASH_ParcelAccessListRequest); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_Data); -	msg->addS32Fast(_PREHASH_SequenceID, 0); -	msg->addU32Fast(_PREHASH_Flags, flags); -	msg->addS32("LocalID", mCurrentParcel->getLocalID() ); -	msg->sendReliable( region->getHost() ); -} - - -void LLViewerParcelMgr::sendParcelDwellRequest() -{ -	if (!mSelected) -	{ -		return; -	} - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) return; - -	LLMessageSystem *msg = gMessageSystem; - -	// Only the headers differ -	msg->newMessage("ParcelDwellRequest"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", gAgent.getID() ); -	msg->addUUID("SessionID", gAgent.getSessionID()); -	msg->nextBlock("Data"); -	msg->addS32("LocalID", mCurrentParcel->getLocalID()); -	msg->addUUID("ParcelID", LLUUID::null);	// filled in on simulator -	msg->sendReliable( region->getHost() ); -} - - -void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) -{ -	if (!mSelected) -	{ -		LLNotificationsUtil::add("CannotSetLandOwnerNothingSelected"); -		return; -	} - -	LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; - -	// BUG: Only works for the region containing mWestSouthBottom -	LLVector3d east_north_region_check( mEastNorth ); -	east_north_region_check.mdV[VX] -= 0.5; -	east_north_region_check.mdV[VY] -= 0.5; - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) -	{ -		// TODO: Add a force owner version of this alert. -		LLNotificationsUtil::add("CannotContentifyNoRegion"); -		return; -	} - -	// BUG: Make work for cross-region selections -	LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check ); -	if (region != region2) -	{ -		LLNotificationsUtil::add("CannotSetLandOwnerMultipleRegions"); -		return; -	} - -	LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL; - -	LLSD payload; -	payload["owner_id"] = owner_id; -	payload["parcel_local_id"] = mCurrentParcel->getLocalID(); -	payload["region_host"] = region->getHost().getIPandPort(); -	LLNotification::Params params("ForceOwnerAuctionWarning"); -	params.payload(payload).functor.function(callback_god_force_owner); - -	if(mCurrentParcel->getAuctionID()) -	{ -		LLNotifications::instance().add(params); -	} -	else -	{ -		LLNotifications::instance().forceResponse(params, 0); -	} -} - -bool callback_god_force_owner(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if(0 == option) -	{ -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessage("ParcelGodForceOwner"); -		msg->nextBlock("AgentData"); -		msg->addUUID("AgentID", gAgent.getID()); -		msg->addUUID("SessionID", gAgent.getSessionID()); -		msg->nextBlock("Data"); -		msg->addUUID("OwnerID", notification["payload"]["owner_id"].asUUID()); -		msg->addS32( "LocalID", notification["payload"]["parcel_local_id"].asInteger()); -		msg->sendReliable(LLHost(notification["payload"]["region_host"].asString())); -	} -	return false; -} - -void LLViewerParcelMgr::sendParcelGodForceToContent() -{ -	if (!mSelected) -	{ -		LLNotificationsUtil::add("CannotContentifyNothingSelected"); -		return; -	} -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotContentifyNoRegion"); -		return; -	} - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessage("ParcelGodMarkAsContent"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", gAgent.getID()); -	msg->addUUID("SessionID", gAgent.getSessionID()); -	msg->nextBlock("ParcelData"); -	msg->addS32("LocalID", mCurrentParcel->getLocalID()); -	msg->sendReliable(region->getHost()); -} - -void LLViewerParcelMgr::sendParcelRelease() -{ -	if (!mSelected) -	{ -        LLNotificationsUtil::add("CannotReleaseLandNothingSelected"); -		return; -	} - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotReleaseLandNoRegion"); -		return; -	} - -	//U32 flags = PR_NONE; -	//if (god_force) flags |= PR_GOD_FORCE; - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessage("ParcelRelease"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", gAgent.getID() ); -	msg->addUUID("SessionID", gAgent.getSessionID() ); -	msg->nextBlock("Data"); -	msg->addS32("LocalID", mCurrentParcel->getLocalID() ); -	//msg->addU32("Flags", flags); -	msg->sendReliable( region->getHost() ); - -	// Blitz selection, since the parcel might be non-rectangular, and -	// we won't have appropriate parcel information. -	deselectLand(); -} - -class LLViewerParcelMgr::ParcelBuyInfo -{ -public: -	LLUUID	mAgent; -	LLUUID	mSession; -	LLUUID	mGroup; -	bool	mIsGroupOwned; -	bool	mRemoveContribution; -	bool	mIsClaim; -	LLHost	mHost; -	 -	// for parcel buys -	S32		mParcelID; -	S32		mPrice; -	S32		mArea; - -	// for land claims -	F32		mWest; -	F32		mSouth; -	F32		mEast; -	F32		mNorth; -}; - -LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy( -	const LLUUID& agent_id, -	const LLUUID& session_id, -	const LLUUID& group_id, -	bool is_group_owned, -	bool is_claim, -	bool remove_contribution) -{ -	if (!mSelected || !mCurrentParcel) -	{ -		LLNotificationsUtil::add("CannotBuyLandNothingSelected"); -		return NULL; -	} - -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotBuyLandNoRegion"); -		return NULL; -	} -	 -	if (is_claim) -	{ -		LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; -		LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL; - -		// BUG: Only works for the region containing mWestSouthBottom -		LLVector3d east_north_region_check( mEastNorth ); -		east_north_region_check.mdV[VX] -= 0.5; -		east_north_region_check.mdV[VY] -= 0.5; - -		LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check ); - -		if (region != region2) -		{ -			LLNotificationsUtil::add("CantBuyLandAcrossMultipleRegions"); -			return NULL; -		} -	} -	 -	 -	ParcelBuyInfo* info = new ParcelBuyInfo; -	 -	info->mAgent = agent_id; -	info->mSession = session_id; -	info->mGroup = group_id; -	info->mIsGroupOwned = is_group_owned; -	info->mIsClaim = is_claim; -	info->mRemoveContribution = remove_contribution; -	info->mHost = region->getHost(); -	info->mPrice = mCurrentParcel->getSalePrice(); -	info->mArea = mCurrentParcel->getArea(); -	 -	if (!is_claim) -	{ -		info->mParcelID = mCurrentParcel->getLocalID(); -	} -	else -	{ -		// BUG: Make work for cross-region selections -		LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth ); -		LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth ); -		 -		info->mWest		= west_south_bottom_region.mV[VX]; -		info->mSouth	= west_south_bottom_region.mV[VY]; -		info->mEast		= east_north_top_region.mV[VX]; -		info->mNorth	= east_north_top_region.mV[VY]; -	} -	 -	return info; -} - -void LLViewerParcelMgr::sendParcelBuy(ParcelBuyInfo* info) -{ -	// send the message -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessage(info->mIsClaim ? "ParcelClaim" : "ParcelBuy"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", info->mAgent); -	msg->addUUID("SessionID", info->mSession); -	msg->nextBlock("Data"); -	msg->addUUID("GroupID", info->mGroup); -	msg->addBOOL("IsGroupOwned", info->mIsGroupOwned); -	if (!info->mIsClaim) -	{ -		msg->addBOOL("RemoveContribution", info->mRemoveContribution); -		msg->addS32("LocalID", info->mParcelID); -	} -	msg->addBOOL("Final", true);	// don't allow escrow buys -	if (info->mIsClaim) -	{ -		msg->nextBlock("ParcelData"); -		msg->addF32("West",  info->mWest); -		msg->addF32("South", info->mSouth); -		msg->addF32("East",  info->mEast); -		msg->addF32("North", info->mNorth); -	} -	else // ParcelBuy -	{ -		msg->nextBlock("ParcelData"); -		msg->addS32("Price",info->mPrice); -		msg->addS32("Area",info->mArea); -	} -	msg->sendReliable(info->mHost); -} - -void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo* *info) -{ -	// Must be here because ParcelBuyInfo is local to this .cpp file -	delete *info; -	*info = NULL; -} - -void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id) -{ -	if (!mSelected || !mCurrentParcel) -	{ -		LLNotificationsUtil::add("CannotDeedLandNothingSelected"); -		return; -	} -	if(group_id.isNull()) -	{ -		LLNotificationsUtil::add("CannotDeedLandNoGroup"); -		return; -	} -	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotDeedLandNoRegion"); -		return; -	} - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessage("ParcelDeedToGroup"); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", gAgent.getID() ); -	msg->addUUID("SessionID", gAgent.getSessionID() ); -	msg->nextBlock("Data"); -	msg->addUUID("GroupID", group_id ); -	msg->addS32("LocalID", mCurrentParcel->getLocalID() ); -	//msg->addU32("JoinNeighbors", join); -	msg->sendReliable( region->getHost() ); -} - - -/* -// *NOTE: We cannot easily make landmarks at global positions because -// global positions probably refer to a sim/local combination which -// can move over time. We could implement this by looking up the -// region global x,y, but it's easier to take it out for now. -void LLViewerParcelMgr::makeLandmarkAtSelection() -{ -	// Don't create for parcels you don't own -	if (gAgent.getID() != mCurrentParcel->getOwnerID()) -	{ -		return; -	} - -	LLVector3d global_center(mWestSouth); -	global_center += mEastNorth; -	global_center *= 0.5f; - -	LLViewerRegion* region; -	region = LLWorld::getInstance()->getRegionFromPosGlobal(global_center); - -	LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth ); -	LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth ); - -	std::string name("My Land"); -	std::string buffer; -	S32 pos_x = (S32)floor((west_south_bottom_region.mV[VX] + east_north_top_region.mV[VX]) / 2.0f); -	S32 pos_y = (S32)floor((west_south_bottom_region.mV[VY] + east_north_top_region.mV[VY]) / 2.0f); -	buffer = llformat("%s in %s (%d, %d)", -			name.c_str(), -			region->getName().c_str(), -			pos_x, pos_y); -	name.assign(buffer); - -	create_landmark(name, "Claimed land", global_center); -} -*/ - -const std::string& LLViewerParcelMgr::getAgentParcelName() const -{ -	return mAgentParcel->getName(); -} - - -const S32 LLViewerParcelMgr::getAgentParcelId() const -{ -    if (mAgentParcel) -        return mAgentParcel->getLocalID(); -    return INVALID_PARCEL_ID; -} - -void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) -{ -	if(!parcel)  -        return; - -	LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region)  -        return; - -	LLSD body; -	std::string url = region->getCapability("ParcelPropertiesUpdate"); -	if (!url.empty()) -	{ -		// request new properties update from simulator -		U32 message_flags = 0x01; -		body["flags"] = ll_sd_from_U32(message_flags); -		parcel->packMessage(body); -		LL_INFOS("ParcelMgr") << "Sending parcel properties update via capability to: " -			<< url << LL_ENDL; - -        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, -            "Parcel Properties sent to sim.", "Parcel Properties failed to send to sim."); -	} -	else -	{ -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessageFast(_PREHASH_ParcelPropertiesUpdate); -		msg->nextBlockFast(_PREHASH_AgentData); -		msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID() ); -		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -		msg->nextBlockFast(_PREHASH_ParcelData); -		msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() ); - -		U32 message_flags = 0x01; -		msg->addU32("Flags", message_flags); - -		parcel->packMessage(msg); - -		msg->sendReliable( region->getHost() ); -	} -} - - -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 -	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; -	} - -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos ); -	if (!region) -	{ -		return; -	} - -	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 -		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; - -		// 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; -	} -} - - -// static -void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user) -{ -	// Extract the packed overlay information -	S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data); - -	if (packed_overlay_size <= 0) -	{ -		LL_WARNS() << "Overlay size " << packed_overlay_size << LL_ENDL; -		return; -	} - -	S32 parcels_per_edge = LLViewerParcelMgr::getInstance()->mParcelsPerEdge; -	S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS; -	if (packed_overlay_size != expected_size) -	{ -		LL_WARNS() << "Got parcel overlay size " << packed_overlay_size -			<< " expecting " << expected_size << LL_ENDL; -		return; -	} - -	S32 sequence_id; -	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id); -	msg->getBinaryDataFast( -			_PREHASH_ParcelData, -			_PREHASH_Data, -			sPackedOverlay, -			expected_size); - -	LLHost host = msg->getSender(); -	LLViewerRegion *region = LLWorld::getInstance()->getRegion(host); -	if (region) -	{ -		region->mParcelOverlay->uncompressLandOverlay( sequence_id, sPackedOverlay ); -	} -} - -// static -void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **user) -{ -    S32		request_result; -    S32		sequence_id; -    bool	snap_selection = false; -    S32		self_count = 0; -    S32		other_count = 0; -    S32		public_count = 0; -    S32		local_id; -    LLUUID	owner_id; -    bool	is_group_owned; -    U32 auction_id = 0; -    S32		claim_price_per_meter = 0; -    S32		rent_price_per_meter = 0; -    S32		claim_date = 0; -    LLVector3	aabb_min; -    LLVector3	aabb_max; -    S32		area = 0; -    S32		sw_max_prims = 0; -    S32		sw_total_prims = 0; -    //LLUUID	buyer_id; -    U8 status = 0; -    S32		max_prims = 0; -    S32		total_prims = 0; -    S32		owner_prims = 0; -    S32		group_prims = 0; -    S32		other_prims = 0; -    S32		selected_prims = 0; -    F32		parcel_prim_bonus = 1.f; -    bool	region_push_override = false; -    bool	region_deny_anonymous_override = false; -    bool	region_deny_identified_override = false; // Deprecated -    bool	region_deny_transacted_override = false; // Deprecated -    bool	region_deny_age_unverified_override = false; -    bool    region_allow_access_override = true; -    bool    region_allow_environment_override = true; -    S32     parcel_environment_version = 0; -    bool	agent_parcel_update = false; // updating previous(existing) agent parcel -    U32     extended_flags = 0; //obscure MOAP - -    S32		other_clean_time = 0; - -    LLViewerParcelMgr& parcel_mgr = LLViewerParcelMgr::instance(); - -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id); - -    if (request_result == PARCEL_RESULT_NO_DATA) -    { -        // no valid parcel data -        LL_INFOS("ParcelMgr") << "no valid parcel data" << LL_ENDL; -        return; -    } - -    // Decide where the data will go. -    LLParcel* parcel = NULL; -    if (sequence_id == SELECTED_PARCEL_SEQ_ID) -    { -        // ...selected parcels report this sequence id -        parcel_mgr.mRequestResult = PARCEL_RESULT_SUCCESS; -        parcel = parcel_mgr.mCurrentParcel; -    } -    else if (sequence_id == HOVERED_PARCEL_SEQ_ID) -    { -        parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS; -        parcel = parcel_mgr.mHoverParcel; -    } -    else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID || -        sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID || -        sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID) -    { -        parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS; -        parcel = parcel_mgr.mCollisionParcel; -    } -    else if (sequence_id == 0 || sequence_id > parcel_mgr.mAgentParcelSequenceID) -    { -        // new agent parcel -        // *TODO: Does it really make sense to set the agent parcel to this -        // parcel if the client doesn't know what kind of parcel data this is? -        parcel_mgr.mAgentParcelSequenceID = sequence_id; -        parcel = parcel_mgr.mAgentParcel; -    } -    else -    { -        LL_INFOS("ParcelMgr") << "out of order agent parcel sequence id " << sequence_id -            << " last good " << parcel_mgr.mAgentParcelSequenceID -            << LL_ENDL; -        return; -    } - -    msg->getBOOL("ParcelData", "SnapSelection", snap_selection); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelfCount, self_count); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherCount, other_count); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_PublicCount, public_count); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_LocalID, local_id); -    msg->getUUIDFast(_PREHASH_ParcelData, _PREHASH_OwnerID, owner_id); -    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_IsGroupOwned, is_group_owned); -    msg->getU32Fast(_PREHASH_ParcelData, _PREHASH_AuctionID, auction_id); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_ClaimDate, claim_date); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_ClaimPrice, claim_price_per_meter); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RentPrice, rent_price_per_meter); -    msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMin, aabb_min); -    msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMax, aabb_max); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_Area, area); -    //msg->getUUIDFast(	_PREHASH_ParcelData, _PREHASH_BuyerID, buyer_id); -    msg->getU8("ParcelData", "Status", status); -    msg->getS32("ParcelData", "SimWideMaxPrims", sw_max_prims); -    msg->getS32("ParcelData", "SimWideTotalPrims", sw_total_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_MaxPrims, max_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_TotalPrims, total_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OwnerPrims, owner_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_GroupPrims, group_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherPrims, other_prims); -    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelectedPrims, selected_prims); -    msg->getF32Fast(_PREHASH_ParcelData, _PREHASH_ParcelPrimBonus, parcel_prim_bonus); -    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionPushOverride, region_push_override); -    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyAnonymous, region_deny_anonymous_override); -    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyIdentified, region_deny_identified_override); // Deprecated -    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyTransacted, region_deny_transacted_override); // Deprecated -    if (msg->getNumberOfBlocksFast(_PREHASH_AgeVerificationBlock)) -    { -        // this block was added later and may not be on older sims, so we have to test its existence first -        msg->getBOOLFast(_PREHASH_AgeVerificationBlock, _PREHASH_RegionDenyAgeUnverified, region_deny_age_unverified_override); -    } - -    if (msg->getNumberOfBlocks(_PREHASH_RegionAllowAccessBlock)) -    { -        msg->getBOOLFast(_PREHASH_RegionAllowAccessBlock, _PREHASH_RegionAllowAccessOverride, region_allow_access_override); -    } - -    if (msg->getNumberOfBlocks(_PREHASH_ParcelExtendedFlags)) -    { -        msg->getU32Fast(_PREHASH_ParcelExtendedFlags, _PREHASH_Flags, extended_flags); -     } - -    if (msg->getNumberOfBlocks(_PREHASH_ParcelEnvironmentBlock)) -    { -        msg->getS32Fast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_ParcelEnvironmentVersion, parcel_environment_version); -        msg->getBOOLFast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_RegionAllowEnvironmentOverride, region_allow_environment_override); -    } - -	msg->getS32("ParcelData", "OtherCleanTime", other_clean_time ); - -	LL_DEBUGS("ParcelMgr") << "Processing parcel " << local_id << " update, target(sequence): " << sequence_id << LL_ENDL; - -	// Actually extract the data. -	if (parcel) -	{ -        if (local_id == parcel_mgr.mAgentParcel->getLocalID()) -        { -            // Parcels in different regions can have same ids. -            LLViewerRegion* parcel_region = LLWorld::getInstance()->getRegion(msg->getSender()); -            LLViewerRegion* agent_region = gAgent.getRegion(); -            if (parcel_region && agent_region && parcel_region->getRegionID() == agent_region->getRegionID()) -            { -                // we got an updated version of agent parcel -                agent_parcel_update = true; -            } -        } - -        S32 cur_parcel_environment_version = parcel->getParcelEnvironmentVersion(); -        bool environment_changed = (cur_parcel_environment_version != parcel_environment_version); - -		parcel->init(owner_id, -			false, false, false, -			claim_date, claim_price_per_meter, rent_price_per_meter, -			area, other_prims, parcel_prim_bonus, is_group_owned); -		parcel->setLocalID(local_id); -		parcel->setAABBMin(aabb_min); -		parcel->setAABBMax(aabb_max); - -		parcel->setAuctionID(auction_id); -		parcel->setOwnershipStatus((LLParcel::EOwnershipStatus)status); - -		parcel->setSimWideMaxPrimCapacity(sw_max_prims); -		parcel->setSimWidePrimCount(sw_total_prims); -		parcel->setMaxPrimCapacity(max_prims); -		parcel->setOwnerPrimCount(owner_prims); -		parcel->setGroupPrimCount(group_prims); -		parcel->setOtherPrimCount(other_prims); -		parcel->setSelectedPrimCount(selected_prims); -		parcel->setParcelPrimBonus(parcel_prim_bonus); - -		parcel->setCleanOtherTime(other_clean_time); -		parcel->setRegionPushOverride(region_push_override); -		parcel->setRegionDenyAnonymousOverride(region_deny_anonymous_override); -		parcel->setRegionDenyAgeUnverifiedOverride(region_deny_age_unverified_override); -        parcel->setRegionAllowAccessOverride(region_allow_access_override); -        parcel->setParcelEnvironmentVersion(cur_parcel_environment_version); -        parcel->setRegionAllowEnvironmentOverride(region_allow_environment_override); - -        parcel->setObscureMOAP((bool)extended_flags); - -		parcel->unpackMessage(msg); - -		if (parcel == parcel_mgr.mAgentParcel) -		{ -			// new agent parcel -			S32 bitmap_size =	parcel_mgr.mParcelsPerEdge -								* parcel_mgr.mParcelsPerEdge -								/ 8; -			U8* bitmap = new U8[ bitmap_size ]; -			msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size); - -			parcel_mgr.writeAgentParcelFromBitmap(bitmap); -			delete[] bitmap; - -			// Let interesting parties know about agent parcel change. -			LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance(); - -			if (instance->mTeleportInProgress) -			{ -				instance->mTeleportInProgress = false; -				if(instance->mTeleportInProgressPosition.isNull()) -				{ -					//initial update -					instance->mTeleportFinishedSignal(gAgent.getPositionGlobal(), false); -				} -				else -				{ -					instance->mTeleportFinishedSignal(instance->mTeleportInProgressPosition, false); -				} -			} -            parcel->setParcelEnvironmentVersion(parcel_environment_version); -            LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; - -            // Notify anything that wants to know when the agent changes parcels -            gAgent.changeParcels(); -            instance->mTeleportInProgress = false; -        } -        else if (agent_parcel_update) -        { -            parcel->setParcelEnvironmentVersion(parcel_environment_version); -            // updated agent parcel -            parcel_mgr.mAgentParcel->unpackMessage(msg); -            if ((LLEnvironment::instance().isExtendedEnvironmentEnabled() && environment_changed)) -            { -                LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; -                LLEnvironment::instance().requestParcel(local_id); -            } -        } -	} - -	// Handle updating selections, if necessary. -	if (sequence_id == SELECTED_PARCEL_SEQ_ID) -	{ -		// Update selected counts -		parcel_mgr.mCurrentParcelSelection->mSelectedSelfCount = self_count; -		parcel_mgr.mCurrentParcelSelection->mSelectedOtherCount = other_count; -		parcel_mgr.mCurrentParcelSelection->mSelectedPublicCount = public_count; - -		parcel_mgr.mCurrentParcelSelection->mSelectedMultipleOwners = -							(request_result == PARCEL_RESULT_MULTIPLE); - -		// Select the whole parcel -		LLViewerRegion* region = LLWorld::getInstance()->getRegion( msg->getSender() ); -		if (region) -		{ -			if (!snap_selection) -			{ -				// don't muck with the westsouth and eastnorth. -				// just highlight it -				LLVector3 west_south = region->getPosRegionFromGlobal(parcel_mgr.mWestSouth); -				LLVector3 east_north = region->getPosRegionFromGlobal(parcel_mgr.mEastNorth); - -				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments); -				parcel_mgr.writeHighlightSegments( -								west_south.mV[VX], -								west_south.mV[VY], -								east_north.mV[VX], -								east_north.mV[VY] ); -				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = false; -			} -			else if (0 == local_id) -			{ -				// this is public land, just highlight the selection -				parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min ); -				parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max ); - -				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments); -				parcel_mgr.writeHighlightSegments( -								aabb_min.mV[VX], -								aabb_min.mV[VY], -								aabb_max.mV[VX], -								aabb_max.mV[VY] ); -				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = true; -			} -			else -			{ -				parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min ); -				parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max ); - -				// Owned land, highlight the boundaries -				S32 bitmap_size =	parcel_mgr.mParcelsPerEdge -									* parcel_mgr.mParcelsPerEdge -									/ 8; -				U8* bitmap = new U8[ bitmap_size ]; -				msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size); - -				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments); -				parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mHighlightSegments ); - -				delete[] bitmap; -				bitmap = NULL; - -				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = true; -			} - -			// Request access list information for this land -			parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_ALLOW_EXPERIENCE | AL_BLOCK_EXPERIENCE); - -			// Request dwell for this land, if it's not public land. -			parcel_mgr.mSelectedDwell = DWELL_NAN; -			if (0 != local_id) -			{ -				parcel_mgr.sendParcelDwellRequest(); -			} - -			parcel_mgr.mSelected = true; -			parcel_mgr.notifyObservers(); -		} -	} -	else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID || -			 sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID  || -			 sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID) -	{ -		// We're about to collide with this parcel -        static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION); -        if (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY) -        { -            parcel_mgr.resetCollisionTimer(); -        } - -		// Differentiate this parcel if we are banned from it. -		if (sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID) -		{ -			parcel_mgr.mCollisionBanned = BA_BANNED; -		} -		else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID) -		{ -			parcel_mgr.mCollisionBanned = BA_NOT_IN_GROUP; -		} -		else  -		{ -			parcel_mgr.mCollisionBanned = BA_NOT_ON_LIST; - -		} - -		S32 bitmap_size =	parcel_mgr.mParcelsPerEdge -							* parcel_mgr.mParcelsPerEdge -							/ 8; -		U8* bitmap = new U8[ bitmap_size ]; -		msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size); - -		parcel_mgr.resetSegments(parcel_mgr.mCollisionSegments); -		parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mCollisionSegments ); - -		delete[] bitmap; -		bitmap = NULL; - -	} -	else if (sequence_id == HOVERED_PARCEL_SEQ_ID) -	{ -		LLViewerRegion *region = LLWorld::getInstance()->getRegion( msg->getSender() ); -		if (region) -		{ -			parcel_mgr.mHoverWestSouth = region->getPosGlobalFromRegion( aabb_min ); -			parcel_mgr.mHoverEastNorth = region->getPosGlobalFromRegion( aabb_max ); -		} -		else -		{ -			parcel_mgr.mHoverWestSouth.clearVec(); -			parcel_mgr.mHoverEastNorth.clearVec(); -		} -	} -	else -	{ -        if (gNonInteractive) -        { -            return; -        } -     -        // Check for video -        LLViewerParcelMedia::getInstance()->update(parcel); - -		// Then check for music -		if (gAudiop) -		{ -			if (parcel) -			{ -                // Only update stream if parcel changed (recreated) or music is playing (enabled) -                static LLCachedControl<bool> already_playing(gSavedSettings, "MediaTentativeAutoPlay", true); -                if (!agent_parcel_update || already_playing) -                { -                    LLViewerParcelAskPlay::getInstance()->cancelNotification(); -                    std::string music_url_raw = parcel->getMusicURL(); - -                    // Trim off whitespace from front and back -                    std::string music_url = music_url_raw; -                    LLStringUtil::trim(music_url); - -                    // If there is a new music URL and it's valid, play it. -                    if (music_url.size() > 12) -                    { -                        if (music_url.substr(0, 7) == "http://" -                            || music_url.substr(0, 8) == "https://") -                        { -                            LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); -                            if (region) -                            { -                                optionallyStartMusic(music_url, parcel->mLocalID, region->getRegionID(), !agent_parcel_update); -                            } -                        } -                        else -                        { -                            LL_INFOS("ParcelMgr") << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL; -                            // clears the URL -                            // null value causes fade out -                            LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); -                        } -                    } -                    else if (!gAudiop->getInternetStreamURL().empty()) -                    { -                        LL_INFOS("ParcelMgr") << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL; -                        // null value causes fade out -                        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); -                    } -                } -			} -			else -			{ -				// Public land has no music -				LLViewerParcelAskPlay::getInstance()->cancelNotification(); -				LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade(); -			} -		}//if gAudiop -	}; -} - -//static -void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play) -{ -    if (play) -    { -        LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL; -        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url); -    } -    else -    { -        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); -    } -} - -void LLViewerParcelMgr::optionallyStartMusic(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id, bool switched_parcel) -{ -	static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true); -	if (streaming_music) -	{ -		static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1); -		static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true); -		// only play music when you enter a new parcel if the UI control for this -		// was not *explicitly* stopped by the user. (part of SL-4878) -		LLPanelNearByMedia* nearby_media_panel = gStatusBar ? gStatusBar->getNearbyMediaPanel() : NULL; -        LLViewerAudio* viewer_audio = LLViewerAudio::getInstance(); - -        // ask mode //todo constants -        if (autoplay_mode == 2) -        { -            // if user set media to play - ask -            if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) -                || (!nearby_media_panel && tentative_autoplay)) -            { -                // user did not stop audio -                if (switched_parcel || music_url != viewer_audio->getNextStreamURI()) -                { -                    viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); - -                    LLViewerParcelAskPlay::getInstance()->askToPlay(region_id, -                        local_id, -                        music_url, -                        onStartMusicResponse); -                } -                // else do nothing: -                // Parcel properties changed, but not url. -                // We are already playing this url and asked about it when agent entered parcel -                // or user started audio manually at some point -            } -            else -            { -                // stopped by the user, do not autoplay -                LLViewerParcelAskPlay::getInstance()->cancelNotification(); -                viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); -            } -        } -        // autoplay -        else if ((nearby_media_panel -                  && nearby_media_panel->getParcelAudioAutoStart()) -                  // or they have expressed no opinion in the UI, but have autoplay on... -                 || (!nearby_media_panel -                     && autoplay_mode == 1 -                     && tentative_autoplay)) -		{ -			LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; -			viewer_audio->startInternetStreamWithAutoFade(music_url); -		} -		// autoplay off -		else if(switched_parcel || music_url != viewer_audio->getNextStreamURI()) -		{ -			viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null); -		} -	} -} - -// static -void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void **user) -{ -	LLUUID agent_id; -	S32 sequence_id = 0; -	U32 message_flags = 0x0; -	S32 parcel_id = -1; - -	msg->getUUIDFast(_PREHASH_Data, _PREHASH_AgentID, agent_id); -	msg->getS32Fast( _PREHASH_Data, _PREHASH_SequenceID, sequence_id );	//ignored -	msg->getU32Fast( _PREHASH_Data, _PREHASH_Flags, message_flags); -	msg->getS32Fast( _PREHASH_Data, _PREHASH_LocalID, parcel_id); - -	LLParcel* parcel = LLViewerParcelMgr::getInstance()->mCurrentParcel; -	if (!parcel) return; - -	if (parcel_id != parcel->getLocalID()) -	{ -		LL_WARNS_ONCE("ParcelMgr") << "processParcelAccessListReply for parcel " << parcel_id -			<< " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL; -		return; -	} - -	if (message_flags & AL_ACCESS) -	{ -		parcel->unpackAccessEntries(msg, &(parcel->mAccessList) ); -	} -	else if (message_flags & AL_BAN) -	{ -		parcel->unpackAccessEntries(msg, &(parcel->mBanList) ); -	} -	else if (message_flags & AL_ALLOW_EXPERIENCE) -	{ -		parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_ALLOWED); -	} -	else if (message_flags & AL_BLOCK_EXPERIENCE) -	{ -		parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_BLOCKED); -	} -	/*else if (message_flags & AL_RENTER) -	{ -		parcel->unpackAccessEntries(msg, &(parcel->mRenterList) ); -	}*/ - -	LLViewerParcelMgr::getInstance()->notifyObservers(); -} - - -// static -void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**) -{ -	LLUUID agent_id; -	msg->getUUID("AgentData", "AgentID", agent_id); - -	S32 local_id; -	msg->getS32("Data", "LocalID", local_id); - -	LLUUID parcel_id; -	msg->getUUID("Data", "ParcelID", parcel_id); - -	F32 dwell; -	msg->getF32("Data", "Dwell", dwell); - -	if (local_id == LLViewerParcelMgr::getInstance()->mCurrentParcel->getLocalID()) -	{ -		LLViewerParcelMgr::getInstance()->mSelectedDwell = dwell; -		LLViewerParcelMgr::getInstance()->notifyObservers(); -	} -} - - -void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) -{ -	if (!mSelected) -	{ -		return; -	} - -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); -	if (!region) return; - -	LLParcel* parcel = mCurrentParcel; -	if (!parcel) return; - -	if (which & AL_ACCESS) -	{	 -		sendParcelAccessListUpdate(AL_ACCESS, parcel->mAccessList, region, parcel->getLocalID()); -	} - -	if (which & AL_BAN) -	{	 -		sendParcelAccessListUpdate(AL_BAN, parcel->mBanList, region, parcel->getLocalID()); -	} - -	if(which & AL_ALLOW_EXPERIENCE) -	{ -		sendParcelAccessListUpdate(AL_ALLOW_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED), region, parcel->getLocalID()); -	} -	if(which & AL_BLOCK_EXPERIENCE) -	{ -		sendParcelAccessListUpdate(AL_BLOCK_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED), region, parcel->getLocalID()); -	} -} - -void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 flags, const LLAccessEntry::map& entries, LLViewerRegion* region, S32 parcel_local_id) -{ -	S32 count = entries.size(); -	S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); -	S32 sequence_id = 1; -	bool start_message = true; -	bool initial = true; - -	LLUUID transactionUUID; -	transactionUUID.generate(); - - -	LLMessageSystem* msg = gMessageSystem; - -	LLAccessEntry::map::const_iterator cit = entries.begin(); -	LLAccessEntry::map::const_iterator  end = entries.end(); -	while ( (cit != end) || initial )  -	{ -		if (start_message)  -		{ -			msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); -			msg->nextBlockFast(_PREHASH_AgentData); -			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); -			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); -			msg->nextBlockFast(_PREHASH_Data); -			msg->addU32Fast(_PREHASH_Flags, flags); -			msg->addS32(_PREHASH_LocalID,  parcel_local_id); -			msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); -			msg->addS32Fast(_PREHASH_SequenceID, sequence_id); -			msg->addS32Fast(_PREHASH_Sections, num_sections); -			start_message = false; - -			if (initial && (cit == end)) -			{ -				// pack an empty block if there will be no data -				msg->nextBlockFast(_PREHASH_List); -				msg->addUUIDFast(_PREHASH_ID,  LLUUID::null ); -				msg->addS32Fast(_PREHASH_Time, 0 ); -				msg->addU32Fast(_PREHASH_Flags,	0 ); -			} - -			initial = false; -			sequence_id++; - -		} - -		while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))  -		{ -			const LLAccessEntry& entry = (*cit).second; - -			msg->nextBlockFast(_PREHASH_List); -			msg->addUUIDFast(_PREHASH_ID,  entry.mID ); -			msg->addS32Fast(_PREHASH_Time, entry.mTime ); -			msg->addU32Fast(_PREHASH_Flags,	entry.mFlags ); -			++cit; -		} - -		start_message = true; -		msg->sendReliable( region->getHost() ); -	} -} - - -void LLViewerParcelMgr::deedLandToGroup() -{ -	std::string group_name; -	gCacheName->getGroupName(mCurrentParcel->getGroupID(), group_name); -	LLSD args; -	args["AREA"] = llformat("%d", mCurrentParcel->getArea()); -	args["GROUP_NAME"] = group_name; -	if(mCurrentParcel->getContributeWithDeed()) -	{ -		args["NAME"] = LLSLURL("agent", mCurrentParcel->getOwnerID(), "completename").getSLURLString(); -		LLNotificationsUtil::add("DeedLandToGroupWithContribution",args, LLSD(), deedAlertCB); -	} -	else -	{ -		LLNotificationsUtil::add("DeedLandToGroup",args, LLSD(), deedAlertCB); -	} -} - -// static -bool LLViewerParcelMgr::deedAlertCB(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option == 0) -	{ -		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); -		LLUUID group_id; -		if(parcel) -		{ -			group_id = parcel->getGroupID(); -		} -		LLViewerParcelMgr::getInstance()->sendParcelDeed(group_id); -	} -	return false; -} - - -void LLViewerParcelMgr::startReleaseLand() -{ -	if (!mSelected) -	{ -		LLNotificationsUtil::add("CannotReleaseLandNothingSelected"); -		return; -	} - -	if (mRequestResult == PARCEL_RESULT_NO_DATA) -	{ -		LLNotificationsUtil::add("CannotReleaseLandWatingForServer"); -		return; -	} - -	if (mRequestResult == PARCEL_RESULT_MULTIPLE) -	{ -		LLNotificationsUtil::add("CannotReleaseLandSelected"); -		return; -	} - -	if (!isParcelOwnedByAgent(mCurrentParcel, GP_LAND_RELEASE) -		&& !(gAgent.canManageEstate())) -	{ -		LLNotificationsUtil::add("CannotReleaseLandDontOwn"); -		return; -	} - -	LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0; -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotReleaseLandRegionNotFound"); -		return; -	} -/* -	if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) -		&& !gAgent.isGodlike()) -	{ -		LLSD args; -		args["REGION"] = region->getName(); -		LLNotificationsUtil::add("CannotReleaseLandNoTransfer", args); -		return; -	} -*/ - -	if (!mCurrentParcelSelection->mWholeParcelSelected) -	{ -		LLNotificationsUtil::add("CannotReleaseLandPartialSelection"); -		return; -	} - -	// Compute claim price -	LLSD args; -	args["AREA"] = llformat("%d",mCurrentParcel->getArea()); -	LLNotificationsUtil::add("ReleaseLandWarning", args, LLSD(), releaseAlertCB); -} - -bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const -{ -	if (!parcel) -	{ -		return false; -	} -	 -	if (mSelected  &&  parcel == mCurrentParcel) -	{ -		if (mRequestResult == PARCEL_RESULT_NO_DATA) -		{ -			return false; -		} -	} -	 -	const LLUUID& parcelOwner = parcel->getOwnerID(); -	const LLUUID& authorizeBuyer = parcel->getAuthorizedBuyerID(); - -	if (parcel->isPublic()) -	{ -		return true;	// change this if want to make it gods only -	} -	 -	LLVector3 parcel_coord = parcel->getCenterpoint(); -	LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosAgent(parcel_coord); -	if (regionp) -	{ -		U8 sim_access = regionp->getSimAccess(); -		const LLAgentAccess& agent_access = gAgent.getAgentAccess(); -		// if the region is PG, we're happy already, so do nothing -		// but if we're set to avoid either mature or adult, get us outta here -		if ((sim_access == SIM_ACCESS_MATURE) && -			!agent_access.canAccessMature()) -		{ -			return false; -		} -		else if ((sim_access == SIM_ACCESS_ADULT) && -				 !agent_access.canAccessAdult()) -		{ -			return false; -		} -	}	 -	 -	bool isForSale = parcel->getForSale() -			&& ((parcel->getSalePrice() > 0) || (authorizeBuyer.notNull())); -			 -	bool isEmpowered -		= forGroup ? gAgent.hasPowerInActiveGroup(GP_LAND_DEED) : true; -		 -	bool isOwner -		= parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID()); -	 -	bool isAuthorized -			= (authorizeBuyer.isNull() -				|| (gAgent.getID() == authorizeBuyer) -				|| (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED) -					&& gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_SET_SALE_INFO))); -	 -	return isForSale && !isOwner && isAuthorized  && isEmpowered; -} - - -void LLViewerParcelMgr::startBuyLand(bool is_for_group) -{ -	LLFloaterBuyLand::buyLand(getSelectionRegion(), mCurrentParcelSelection, is_for_group); -} - -void LLViewerParcelMgr::startSellLand() -{ -	LLFloaterSellLand::sellLand(getSelectionRegion(), mCurrentParcelSelection); -} - -void LLViewerParcelMgr::startDivideLand() -{ -	if (!mSelected) -	{ -		LLNotificationsUtil::add("CannotDivideLandNothingSelected"); -		return; -	} - -	if (mCurrentParcelSelection->mWholeParcelSelected) -	{ -		LLNotificationsUtil::add("CannotDivideLandPartialSelection"); -		return; -	} - -	LLSD payload; -	payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth); -	payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth); - -	LLNotificationsUtil::add("LandDivideWarning", LLSD(), payload, callbackDivideLand); -} - -// static -bool LLViewerParcelMgr::callbackDivideLand(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]); -	LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]); -	LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0; - -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotDivideLandNoRegion"); -		return false; -	} - -	if (0 == option) -	{ -		LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d); -		LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d); - -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessage("ParcelDivide"); -		msg->nextBlock("AgentData"); -		msg->addUUID("AgentID", gAgent.getID()); -		msg->addUUID("SessionID", gAgent.getSessionID()); -		msg->nextBlock("ParcelData"); -		msg->addF32("West", west_south.mV[VX]); -		msg->addF32("South", west_south.mV[VY]); -		msg->addF32("East", east_north.mV[VX]); -		msg->addF32("North", east_north.mV[VY]); -		msg->sendReliable(region->getHost()); -	} -	return false; -} - - -void LLViewerParcelMgr::startJoinLand() -{ -	if (!mSelected) -	{ -		LLNotificationsUtil::add("CannotJoinLandNothingSelected"); -		return; -	} - -	if (mCurrentParcelSelection->mWholeParcelSelected) -	{ -		LLNotificationsUtil::add("CannotJoinLandEntireParcelSelected"); -		return; -	} - -	if (!mCurrentParcelSelection->mSelectedMultipleOwners) -	{ -		LLNotificationsUtil::add("CannotJoinLandSelection"); -		return; -	} - -	LLSD payload; -	payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth); -	payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth); - -	LLNotificationsUtil::add("JoinLandWarning", LLSD(), payload, callbackJoinLand); -} - -// static -bool LLViewerParcelMgr::callbackJoinLand(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]); -	LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]); -	LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0; - -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotJoinLandNoRegion"); -		return false; -	} - -	if (0 == option) -	{ -		LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d); -		LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d); - -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessage("ParcelJoin"); -		msg->nextBlock("AgentData"); -		msg->addUUID("AgentID", gAgent.getID()); -		msg->addUUID("SessionID", gAgent.getSessionID()); -		msg->nextBlock("ParcelData"); -		msg->addF32("West", west_south.mV[VX]); -		msg->addF32("South", west_south.mV[VY]); -		msg->addF32("East", east_north.mV[VX]); -		msg->addF32("North", east_north.mV[VY]); -		msg->sendReliable(region->getHost()); -	} -	return false; -} - - -void LLViewerParcelMgr::startDeedLandToGroup() -{ -	if (!mSelected || !mCurrentParcel) -	{ -		LLNotificationsUtil::add("CannotDeedLandNothingSelected"); -		return; -	} - -	if (mRequestResult == PARCEL_RESULT_NO_DATA) -	{ -		LLNotificationsUtil::add("CannotDeedLandWaitingForServer"); -		return; -	} - -	if (mRequestResult == PARCEL_RESULT_MULTIPLE) -	{ -		LLNotificationsUtil::add("CannotDeedLandMultipleSelected"); -		return; -	} - -	LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0; -	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center); -	if (!region) -	{ -		LLNotificationsUtil::add("CannotDeedLandNoRegion"); -		return; -	} - -	/* -	if(!gAgent.isGodlike()) -	{ -		if(region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) -			&& (mCurrentParcel->getOwnerID() != region->getOwner())) -		{ -			LLSD args; -			args["REGION"] = region->getName(); -			LLNotificationsUtil::add("CannotDeedLandNoTransfer", args); -			return; -		} -	} -	*/ - -	deedLandToGroup(); -} -void LLViewerParcelMgr::reclaimParcel() -{ -	LLParcel* parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(); -	LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); -	if(parcel && parcel->getOwnerID().notNull() -	   && (parcel->getOwnerID() != gAgent.getID()) -	   && regionp && (regionp->getOwner() == gAgent.getID())) -	{ -		LLMessageSystem* msg = gMessageSystem; -		msg->newMessage("ParcelReclaim"); -		msg->nextBlock("AgentData"); -		msg->addUUID("AgentID", gAgent.getID()); -		msg->addUUID("SessionID", gAgent.getSessionID()); -		msg->nextBlock("Data"); -		msg->addS32("LocalID", parcel->getLocalID()); -		msg->sendReliable(regionp->getHost()); -	} -} - -// static -bool LLViewerParcelMgr::releaseAlertCB(const LLSD& notification, const LLSD& response) -{ -	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	if (option == 0) -	{ -		// Send the release message, not a force -		LLViewerParcelMgr::getInstance()->sendParcelRelease(); -	} -	return false; -} - -void LLViewerParcelMgr::buyPass() -{ -	LLParcel* parcel = getParcelSelection()->getParcel(); -	if (!parcel) return; - -	LLViewerRegion* region = getSelectionRegion(); -	if (!region) return; - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_ParcelBuyPass); -	msg->nextBlock("AgentData"); -	msg->addUUID("AgentID", gAgent.getID()); -	msg->addUUID("SessionID", gAgent.getSessionID()); -	msg->nextBlockFast(_PREHASH_ParcelData); -	msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() ); -	msg->sendReliable( region->getHost() ); -} - -//Tells whether we are allowed to buy a pass or not -bool LLViewerParcelMgr::isCollisionBanned()	 -{  -	if ((mCollisionBanned == BA_ALLOWED) || (mCollisionBanned == BA_NOT_ON_LIST) || (mCollisionBanned == BA_NOT_IN_GROUP)) -		return false; -	else  -		return true; -} - -// This implementation should mirror LLSimParcelMgr::isParcelOwnedBy -// static -bool LLViewerParcelMgr::isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power) -{ -	if (!parcelp) -	{ -		return false; -	} - -	// Gods can always assume ownership. -	if (gAgent.isGodlike()) -	{ -		return true; -	} - -	// The owner of a parcel automatically gets all powersr. -	if (parcelp->getOwnerID() == gAgent.getID()) -	{ -		return true; -	} - -	// Only gods can assume 'ownership' of public land. -	if (parcelp->isPublic()) -	{ -		return false; -	} - -	// Return whether or not the agent has group_proxy_power powers in the -	// parcel's group. -	return gAgent.hasPowerInGroup(parcelp->getOwnerID(), group_proxy_power); -} - -// This implementation should mirror llSimParcelMgr::isParcelModifiableBy -// static -bool LLViewerParcelMgr::isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power) -{ -	// If the agent can assume ownership, it is probably modifiable. -	bool rv = false; -	if (parcelp) -	{ -		// *NOTE: This should only work for leased parcels, but group owned -		// parcels cannot be OS_LEASED yet. Phoenix 2003-12-15. -		rv = isParcelOwnedByAgent(parcelp, group_proxy_power); - -		// ... except for the case that the parcel is not OS_LEASED for agent-owned parcels. -		if( (gAgent.getID() == parcelp->getOwnerID()) -			&& !gAgent.isGodlike() -			&& (parcelp->getOwnershipStatus() != LLParcel::OS_LEASED) ) -		{ -			rv = false; -		} -	} -	return rv; -} - -void sanitize_corners(const LLVector3d &corner1, -										const LLVector3d &corner2, -										LLVector3d &west_south_bottom, -										LLVector3d &east_north_top) -{ -	west_south_bottom.mdV[VX] = llmin( corner1.mdV[VX], corner2.mdV[VX] ); -	west_south_bottom.mdV[VY] = llmin( corner1.mdV[VY], corner2.mdV[VY] ); -	west_south_bottom.mdV[VZ] = llmin( corner1.mdV[VZ], corner2.mdV[VZ] ); - -	east_north_top.mdV[VX] = llmax( corner1.mdV[VX], corner2.mdV[VX] ); -	east_north_top.mdV[VY] = llmax( corner1.mdV[VY], corner2.mdV[VY] ); -	east_north_top.mdV[VZ] = llmax( corner1.mdV[VZ], corner2.mdV[VZ] ); -} - - -void LLViewerParcelMgr::cleanupGlobals() -{ -} - -LLViewerTexture* LLViewerParcelMgr::getBlockedImage() const -{ -	return sBlockedImage; -} - -LLViewerTexture* LLViewerParcelMgr::getPassImage() const -{ -	return sPassImage; -} - -/* - * Set finish teleport callback. You can use it to observe all  teleport events. - * NOTE: - * After local( in one region) teleports we - *  cannot rely on gAgent.getPositionGlobal(), - *  so the new position gets passed explicitly. - *  Use args of this callback to get global position of avatar after teleport event. - */ -boost::signals2::connection LLViewerParcelMgr::setTeleportFinishedCallback(teleport_finished_callback_t cb) -{ -	return mTeleportFinishedSignal.connect(cb); -} - -boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(teleport_failed_callback_t cb) -{ -	return mTeleportFailedSignal.connect(cb); -} - -/* Ok, we're notified that teleport has been finished. - * We should now propagate the notification via mTeleportFinishedSignal - * to all interested parties. - */ -void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos) -{ -	// Treat only teleports within the same parcel as local (EXT-3139). -	if (local && LLViewerParcelMgr::getInstance()->inAgentParcel(new_pos)) -	{ -		// Local teleport. We already have the agent parcel data. -		// Emit the signal immediately. -		getInstance()->mTeleportFinishedSignal(new_pos, local); -	} -	else -	{ -		// Non-local teleport (inter-region or between different parcels of the same region). -		// The agent parcel data has not been updated yet. -		// Let's wait for the update and then emit the signal. -		mTeleportInProgressPosition = new_pos; -		mTeleportInProgress = true; -	} -} - -void LLViewerParcelMgr::onTeleportFailed() -{ -	mTeleportFailedSignal(); -} - -bool  LLViewerParcelMgr::getTeleportInProgress() -{ -    return mTeleportInProgress // case where parcel data arrives after teleport -        || gAgent.getTeleportState() > LLAgent::TELEPORT_NONE; // For LOCAL, no mTeleportInProgress -} +/**
 + * @file llviewerparcelmgr.cpp
 + * @brief Viewer-side representation of owned land
 + *
 + * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 + * Second Life Viewer Source Code
 + * Copyright (C) 2010, Linden Research, Inc.
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation;
 + * version 2.1 of the License only.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 + *
 + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 + * $/LicenseInfo$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "llviewerparcelmgr.h"
 +
 +// Library includes
 +#include "llaudioengine.h"
 +#include "indra_constants.h"
 +#include "llcachename.h"
 +#include "llgl.h"
 +#include "llnotifications.h"
 +#include "llnotificationsutil.h"
 +#include "llparcel.h"
 +#include "message.h"
 +#include "llfloaterreg.h"
 +
 +// Viewer includes
 +#include "llagent.h"
 +#include "llagentaccess.h"
 +#include "llviewerparcelaskplay.h"
 +#include "llviewerwindow.h"
 +#include "llviewercontrol.h"
 +//#include "llfirstuse.h"
 +#include "llfloaterbuyland.h"
 +#include "llfloatergroups.h"
 +#include "llpanelnearbymedia.h"
 +#include "llfloatersellland.h"
 +#include "llfloatertools.h"
 +#include "llparcelselection.h"
 +#include "llresmgr.h"
 +#include "llsdutil.h"
 +#include "llsdutil_math.h"
 +#include "llslurl.h"
 +#include "llstatusbar.h"
 +#include "llui.h"
 +#include "llviewertexture.h"
 +#include "llviewertexturelist.h"
 +#include "llviewermenu.h"
 +#include "llviewerparcelmedia.h"
 +#include "llviewerparceloverlay.h"
 +#include "llviewerregion.h"
 +#include "llworld.h"
 +#include "roles_constants.h"
 +#include "llweb.h"
 +#include "llvieweraudio.h"
 +#include "llcorehttputil.h"
 +
 +#include "llenvironment.h"
 +
 +const F32 PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION = 10.f;
 +const F32 PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY = 1.f;
 +
 +
 +// Globals
 +
 +U8* LLViewerParcelMgr::sPackedOverlay = NULL;
 +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_HIDE = 0;
 +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_COLLISION = 1;
 +S32 LLViewerParcelMgr::PARCEL_BAN_LINES_ON_PROXIMITY = 2;
 +
 +LLUUID gCurrentMovieID = LLUUID::null;
 +
 +LLPointer<LLViewerTexture> sBlockedImage;
 +LLPointer<LLViewerTexture> sPassImage;
 +
 +// Local functions
 +void callback_start_music(S32 option, void* data);
 +void optionally_prepare_video(const LLParcel *parcelp);
 +void callback_prepare_video(S32 option, void* data);
 +void prepare_video(const LLParcel *parcelp);
 +void start_video(const LLParcel *parcelp);
 +void stop_video();
 +bool callback_god_force_owner(const LLSD&, const LLSD&);
 +
 +struct LLGodForceOwnerData
 +{
 +    LLUUID mOwnerID;
 +    S32 mLocalID;
 +    LLHost mHost;
 +
 +    LLGodForceOwnerData(
 +        const LLUUID& owner_id,
 +        S32 local_parcel_id,
 +        const LLHost& host) :
 +        mOwnerID(owner_id),
 +        mLocalID(local_parcel_id),
 +        mHost(host) {}
 +};
 +
 +//
 +// Methods
 +//
 +LLViewerParcelMgr::LLViewerParcelMgr()
 +:   mSelected(false),
 +    mRequestResult(0),
 +    mWestSouth(),
 +    mEastNorth(),
 +    mSelectedDwell(DWELL_NAN),
 +    mAgentParcelSequenceID(-1),
 +    mHoverRequestResult(0),
 +    mHoverWestSouth(),
 +    mHoverEastNorth(),
 +    mTeleportInProgressPosition(),
 +    mRenderCollision(false),
 +    mRenderSelection(true),
 +    mCollisionBanned(0),
 +    mCollisionTimer(),
 +    mMediaParcelId(0),
 +    mMediaRegionId(0)
 +{
 +    mCurrentParcel = new LLParcel();
 +    mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 +    mFloatingParcelSelection = new LLParcelSelection(mCurrentParcel);
 +
 +    mAgentParcel = new LLParcel();
 +    mHoverParcel = new LLParcel();
 +    mCollisionParcel = new LLParcel();
 +
 +    mParcelsPerEdge = S32(  REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS );
 +    mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
 +    resetSegments(mHighlightSegments);
 +
 +    mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
 +    resetSegments(mCollisionSegments);
 +
 +    // JC: Resolved a merge conflict here, eliminated
 +    // mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP);
 +    // because it is done in llviewertexturelist.cpp
 +    mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI);
 +    mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", FTT_LOCAL_FILE, true, LLGLTexture::BOOST_UI);
 +
 +    S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS;
 +    sPackedOverlay = new U8[overlay_size];
 +
 +    mAgentParcelOverlay = new U8[mParcelsPerEdge * mParcelsPerEdge];
 +    S32 i;
 +    for (i = 0; i < mParcelsPerEdge * mParcelsPerEdge; i++)
 +    {
 +        mAgentParcelOverlay[i] = 0;
 +    }
 +
 +    mTeleportInProgress = true; // the initial parcel update is treated like teleport
 +}
 +
 +
 +LLViewerParcelMgr::~LLViewerParcelMgr()
 +{
 +    mCurrentParcelSelection->setParcel(NULL);
 +    mCurrentParcelSelection = NULL;
 +
 +    mFloatingParcelSelection->setParcel(NULL);
 +    mFloatingParcelSelection = NULL;
 +
 +    delete mCurrentParcel;
 +    mCurrentParcel = NULL;
 +
 +    delete mAgentParcel;
 +    mAgentParcel = NULL;
 +
 +    delete mCollisionParcel;
 +    mCollisionParcel = NULL;
 +
 +    delete mHoverParcel;
 +    mHoverParcel = NULL;
 +
 +    delete[] mHighlightSegments;
 +    mHighlightSegments = NULL;
 +
 +    delete[] mCollisionSegments;
 +    mCollisionSegments = NULL;
 +
 +    delete[] sPackedOverlay;
 +    sPackedOverlay = NULL;
 +
 +    delete[] mAgentParcelOverlay;
 +    mAgentParcelOverlay = NULL;
 +
 +    sBlockedImage = NULL;
 +    sPassImage = NULL;
 +}
 +
 +void LLViewerParcelMgr::dump()
 +{
 +    LL_INFOS() << "Parcel Manager Dump" << LL_ENDL;
 +    LL_INFOS() << "mSelected " << S32(mSelected) << LL_ENDL;
 +    LL_INFOS() << "Selected parcel: " << LL_ENDL;
 +    LL_INFOS() << mWestSouth << " to " << mEastNorth << LL_ENDL;
 +    mCurrentParcel->dump();
 +    LL_INFOS() << "banning " << mCurrentParcel->mBanList.size() << LL_ENDL;
 +
 +    LLAccessEntry::map::const_iterator cit = mCurrentParcel->mBanList.begin();
 +    LLAccessEntry::map::const_iterator end = mCurrentParcel->mBanList.end();
 +    for ( ; cit != end; ++cit)
 +    {
 +        LL_INFOS() << "ban id " << (*cit).first << LL_ENDL;
 +    }
 +    LL_INFOS() << "Hover parcel:" << LL_ENDL;
 +    mHoverParcel->dump();
 +    LL_INFOS() << "Agent parcel:" << LL_ENDL;
 +    mAgentParcel->dump();
 +}
 +
 +
 +LLViewerRegion* LLViewerParcelMgr::getSelectionRegion()
 +{
 +    return LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +}
 +
 +
 +void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out,
 +                                       S32* rent_out,
 +                                       bool* for_sale_out,
 +                                       F32* dwell_out)
 +{
 +    S32 area = 0;
 +    S32 price = 0;
 +    S32 rent = 0;
 +    bool for_sale = false;
 +    F32 dwell = DWELL_NAN;
 +
 +    if (mSelected)
 +    {
 +        if (mCurrentParcelSelection->mSelectedMultipleOwners)
 +        {
 +            area = mCurrentParcelSelection->getClaimableArea();
 +        }
 +        else
 +        {
 +            area = getSelectedArea();
 +        }
 +
 +        if (mCurrentParcel->getForSale())
 +        {
 +            price = mCurrentParcel->getSalePrice();
 +            for_sale = true;
 +        }
 +        else
 +        {
 +            price = area * mCurrentParcel->getClaimPricePerMeter();
 +            for_sale = false;
 +        }
 +
 +        rent = mCurrentParcel->getTotalRent();
 +
 +        dwell = mSelectedDwell;
 +    }
 +
 +    *area_out = area;
 +    *claim_out = price;
 +    *rent_out = rent;
 +    *for_sale_out = for_sale;
 +    *dwell_out = dwell;
 +}
 +
 +S32 LLViewerParcelMgr::getSelectedArea() const
 +{
 +    S32 rv = 0;
 +    if(mSelected && mCurrentParcel && mCurrentParcelSelection->mWholeParcelSelected)
 +    {
 +        rv = mCurrentParcel->getArea();
 +    }
 +    else if(mSelected)
 +    {
 +        F64 width = mEastNorth.mdV[VX] - mWestSouth.mdV[VX];
 +        F64 height = mEastNorth.mdV[VY] - mWestSouth.mdV[VY];
 +        F32 area = (F32)(width * height);
 +        rv = ll_round(area);
 +    }
 +    return rv;
 +}
 +
 +void LLViewerParcelMgr::resetSegments(U8* segments)
 +{
 +    S32 i;
 +    S32 count = (mParcelsPerEdge+1)*(mParcelsPerEdge+1);
 +    for (i = 0; i < count; i++)
 +    {
 +        segments[i] = 0x0;
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::writeHighlightSegments(F32 west, F32 south, F32 east,
 +                                               F32 north)
 +{
 +    S32 x, y;
 +    S32 min_x = ll_round( west / PARCEL_GRID_STEP_METERS );
 +    S32 max_x = ll_round( east / PARCEL_GRID_STEP_METERS );
 +    S32 min_y = ll_round( south / PARCEL_GRID_STEP_METERS );
 +    S32 max_y = ll_round( north / PARCEL_GRID_STEP_METERS );
 +
 +    const S32 STRIDE = mParcelsPerEdge+1;
 +
 +    // south edge
 +    y = min_y;
 +    for (x = min_x; x < max_x; x++)
 +    {
 +        // exclusive OR means that writing to this segment twice
 +        // will turn it off
 +        mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
 +    }
 +
 +    // west edge
 +    x = min_x;
 +    for (y = min_y; y < max_y; y++)
 +    {
 +        mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
 +    }
 +
 +    // north edge - draw the south border on the y+1'th cell,
 +    // which given C-style arrays, is item foo[max_y]
 +    y = max_y;
 +    for (x = min_x; x < max_x; x++)
 +    {
 +        mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
 +    }
 +
 +    // east edge - draw west border on x+1'th cell
 +    x = max_x;
 +    for (y = min_y; y < max_y; y++)
 +    {
 +        mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::writeSegmentsFromBitmap(U8* bitmap, U8* segments)
 +{
 +    S32 x;
 +    S32 y;
 +    const S32 IN_STRIDE = mParcelsPerEdge;
 +    const S32 OUT_STRIDE = mParcelsPerEdge+1;
 +
 +    for (y = 0; y < IN_STRIDE; y++)
 +    {
 +        x = 0;
 +        while( x < IN_STRIDE )
 +        {
 +            U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
 +
 +            S32 bit;
 +            for (bit = 0; bit < 8; bit++)
 +            {
 +                if (byte & (1 << bit) )
 +                {
 +                    S32 out = x+y*OUT_STRIDE;
 +
 +                    // This and one above it
 +                    segments[out]            ^= SOUTH_MASK;
 +                    segments[out+OUT_STRIDE] ^= SOUTH_MASK;
 +
 +                    // This and one to the right
 +                    segments[out]   ^= WEST_MASK;
 +                    segments[out+1] ^= WEST_MASK;
 +                }
 +                x++;
 +            }
 +        }
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::writeAgentParcelFromBitmap(U8* bitmap)
 +{
 +    S32 x;
 +    S32 y;
 +    const S32 IN_STRIDE = mParcelsPerEdge;
 +
 +    for (y = 0; y < IN_STRIDE; y++)
 +    {
 +        x = 0;
 +        while( x < IN_STRIDE )
 +        {
 +            U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
 +
 +            S32 bit;
 +            for (bit = 0; bit < 8; bit++)
 +            {
 +                if (byte & (1 << bit) )
 +                {
 +                    mAgentParcelOverlay[x+y*IN_STRIDE] = 1;
 +                }
 +                else
 +                {
 +                    mAgentParcelOverlay[x+y*IN_STRIDE] = 0;
 +                }
 +                x++;
 +            }
 +        }
 +    }
 +}
 +
 +
 +// Given a point, find the PARCEL_GRID_STEP x PARCEL_GRID_STEP block
 +// containing it and select that.
 +LLParcelSelectionHandle LLViewerParcelMgr::selectParcelAt(const LLVector3d& pos_global)
 +{
 +    LLVector3d southwest = pos_global;
 +    LLVector3d northeast = pos_global;
 +
 +    southwest -= LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
 +    southwest.mdV[VX] = ll_round( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
 +    southwest.mdV[VY] = ll_round( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
 +
 +    northeast += LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
 +    northeast.mdV[VX] = ll_round( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
 +    northeast.mdV[VY] = ll_round( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
 +
 +    // Snap to parcel
 +    return selectLand( southwest, northeast, true );
 +}
 +
 +
 +// Tries to select the parcel inside the rectangle
 +LLParcelSelectionHandle LLViewerParcelMgr::selectParcelInRectangle()
 +{
 +    return selectLand(mWestSouth, mEastNorth, true);
 +}
 +
 +
 +void LLViewerParcelMgr::selectCollisionParcel()
 +{
 +    // BUG: Claim to be in the agent's region
 +    mWestSouth = gAgent.getRegion()->getOriginGlobal();
 +    mEastNorth = mWestSouth;
 +    mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0);
 +
 +    // BUG: must be in the sim you are in
 +    LLMessageSystem *msg = gMessageSystem;
 +    msg->newMessageFast(_PREHASH_ParcelPropertiesRequestByID);
 +    msg->nextBlockFast(_PREHASH_AgentID);
 +    msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
 +    msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
 +    msg->nextBlockFast(_PREHASH_ParcelData);
 +    msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID );
 +    msg->addS32Fast(_PREHASH_LocalID, mCollisionParcel->getLocalID() );
 +    gAgent.sendReliableMessage();
 +
 +    mRequestResult = PARCEL_RESULT_NO_DATA;
 +
 +    // Hack: Copy some data over temporarily
 +    mCurrentParcel->setName( mCollisionParcel->getName() );
 +    mCurrentParcel->setDesc( mCollisionParcel->getDesc() );
 +    mCurrentParcel->setPassPrice(mCollisionParcel->getPassPrice());
 +    mCurrentParcel->setPassHours(mCollisionParcel->getPassHours());
 +
 +    // clear the list of segments to prevent flashing
 +    resetSegments(mHighlightSegments);
 +
 +    mFloatingParcelSelection->setParcel(mCurrentParcel);
 +    mCurrentParcelSelection->setParcel(NULL);
 +    mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 +
 +    mSelected = true;
 +    mCurrentParcelSelection->mWholeParcelSelected = true;
 +    notifyObservers();
 +    return;
 +}
 +
 +
 +// snap_selection = auto-select the hit parcel, if there is exactly one
 +LLParcelSelectionHandle LLViewerParcelMgr::selectLand(const LLVector3d &corner1, const LLVector3d &corner2,
 +                                   bool snap_selection)
 +{
 +    sanitize_corners( corner1, corner2, mWestSouth, mEastNorth );
 +
 +    // ...x isn't more than one meter away
 +    F32 delta_x = getSelectionWidth();
 +    if (delta_x * delta_x <= 1.f * 1.f)
 +    {
 +        mSelected = false;
 +        notifyObservers();
 +        return NULL;
 +    }
 +
 +    // ...y isn't more than one meter away
 +    F32 delta_y = getSelectionHeight();
 +    if (delta_y * delta_y <= 1.f * 1.f)
 +    {
 +        mSelected = false;
 +        notifyObservers();
 +        return NULL;
 +    }
 +
 +    // Can't select across region boundary
 +    // We need to pull in the upper right corner by a little bit to allow
 +    // selection up to the x = 256 or y = 256 edge.
 +    LLVector3d east_north_region_check( mEastNorth );
 +    east_north_region_check.mdV[VX] -= 0.5;
 +    east_north_region_check.mdV[VY] -= 0.5;
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth);
 +    LLViewerRegion *region_other = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
 +
 +    if(!region)
 +    {
 +        // just in case they somehow selected no land.
 +        mSelected = false;
 +        return NULL;
 +    }
 +
 +    if (region != region_other)
 +    {
 +        LLNotificationsUtil::add("CantSelectLandFromMultipleRegions");
 +        mSelected = false;
 +        notifyObservers();
 +        return NULL;
 +    }
 +
 +    // Build region global copies of corners
 +    LLVector3 wsb_region = region->getPosRegionFromGlobal( mWestSouth );
 +    LLVector3 ent_region = region->getPosRegionFromGlobal( mEastNorth );
 +
 +    // 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, SELECTED_PARCEL_SEQ_ID );
 +    msg->addF32Fast(_PREHASH_West,  wsb_region.mV[VX] );
 +    msg->addF32Fast(_PREHASH_South, wsb_region.mV[VY] );
 +    msg->addF32Fast(_PREHASH_East,  ent_region.mV[VX] );
 +    msg->addF32Fast(_PREHASH_North, ent_region.mV[VY] );
 +    msg->addBOOL("SnapSelection", snap_selection);
 +    msg->sendReliable( region->getHost() );
 +
 +    mRequestResult = PARCEL_RESULT_NO_DATA;
 +
 +    mFloatingParcelSelection->setParcel(mCurrentParcel);
 +    mCurrentParcelSelection->setParcel(NULL);
 +    mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 +
 +    mSelected = true;
 +    mCurrentParcelSelection->mWholeParcelSelected = snap_selection;
 +    notifyObservers();
 +    return mCurrentParcelSelection;
 +}
 +
 +void LLViewerParcelMgr::deselectUnused()
 +{
 +    // no more outstanding references to this selection, other than our own
 +    if (mCurrentParcelSelection->getNumRefs() == 1 && mFloatingParcelSelection->getNumRefs() == 1)
 +    {
 +        deselectLand();
 +    }
 +}
 +
 +void LLViewerParcelMgr::deselectLand()
 +{
 +    if (mSelected)
 +    {
 +        mSelected = false;
 +
 +        // Invalidate the selected parcel
 +        mCurrentParcel->setLocalID(-1);
 +        mCurrentParcel->mAccessList.clear();
 +        mCurrentParcel->mBanList.clear();
 +        //mCurrentParcel->mRenterList.reset();
 +
 +        mSelectedDwell = DWELL_NAN;
 +
 +        // invalidate parcel selection so that existing users of this selection can clean up
 +        mCurrentParcelSelection->setParcel(NULL);
 +        mFloatingParcelSelection->setParcel(NULL);
 +        // create new parcel selection
 +        mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 +
 +        notifyObservers(); // Notify observers *after* changing the parcel selection
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::addObserver(LLParcelObserver* observer)
 +{
 +    mObservers.push_back(observer);
 +}
 +
 +
 +void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer)
 +{
 +    vector_replace_with_last(mObservers, observer);
 +}
 +
 +
 +// Call this method when it's time to update everyone on a new state.
 +// Copy the list because an observer could respond by removing itself
 +// from the list.
 +void LLViewerParcelMgr::notifyObservers()
 +{
 +    std::vector<LLParcelObserver*> observers;
 +    S32 count = mObservers.size();
 +    S32 i;
 +    for(i = 0; i < count; ++i)
 +    {
 +        observers.push_back(mObservers.at(i));
 +    }
 +    for(i = 0; i < count; ++i)
 +    {
 +        observers.at(i)->changed();
 +    }
 +}
 +
 +
 +//
 +// ACCESSORS
 +//
 +bool LLViewerParcelMgr::selectionEmpty() const
 +{
 +    return !mSelected;
 +}
 +
 +
 +LLParcelSelectionHandle LLViewerParcelMgr::getParcelSelection() const
 +{
 +    return mCurrentParcelSelection;
 +}
 +
 +LLParcelSelectionHandle LLViewerParcelMgr::getFloatingParcelSelection() const
 +{
 +    return mFloatingParcelSelection;
 +}
 +
 +LLParcel *LLViewerParcelMgr::getAgentParcel() const
 +{
 +    return mAgentParcel;
 +}
 +
 +
 +LLParcel * LLViewerParcelMgr::getAgentOrSelectedParcel() const
 +{
 +    LLParcel *parcel(nullptr);
 +
 +    LLParcelSelectionHandle sel_handle(getFloatingParcelSelection());
 +    if (sel_handle)
 +    {
 +        LLParcelSelection *selection(sel_handle.get());
 +        if (selection)
 +        {
 +            parcel = selection->getParcel();
 +            if (parcel && (parcel->getLocalID() == INVALID_PARCEL_ID))
 +            {
 +                parcel = NULL;
 +            }
 +        }
 +    }
 +
 +    if (!parcel)
 +        parcel = LLViewerParcelMgr::instance().getAgentParcel();
 +
 +    return parcel;
 +}
 +
 +// Return whether the agent can build on the land they are on
 +bool LLViewerParcelMgr::allowAgentBuild() const
 +{
 +    if (mAgentParcel)
 +    {
 +        return (gAgent.isGodlike() ||
 +                (mAgentParcel->allowModifyBy(gAgent.getID(), gAgent.getGroupID())) ||
 +                (isParcelOwnedByAgent(mAgentParcel, GP_LAND_ALLOW_CREATE)));
 +    }
 +    else
 +    {
 +        return gAgent.isGodlike();
 +    }
 +}
 +
 +// Return whether anyone can build on the given parcel
 +bool LLViewerParcelMgr::allowAgentBuild(const LLParcel* parcel) const
 +{
 +    return parcel->getAllowModify();
 +}
 +
 +bool LLViewerParcelMgr::allowAgentVoice() const
 +{
 +    return allowAgentVoice(gAgent.getRegion(), mAgentParcel);
 +}
 +
 +bool LLViewerParcelMgr::allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const
 +{
 +    return region && region->isVoiceEnabled()
 +        && parcel   && parcel->getParcelFlagAllowVoice();
 +}
 +
 +bool LLViewerParcelMgr::allowAgentFly(const LLViewerRegion* region, const LLParcel* parcel) const
 +{
 +    return region && !region->getBlockFly()
 +        && parcel && parcel->getAllowFly();
 +}
 +
 +// Can the agent be pushed around by LLPushObject?
 +bool LLViewerParcelMgr::allowAgentPush(const LLViewerRegion* region, const LLParcel* parcel) const
 +{
 +    return region && !region->getRestrictPushObject()
 +        && parcel && !parcel->getRestrictPushObject();
 +}
 +
 +bool LLViewerParcelMgr::allowAgentScripts(const LLViewerRegion* region, const LLParcel* parcel) const
 +{
 +    // *NOTE: This code does not take into account group-owned parcels
 +    // and the flag to allow group-owned scripted objects to run.
 +    // This mirrors the traditional menu bar parcel icon code, but is not
 +    // technically correct.
 +    return region
 +        && !region->getRegionFlag(REGION_FLAGS_SKIP_SCRIPTS)
 +        && !region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS)
 +        && parcel
 +        && parcel->getAllowOtherScripts();
 +}
 +
 +bool LLViewerParcelMgr::allowAgentDamage(const LLViewerRegion* region, const LLParcel* parcel) const
 +{
 +    return (region && region->getAllowDamage())
 +        || (parcel && parcel->getAllowDamage());
 +}
 +
 +bool LLViewerParcelMgr::isOwnedAt(const LLVector3d& pos_global) const
 +{
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 +    if (!region) return false;
 +
 +    LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 +    if (!overlay) return false;
 +
 +    LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 +
 +    return overlay->isOwned( pos_region );
 +}
 +
 +bool LLViewerParcelMgr::isOwnedSelfAt(const LLVector3d& pos_global) const
 +{
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 +    if (!region) return false;
 +
 +    LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 +    if (!overlay) return false;
 +
 +    LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 +
 +    return overlay->isOwnedSelf( pos_region );
 +}
 +
 +bool LLViewerParcelMgr::isOwnedOtherAt(const LLVector3d& pos_global) const
 +{
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 +    if (!region) return false;
 +
 +    LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 +    if (!overlay) return false;
 +
 +    LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 +
 +    return overlay->isOwnedOther( pos_region );
 +}
 +
 +bool LLViewerParcelMgr::isSoundLocal(const LLVector3d& pos_global) const
 +{
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 +    if (!region) return false;
 +
 +    LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 +    if (!overlay) return false;
 +
 +    LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 +
 +    return overlay->isSoundLocal( pos_region );
 +}
 +
 +bool LLViewerParcelMgr::canHearSound(const LLVector3d &pos_global) const
 +{
 +    bool in_agent_parcel = inAgentParcel(pos_global);
 +
 +    if (in_agent_parcel)
 +    {
 +        // In same parcel as the agent
 +        return true;
 +    }
 +    else
 +    {
 +        if (LLViewerParcelMgr::getInstance()->getAgentParcel()->getSoundLocal())
 +        {
 +            // Not in same parcel, and agent parcel only has local sound
 +            return false;
 +        }
 +        else if (LLViewerParcelMgr::getInstance()->isSoundLocal(pos_global))
 +        {
 +            // Not in same parcel, and target parcel only has local sound
 +            return false;
 +        }
 +        else
 +        {
 +            // Not in same parcel, but neither are local sound
 +            return true;
 +        }
 +    }
 +}
 +
 +
 +bool LLViewerParcelMgr::inAgentParcel(const LLVector3d &pos_global) const
 +{
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(pos_global);
 +    LLViewerRegion* agent_region = gAgent.getRegion();
 +    if (!region || !agent_region)
 +        return false;
 +
 +    if (region != agent_region)
 +    {
 +        // Can't be in the agent parcel if you're not in the same region.
 +        return false;
 +    }
 +
 +    LLVector3 pos_region = agent_region->getPosRegionFromGlobal(pos_global);
 +    S32 row =    S32(pos_region.mV[VY] / PARCEL_GRID_STEP_METERS);
 +    S32 column = S32(pos_region.mV[VX] / PARCEL_GRID_STEP_METERS);
 +
 +    if (mAgentParcelOverlay[row*mParcelsPerEdge + column])
 +    {
 +        return true;
 +    }
 +    else
 +    {
 +        return false;
 +    }
 +}
 +
 +// Returns NULL when there is no valid data.
 +LLParcel* LLViewerParcelMgr::getHoverParcel() const
 +{
 +    if (mHoverRequestResult == PARCEL_RESULT_SUCCESS)
 +    {
 +        return mHoverParcel;
 +    }
 +    else
 +    {
 +        return NULL;
 +    }
 +}
 +
 +// Returns NULL when there is no valid data.
 +LLParcel* LLViewerParcelMgr::getCollisionParcel() const
 +{
 +    if (mRenderCollision)
 +    {
 +        return mCollisionParcel;
 +    }
 +    else
 +    {
 +        return NULL;
 +    }
 +}
 +
 +//
 +// UTILITIES
 +//
 +
 +void LLViewerParcelMgr::render()
 +{
 +    if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)
 +    {
 +        // Rendering is done in agent-coordinates, so need to supply
 +        // an appropriate offset to the render code.
 +        LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth);
 +        if (!regionp) return;
 +
 +        renderHighlightSegments(mHighlightSegments, regionp);
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::renderParcelCollision()
 +{
 +    static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION);
 +
 +    // check for expiration
 +    F32 expiration = (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY)
 +        ? PARCEL_COLLISION_DRAW_SECS_ON_PROXIMITY
 +        : PARCEL_BAN_LINES_DRAW_SECS_ON_COLLISION;
 +    if (mCollisionTimer.getElapsedTimeF32() > expiration)
 +    {
 +        mRenderCollision = false;
 +    }
 +
 +    if (mRenderCollision && ban_lines_mode != PARCEL_BAN_LINES_HIDE)
 +    {
 +        LLViewerRegion* regionp = gAgent.getRegion();
 +        if (regionp)
 +        {
 +            bool use_pass = mCollisionParcel->getParcelFlag(PF_USE_PASS_LIST);
 +            renderCollisionSegments(mCollisionSegments, use_pass, regionp);
 +        }
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
 +{
 +    if (!mSelected)
 +    {
 +        return;
 +    }
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region) return;
 +
 +    LLMessageSystem *msg = gMessageSystem;
 +
 +
 +    if (flags & AL_BAN)
 +    {
 +        mCurrentParcel->mBanList.clear();
 +    }
 +    if (flags & AL_ACCESS)
 +    {
 +        mCurrentParcel->mAccessList.clear();
 +    }
 +    if (flags & AL_ALLOW_EXPERIENCE)
 +    {
 +        mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED);
 +    }
 +    if (flags & AL_BLOCK_EXPERIENCE)
 +    {
 +        mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED);
 +    }
 +
 +    // Only the headers differ
 +    msg->newMessageFast(_PREHASH_ParcelAccessListRequest);
 +    msg->nextBlockFast(_PREHASH_AgentData);
 +    msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 +    msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 +    msg->nextBlockFast(_PREHASH_Data);
 +    msg->addS32Fast(_PREHASH_SequenceID, 0);
 +    msg->addU32Fast(_PREHASH_Flags, flags);
 +    msg->addS32("LocalID", mCurrentParcel->getLocalID() );
 +    msg->sendReliable( region->getHost() );
 +}
 +
 +
 +void LLViewerParcelMgr::sendParcelDwellRequest()
 +{
 +    if (!mSelected)
 +    {
 +        return;
 +    }
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region) return;
 +
 +    LLMessageSystem *msg = gMessageSystem;
 +
 +    // Only the headers differ
 +    msg->newMessage("ParcelDwellRequest");
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", gAgent.getID() );
 +    msg->addUUID("SessionID", gAgent.getSessionID());
 +    msg->nextBlock("Data");
 +    msg->addS32("LocalID", mCurrentParcel->getLocalID());
 +    msg->addUUID("ParcelID", LLUUID::null); // filled in on simulator
 +    msg->sendReliable( region->getHost() );
 +}
 +
 +
 +void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id)
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotSetLandOwnerNothingSelected");
 +        return;
 +    }
 +
 +    LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
 +
 +    // BUG: Only works for the region containing mWestSouthBottom
 +    LLVector3d east_north_region_check( mEastNorth );
 +    east_north_region_check.mdV[VX] -= 0.5;
 +    east_north_region_check.mdV[VY] -= 0.5;
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +    {
 +        // TODO: Add a force owner version of this alert.
 +        LLNotificationsUtil::add("CannotContentifyNoRegion");
 +        return;
 +    }
 +
 +    // BUG: Make work for cross-region selections
 +    LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
 +    if (region != region2)
 +    {
 +        LLNotificationsUtil::add("CannotSetLandOwnerMultipleRegions");
 +        return;
 +    }
 +
 +    LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL;
 +
 +    LLSD payload;
 +    payload["owner_id"] = owner_id;
 +    payload["parcel_local_id"] = mCurrentParcel->getLocalID();
 +    payload["region_host"] = region->getHost().getIPandPort();
 +    LLNotification::Params params("ForceOwnerAuctionWarning");
 +    params.payload(payload).functor.function(callback_god_force_owner);
 +
 +    if(mCurrentParcel->getAuctionID())
 +    {
 +        LLNotifications::instance().add(params);
 +    }
 +    else
 +    {
 +        LLNotifications::instance().forceResponse(params, 0);
 +    }
 +}
 +
 +bool callback_god_force_owner(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    if(0 == option)
 +    {
 +        LLMessageSystem* msg = gMessageSystem;
 +        msg->newMessage("ParcelGodForceOwner");
 +        msg->nextBlock("AgentData");
 +        msg->addUUID("AgentID", gAgent.getID());
 +        msg->addUUID("SessionID", gAgent.getSessionID());
 +        msg->nextBlock("Data");
 +        msg->addUUID("OwnerID", notification["payload"]["owner_id"].asUUID());
 +        msg->addS32( "LocalID", notification["payload"]["parcel_local_id"].asInteger());
 +        msg->sendReliable(LLHost(notification["payload"]["region_host"].asString()));
 +    }
 +    return false;
 +}
 +
 +void LLViewerParcelMgr::sendParcelGodForceToContent()
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotContentifyNothingSelected");
 +        return;
 +    }
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotContentifyNoRegion");
 +        return;
 +    }
 +
 +    LLMessageSystem* msg = gMessageSystem;
 +    msg->newMessage("ParcelGodMarkAsContent");
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", gAgent.getID());
 +    msg->addUUID("SessionID", gAgent.getSessionID());
 +    msg->nextBlock("ParcelData");
 +    msg->addS32("LocalID", mCurrentParcel->getLocalID());
 +    msg->sendReliable(region->getHost());
 +}
 +
 +void LLViewerParcelMgr::sendParcelRelease()
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandNothingSelected");
 +        return;
 +    }
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandNoRegion");
 +        return;
 +    }
 +
 +    //U32 flags = PR_NONE;
 +    //if (god_force) flags |= PR_GOD_FORCE;
 +
 +    LLMessageSystem* msg = gMessageSystem;
 +    msg->newMessage("ParcelRelease");
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", gAgent.getID() );
 +    msg->addUUID("SessionID", gAgent.getSessionID() );
 +    msg->nextBlock("Data");
 +    msg->addS32("LocalID", mCurrentParcel->getLocalID() );
 +    //msg->addU32("Flags", flags);
 +    msg->sendReliable( region->getHost() );
 +
 +    // Blitz selection, since the parcel might be non-rectangular, and
 +    // we won't have appropriate parcel information.
 +    deselectLand();
 +}
 +
 +class LLViewerParcelMgr::ParcelBuyInfo
 +{
 +public:
 +    LLUUID  mAgent;
 +    LLUUID  mSession;
 +    LLUUID  mGroup;
 +    bool    mIsGroupOwned;
 +    bool    mRemoveContribution;
 +    bool    mIsClaim;
 +    LLHost  mHost;
 +
 +    // for parcel buys
 +    S32     mParcelID;
 +    S32     mPrice;
 +    S32     mArea;
 +
 +    // for land claims
 +    F32     mWest;
 +    F32     mSouth;
 +    F32     mEast;
 +    F32     mNorth;
 +};
 +
 +LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy(
 +    const LLUUID& agent_id,
 +    const LLUUID& session_id,
 +    const LLUUID& group_id,
 +    bool is_group_owned,
 +    bool is_claim,
 +    bool remove_contribution)
 +{
 +    if (!mSelected || !mCurrentParcel)
 +    {
 +        LLNotificationsUtil::add("CannotBuyLandNothingSelected");
 +        return NULL;
 +    }
 +
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotBuyLandNoRegion");
 +        return NULL;
 +    }
 +
 +    if (is_claim)
 +    {
 +        LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL;
 +        LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL;
 +
 +        // BUG: Only works for the region containing mWestSouthBottom
 +        LLVector3d east_north_region_check( mEastNorth );
 +        east_north_region_check.mdV[VX] -= 0.5;
 +        east_north_region_check.mdV[VY] -= 0.5;
 +
 +        LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
 +
 +        if (region != region2)
 +        {
 +            LLNotificationsUtil::add("CantBuyLandAcrossMultipleRegions");
 +            return NULL;
 +        }
 +    }
 +
 +
 +    ParcelBuyInfo* info = new ParcelBuyInfo;
 +
 +    info->mAgent = agent_id;
 +    info->mSession = session_id;
 +    info->mGroup = group_id;
 +    info->mIsGroupOwned = is_group_owned;
 +    info->mIsClaim = is_claim;
 +    info->mRemoveContribution = remove_contribution;
 +    info->mHost = region->getHost();
 +    info->mPrice = mCurrentParcel->getSalePrice();
 +    info->mArea = mCurrentParcel->getArea();
 +
 +    if (!is_claim)
 +    {
 +        info->mParcelID = mCurrentParcel->getLocalID();
 +    }
 +    else
 +    {
 +        // BUG: Make work for cross-region selections
 +        LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
 +        LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
 +
 +        info->mWest     = west_south_bottom_region.mV[VX];
 +        info->mSouth    = west_south_bottom_region.mV[VY];
 +        info->mEast     = east_north_top_region.mV[VX];
 +        info->mNorth    = east_north_top_region.mV[VY];
 +    }
 +
 +    return info;
 +}
 +
 +void LLViewerParcelMgr::sendParcelBuy(ParcelBuyInfo* info)
 +{
 +    // send the message
 +    LLMessageSystem* msg = gMessageSystem;
 +    msg->newMessage(info->mIsClaim ? "ParcelClaim" : "ParcelBuy");
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", info->mAgent);
 +    msg->addUUID("SessionID", info->mSession);
 +    msg->nextBlock("Data");
 +    msg->addUUID("GroupID", info->mGroup);
 +    msg->addBOOL("IsGroupOwned", info->mIsGroupOwned);
 +    if (!info->mIsClaim)
 +    {
 +        msg->addBOOL("RemoveContribution", info->mRemoveContribution);
 +        msg->addS32("LocalID", info->mParcelID);
 +    }
 +    msg->addBOOL("Final", true);    // don't allow escrow buys
 +    if (info->mIsClaim)
 +    {
 +        msg->nextBlock("ParcelData");
 +        msg->addF32("West",  info->mWest);
 +        msg->addF32("South", info->mSouth);
 +        msg->addF32("East",  info->mEast);
 +        msg->addF32("North", info->mNorth);
 +    }
 +    else // ParcelBuy
 +    {
 +        msg->nextBlock("ParcelData");
 +        msg->addS32("Price",info->mPrice);
 +        msg->addS32("Area",info->mArea);
 +    }
 +    msg->sendReliable(info->mHost);
 +}
 +
 +void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo* *info)
 +{
 +    // Must be here because ParcelBuyInfo is local to this .cpp file
 +    delete *info;
 +    *info = NULL;
 +}
 +
 +void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id)
 +{
 +    if (!mSelected || !mCurrentParcel)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandNothingSelected");
 +        return;
 +    }
 +    if(group_id.isNull())
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandNoGroup");
 +        return;
 +    }
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandNoRegion");
 +        return;
 +    }
 +
 +    LLMessageSystem* msg = gMessageSystem;
 +    msg->newMessage("ParcelDeedToGroup");
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", gAgent.getID() );
 +    msg->addUUID("SessionID", gAgent.getSessionID() );
 +    msg->nextBlock("Data");
 +    msg->addUUID("GroupID", group_id );
 +    msg->addS32("LocalID", mCurrentParcel->getLocalID() );
 +    //msg->addU32("JoinNeighbors", join);
 +    msg->sendReliable( region->getHost() );
 +}
 +
 +
 +/*
 +// *NOTE: We cannot easily make landmarks at global positions because
 +// global positions probably refer to a sim/local combination which
 +// can move over time. We could implement this by looking up the
 +// region global x,y, but it's easier to take it out for now.
 +void LLViewerParcelMgr::makeLandmarkAtSelection()
 +{
 +    // Don't create for parcels you don't own
 +    if (gAgent.getID() != mCurrentParcel->getOwnerID())
 +    {
 +        return;
 +    }
 +
 +    LLVector3d global_center(mWestSouth);
 +    global_center += mEastNorth;
 +    global_center *= 0.5f;
 +
 +    LLViewerRegion* region;
 +    region = LLWorld::getInstance()->getRegionFromPosGlobal(global_center);
 +
 +    LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
 +    LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
 +
 +    std::string name("My Land");
 +    std::string buffer;
 +    S32 pos_x = (S32)floor((west_south_bottom_region.mV[VX] + east_north_top_region.mV[VX]) / 2.0f);
 +    S32 pos_y = (S32)floor((west_south_bottom_region.mV[VY] + east_north_top_region.mV[VY]) / 2.0f);
 +    buffer = llformat("%s in %s (%d, %d)",
 +            name.c_str(),
 +            region->getName().c_str(),
 +            pos_x, pos_y);
 +    name.assign(buffer);
 +
 +    create_landmark(name, "Claimed land", global_center);
 +}
 +*/
 +
 +const std::string& LLViewerParcelMgr::getAgentParcelName() const
 +{
 +    return mAgentParcel->getName();
 +}
 +
 +
 +const S32 LLViewerParcelMgr::getAgentParcelId() const
 +{
 +    if (mAgentParcel)
 +        return mAgentParcel->getLocalID();
 +    return INVALID_PARCEL_ID;
 +}
 +
 +void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region)
 +{
 +    if(!parcel)
 +        return;
 +
 +    LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region)
 +        return;
 +
 +    LLSD body;
 +    std::string url = region->getCapability("ParcelPropertiesUpdate");
 +    if (!url.empty())
 +    {
 +        // request new properties update from simulator
 +        U32 message_flags = 0x01;
 +        body["flags"] = ll_sd_from_U32(message_flags);
 +        parcel->packMessage(body);
 +        LL_INFOS("ParcelMgr") << "Sending parcel properties update via capability to: "
 +            << url << LL_ENDL;
 +
 +        LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
 +            "Parcel Properties sent to sim.", "Parcel Properties failed to send to sim.");
 +    }
 +    else
 +    {
 +        LLMessageSystem* msg = gMessageSystem;
 +        msg->newMessageFast(_PREHASH_ParcelPropertiesUpdate);
 +        msg->nextBlockFast(_PREHASH_AgentData);
 +        msg->addUUIDFast(_PREHASH_AgentID,  gAgent.getID() );
 +        msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 +        msg->nextBlockFast(_PREHASH_ParcelData);
 +        msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() );
 +
 +        U32 message_flags = 0x01;
 +        msg->addU32("Flags", message_flags);
 +
 +        parcel->packMessage(msg);
 +
 +        msg->sendReliable( region->getHost() );
 +    }
 +}
 +
 +
 +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
 +    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;
 +    }
 +
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos );
 +    if (!region)
 +    {
 +        return;
 +    }
 +
 +    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
 +        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;
 +
 +        // 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;
 +    }
 +}
 +
 +
 +// static
 +void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user)
 +{
 +    // Extract the packed overlay information
 +    S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data);
 +
 +    if (packed_overlay_size <= 0)
 +    {
 +        LL_WARNS() << "Overlay size " << packed_overlay_size << LL_ENDL;
 +        return;
 +    }
 +
 +    S32 parcels_per_edge = LLViewerParcelMgr::getInstance()->mParcelsPerEdge;
 +    S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS;
 +    if (packed_overlay_size != expected_size)
 +    {
 +        LL_WARNS() << "Got parcel overlay size " << packed_overlay_size
 +            << " expecting " << expected_size << LL_ENDL;
 +        return;
 +    }
 +
 +    S32 sequence_id;
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id);
 +    msg->getBinaryDataFast(
 +            _PREHASH_ParcelData,
 +            _PREHASH_Data,
 +            sPackedOverlay,
 +            expected_size);
 +
 +    LLHost host = msg->getSender();
 +    LLViewerRegion *region = LLWorld::getInstance()->getRegion(host);
 +    if (region)
 +    {
 +        region->mParcelOverlay->uncompressLandOverlay( sequence_id, sPackedOverlay );
 +    }
 +}
 +
 +// static
 +void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **user)
 +{
 +    if (LLApp::isExiting() || gDisconnected)
 +    {
 +        LL_DEBUGS("ParcelMgr") << "Ignoring parcel properties, shutting down" << LL_ENDL;
 +        return;
 +    }
 +
 +    S32     request_result;
 +    S32     sequence_id;
 +    bool    snap_selection = false;
 +    S32     self_count = 0;
 +    S32     other_count = 0;
 +    S32     public_count = 0;
 +    S32     local_id;
 +    LLUUID  owner_id;
 +    bool    is_group_owned;
 +    U32 auction_id = 0;
 +    S32     claim_price_per_meter = 0;
 +    S32     rent_price_per_meter = 0;
 +    S32     claim_date = 0;
 +    LLVector3   aabb_min;
 +    LLVector3   aabb_max;
 +    S32     area = 0;
 +    S32     sw_max_prims = 0;
 +    S32     sw_total_prims = 0;
 +    //LLUUID    buyer_id;
 +    U8 status = 0;
 +    S32     max_prims = 0;
 +    S32     total_prims = 0;
 +    S32     owner_prims = 0;
 +    S32     group_prims = 0;
 +    S32     other_prims = 0;
 +    S32     selected_prims = 0;
 +    F32     parcel_prim_bonus = 1.f;
 +    bool    region_push_override = false;
 +    bool    region_deny_anonymous_override = false;
 +    bool    region_deny_identified_override = false; // Deprecated
 +    bool    region_deny_transacted_override = false; // Deprecated
 +    bool    region_deny_age_unverified_override = false;
 +    bool    region_allow_access_override = true;
 +    bool    region_allow_environment_override = true;
 +    S32     parcel_environment_version = 0;
 +    bool    agent_parcel_update = false; // updating previous(existing) agent parcel
 +    U32     extended_flags = 0; //obscure MOAP
 +
 +    S32     other_clean_time = 0;
 +
 +    LLViewerParcelMgr& parcel_mgr = LLViewerParcelMgr::instance();
 +
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id);
 +
 +    if (request_result == PARCEL_RESULT_NO_DATA)
 +    {
 +        // no valid parcel data
 +        LL_INFOS("ParcelMgr") << "no valid parcel data" << LL_ENDL;
 +        return;
 +    }
 +
 +    // Decide where the data will go.
 +    LLParcel* parcel = NULL;
 +    if (sequence_id == SELECTED_PARCEL_SEQ_ID)
 +    {
 +        // ...selected parcels report this sequence id
 +        parcel_mgr.mRequestResult = PARCEL_RESULT_SUCCESS;
 +        parcel = parcel_mgr.mCurrentParcel;
 +    }
 +    else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
 +    {
 +        parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS;
 +        parcel = parcel_mgr.mHoverParcel;
 +    }
 +    else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
 +        sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID ||
 +        sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
 +    {
 +        parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS;
 +        parcel = parcel_mgr.mCollisionParcel;
 +    }
 +    else if (sequence_id == 0 || sequence_id > parcel_mgr.mAgentParcelSequenceID)
 +    {
 +        // new agent parcel
 +        // *TODO: Does it really make sense to set the agent parcel to this
 +        // parcel if the client doesn't know what kind of parcel data this is?
 +        parcel_mgr.mAgentParcelSequenceID = sequence_id;
 +        parcel = parcel_mgr.mAgentParcel;
 +    }
 +    else
 +    {
 +        LL_INFOS("ParcelMgr") << "out of order agent parcel sequence id " << sequence_id
 +            << " last good " << parcel_mgr.mAgentParcelSequenceID
 +            << LL_ENDL;
 +        return;
 +    }
 +
 +    msg->getBOOL("ParcelData", "SnapSelection", snap_selection);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelfCount, self_count);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherCount, other_count);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_PublicCount, public_count);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_LocalID, local_id);
 +    msg->getUUIDFast(_PREHASH_ParcelData, _PREHASH_OwnerID, owner_id);
 +    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_IsGroupOwned, is_group_owned);
 +    msg->getU32Fast(_PREHASH_ParcelData, _PREHASH_AuctionID, auction_id);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_ClaimDate, claim_date);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_ClaimPrice, claim_price_per_meter);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RentPrice, rent_price_per_meter);
 +    msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMin, aabb_min);
 +    msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMax, aabb_max);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_Area, area);
 +    //msg->getUUIDFast( _PREHASH_ParcelData, _PREHASH_BuyerID, buyer_id);
 +    msg->getU8("ParcelData", "Status", status);
 +    msg->getS32("ParcelData", "SimWideMaxPrims", sw_max_prims);
 +    msg->getS32("ParcelData", "SimWideTotalPrims", sw_total_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_MaxPrims, max_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_TotalPrims, total_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OwnerPrims, owner_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_GroupPrims, group_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherPrims, other_prims);
 +    msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelectedPrims, selected_prims);
 +    msg->getF32Fast(_PREHASH_ParcelData, _PREHASH_ParcelPrimBonus, parcel_prim_bonus);
 +    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionPushOverride, region_push_override);
 +    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyAnonymous, region_deny_anonymous_override);
 +    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyIdentified, region_deny_identified_override); // Deprecated
 +    msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyTransacted, region_deny_transacted_override); // Deprecated
 +    if (msg->getNumberOfBlocksFast(_PREHASH_AgeVerificationBlock))
 +    {
 +        // this block was added later and may not be on older sims, so we have to test its existence first
 +        msg->getBOOLFast(_PREHASH_AgeVerificationBlock, _PREHASH_RegionDenyAgeUnverified, region_deny_age_unverified_override);
 +    }
 +
 +    if (msg->getNumberOfBlocks(_PREHASH_RegionAllowAccessBlock))
 +    {
 +        msg->getBOOLFast(_PREHASH_RegionAllowAccessBlock, _PREHASH_RegionAllowAccessOverride, region_allow_access_override);
 +    }
 +
 +    if (msg->getNumberOfBlocks(_PREHASH_ParcelExtendedFlags))
 +    {
 +        msg->getU32Fast(_PREHASH_ParcelExtendedFlags, _PREHASH_Flags, extended_flags);
 +     }
 +
 +    if (msg->getNumberOfBlocks(_PREHASH_ParcelEnvironmentBlock))
 +    {
 +        msg->getS32Fast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_ParcelEnvironmentVersion, parcel_environment_version);
 +        msg->getBOOLFast(_PREHASH_ParcelEnvironmentBlock, _PREHASH_RegionAllowEnvironmentOverride, region_allow_environment_override);
 +    }
 +
 +    msg->getS32("ParcelData", "OtherCleanTime", other_clean_time );
 +
 +    LL_DEBUGS("ParcelMgr") << "Processing parcel " << local_id << " update, target(sequence): " << sequence_id << LL_ENDL;
 +
 +    // Actually extract the data.
 +    if (parcel)
 +    {
 +        if (local_id == parcel_mgr.mAgentParcel->getLocalID())
 +        {
 +            // Parcels in different regions can have same ids.
 +            LLViewerRegion* parcel_region = LLWorld::getInstance()->getRegion(msg->getSender());
 +            LLViewerRegion* agent_region = gAgent.getRegion();
 +            if (parcel_region && agent_region && parcel_region->getRegionID() == agent_region->getRegionID())
 +            {
 +                // we got an updated version of agent parcel
 +                agent_parcel_update = true;
 +            }
 +        }
 +
 +        S32 cur_parcel_environment_version = parcel->getParcelEnvironmentVersion();
 +        bool environment_changed = (cur_parcel_environment_version != parcel_environment_version);
 +
 +        parcel->init(owner_id,
 +            false, false, false,
 +            claim_date, claim_price_per_meter, rent_price_per_meter,
 +            area, other_prims, parcel_prim_bonus, is_group_owned);
 +        parcel->setLocalID(local_id);
 +        parcel->setAABBMin(aabb_min);
 +        parcel->setAABBMax(aabb_max);
 +
 +        parcel->setAuctionID(auction_id);
 +        parcel->setOwnershipStatus((LLParcel::EOwnershipStatus)status);
 +
 +        parcel->setSimWideMaxPrimCapacity(sw_max_prims);
 +        parcel->setSimWidePrimCount(sw_total_prims);
 +        parcel->setMaxPrimCapacity(max_prims);
 +        parcel->setOwnerPrimCount(owner_prims);
 +        parcel->setGroupPrimCount(group_prims);
 +        parcel->setOtherPrimCount(other_prims);
 +        parcel->setSelectedPrimCount(selected_prims);
 +        parcel->setParcelPrimBonus(parcel_prim_bonus);
 +
 +        parcel->setCleanOtherTime(other_clean_time);
 +        parcel->setRegionPushOverride(region_push_override);
 +        parcel->setRegionDenyAnonymousOverride(region_deny_anonymous_override);
 +        parcel->setRegionDenyAgeUnverifiedOverride(region_deny_age_unverified_override);
 +        parcel->setRegionAllowAccessOverride(region_allow_access_override);
 +        parcel->setParcelEnvironmentVersion(cur_parcel_environment_version);
 +        parcel->setRegionAllowEnvironmentOverride(region_allow_environment_override);
 +
 +        parcel->setObscureMOAP((bool)extended_flags);
 +
 +        parcel->unpackMessage(msg);
 +
 +        if (parcel == parcel_mgr.mAgentParcel)
 +        {
 +            // new agent parcel
 +            S32 bitmap_size =   parcel_mgr.mParcelsPerEdge
 +                                * parcel_mgr.mParcelsPerEdge
 +                                / 8;
 +            U8* bitmap = new U8[ bitmap_size ];
 +            msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
 +
 +            parcel_mgr.writeAgentParcelFromBitmap(bitmap);
 +            delete[] bitmap;
 +
 +            // Let interesting parties know about agent parcel change.
 +            LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance();
 +
 +            if (instance->mTeleportInProgress)
 +            {
 +                instance->mTeleportInProgress = false;
 +                if(instance->mTeleportInProgressPosition.isNull())
 +                {
 +                    //initial update
 +                    instance->mTeleportFinishedSignal(gAgent.getPositionGlobal(), false);
 +                }
 +                else
 +                {
 +                    instance->mTeleportFinishedSignal(instance->mTeleportInProgressPosition, false);
 +                }
 +            }
 +            parcel->setParcelEnvironmentVersion(parcel_environment_version);
 +            LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL;
 +
 +            // Notify anything that wants to know when the agent changes parcels
 +            gAgent.changeParcels();
 +            instance->mTeleportInProgress = false;
 +        }
 +        else if (agent_parcel_update)
 +        {
 +            parcel->setParcelEnvironmentVersion(parcel_environment_version);
 +            // updated agent parcel
 +            parcel_mgr.mAgentParcel->unpackMessage(msg);
 +            if ((LLEnvironment::instance().isExtendedEnvironmentEnabled() && environment_changed))
 +            {
 +                LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL;
 +                LLEnvironment::instance().requestParcel(local_id);
 +            }
 +        }
 +    }
 +
 +    // Handle updating selections, if necessary.
 +    if (sequence_id == SELECTED_PARCEL_SEQ_ID)
 +    {
 +        // Update selected counts
 +        parcel_mgr.mCurrentParcelSelection->mSelectedSelfCount = self_count;
 +        parcel_mgr.mCurrentParcelSelection->mSelectedOtherCount = other_count;
 +        parcel_mgr.mCurrentParcelSelection->mSelectedPublicCount = public_count;
 +
 +        parcel_mgr.mCurrentParcelSelection->mSelectedMultipleOwners =
 +                            (request_result == PARCEL_RESULT_MULTIPLE);
 +
 +        // Select the whole parcel
 +        LLViewerRegion* region = LLWorld::getInstance()->getRegion( msg->getSender() );
 +        if (region)
 +        {
 +            if (!snap_selection)
 +            {
 +                // don't muck with the westsouth and eastnorth.
 +                // just highlight it
 +                LLVector3 west_south = region->getPosRegionFromGlobal(parcel_mgr.mWestSouth);
 +                LLVector3 east_north = region->getPosRegionFromGlobal(parcel_mgr.mEastNorth);
 +
 +                parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
 +                parcel_mgr.writeHighlightSegments(
 +                                west_south.mV[VX],
 +                                west_south.mV[VY],
 +                                east_north.mV[VX],
 +                                east_north.mV[VY] );
 +                parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = false;
 +            }
 +            else if (0 == local_id)
 +            {
 +                // this is public land, just highlight the selection
 +                parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min );
 +                parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max );
 +
 +                parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
 +                parcel_mgr.writeHighlightSegments(
 +                                aabb_min.mV[VX],
 +                                aabb_min.mV[VY],
 +                                aabb_max.mV[VX],
 +                                aabb_max.mV[VY] );
 +                parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = true;
 +            }
 +            else
 +            {
 +                parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min );
 +                parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max );
 +
 +                // Owned land, highlight the boundaries
 +                S32 bitmap_size =   parcel_mgr.mParcelsPerEdge
 +                                    * parcel_mgr.mParcelsPerEdge
 +                                    / 8;
 +                U8* bitmap = new U8[ bitmap_size ];
 +                msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
 +
 +                parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
 +                parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mHighlightSegments );
 +
 +                delete[] bitmap;
 +                bitmap = NULL;
 +
 +                parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = true;
 +            }
 +
 +            // Request access list information for this land
 +            parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_ALLOW_EXPERIENCE | AL_BLOCK_EXPERIENCE);
 +
 +            // Request dwell for this land, if it's not public land.
 +            parcel_mgr.mSelectedDwell = DWELL_NAN;
 +            if (0 != local_id)
 +            {
 +                parcel_mgr.sendParcelDwellRequest();
 +            }
 +
 +            parcel_mgr.mSelected = true;
 +            parcel_mgr.notifyObservers();
 +        }
 +    }
 +    else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
 +             sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID  ||
 +             sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
 +    {
 +        // We're about to collide with this parcel
 +        static LLCachedControl<S32> ban_lines_mode(gSavedSettings , "ShowBanLines" , PARCEL_BAN_LINES_ON_COLLISION);
 +        if (ban_lines_mode == PARCEL_BAN_LINES_ON_PROXIMITY)
 +        {
 +            parcel_mgr.resetCollisionTimer();
 +        }
 +
 +        // Differentiate this parcel if we are banned from it.
 +        if (sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
 +        {
 +            parcel_mgr.mCollisionBanned = BA_BANNED;
 +        }
 +        else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID)
 +        {
 +            parcel_mgr.mCollisionBanned = BA_NOT_IN_GROUP;
 +        }
 +        else
 +        {
 +            parcel_mgr.mCollisionBanned = BA_NOT_ON_LIST;
 +
 +        }
 +
 +        S32 bitmap_size =   parcel_mgr.mParcelsPerEdge
 +                            * parcel_mgr.mParcelsPerEdge
 +                            / 8;
 +        U8* bitmap = new U8[ bitmap_size ];
 +        msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
 +
 +        parcel_mgr.resetSegments(parcel_mgr.mCollisionSegments);
 +        parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mCollisionSegments );
 +
 +        delete[] bitmap;
 +        bitmap = NULL;
 +
 +    }
 +    else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
 +    {
 +        LLViewerRegion *region = LLWorld::getInstance()->getRegion( msg->getSender() );
 +        if (region)
 +        {
 +            parcel_mgr.mHoverWestSouth = region->getPosGlobalFromRegion( aabb_min );
 +            parcel_mgr.mHoverEastNorth = region->getPosGlobalFromRegion( aabb_max );
 +        }
 +        else
 +        {
 +            parcel_mgr.mHoverWestSouth.clearVec();
 +            parcel_mgr.mHoverEastNorth.clearVec();
 +        }
 +    }
 +    else
 +    {
 +        if (gNonInteractive)
 +        {
 +            return;
 +        }
 +
 +        // Check for video
 +        LLViewerParcelMedia::getInstance()->update(parcel);
 +
 +        // Then check for music
 +        if (gAudiop)
 +        {
 +            if (parcel)
 +            {
 +                // Only update stream if parcel changed (recreated) or music is playing (enabled)
 +                static LLCachedControl<bool> already_playing(gSavedSettings, "MediaTentativeAutoPlay", true);
 +                if (!agent_parcel_update || already_playing)
 +                {
 +                    LLViewerParcelAskPlay::getInstance()->cancelNotification();
 +                    std::string music_url_raw = parcel->getMusicURL();
 +
 +                    // Trim off whitespace from front and back
 +                    std::string music_url = music_url_raw;
 +                    LLStringUtil::trim(music_url);
 +
 +                    // If there is a new music URL and it's valid, play it.
 +                    if (music_url.size() > 12)
 +                    {
 +                        if (music_url.substr(0, 7) == "http://"
 +                            || music_url.substr(0, 8) == "https://")
 +                        {
 +                            LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender());
 +                            if (region)
 +                            {
 +                                optionallyStartMusic(music_url, parcel->mLocalID, region->getRegionID(), !agent_parcel_update);
 +                            }
 +                        }
 +                        else
 +                        {
 +                            LL_INFOS("ParcelMgr") << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL;
 +                            // clears the URL
 +                            // null value causes fade out
 +                            LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
 +                        }
 +                    }
 +                    else if (!gAudiop->getInternetStreamURL().empty())
 +                    {
 +                        LL_INFOS("ParcelMgr") << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL;
 +                        // null value causes fade out
 +                        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
 +                    }
 +                }
 +            }
 +            else
 +            {
 +                // Public land has no music
 +                LLViewerParcelAskPlay::getInstance()->cancelNotification();
 +                LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
 +            }
 +        }//if gAudiop
 +    };
 +}
 +
 +//static
 +void LLViewerParcelMgr::onStartMusicResponse(const LLUUID ®ion_id, const S32 &parcel_id, const std::string &url, const bool &play)
 +{
 +    if (play)
 +    {
 +        LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL;
 +        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url);
 +    }
 +    else
 +    {
 +        LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
 +    }
 +}
 +
 +void LLViewerParcelMgr::optionallyStartMusic(const std::string &music_url, const S32 &local_id, const LLUUID ®ion_id, bool switched_parcel)
 +{
 +    static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true);
 +    if (streaming_music)
 +    {
 +        static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1);
 +        static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true);
 +        // only play music when you enter a new parcel if the UI control for this
 +        // was not *explicitly* stopped by the user. (part of SL-4878)
 +        LLPanelNearByMedia* nearby_media_panel = gStatusBar ? gStatusBar->getNearbyMediaPanel() : NULL;
 +        LLViewerAudio* viewer_audio = LLViewerAudio::getInstance();
 +
 +        // ask mode //todo constants
 +        if (autoplay_mode == 2)
 +        {
 +            // if user set media to play - ask
 +            if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart())
 +                || (!nearby_media_panel && tentative_autoplay))
 +            {
 +                // user did not stop audio
 +                if (switched_parcel || music_url != viewer_audio->getNextStreamURI())
 +                {
 +                    viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null);
 +
 +                    LLViewerParcelAskPlay::getInstance()->askToPlay(region_id,
 +                        local_id,
 +                        music_url,
 +                        onStartMusicResponse);
 +                }
 +                // else do nothing:
 +                // Parcel properties changed, but not url.
 +                // We are already playing this url and asked about it when agent entered parcel
 +                // or user started audio manually at some point
 +            }
 +            else
 +            {
 +                // stopped by the user, do not autoplay
 +                LLViewerParcelAskPlay::getInstance()->cancelNotification();
 +                viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null);
 +            }
 +        }
 +        // autoplay
 +        else if ((nearby_media_panel
 +                  && nearby_media_panel->getParcelAudioAutoStart())
 +                  // or they have expressed no opinion in the UI, but have autoplay on...
 +                 || (!nearby_media_panel
 +                     && autoplay_mode == 1
 +                     && tentative_autoplay))
 +        {
 +            LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL;
 +            viewer_audio->startInternetStreamWithAutoFade(music_url);
 +        }
 +        // autoplay off
 +        else if(switched_parcel || music_url != viewer_audio->getNextStreamURI())
 +        {
 +            viewer_audio->startInternetStreamWithAutoFade(LLStringUtil::null);
 +        }
 +    }
 +}
 +
 +// static
 +void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void **user)
 +{
 +    LLUUID agent_id;
 +    S32 sequence_id = 0;
 +    U32 message_flags = 0x0;
 +    S32 parcel_id = -1;
 +
 +    msg->getUUIDFast(_PREHASH_Data, _PREHASH_AgentID, agent_id);
 +    msg->getS32Fast( _PREHASH_Data, _PREHASH_SequenceID, sequence_id ); //ignored
 +    msg->getU32Fast( _PREHASH_Data, _PREHASH_Flags, message_flags);
 +    msg->getS32Fast( _PREHASH_Data, _PREHASH_LocalID, parcel_id);
 +
 +    LLParcel* parcel = LLViewerParcelMgr::getInstance()->mCurrentParcel;
 +    if (!parcel) return;
 +
 +    if (parcel_id != parcel->getLocalID())
 +    {
 +        LL_WARNS_ONCE("ParcelMgr") << "processParcelAccessListReply for parcel " << parcel_id
 +            << " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL;
 +        return;
 +    }
 +
 +    if (message_flags & AL_ACCESS)
 +    {
 +        parcel->unpackAccessEntries(msg, &(parcel->mAccessList) );
 +    }
 +    else if (message_flags & AL_BAN)
 +    {
 +        parcel->unpackAccessEntries(msg, &(parcel->mBanList) );
 +    }
 +    else if (message_flags & AL_ALLOW_EXPERIENCE)
 +    {
 +        parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_ALLOWED);
 +    }
 +    else if (message_flags & AL_BLOCK_EXPERIENCE)
 +    {
 +        parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_BLOCKED);
 +    }
 +    /*else if (message_flags & AL_RENTER)
 +    {
 +        parcel->unpackAccessEntries(msg, &(parcel->mRenterList) );
 +    }*/
 +
 +    LLViewerParcelMgr::getInstance()->notifyObservers();
 +}
 +
 +
 +// static
 +void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**)
 +{
 +    LLUUID agent_id;
 +    msg->getUUID("AgentData", "AgentID", agent_id);
 +
 +    S32 local_id;
 +    msg->getS32("Data", "LocalID", local_id);
 +
 +    LLUUID parcel_id;
 +    msg->getUUID("Data", "ParcelID", parcel_id);
 +
 +    F32 dwell;
 +    msg->getF32("Data", "Dwell", dwell);
 +
 +    if (local_id == LLViewerParcelMgr::getInstance()->mCurrentParcel->getLocalID())
 +    {
 +        LLViewerParcelMgr::getInstance()->mSelectedDwell = dwell;
 +        LLViewerParcelMgr::getInstance()->notifyObservers();
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which)
 +{
 +    if (!mSelected)
 +    {
 +        return;
 +    }
 +
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 +    if (!region) return;
 +
 +    LLParcel* parcel = mCurrentParcel;
 +    if (!parcel) return;
 +
 +    if (which & AL_ACCESS)
 +    {
 +        sendParcelAccessListUpdate(AL_ACCESS, parcel->mAccessList, region, parcel->getLocalID());
 +    }
 +
 +    if (which & AL_BAN)
 +    {
 +        sendParcelAccessListUpdate(AL_BAN, parcel->mBanList, region, parcel->getLocalID());
 +    }
 +
 +    if(which & AL_ALLOW_EXPERIENCE)
 +    {
 +        sendParcelAccessListUpdate(AL_ALLOW_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED), region, parcel->getLocalID());
 +    }
 +    if(which & AL_BLOCK_EXPERIENCE)
 +    {
 +        sendParcelAccessListUpdate(AL_BLOCK_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED), region, parcel->getLocalID());
 +    }
 +}
 +
 +void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 flags, const LLAccessEntry::map& entries, LLViewerRegion* region, S32 parcel_local_id)
 +{
 +    S32 count = entries.size();
 +    S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
 +    S32 sequence_id = 1;
 +    bool start_message = true;
 +    bool initial = true;
 +
 +    LLUUID transactionUUID;
 +    transactionUUID.generate();
 +
 +
 +    LLMessageSystem* msg = gMessageSystem;
 +
 +    LLAccessEntry::map::const_iterator cit = entries.begin();
 +    LLAccessEntry::map::const_iterator  end = entries.end();
 +    while ( (cit != end) || initial )
 +    {
 +        if (start_message)
 +        {
 +            msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
 +            msg->nextBlockFast(_PREHASH_AgentData);
 +            msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
 +            msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
 +            msg->nextBlockFast(_PREHASH_Data);
 +            msg->addU32Fast(_PREHASH_Flags, flags);
 +            msg->addS32(_PREHASH_LocalID,  parcel_local_id);
 +            msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
 +            msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
 +            msg->addS32Fast(_PREHASH_Sections, num_sections);
 +            start_message = false;
 +
 +            if (initial && (cit == end))
 +            {
 +                // pack an empty block if there will be no data
 +                msg->nextBlockFast(_PREHASH_List);
 +                msg->addUUIDFast(_PREHASH_ID,  LLUUID::null );
 +                msg->addS32Fast(_PREHASH_Time, 0 );
 +                msg->addU32Fast(_PREHASH_Flags, 0 );
 +            }
 +
 +            initial = false;
 +            sequence_id++;
 +
 +        }
 +
 +        while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
 +        {
 +            const LLAccessEntry& entry = (*cit).second;
 +
 +            msg->nextBlockFast(_PREHASH_List);
 +            msg->addUUIDFast(_PREHASH_ID,  entry.mID );
 +            msg->addS32Fast(_PREHASH_Time, entry.mTime );
 +            msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
 +            ++cit;
 +        }
 +
 +        start_message = true;
 +        msg->sendReliable( region->getHost() );
 +    }
 +}
 +
 +
 +void LLViewerParcelMgr::deedLandToGroup()
 +{
 +    std::string group_name;
 +    gCacheName->getGroupName(mCurrentParcel->getGroupID(), group_name);
 +    LLSD args;
 +    args["AREA"] = llformat("%d", mCurrentParcel->getArea());
 +    args["GROUP_NAME"] = group_name;
 +    if(mCurrentParcel->getContributeWithDeed())
 +    {
 +        args["NAME"] = LLSLURL("agent", mCurrentParcel->getOwnerID(), "completename").getSLURLString();
 +        LLNotificationsUtil::add("DeedLandToGroupWithContribution",args, LLSD(), deedAlertCB);
 +    }
 +    else
 +    {
 +        LLNotificationsUtil::add("DeedLandToGroup",args, LLSD(), deedAlertCB);
 +    }
 +}
 +
 +// static
 +bool LLViewerParcelMgr::deedAlertCB(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    if (option == 0)
 +    {
 +        LLParcel* parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel();
 +        LLUUID group_id;
 +        if(parcel)
 +        {
 +            group_id = parcel->getGroupID();
 +        }
 +        LLViewerParcelMgr::getInstance()->sendParcelDeed(group_id);
 +    }
 +    return false;
 +}
 +
 +
 +void LLViewerParcelMgr::startReleaseLand()
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandNothingSelected");
 +        return;
 +    }
 +
 +    if (mRequestResult == PARCEL_RESULT_NO_DATA)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandWatingForServer");
 +        return;
 +    }
 +
 +    if (mRequestResult == PARCEL_RESULT_MULTIPLE)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandSelected");
 +        return;
 +    }
 +
 +    if (!isParcelOwnedByAgent(mCurrentParcel, GP_LAND_RELEASE)
 +        && !(gAgent.canManageEstate()))
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandDontOwn");
 +        return;
 +    }
 +
 +    LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0;
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center);
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandRegionNotFound");
 +        return;
 +    }
 +/*
 +    if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)
 +        && !gAgent.isGodlike())
 +    {
 +        LLSD args;
 +        args["REGION"] = region->getName();
 +        LLNotificationsUtil::add("CannotReleaseLandNoTransfer", args);
 +        return;
 +    }
 +*/
 +
 +    if (!mCurrentParcelSelection->mWholeParcelSelected)
 +    {
 +        LLNotificationsUtil::add("CannotReleaseLandPartialSelection");
 +        return;
 +    }
 +
 +    // Compute claim price
 +    LLSD args;
 +    args["AREA"] = llformat("%d",mCurrentParcel->getArea());
 +    LLNotificationsUtil::add("ReleaseLandWarning", args, LLSD(), releaseAlertCB);
 +}
 +
 +bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const
 +{
 +    if (!parcel)
 +    {
 +        return false;
 +    }
 +
 +    if (mSelected  &&  parcel == mCurrentParcel)
 +    {
 +        if (mRequestResult == PARCEL_RESULT_NO_DATA)
 +        {
 +            return false;
 +        }
 +    }
 +
 +    const LLUUID& parcelOwner = parcel->getOwnerID();
 +    const LLUUID& authorizeBuyer = parcel->getAuthorizedBuyerID();
 +
 +    if (parcel->isPublic())
 +    {
 +        return true;    // change this if want to make it gods only
 +    }
 +
 +    LLVector3 parcel_coord = parcel->getCenterpoint();
 +    LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosAgent(parcel_coord);
 +    if (regionp)
 +    {
 +        U8 sim_access = regionp->getSimAccess();
 +        const LLAgentAccess& agent_access = gAgent.getAgentAccess();
 +        // if the region is PG, we're happy already, so do nothing
 +        // but if we're set to avoid either mature or adult, get us outta here
 +        if ((sim_access == SIM_ACCESS_MATURE) &&
 +            !agent_access.canAccessMature())
 +        {
 +            return false;
 +        }
 +        else if ((sim_access == SIM_ACCESS_ADULT) &&
 +                 !agent_access.canAccessAdult())
 +        {
 +            return false;
 +        }
 +    }
 +
 +    bool isForSale = parcel->getForSale()
 +            && ((parcel->getSalePrice() > 0) || (authorizeBuyer.notNull()));
 +
 +    bool isEmpowered
 +        = forGroup ? gAgent.hasPowerInActiveGroup(GP_LAND_DEED) : true;
 +
 +    bool isOwner
 +        = parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID());
 +
 +    bool isAuthorized
 +            = (authorizeBuyer.isNull()
 +                || (gAgent.getID() == authorizeBuyer)
 +                || (gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_DEED)
 +                    && gAgent.hasPowerInGroup(authorizeBuyer,GP_LAND_SET_SALE_INFO)));
 +
 +    return isForSale && !isOwner && isAuthorized  && isEmpowered;
 +}
 +
 +
 +void LLViewerParcelMgr::startBuyLand(bool is_for_group)
 +{
 +    LLFloaterBuyLand::buyLand(getSelectionRegion(), mCurrentParcelSelection, is_for_group);
 +}
 +
 +void LLViewerParcelMgr::startSellLand()
 +{
 +    LLFloaterSellLand::sellLand(getSelectionRegion(), mCurrentParcelSelection);
 +}
 +
 +void LLViewerParcelMgr::startDivideLand()
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotDivideLandNothingSelected");
 +        return;
 +    }
 +
 +    if (mCurrentParcelSelection->mWholeParcelSelected)
 +    {
 +        LLNotificationsUtil::add("CannotDivideLandPartialSelection");
 +        return;
 +    }
 +
 +    LLSD payload;
 +    payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth);
 +    payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth);
 +
 +    LLNotificationsUtil::add("LandDivideWarning", LLSD(), payload, callbackDivideLand);
 +}
 +
 +// static
 +bool LLViewerParcelMgr::callbackDivideLand(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]);
 +    LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]);
 +    LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0;
 +
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center);
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotDivideLandNoRegion");
 +        return false;
 +    }
 +
 +    if (0 == option)
 +    {
 +        LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d);
 +        LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d);
 +
 +        LLMessageSystem* msg = gMessageSystem;
 +        msg->newMessage("ParcelDivide");
 +        msg->nextBlock("AgentData");
 +        msg->addUUID("AgentID", gAgent.getID());
 +        msg->addUUID("SessionID", gAgent.getSessionID());
 +        msg->nextBlock("ParcelData");
 +        msg->addF32("West", west_south.mV[VX]);
 +        msg->addF32("South", west_south.mV[VY]);
 +        msg->addF32("East", east_north.mV[VX]);
 +        msg->addF32("North", east_north.mV[VY]);
 +        msg->sendReliable(region->getHost());
 +    }
 +    return false;
 +}
 +
 +
 +void LLViewerParcelMgr::startJoinLand()
 +{
 +    if (!mSelected)
 +    {
 +        LLNotificationsUtil::add("CannotJoinLandNothingSelected");
 +        return;
 +    }
 +
 +    if (mCurrentParcelSelection->mWholeParcelSelected)
 +    {
 +        LLNotificationsUtil::add("CannotJoinLandEntireParcelSelected");
 +        return;
 +    }
 +
 +    if (!mCurrentParcelSelection->mSelectedMultipleOwners)
 +    {
 +        LLNotificationsUtil::add("CannotJoinLandSelection");
 +        return;
 +    }
 +
 +    LLSD payload;
 +    payload["west_south_border"] = ll_sd_from_vector3d(mWestSouth);
 +    payload["east_north_border"] = ll_sd_from_vector3d(mEastNorth);
 +
 +    LLNotificationsUtil::add("JoinLandWarning", LLSD(), payload, callbackJoinLand);
 +}
 +
 +// static
 +bool LLViewerParcelMgr::callbackJoinLand(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    LLVector3d west_south_d = ll_vector3d_from_sd(notification["payload"]["west_south_border"]);
 +    LLVector3d east_north_d = ll_vector3d_from_sd(notification["payload"]["east_north_border"]);
 +    LLVector3d parcel_center = (west_south_d + east_north_d) / 2.0;
 +
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center);
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotJoinLandNoRegion");
 +        return false;
 +    }
 +
 +    if (0 == option)
 +    {
 +        LLVector3 west_south = region->getPosRegionFromGlobal(west_south_d);
 +        LLVector3 east_north = region->getPosRegionFromGlobal(east_north_d);
 +
 +        LLMessageSystem* msg = gMessageSystem;
 +        msg->newMessage("ParcelJoin");
 +        msg->nextBlock("AgentData");
 +        msg->addUUID("AgentID", gAgent.getID());
 +        msg->addUUID("SessionID", gAgent.getSessionID());
 +        msg->nextBlock("ParcelData");
 +        msg->addF32("West", west_south.mV[VX]);
 +        msg->addF32("South", west_south.mV[VY]);
 +        msg->addF32("East", east_north.mV[VX]);
 +        msg->addF32("North", east_north.mV[VY]);
 +        msg->sendReliable(region->getHost());
 +    }
 +    return false;
 +}
 +
 +
 +void LLViewerParcelMgr::startDeedLandToGroup()
 +{
 +    if (!mSelected || !mCurrentParcel)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandNothingSelected");
 +        return;
 +    }
 +
 +    if (mRequestResult == PARCEL_RESULT_NO_DATA)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandWaitingForServer");
 +        return;
 +    }
 +
 +    if (mRequestResult == PARCEL_RESULT_MULTIPLE)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandMultipleSelected");
 +        return;
 +    }
 +
 +    LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0;
 +    LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(parcel_center);
 +    if (!region)
 +    {
 +        LLNotificationsUtil::add("CannotDeedLandNoRegion");
 +        return;
 +    }
 +
 +    /*
 +    if(!gAgent.isGodlike())
 +    {
 +        if(region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)
 +            && (mCurrentParcel->getOwnerID() != region->getOwner()))
 +        {
 +            LLSD args;
 +            args["REGION"] = region->getName();
 +            LLNotificationsUtil::add("CannotDeedLandNoTransfer", args);
 +            return;
 +        }
 +    }
 +    */
 +
 +    deedLandToGroup();
 +}
 +void LLViewerParcelMgr::reclaimParcel()
 +{
 +    LLParcel* parcel = LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel();
 +    LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion();
 +    if(parcel && parcel->getOwnerID().notNull()
 +       && (parcel->getOwnerID() != gAgent.getID())
 +       && regionp && (regionp->getOwner() == gAgent.getID()))
 +    {
 +        LLMessageSystem* msg = gMessageSystem;
 +        msg->newMessage("ParcelReclaim");
 +        msg->nextBlock("AgentData");
 +        msg->addUUID("AgentID", gAgent.getID());
 +        msg->addUUID("SessionID", gAgent.getSessionID());
 +        msg->nextBlock("Data");
 +        msg->addS32("LocalID", parcel->getLocalID());
 +        msg->sendReliable(regionp->getHost());
 +    }
 +}
 +
 +// static
 +bool LLViewerParcelMgr::releaseAlertCB(const LLSD& notification, const LLSD& response)
 +{
 +    S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
 +    if (option == 0)
 +    {
 +        // Send the release message, not a force
 +        LLViewerParcelMgr::getInstance()->sendParcelRelease();
 +    }
 +    return false;
 +}
 +
 +void LLViewerParcelMgr::buyPass()
 +{
 +    LLParcel* parcel = getParcelSelection()->getParcel();
 +    if (!parcel) return;
 +
 +    LLViewerRegion* region = getSelectionRegion();
 +    if (!region) return;
 +
 +    LLMessageSystem* msg = gMessageSystem;
 +    msg->newMessageFast(_PREHASH_ParcelBuyPass);
 +    msg->nextBlock("AgentData");
 +    msg->addUUID("AgentID", gAgent.getID());
 +    msg->addUUID("SessionID", gAgent.getSessionID());
 +    msg->nextBlockFast(_PREHASH_ParcelData);
 +    msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() );
 +    msg->sendReliable( region->getHost() );
 +}
 +
 +//Tells whether we are allowed to buy a pass or not
 +bool LLViewerParcelMgr::isCollisionBanned()
 +{
 +    if ((mCollisionBanned == BA_ALLOWED) || (mCollisionBanned == BA_NOT_ON_LIST) || (mCollisionBanned == BA_NOT_IN_GROUP))
 +        return false;
 +    else
 +        return true;
 +}
 +
 +// This implementation should mirror LLSimParcelMgr::isParcelOwnedBy
 +// static
 +bool LLViewerParcelMgr::isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power)
 +{
 +    if (!parcelp)
 +    {
 +        return false;
 +    }
 +
 +    // Gods can always assume ownership.
 +    if (gAgent.isGodlike())
 +    {
 +        return true;
 +    }
 +
 +    // The owner of a parcel automatically gets all powersr.
 +    if (parcelp->getOwnerID() == gAgent.getID())
 +    {
 +        return true;
 +    }
 +
 +    // Only gods can assume 'ownership' of public land.
 +    if (parcelp->isPublic())
 +    {
 +        return false;
 +    }
 +
 +    // Return whether or not the agent has group_proxy_power powers in the
 +    // parcel's group.
 +    return gAgent.hasPowerInGroup(parcelp->getOwnerID(), group_proxy_power);
 +}
 +
 +// This implementation should mirror llSimParcelMgr::isParcelModifiableBy
 +// static
 +bool LLViewerParcelMgr::isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power)
 +{
 +    // If the agent can assume ownership, it is probably modifiable.
 +    bool rv = false;
 +    if (parcelp)
 +    {
 +        // *NOTE: This should only work for leased parcels, but group owned
 +        // parcels cannot be OS_LEASED yet. Phoenix 2003-12-15.
 +        rv = isParcelOwnedByAgent(parcelp, group_proxy_power);
 +
 +        // ... except for the case that the parcel is not OS_LEASED for agent-owned parcels.
 +        if( (gAgent.getID() == parcelp->getOwnerID())
 +            && !gAgent.isGodlike()
 +            && (parcelp->getOwnershipStatus() != LLParcel::OS_LEASED) )
 +        {
 +            rv = false;
 +        }
 +    }
 +    return rv;
 +}
 +
 +void sanitize_corners(const LLVector3d &corner1,
 +                                        const LLVector3d &corner2,
 +                                        LLVector3d &west_south_bottom,
 +                                        LLVector3d &east_north_top)
 +{
 +    west_south_bottom.mdV[VX] = llmin( corner1.mdV[VX], corner2.mdV[VX] );
 +    west_south_bottom.mdV[VY] = llmin( corner1.mdV[VY], corner2.mdV[VY] );
 +    west_south_bottom.mdV[VZ] = llmin( corner1.mdV[VZ], corner2.mdV[VZ] );
 +
 +    east_north_top.mdV[VX] = llmax( corner1.mdV[VX], corner2.mdV[VX] );
 +    east_north_top.mdV[VY] = llmax( corner1.mdV[VY], corner2.mdV[VY] );
 +    east_north_top.mdV[VZ] = llmax( corner1.mdV[VZ], corner2.mdV[VZ] );
 +}
 +
 +
 +void LLViewerParcelMgr::cleanupGlobals()
 +{
 +}
 +
 +LLViewerTexture* LLViewerParcelMgr::getBlockedImage() const
 +{
 +    return sBlockedImage;
 +}
 +
 +LLViewerTexture* LLViewerParcelMgr::getPassImage() const
 +{
 +    return sPassImage;
 +}
 +
 +/*
 + * Set finish teleport callback. You can use it to observe all  teleport events.
 + * NOTE:
 + * After local( in one region) teleports we
 + *  cannot rely on gAgent.getPositionGlobal(),
 + *  so the new position gets passed explicitly.
 + *  Use args of this callback to get global position of avatar after teleport event.
 + */
 +boost::signals2::connection LLViewerParcelMgr::setTeleportFinishedCallback(teleport_finished_callback_t cb)
 +{
 +    return mTeleportFinishedSignal.connect(cb);
 +}
 +
 +boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(teleport_failed_callback_t cb)
 +{
 +    return mTeleportFailedSignal.connect(cb);
 +}
 +
 +/* Ok, we're notified that teleport has been finished.
 + * We should now propagate the notification via mTeleportFinishedSignal
 + * to all interested parties.
 + */
 +void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos)
 +{
 +    // Treat only teleports within the same parcel as local (EXT-3139).
 +    if (local && LLViewerParcelMgr::getInstance()->inAgentParcel(new_pos))
 +    {
 +        // Local teleport. We already have the agent parcel data.
 +        // Emit the signal immediately.
 +        getInstance()->mTeleportFinishedSignal(new_pos, local);
 +    }
 +    else
 +    {
 +        // Non-local teleport (inter-region or between different parcels of the same region).
 +        // The agent parcel data has not been updated yet.
 +        // Let's wait for the update and then emit the signal.
 +        mTeleportInProgressPosition = new_pos;
 +        mTeleportInProgress = true;
 +    }
 +}
 +
 +void LLViewerParcelMgr::onTeleportFailed()
 +{
 +    mTeleportFailedSignal();
 +}
 +
 +bool  LLViewerParcelMgr::getTeleportInProgress()
 +{
 +    return mTeleportInProgress // case where parcel data arrives after teleport
 +        || gAgent.getTeleportState() > LLAgent::TELEPORT_NONE; // For LOCAL, no mTeleportInProgress
 +}
  | 
