PageRenderTime 137ms CodeModel.GetById 16ms app.highlight 107ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llviewerparcelmgr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2332 lines | 1763 code | 354 blank | 215 comment | 269 complexity | 68823a547156306d4d5b6d9238b3b96e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llviewerparcelmgr.cpp
   3 * @brief Viewer-side representation of owned land
   4 *
   5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llviewerparcelmgr.h"
  30
  31// Library includes
  32#include "llaudioengine.h"
  33#include "indra_constants.h"
  34#include "llcachename.h"
  35#include "llgl.h"
  36#include "llnotifications.h"
  37#include "llnotificationsutil.h"
  38#include "llparcel.h"
  39#include "llsecondlifeurls.h"
  40#include "message.h"
  41#include "llfloaterreg.h"
  42
  43// Viewer includes
  44#include "llagent.h"
  45#include "llagentaccess.h"
  46#include "llviewerwindow.h"
  47#include "llviewercontrol.h"
  48//#include "llfirstuse.h"
  49#include "llfloaterbuyland.h"
  50#include "llfloatergroups.h"
  51#include "llpanelnearbymedia.h"
  52#include "llfloatersellland.h"
  53#include "llfloatertools.h"
  54#include "llparcelselection.h"
  55#include "llresmgr.h"
  56#include "llsdutil.h"
  57#include "llsdutil_math.h"
  58#include "llslurl.h"
  59#include "llstatusbar.h"
  60#include "llui.h"
  61#include "llviewertexture.h"
  62#include "llviewertexturelist.h"
  63#include "llviewermenu.h"
  64#include "llviewerparcelmedia.h"
  65#include "llviewerparceloverlay.h"
  66#include "llviewerregion.h"
  67#include "llworld.h"
  68#include "roles_constants.h"
  69#include "llweb.h"
  70#include "llvieweraudio.h"
  71
  72const F32 PARCEL_COLLISION_DRAW_SECS = 1.f;
  73
  74
  75// Globals
  76
  77U8* LLViewerParcelMgr::sPackedOverlay = NULL;
  78
  79LLUUID gCurrentMovieID = LLUUID::null;
  80
  81LLPointer<LLViewerTexture> sBlockedImage;
  82LLPointer<LLViewerTexture> sPassImage;
  83
  84// Local functions
  85void optionally_start_music(const std::string& music_url);
  86void callback_start_music(S32 option, void* data);
  87void optionally_prepare_video(const LLParcel *parcelp);
  88void callback_prepare_video(S32 option, void* data);
  89void prepare_video(const LLParcel *parcelp);
  90void start_video(const LLParcel *parcelp);
  91void stop_video();
  92bool callback_god_force_owner(const LLSD&, const LLSD&);
  93
  94struct LLGodForceOwnerData
  95{
  96	LLUUID mOwnerID;
  97	S32 mLocalID;
  98	LLHost mHost;
  99
 100	LLGodForceOwnerData(
 101		const LLUUID& owner_id,
 102		S32 local_parcel_id,
 103		const LLHost& host) :
 104		mOwnerID(owner_id),
 105		mLocalID(local_parcel_id),
 106		mHost(host) {}
 107};
 108
 109//
 110// Methods
 111//
 112LLViewerParcelMgr::LLViewerParcelMgr()
 113:	mSelected(FALSE),
 114	mRequestResult(0),
 115	mWestSouth(),
 116	mEastNorth(),
 117	mSelectedDwell(DWELL_NAN),
 118	mAgentParcelSequenceID(-1),
 119	mHoverRequestResult(0),
 120	mHoverWestSouth(),
 121	mHoverEastNorth(),
 122	mRenderCollision(FALSE),
 123	mRenderSelection(TRUE),
 124	mCollisionBanned(0),
 125	mCollisionTimer(),
 126	mMediaParcelId(0),
 127	mMediaRegionId(0)
 128{
 129	mCurrentParcel = new LLParcel();
 130	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 131	mFloatingParcelSelection = new LLParcelSelection(mCurrentParcel);
 132
 133	mAgentParcel = new LLParcel();
 134	mHoverParcel = new LLParcel();
 135	mCollisionParcel = new LLParcel();
 136
 137	mParcelsPerEdge = S32(	REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS );
 138	mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
 139	resetSegments(mHighlightSegments);
 140
 141	mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
 142	resetSegments(mCollisionSegments);
 143
 144	// JC: Resolved a merge conflict here, eliminated
 145	// mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP);
 146	// because it is done in llviewertexturelist.cpp
 147	mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png");
 148	mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png");
 149
 150	S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS;
 151	sPackedOverlay = new U8[overlay_size];
 152
 153	mAgentParcelOverlay = new U8[mParcelsPerEdge * mParcelsPerEdge];
 154	S32 i;
 155	for (i = 0; i < mParcelsPerEdge * mParcelsPerEdge; i++)
 156	{
 157		mAgentParcelOverlay[i] = 0;
 158	}
 159
 160	mTeleportInProgress = TRUE; // the initial parcel update is treated like teleport
 161}
 162
 163
 164LLViewerParcelMgr::~LLViewerParcelMgr()
 165{
 166	mCurrentParcelSelection->setParcel(NULL);
 167	mCurrentParcelSelection = NULL;
 168
 169	mFloatingParcelSelection->setParcel(NULL);
 170	mFloatingParcelSelection = NULL;
 171
 172	delete mCurrentParcel;
 173	mCurrentParcel = NULL;
 174
 175	delete mAgentParcel;
 176	mAgentParcel = NULL;
 177
 178	delete mCollisionParcel;
 179	mCollisionParcel = NULL;
 180
 181	delete mHoverParcel;
 182	mHoverParcel = NULL;
 183
 184	delete[] mHighlightSegments;
 185	mHighlightSegments = NULL;
 186
 187	delete[] mCollisionSegments;
 188	mCollisionSegments = NULL;
 189
 190	delete[] sPackedOverlay;
 191	sPackedOverlay = NULL;
 192
 193	delete[] mAgentParcelOverlay;
 194	mAgentParcelOverlay = NULL;
 195
 196	sBlockedImage = NULL;
 197	sPassImage = NULL;
 198}
 199
 200void LLViewerParcelMgr::dump()
 201{
 202	llinfos << "Parcel Manager Dump" << llendl;
 203	llinfos << "mSelected " << S32(mSelected) << llendl;
 204	llinfos << "Selected parcel: " << llendl;
 205	llinfos << mWestSouth << " to " << mEastNorth << llendl;
 206	mCurrentParcel->dump();
 207	llinfos << "banning " << mCurrentParcel->mBanList.size() << llendl;
 208	
 209	access_map_const_iterator cit = mCurrentParcel->mBanList.begin();
 210	access_map_const_iterator end = mCurrentParcel->mBanList.end();
 211	for ( ; cit != end; ++cit)
 212	{
 213		llinfos << "ban id " << (*cit).first << llendl;
 214	}
 215	llinfos << "Hover parcel:" << llendl;
 216	mHoverParcel->dump();
 217	llinfos << "Agent parcel:" << llendl;
 218	mAgentParcel->dump();
 219}
 220
 221
 222LLViewerRegion* LLViewerParcelMgr::getSelectionRegion()
 223{
 224	return LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 225}
 226
 227
 228void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out,
 229									   S32* rent_out,
 230									   BOOL* for_sale_out,
 231									   F32* dwell_out)
 232{
 233	S32 area = 0;
 234	S32 price = 0;
 235	S32 rent = 0;
 236	BOOL for_sale = FALSE;
 237	F32 dwell = DWELL_NAN;
 238
 239	if (mSelected)
 240	{
 241		if (mCurrentParcelSelection->mSelectedMultipleOwners)
 242		{
 243			area = mCurrentParcelSelection->getClaimableArea();
 244		}
 245		else
 246		{
 247			area = getSelectedArea();
 248		}
 249
 250		if (mCurrentParcel->getForSale())
 251		{
 252			price = mCurrentParcel->getSalePrice();
 253			for_sale = TRUE;
 254		}
 255		else
 256		{
 257			price = area * mCurrentParcel->getClaimPricePerMeter();
 258			for_sale = FALSE;
 259		}
 260
 261		rent = mCurrentParcel->getTotalRent();
 262
 263		dwell = mSelectedDwell;
 264	}
 265
 266	*area_out = area;
 267	*claim_out = price;
 268	*rent_out = rent;
 269	*for_sale_out = for_sale;
 270	*dwell_out = dwell;
 271}
 272
 273S32 LLViewerParcelMgr::getSelectedArea() const
 274{
 275	S32 rv = 0;
 276	if(mSelected && mCurrentParcel && mCurrentParcelSelection->mWholeParcelSelected)
 277	{
 278		rv = mCurrentParcel->getArea();
 279	}
 280	else if(mSelected)
 281	{
 282		F64 width = mEastNorth.mdV[VX] - mWestSouth.mdV[VX];
 283		F64 height = mEastNorth.mdV[VY] - mWestSouth.mdV[VY];
 284		F32 area = (F32)(width * height);
 285		rv = llround(area);
 286	}
 287	return rv;
 288}
 289
 290void LLViewerParcelMgr::resetSegments(U8* segments)
 291{
 292	S32 i;
 293	S32 count = (mParcelsPerEdge+1)*(mParcelsPerEdge+1);
 294	for (i = 0; i < count; i++)
 295	{
 296		segments[i] = 0x0;
 297	}
 298}
 299
 300
 301void LLViewerParcelMgr::writeHighlightSegments(F32 west, F32 south, F32 east,
 302											   F32 north)
 303{
 304	S32 x, y;
 305	S32 min_x = llround( west / PARCEL_GRID_STEP_METERS );
 306	S32 max_x = llround( east / PARCEL_GRID_STEP_METERS );
 307	S32 min_y = llround( south / PARCEL_GRID_STEP_METERS );
 308	S32 max_y = llround( north / PARCEL_GRID_STEP_METERS );
 309
 310	const S32 STRIDE = mParcelsPerEdge+1;
 311
 312	// south edge
 313	y = min_y;
 314	for (x = min_x; x < max_x; x++)
 315	{
 316		// exclusive OR means that writing to this segment twice
 317		// will turn it off
 318		mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
 319	}
 320
 321	// west edge
 322	x = min_x;
 323	for (y = min_y; y < max_y; y++)
 324	{
 325		mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
 326	}
 327
 328	// north edge - draw the south border on the y+1'th cell,
 329	// which given C-style arrays, is item foo[max_y]
 330	y = max_y;
 331	for (x = min_x; x < max_x; x++)
 332	{
 333		mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
 334	}
 335
 336	// east edge - draw west border on x+1'th cell
 337	x = max_x;
 338	for (y = min_y; y < max_y; y++)
 339	{
 340		mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
 341	}
 342}
 343
 344
 345void LLViewerParcelMgr::writeSegmentsFromBitmap(U8* bitmap, U8* segments)
 346{
 347	S32 x;
 348	S32 y;
 349	const S32 IN_STRIDE = mParcelsPerEdge;
 350	const S32 OUT_STRIDE = mParcelsPerEdge+1;
 351
 352	for (y = 0; y < IN_STRIDE; y++)
 353	{
 354		x = 0;
 355		while( x < IN_STRIDE )
 356		{
 357			U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
 358
 359			S32 bit;
 360			for (bit = 0; bit < 8; bit++)
 361			{
 362				if (byte & (1 << bit) )
 363				{
 364					S32 out = x+y*OUT_STRIDE;
 365
 366					// This and one above it
 367					segments[out]            ^= SOUTH_MASK;
 368					segments[out+OUT_STRIDE] ^= SOUTH_MASK;
 369
 370					// This and one to the right
 371					segments[out]   ^= WEST_MASK;
 372					segments[out+1] ^= WEST_MASK;
 373				}
 374				x++;
 375			}
 376		}
 377	}
 378}
 379
 380
 381void LLViewerParcelMgr::writeAgentParcelFromBitmap(U8* bitmap)
 382{
 383	S32 x;
 384	S32 y;
 385	const S32 IN_STRIDE = mParcelsPerEdge;
 386
 387	for (y = 0; y < IN_STRIDE; y++)
 388	{
 389		x = 0;
 390		while( x < IN_STRIDE )
 391		{
 392			U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
 393
 394			S32 bit;
 395			for (bit = 0; bit < 8; bit++)
 396			{
 397				if (byte & (1 << bit) )
 398				{
 399					mAgentParcelOverlay[x+y*IN_STRIDE] = 1;
 400				}
 401				else
 402				{
 403					mAgentParcelOverlay[x+y*IN_STRIDE] = 0;
 404				}
 405				x++;
 406			}
 407		}
 408	}
 409}
 410
 411
 412// Given a point, find the PARCEL_GRID_STEP x PARCEL_GRID_STEP block
 413// containing it and select that.
 414LLParcelSelectionHandle LLViewerParcelMgr::selectParcelAt(const LLVector3d& pos_global)
 415{
 416	LLVector3d southwest = pos_global;
 417	LLVector3d northeast = pos_global;
 418
 419	southwest -= LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
 420	southwest.mdV[VX] = llround( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
 421	southwest.mdV[VY] = llround( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
 422
 423	northeast += LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
 424	northeast.mdV[VX] = llround( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
 425	northeast.mdV[VY] = llround( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
 426
 427	// Snap to parcel
 428	return selectLand( southwest, northeast, TRUE );
 429}
 430
 431
 432// Tries to select the parcel inside the rectangle
 433LLParcelSelectionHandle LLViewerParcelMgr::selectParcelInRectangle()
 434{
 435	return selectLand(mWestSouth, mEastNorth, TRUE);
 436}
 437
 438
 439void LLViewerParcelMgr::selectCollisionParcel()
 440{
 441	// BUG: Claim to be in the agent's region
 442	mWestSouth = gAgent.getRegion()->getOriginGlobal();
 443	mEastNorth = mWestSouth;
 444	mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0);
 445
 446	// BUG: must be in the sim you are in
 447	LLMessageSystem *msg = gMessageSystem;
 448	msg->newMessageFast(_PREHASH_ParcelPropertiesRequestByID);
 449	msg->nextBlockFast(_PREHASH_AgentID);
 450	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
 451	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
 452	msg->nextBlockFast(_PREHASH_ParcelData);
 453	msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID );
 454	msg->addS32Fast(_PREHASH_LocalID, mCollisionParcel->getLocalID() );
 455	gAgent.sendReliableMessage();
 456
 457	mRequestResult = PARCEL_RESULT_NO_DATA;
 458
 459	// Hack: Copy some data over temporarily
 460	mCurrentParcel->setName( mCollisionParcel->getName() );
 461	mCurrentParcel->setDesc( mCollisionParcel->getDesc() );
 462	mCurrentParcel->setPassPrice(mCollisionParcel->getPassPrice());
 463	mCurrentParcel->setPassHours(mCollisionParcel->getPassHours());
 464
 465	// clear the list of segments to prevent flashing
 466	resetSegments(mHighlightSegments);
 467
 468	mFloatingParcelSelection->setParcel(mCurrentParcel);
 469	mCurrentParcelSelection->setParcel(NULL);
 470	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 471
 472	mSelected = TRUE;
 473	mCurrentParcelSelection->mWholeParcelSelected = TRUE;
 474	notifyObservers();
 475	return;
 476}
 477
 478
 479// snap_selection = auto-select the hit parcel, if there is exactly one
 480LLParcelSelectionHandle LLViewerParcelMgr::selectLand(const LLVector3d &corner1, const LLVector3d &corner2,
 481								   BOOL snap_selection)
 482{
 483	sanitize_corners( corner1, corner2, mWestSouth, mEastNorth );
 484
 485	// ...x isn't more than one meter away
 486	F32 delta_x = getSelectionWidth();
 487	if (delta_x * delta_x <= 1.f * 1.f)
 488	{
 489		mSelected = FALSE;
 490		notifyObservers();
 491		return NULL;
 492	}
 493
 494	// ...y isn't more than one meter away
 495	F32 delta_y = getSelectionHeight();
 496	if (delta_y * delta_y <= 1.f * 1.f)
 497	{
 498		mSelected = FALSE;
 499		notifyObservers();
 500		return NULL;
 501	}
 502
 503	// Can't select across region boundary
 504	// We need to pull in the upper right corner by a little bit to allow
 505	// selection up to the x = 256 or y = 256 edge.
 506	LLVector3d east_north_region_check( mEastNorth );
 507	east_north_region_check.mdV[VX] -= 0.5;
 508	east_north_region_check.mdV[VY] -= 0.5;
 509
 510	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth);
 511	LLViewerRegion *region_other = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
 512
 513	if(!region)
 514	{
 515		// just in case they somehow selected no land.
 516		mSelected = FALSE;
 517		return NULL;
 518	}
 519
 520	if (region != region_other)
 521	{
 522		LLNotificationsUtil::add("CantSelectLandFromMultipleRegions");
 523		mSelected = FALSE;
 524		notifyObservers();
 525		return NULL;
 526	}
 527
 528	// Build region global copies of corners
 529	LLVector3 wsb_region = region->getPosRegionFromGlobal( mWestSouth );
 530	LLVector3 ent_region = region->getPosRegionFromGlobal( mEastNorth );
 531
 532	// Send request message
 533	LLMessageSystem *msg = gMessageSystem;
 534	msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
 535	msg->nextBlockFast(_PREHASH_AgentData);
 536	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
 537	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
 538	msg->nextBlockFast(_PREHASH_ParcelData);
 539	msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID );
 540	msg->addF32Fast(_PREHASH_West,  wsb_region.mV[VX] );
 541	msg->addF32Fast(_PREHASH_South, wsb_region.mV[VY] );
 542	msg->addF32Fast(_PREHASH_East,  ent_region.mV[VX] );
 543	msg->addF32Fast(_PREHASH_North, ent_region.mV[VY] );
 544	msg->addBOOL("SnapSelection", snap_selection);
 545	msg->sendReliable( region->getHost() );
 546
 547	mRequestResult = PARCEL_RESULT_NO_DATA;
 548
 549	// clear the list of segments to prevent flashing
 550	resetSegments(mHighlightSegments);
 551
 552	mFloatingParcelSelection->setParcel(mCurrentParcel);
 553	mCurrentParcelSelection->setParcel(NULL);
 554	mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 555
 556	mSelected = TRUE;
 557	mCurrentParcelSelection->mWholeParcelSelected = snap_selection;
 558	notifyObservers();
 559	return mCurrentParcelSelection;
 560}
 561
 562void LLViewerParcelMgr::deselectUnused()
 563{
 564	// no more outstanding references to this selection, other than our own
 565	if (mCurrentParcelSelection->getNumRefs() == 1 && mFloatingParcelSelection->getNumRefs() == 1)
 566	{
 567		deselectLand();
 568	}
 569}
 570
 571void LLViewerParcelMgr::deselectLand()
 572{
 573	if (mSelected)
 574	{
 575		mSelected = FALSE;
 576
 577		// Invalidate the selected parcel
 578		mCurrentParcel->setLocalID(-1);
 579		mCurrentParcel->mAccessList.clear();
 580		mCurrentParcel->mBanList.clear();
 581		//mCurrentParcel->mRenterList.reset();
 582
 583		mSelectedDwell = DWELL_NAN;
 584
 585		// invalidate parcel selection so that existing users of this selection can clean up
 586		mCurrentParcelSelection->setParcel(NULL);
 587		mFloatingParcelSelection->setParcel(NULL);
 588		// create new parcel selection
 589		mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel);
 590
 591		notifyObservers(); // Notify observers *after* changing the parcel selection
 592	}
 593}
 594
 595
 596void LLViewerParcelMgr::addObserver(LLParcelObserver* observer)
 597{
 598	mObservers.put(observer);
 599}
 600
 601
 602void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer)
 603{
 604	mObservers.removeObj(observer);
 605}
 606
 607
 608// Call this method when it's time to update everyone on a new state.
 609// Copy the list because an observer could respond by removing itself
 610// from the list.
 611void LLViewerParcelMgr::notifyObservers()
 612{
 613	LLDynamicArray<LLParcelObserver*> observers;
 614	S32 count = mObservers.count();
 615	S32 i;
 616	for(i = 0; i < count; ++i)
 617	{
 618		observers.put(mObservers.get(i));
 619	}
 620	for(i = 0; i < count; ++i)
 621	{
 622		observers.get(i)->changed();
 623	}
 624}
 625
 626
 627//
 628// ACCESSORS
 629//
 630BOOL LLViewerParcelMgr::selectionEmpty() const
 631{
 632	return !mSelected;
 633}
 634
 635
 636LLParcelSelectionHandle LLViewerParcelMgr::getParcelSelection() const
 637{
 638	return mCurrentParcelSelection;
 639}
 640
 641LLParcelSelectionHandle LLViewerParcelMgr::getFloatingParcelSelection() const
 642{
 643	return mFloatingParcelSelection;
 644}
 645
 646LLParcel *LLViewerParcelMgr::getAgentParcel() const
 647{
 648	return mAgentParcel;
 649}
 650
 651// Return whether the agent can build on the land they are on
 652bool LLViewerParcelMgr::allowAgentBuild() const
 653{
 654	if (mAgentParcel)
 655	{
 656		return (gAgent.isGodlike() ||
 657				(mAgentParcel->allowModifyBy(gAgent.getID(), gAgent.getGroupID())) ||
 658				(isParcelOwnedByAgent(mAgentParcel, GP_LAND_ALLOW_CREATE)));
 659	}
 660	else
 661	{
 662		return gAgent.isGodlike();
 663	}
 664}
 665
 666// Return whether anyone can build on the given parcel
 667bool LLViewerParcelMgr::allowAgentBuild(const LLParcel* parcel) const
 668{
 669	return parcel->getAllowModify();
 670}
 671
 672bool LLViewerParcelMgr::allowAgentVoice() const
 673{
 674	return allowAgentVoice(gAgent.getRegion(), mAgentParcel);
 675}
 676
 677bool LLViewerParcelMgr::allowAgentVoice(const LLViewerRegion* region, const LLParcel* parcel) const
 678{
 679	return region && region->isVoiceEnabled()
 680		&& parcel	&& parcel->getParcelFlagAllowVoice();
 681}
 682
 683bool LLViewerParcelMgr::allowAgentFly(const LLViewerRegion* region, const LLParcel* parcel) const
 684{
 685	return region && !region->getBlockFly()
 686		&& parcel && parcel->getAllowFly();
 687}
 688
 689// Can the agent be pushed around by LLPushObject?
 690bool LLViewerParcelMgr::allowAgentPush(const LLViewerRegion* region, const LLParcel* parcel) const
 691{
 692	return region && !region->getRestrictPushObject()
 693		&& parcel && !parcel->getRestrictPushObject();
 694}
 695
 696bool LLViewerParcelMgr::allowAgentScripts(const LLViewerRegion* region, const LLParcel* parcel) const
 697{
 698	// *NOTE: This code does not take into account group-owned parcels
 699	// and the flag to allow group-owned scripted objects to run.
 700	// This mirrors the traditional menu bar parcel icon code, but is not
 701	// technically correct.
 702	return region
 703		&& !(region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS)
 704		&& !(region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS)
 705		&& parcel
 706		&& parcel->getAllowOtherScripts();
 707}
 708
 709bool LLViewerParcelMgr::allowAgentDamage(const LLViewerRegion* region, const LLParcel* parcel) const
 710{
 711	return (region && region->getAllowDamage())
 712		|| (parcel && parcel->getAllowDamage());
 713}
 714
 715BOOL LLViewerParcelMgr::isOwnedAt(const LLVector3d& pos_global) const
 716{
 717	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 718	if (!region) return FALSE;
 719
 720	LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 721	if (!overlay) return FALSE;
 722
 723	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 724
 725	return overlay->isOwned( pos_region );
 726}
 727
 728BOOL LLViewerParcelMgr::isOwnedSelfAt(const LLVector3d& pos_global) const
 729{
 730	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 731	if (!region) return FALSE;
 732
 733	LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 734	if (!overlay) return FALSE;
 735
 736	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 737
 738	return overlay->isOwnedSelf( pos_region );
 739}
 740
 741BOOL LLViewerParcelMgr::isOwnedOtherAt(const LLVector3d& pos_global) const
 742{
 743	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 744	if (!region) return FALSE;
 745
 746	LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 747	if (!overlay) return FALSE;
 748
 749	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 750
 751	return overlay->isOwnedOther( pos_region );
 752}
 753
 754BOOL LLViewerParcelMgr::isSoundLocal(const LLVector3d& pos_global) const
 755{
 756	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos_global );
 757	if (!region) return FALSE;
 758
 759	LLViewerParcelOverlay* overlay = region->getParcelOverlay();
 760	if (!overlay) return FALSE;
 761
 762	LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
 763
 764	return overlay->isSoundLocal( pos_region );
 765}
 766
 767BOOL LLViewerParcelMgr::canHearSound(const LLVector3d &pos_global) const
 768{
 769	BOOL in_agent_parcel = inAgentParcel(pos_global);
 770
 771	if (in_agent_parcel)
 772	{
 773		// In same parcel as the agent
 774		return TRUE;
 775	}
 776	else
 777	{
 778		if (LLViewerParcelMgr::getInstance()->getAgentParcel()->getSoundLocal())
 779		{
 780			// Not in same parcel, and agent parcel only has local sound
 781			return FALSE;
 782		}
 783		else if (LLViewerParcelMgr::getInstance()->isSoundLocal(pos_global))
 784		{
 785			// Not in same parcel, and target parcel only has local sound
 786			return FALSE;
 787		}
 788		else
 789		{
 790			// Not in same parcel, but neither are local sound
 791			return TRUE;
 792		}
 793	}
 794}
 795
 796
 797BOOL LLViewerParcelMgr::inAgentParcel(const LLVector3d &pos_global) const
 798{
 799	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(pos_global);
 800	LLViewerRegion* agent_region = gAgent.getRegion();
 801	if (!region || !agent_region)
 802		return FALSE;
 803
 804	if (region != agent_region)
 805	{
 806		// Can't be in the agent parcel if you're not in the same region.
 807		return FALSE;
 808	}
 809
 810	LLVector3 pos_region = agent_region->getPosRegionFromGlobal(pos_global);
 811	S32 row =    S32(pos_region.mV[VY] / PARCEL_GRID_STEP_METERS);
 812	S32 column = S32(pos_region.mV[VX] / PARCEL_GRID_STEP_METERS);
 813
 814	if (mAgentParcelOverlay[row*mParcelsPerEdge + column])
 815	{
 816		return TRUE;
 817	}
 818	else
 819	{
 820		return FALSE;
 821	}
 822}
 823
 824// Returns NULL when there is no valid data.
 825LLParcel* LLViewerParcelMgr::getHoverParcel() const
 826{
 827	if (mHoverRequestResult == PARCEL_RESULT_SUCCESS)
 828	{
 829		return mHoverParcel;
 830	}
 831	else
 832	{
 833		return NULL;
 834	}
 835}
 836
 837// Returns NULL when there is no valid data.
 838LLParcel* LLViewerParcelMgr::getCollisionParcel() const
 839{
 840	if (mRenderCollision)
 841	{
 842		return mCollisionParcel;
 843	}
 844	else
 845	{
 846		return NULL;
 847	}
 848}
 849
 850//
 851// UTILITIES
 852//
 853
 854void LLViewerParcelMgr::render()
 855{
 856	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
 857	{
 858		// Rendering is done in agent-coordinates, so need to supply
 859		// an appropriate offset to the render code.
 860		LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mWestSouth);
 861		if (!regionp) return;
 862
 863		renderHighlightSegments(mHighlightSegments, regionp);
 864	}
 865}
 866
 867
 868void LLViewerParcelMgr::renderParcelCollision()
 869{
 870	// check for expiration
 871	if (mCollisionTimer.getElapsedTimeF32() > PARCEL_COLLISION_DRAW_SECS)
 872	{
 873		mRenderCollision = FALSE;
 874	}
 875
 876	if (mRenderCollision && gSavedSettings.getBOOL("ShowBanLines"))
 877	{
 878		LLViewerRegion* regionp = gAgent.getRegion();
 879		if (regionp)
 880		{
 881			BOOL use_pass = mCollisionParcel->getParcelFlag(PF_USE_PASS_LIST);
 882			renderCollisionSegments(mCollisionSegments, use_pass, regionp);
 883		}
 884	}
 885}
 886
 887
 888void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
 889{
 890	if (!mSelected)
 891	{
 892		return;
 893	}
 894
 895	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 896	if (!region) return;
 897
 898	LLMessageSystem *msg = gMessageSystem;
 899	
 900
 901	if (flags & AL_BAN) 
 902	{
 903		mCurrentParcel->mBanList.clear();
 904	}
 905	if (flags & AL_ACCESS) 
 906	{
 907		mCurrentParcel->mAccessList.clear();
 908	}		
 909
 910	// Only the headers differ
 911	msg->newMessageFast(_PREHASH_ParcelAccessListRequest);
 912	msg->nextBlockFast(_PREHASH_AgentData);
 913	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 914	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 915	msg->nextBlockFast(_PREHASH_Data);
 916	msg->addS32Fast(_PREHASH_SequenceID, 0);
 917	msg->addU32Fast(_PREHASH_Flags, flags);
 918	msg->addS32("LocalID", mCurrentParcel->getLocalID() );
 919	msg->sendReliable( region->getHost() );
 920}
 921
 922
 923void LLViewerParcelMgr::sendParcelDwellRequest()
 924{
 925	if (!mSelected)
 926	{
 927		return;
 928	}
 929
 930	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 931	if (!region) return;
 932
 933	LLMessageSystem *msg = gMessageSystem;
 934
 935	// Only the headers differ
 936	msg->newMessage("ParcelDwellRequest");
 937	msg->nextBlock("AgentData");
 938	msg->addUUID("AgentID", gAgent.getID() );
 939	msg->addUUID("SessionID", gAgent.getSessionID());
 940	msg->nextBlock("Data");
 941	msg->addS32("LocalID", mCurrentParcel->getLocalID());
 942	msg->addUUID("ParcelID", LLUUID::null);	// filled in on simulator
 943	msg->sendReliable( region->getHost() );
 944}
 945
 946
 947void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id)
 948{
 949	if (!mSelected)
 950	{
 951		LLNotificationsUtil::add("CannotSetLandOwnerNothingSelected");
 952		return;
 953	}
 954
 955	llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl;
 956
 957	// BUG: Only works for the region containing mWestSouthBottom
 958	LLVector3d east_north_region_check( mEastNorth );
 959	east_north_region_check.mdV[VX] -= 0.5;
 960	east_north_region_check.mdV[VY] -= 0.5;
 961
 962	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
 963	if (!region)
 964	{
 965		// TODO: Add a force owner version of this alert.
 966		LLNotificationsUtil::add("CannotContentifyNoRegion");
 967		return;
 968	}
 969
 970	// BUG: Make work for cross-region selections
 971	LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
 972	if (region != region2)
 973	{
 974		LLNotificationsUtil::add("CannotSetLandOwnerMultipleRegions");
 975		return;
 976	}
 977
 978	llinfos << "Region " << region->getOriginGlobal() << llendl;
 979
 980	LLSD payload;
 981	payload["owner_id"] = owner_id;
 982	payload["parcel_local_id"] = mCurrentParcel->getLocalID();
 983	payload["region_host"] = region->getHost().getIPandPort();
 984	LLNotification::Params params("ForceOwnerAuctionWarning");
 985	params.payload(payload).functor.function(callback_god_force_owner);
 986
 987	if(mCurrentParcel->getAuctionID())
 988	{
 989		LLNotifications::instance().add(params);
 990	}
 991	else
 992	{
 993		LLNotifications::instance().forceResponse(params, 0);
 994	}
 995}
 996
 997bool callback_god_force_owner(const LLSD& notification, const LLSD& response)
 998{
 999	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
1000	if(0 == option)
1001	{
1002		LLMessageSystem* msg = gMessageSystem;
1003		msg->newMessage("ParcelGodForceOwner");
1004		msg->nextBlock("AgentData");
1005		msg->addUUID("AgentID", gAgent.getID());
1006		msg->addUUID("SessionID", gAgent.getSessionID());
1007		msg->nextBlock("Data");
1008		msg->addUUID("OwnerID", notification["payload"]["owner_id"].asUUID());
1009		msg->addS32( "LocalID", notification["payload"]["parcel_local_id"].asInteger());
1010		msg->sendReliable(LLHost(notification["payload"]["region_host"].asString()));
1011	}
1012	return false;
1013}
1014
1015void LLViewerParcelMgr::sendParcelGodForceToContent()
1016{
1017	if (!mSelected)
1018	{
1019		LLNotificationsUtil::add("CannotContentifyNothingSelected");
1020		return;
1021	}
1022	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
1023	if (!region)
1024	{
1025		LLNotificationsUtil::add("CannotContentifyNoRegion");
1026		return;
1027	}
1028
1029	LLMessageSystem* msg = gMessageSystem;
1030	msg->newMessage("ParcelGodMarkAsContent");
1031	msg->nextBlock("AgentData");
1032	msg->addUUID("AgentID", gAgent.getID());
1033	msg->addUUID("SessionID", gAgent.getSessionID());
1034	msg->nextBlock("ParcelData");
1035	msg->addS32("LocalID", mCurrentParcel->getLocalID());
1036	msg->sendReliable(region->getHost());
1037}
1038
1039void LLViewerParcelMgr::sendParcelRelease()
1040{
1041	if (!mSelected)
1042	{
1043        LLNotificationsUtil::add("CannotReleaseLandNothingSelected");
1044		return;
1045	}
1046
1047	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
1048	if (!region)
1049	{
1050		LLNotificationsUtil::add("CannotReleaseLandNoRegion");
1051		return;
1052	}
1053
1054	//U32 flags = PR_NONE;
1055	//if (god_force) flags |= PR_GOD_FORCE;
1056
1057	LLMessageSystem* msg = gMessageSystem;
1058	msg->newMessage("ParcelRelease");
1059	msg->nextBlock("AgentData");
1060	msg->addUUID("AgentID", gAgent.getID() );
1061	msg->addUUID("SessionID", gAgent.getSessionID() );
1062	msg->nextBlock("Data");
1063	msg->addS32("LocalID", mCurrentParcel->getLocalID() );
1064	//msg->addU32("Flags", flags);
1065	msg->sendReliable( region->getHost() );
1066
1067	// Blitz selection, since the parcel might be non-rectangular, and
1068	// we won't have appropriate parcel information.
1069	deselectLand();
1070}
1071
1072class LLViewerParcelMgr::ParcelBuyInfo
1073{
1074public:
1075	LLUUID	mAgent;
1076	LLUUID	mSession;
1077	LLUUID	mGroup;
1078	BOOL	mIsGroupOwned;
1079	BOOL	mRemoveContribution;
1080	BOOL	mIsClaim;
1081	LLHost	mHost;
1082	
1083	// for parcel buys
1084	S32		mParcelID;
1085	S32		mPrice;
1086	S32		mArea;
1087
1088	// for land claims
1089	F32		mWest;
1090	F32		mSouth;
1091	F32		mEast;
1092	F32		mNorth;
1093};
1094
1095LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy(
1096	const LLUUID& agent_id,
1097	const LLUUID& session_id,
1098	const LLUUID& group_id,
1099	BOOL is_group_owned,
1100	BOOL is_claim,
1101	BOOL remove_contribution)
1102{
1103	if (!mSelected || !mCurrentParcel)
1104	{
1105		LLNotificationsUtil::add("CannotBuyLandNothingSelected");
1106		return NULL;
1107	}
1108
1109	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
1110	if (!region)
1111	{
1112		LLNotificationsUtil::add("CannotBuyLandNoRegion");
1113		return NULL;
1114	}
1115	
1116	if (is_claim)
1117	{
1118		llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl;
1119		llinfos << "Region " << region->getOriginGlobal() << llendl;
1120
1121		// BUG: Only works for the region containing mWestSouthBottom
1122		LLVector3d east_north_region_check( mEastNorth );
1123		east_north_region_check.mdV[VX] -= 0.5;
1124		east_north_region_check.mdV[VY] -= 0.5;
1125
1126		LLViewerRegion *region2 = LLWorld::getInstance()->getRegionFromPosGlobal( east_north_region_check );
1127
1128		if (region != region2)
1129		{
1130			LLNotificationsUtil::add("CantBuyLandAcrossMultipleRegions");
1131			return NULL;
1132		}
1133	}
1134	
1135	
1136	ParcelBuyInfo* info = new ParcelBuyInfo;
1137	
1138	info->mAgent = agent_id;
1139	info->mSession = session_id;
1140	info->mGroup = group_id;
1141	info->mIsGroupOwned = is_group_owned;
1142	info->mIsClaim = is_claim;
1143	info->mRemoveContribution = remove_contribution;
1144	info->mHost = region->getHost();
1145	info->mPrice = mCurrentParcel->getSalePrice();
1146	info->mArea = mCurrentParcel->getArea();
1147	
1148	if (!is_claim)
1149	{
1150		info->mParcelID = mCurrentParcel->getLocalID();
1151	}
1152	else
1153	{
1154		// BUG: Make work for cross-region selections
1155		LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
1156		LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
1157		
1158		info->mWest		= west_south_bottom_region.mV[VX];
1159		info->mSouth	= west_south_bottom_region.mV[VY];
1160		info->mEast		= east_north_top_region.mV[VX];
1161		info->mNorth	= east_north_top_region.mV[VY];
1162	}
1163	
1164	return info;
1165}
1166
1167void LLViewerParcelMgr::sendParcelBuy(ParcelBuyInfo* info)
1168{
1169	// send the message
1170	LLMessageSystem* msg = gMessageSystem;
1171	msg->newMessage(info->mIsClaim ? "ParcelClaim" : "ParcelBuy");
1172	msg->nextBlock("AgentData");
1173	msg->addUUID("AgentID", info->mAgent);
1174	msg->addUUID("SessionID", info->mSession);
1175	msg->nextBlock("Data");
1176	msg->addUUID("GroupID", info->mGroup);
1177	msg->addBOOL("IsGroupOwned", info->mIsGroupOwned);
1178	if (!info->mIsClaim)
1179	{
1180		msg->addBOOL("RemoveContribution", info->mRemoveContribution);
1181		msg->addS32("LocalID", info->mParcelID);
1182	}
1183	msg->addBOOL("Final", TRUE);	// don't allow escrow buys
1184	if (info->mIsClaim)
1185	{
1186		msg->nextBlock("ParcelData");
1187		msg->addF32("West",  info->mWest);
1188		msg->addF32("South", info->mSouth);
1189		msg->addF32("East",  info->mEast);
1190		msg->addF32("North", info->mNorth);
1191	}
1192	else // ParcelBuy
1193	{
1194		msg->nextBlock("ParcelData");
1195		msg->addS32("Price",info->mPrice);
1196		msg->addS32("Area",info->mArea);
1197	}
1198	msg->sendReliable(info->mHost);
1199}
1200
1201void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo* *info)
1202{
1203	// Must be here because ParcelBuyInfo is local to this .cpp file
1204	delete *info;
1205	*info = NULL;
1206}
1207
1208void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id)
1209{
1210	if (!mSelected || !mCurrentParcel)
1211	{
1212		LLNotificationsUtil::add("CannotDeedLandNothingSelected");
1213		return;
1214	}
1215	if(group_id.isNull())
1216	{
1217		LLNotificationsUtil::add("CannotDeedLandNoGroup");
1218		return;
1219	}
1220	LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
1221	if (!region)
1222	{
1223		LLNotificationsUtil::add("CannotDeedLandNoRegion");
1224		return;
1225	}
1226
1227	LLMessageSystem* msg = gMessageSystem;
1228	msg->newMessage("ParcelDeedToGroup");
1229	msg->nextBlock("AgentData");
1230	msg->addUUID("AgentID", gAgent.getID() );
1231	msg->addUUID("SessionID", gAgent.getSessionID() );
1232	msg->nextBlock("Data");
1233	msg->addUUID("GroupID", group_id );
1234	msg->addS32("LocalID", mCurrentParcel->getLocalID() );
1235	//msg->addU32("JoinNeighbors", join);
1236	msg->sendReliable( region->getHost() );
1237}
1238
1239
1240/*
1241// *NOTE: We cannot easily make landmarks at global positions because
1242// global positions probably refer to a sim/local combination which
1243// can move over time. We could implement this by looking up the
1244// region global x,y, but it's easier to take it out for now.
1245void LLViewerParcelMgr::makeLandmarkAtSelection()
1246{
1247	// Don't create for parcels you don't own
1248	if (gAgent.getID() != mCurrentParcel->getOwnerID())
1249	{
1250		return;
1251	}
1252
1253	LLVector3d global_center(mWestSouth);
1254	global_center += mEastNorth;
1255	global_center *= 0.5f;
1256
1257	LLViewerRegion* region;
1258	region = LLWorld::getInstance()->getRegionFromPosGlobal(global_center);
1259
1260	LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
1261	LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
1262
1263	std::string name("My Land");
1264	std::string buffer;
1265	S32 pos_x = (S32)floor((west_south_bottom_region.mV[VX] + east_north_top_region.mV[VX]) / 2.0f);
1266	S32 pos_y = (S32)floor((west_south_bottom_region.mV[VY] + east_north_top_region.mV[VY]) / 2.0f);
1267	buffer = llformat("%s in %s (%d, %d)",
1268			name.c_str(),
1269			region->getName().c_str(),
1270			pos_x, pos_y);
1271	name.assign(buffer);
1272
1273	create_landmark(name, "Claimed land", global_center);
1274}
1275*/
1276
1277const std::string& LLViewerParcelMgr::getAgentParcelName() const
1278{
1279	return mAgentParcel->getName();
1280}
1281
1282
1283void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region)
1284{
1285	if(!parcel) return;
1286
1287	LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
1288	if (!region) return;
1289	//llinfos << "found region: " << region->getName() << llendl;
1290
1291	LLSD body;
1292	std::string url = region->getCapability("ParcelPropertiesUpdate");
1293	if (!url.empty())
1294	{
1295		// request new properties update from simulator
1296		U32 message_flags = 0x01;
1297		body["flags"] = ll_sd_from_U32(message_flags);
1298		parcel->packMessage(body);
1299		llinfos << "Sending parcel properties update via capability to: "
1300			<< url << llendl;
1301		LLHTTPClient::post(url, body, new LLHTTPClient::Responder());
1302	}
1303	else
1304	{
1305		LLMessageSystem* msg = gMessageSystem;
1306		msg->newMessageFast(_PREHASH_ParcelPropertiesUpdate);
1307		msg->nextBlockFast(_PREHASH_AgentData);
1308		msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID() );
1309		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1310		msg->nextBlockFast(_PREHASH_ParcelData);
1311		msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() );
1312
1313		U32 message_flags = 0x01;
1314		msg->addU32("Flags", message_flags);
1315
1316		parcel->packMessage(msg);
1317
1318		msg->sendReliable( region->getHost() );
1319	}
1320}
1321
1322
1323void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos)
1324{
1325	static U32 last_west, last_south;
1326
1327
1328	// only request parcel info when tooltip is shown
1329	if (!gSavedSettings.getBOOL("ShowLandHoverTip"))
1330	{
1331		return;
1332	}
1333
1334	// only request parcel info if position has changed outside of the
1335	// last parcel grid step
1336	U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS );
1337	U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS );
1338	
1339	if ((west_parcel_step == last_west) && (south_parcel_step == last_south))
1340	{
1341		return;
1342	}
1343	else 
1344	{
1345		last_west = west_parcel_step;
1346		last_south = south_parcel_step;
1347	}
1348
1349	LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos );
1350	if (!region)
1351	{
1352		return;
1353	}
1354
1355
1356	// Send a rectangle around the point.
1357	// This means the parcel sent back is at least a rectangle around the point,
1358	// which is more efficient for public land.  Fewer requests are sent.  JC
1359	LLVector3 wsb_region = region->getPosRegionFromGlobal( pos );
1360
1361	F32 west  = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VX] / PARCEL_GRID_STEP_METERS );
1362	F32 south = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VY] / PARCEL_GRID_STEP_METERS );
1363
1364	F32 east  = west  + PARCEL_GRID_STEP_METERS;
1365	F32 north = south + PARCEL_GRID_STEP_METERS;
1366
1367	// Send request message
1368	LLMessageSystem *msg = gMessageSystem;
1369	msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
1370	msg->nextBlockFast(_PREHASH_AgentData);
1371	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
1372	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
1373	msg->nextBlockFast(_PREHASH_ParcelData);
1374	msg->addS32Fast(_PREHASH_SequenceID,	HOVERED_PARCEL_SEQ_ID );
1375	msg->addF32Fast(_PREHASH_West,			west );
1376	msg->addF32Fast(_PREHASH_South,			south );
1377	msg->addF32Fast(_PREHASH_East,			east );
1378	msg->addF32Fast(_PREHASH_North,			north );
1379	msg->addBOOL("SnapSelection",			FALSE );
1380	msg->sendReliable( region->getHost() );
1381
1382	mHoverRequestResult = PARCEL_RESULT_NO_DATA;
1383}
1384
1385
1386// static
1387void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user)
1388{
1389	// Extract the packed overlay information
1390	S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data);
1391
1392	if (packed_overlay_size <= 0)
1393	{
1394		llwarns << "Overlay size " << packed_overlay_size << llendl;
1395		return;
1396	}
1397
1398	S32 parcels_per_edge = LLViewerParcelMgr::getInstance()->mParcelsPerEdge;
1399	S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS;
1400	if (packed_overlay_size != expected_size)
1401	{
1402		llwarns << "Got parcel overlay size " << packed_overlay_size
1403			<< " expecting " << expected_size << llendl;
1404		return;
1405	}
1406
1407	S32 sequence_id;
1408	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id);
1409	msg->getBinaryDataFast(
1410			_PREHASH_ParcelData,
1411			_PREHASH_Data,
1412			sPackedOverlay,
1413			expected_size);
1414
1415	LLHost host = msg->getSender();
1416	LLViewerRegion *region = LLWorld::getInstance()->getRegion(host);
1417	if (region)
1418	{
1419		region->mParcelOverlay->uncompressLandOverlay( sequence_id, sPackedOverlay );
1420	}
1421}
1422
1423// static
1424void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **user)
1425{
1426	S32		request_result;
1427	S32		sequence_id;
1428	BOOL	snap_selection = FALSE;
1429	S32		self_count = 0;
1430	S32		other_count = 0;
1431	S32		public_count = 0;
1432	S32		local_id;
1433	LLUUID	owner_id;
1434	BOOL	is_group_owned;
1435	U32 auction_id = 0;
1436	S32		claim_price_per_meter = 0;
1437	S32		rent_price_per_meter = 0;
1438	S32		claim_date = 0;
1439	LLVector3	aabb_min;
1440	LLVector3	aabb_max;
1441	S32		area = 0;
1442	S32		sw_max_prims = 0;
1443	S32		sw_total_prims = 0;
1444	//LLUUID	buyer_id;
1445	U8 status = 0;
1446	S32		max_prims = 0;
1447	S32		total_prims = 0;
1448	S32		owner_prims = 0;
1449	S32		group_prims = 0;
1450	S32		other_prims = 0;
1451	S32		selected_prims = 0;
1452	F32		parcel_prim_bonus = 1.f;
1453	BOOL	region_push_override = false;
1454	BOOL	region_deny_anonymous_override = false;
1455	BOOL	region_deny_identified_override = false; // Deprecated
1456	BOOL	region_deny_transacted_override = false; // Deprecated
1457	BOOL	region_deny_age_unverified_override = false;
1458
1459	S32		other_clean_time = 0;
1460
1461	LLViewerParcelMgr& parcel_mgr = LLViewerParcelMgr::instance();
1462
1463	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result );
1464	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id );
1465
1466	if (request_result == PARCEL_RESULT_NO_DATA)
1467	{
1468		// no valid parcel data
1469		llinfos << "no valid parcel data" << llendl;
1470		return;
1471	}
1472
1473	// Decide where the data will go.
1474	LLParcel* parcel = NULL;
1475	if (sequence_id == SELECTED_PARCEL_SEQ_ID)
1476	{
1477		// ...selected parcels report this sequence id
1478		parcel_mgr.mRequestResult = PARCEL_RESULT_SUCCESS;
1479		parcel = parcel_mgr.mCurrentParcel;
1480	}
1481	else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
1482	{
1483		parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS;
1484		parcel = parcel_mgr.mHoverParcel;
1485	}
1486	else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
1487			 sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID ||
1488			 sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1489	{
1490		parcel_mgr.mHoverRequestResult = PARCEL_RESULT_SUCCESS;
1491		parcel = parcel_mgr.mCollisionParcel;
1492	}
1493	else if (sequence_id == 0 || sequence_id > parcel_mgr.mAgentParcelSequenceID)
1494	{
1495		// new agent parcel
1496		parcel_mgr.mAgentParcelSequenceID = sequence_id;
1497		parcel = parcel_mgr.mAgentParcel;
1498	}
1499	else
1500	{
1501		llinfos << "out of order agent parcel sequence id " << sequence_id
1502			<< " last good " << parcel_mgr.mAgentParcelSequenceID
1503			<< llendl;
1504		return;
1505	}
1506
1507	msg->getBOOL("ParcelData", "SnapSelection", snap_selection);
1508	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelfCount, self_count);
1509	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherCount, other_count);
1510	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_PublicCount, public_count);
1511	msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_LocalID,		local_id );
1512	msg->getUUIDFast(_PREHASH_ParcelData, _PREHASH_OwnerID,		owner_id);
1513	msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_IsGroupOwned, is_group_owned);
1514	msg->getU32Fast(_PREHASH_ParcelData, _PREHASH_AuctionID, auction_id);
1515	msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_ClaimDate,	claim_date);
1516	msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_ClaimPrice,	claim_price_per_meter);
1517	msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_RentPrice,	rent_price_per_meter);
1518	msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMin, aabb_min);
1519	msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMax, aabb_max);
1520	msg->getS32Fast(	_PREHASH_ParcelData, _PREHASH_Area, area );
1521	//msg->getUUIDFast(	_PREHASH_ParcelData, _PREHASH_BuyerID, buyer_id);
1522	msg->getU8("ParcelData", "Status", status);
1523	msg->getS32("ParcelData", "SimWideMaxPrims", sw_max_prims );
1524	msg->getS32("ParcelData", "SimWideTotalPrims", sw_total_prims );
1525	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_MaxPrims, max_prims );
1526	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_TotalPrims, total_prims );
1527	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OwnerPrims, owner_prims );
1528	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_GroupPrims, group_prims );
1529	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherPrims, other_prims );
1530	msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelectedPrims, selected_prims );
1531	msg->getF32Fast(_PREHASH_ParcelData, _PREHASH_ParcelPrimBonus, parcel_prim_bonus );
1532	msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionPushOverride, region_push_override );
1533	msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyAnonymous, region_deny_anonymous_override );
1534	msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyIdentified, region_deny_identified_override ); // Deprecated
1535	msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyTransacted, region_deny_transacted_override ); // Deprecated
1536	if (msg->getNumberOfBlocksFast(_PREHASH_AgeVerificationBlock))
1537	{
1538		// this block was added later and may not be on older sims, so we have to test its existence first
1539		msg->getBOOLFast(_PREHASH_AgeVerificationBlock, _PREHASH_RegionDenyAgeUnverified, region_deny_age_unverified_override );
1540	}
1541
1542	msg->getS32("ParcelData", "OtherCleanTime", other_clean_time );
1543
1544	// Actually extract the data.
1545	if (parcel)
1546	{
1547		parcel->init(owner_id,
1548			FALSE, FALSE, FALSE,
1549			claim_date, claim_price_per_meter, rent_price_per_meter,
1550			area, other_prims, parcel_prim_bonus, is_group_owned);
1551		parcel->setLocalID(local_id);
1552		parcel->setAABBMin(aabb_min);
1553		parcel->setAABBMax(aabb_max);
1554
1555		parcel->setAuctionID(auction_id);
1556		parcel->setOwnershipStatus((LLParcel::EOwnershipStatus)status);
1557
1558		parcel->setSimWideMaxPrimCapacity(sw_max_prims);
1559		parcel->setSimWidePrimCount(sw_total_prims);
1560		parcel->setMaxPrimCapacity(max_prims);
1561		parcel->setOwnerPrimCount(owner_prims);
1562		parcel->setGroupPrimCount(group_prims);
1563		parcel->setOtherPrimCount(other_prims);
1564		parcel->setSelectedPrimCount(selected_prims);
1565		parcel->setParcelPrimBonus(parcel_prim_bonus);
1566
1567		parcel->setCleanOtherTime(other_clean_time);
1568		parcel->setRegionPushOverride(region_push_override);
1569		parcel->setRegionDenyAnonymousOverride(region_deny_anonymous_override);
1570		parcel->setRegionDenyAgeUnverifiedOverride(region_deny_age_unverified_override);
1571		parcel->unpackMessage(msg);
1572
1573		if (parcel == parcel_mgr.mAgentParcel)
1574		{
1575			S32 bitmap_size =	parcel_mgr.mParcelsPerEdge
1576								* parcel_mgr.mParcelsPerEdge
1577								/ 8;
1578			U8* bitmap = new U8[ bitmap_size ];
1579			msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1580
1581			parcel_mgr.writeAgentParcelFromBitmap(bitmap);
1582			delete[] bitmap;
1583
1584			// Let interesting parties know about agent parcel change.
1585			LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance();
1586
1587			instance->mAgentParcelChangedSignal();
1588
1589			if (instance->mTeleportInProgress)
1590			{
1591				instance->mTeleportInProgress = FALSE;
1592				instance->mTeleportFinishedSignal(gAgent.getPositionGlobal());
1593			}
1594		}
1595	}
1596
1597	// Handle updating selections, if necessary.
1598	if (sequence_id == SELECTED_PARCEL_SEQ_ID)
1599	{
1600		// Update selected counts
1601		parcel_mgr.mCurrentParcelSelection->mSelectedSelfCount = self_count;
1602		parcel_mgr.mCurrentParcelSelection->mSelectedOtherCount = other_count;
1603		parcel_mgr.mCurrentParcelSelection->mSelectedPublicCount = public_count;
1604
1605		parcel_mgr.mCurrentParcelSelection->mSelectedMultipleOwners =
1606							(request_result == PARCEL_RESULT_MULTIPLE);
1607
1608		// Select the whole parcel
1609		LLViewerRegion* region = LLWorld::getInstance()->getRegion( msg->getSender() );
1610		if (region)
1611		{
1612			if (!snap_selection)
1613			{
1614				// don't muck with the westsouth and eastnorth.
1615				// just highlight it
1616				LLVector3 west_south = region->getPosRegionFromGlobal(parcel_mgr.mWestSouth);
1617				LLVector3 east_north = region->getPosRegionFromGlobal(parcel_mgr.mEastNorth);
1618
1619				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
1620				parcel_mgr.writeHighlightSegments(
1621								west_south.mV[VX],
1622								west_south.mV[VY],
1623								east_north.mV[VX],
1624								east_north.mV[VY] );
1625				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = FALSE;
1626			}
1627			else if (0 == local_id)
1628			{
1629				// this is public land, just highlight the selection
1630				parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min );
1631				parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max );
1632
1633				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
1634				parcel_mgr.writeHighlightSegments(
1635								aabb_min.mV[VX],
1636								aabb_min.mV[VY],
1637								aabb_max.mV[VX],
1638								aabb_max.mV[VY] );
1639				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = TRUE;
1640			}
1641			else
1642			{
1643				parcel_mgr.mWestSouth = region->getPosGlobalFromRegion( aabb_min );
1644				parcel_mgr.mEastNorth = region->getPosGlobalFromRegion( aabb_max );
1645
1646				// Owned land, highlight the boundaries
1647				S32 bitmap_size =	parcel_mgr.mParcelsPerEdge
1648									* parcel_mgr.mParcelsPerEdge
1649									/ 8;
1650				U8* bitmap = new U8[ bitmap_size ];
1651				msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1652
1653				parcel_mgr.resetSegments(parcel_mgr.mHighlightSegments);
1654				parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mHighlightSegments );
1655
1656				delete[] bitmap;
1657				bitmap = NULL;
1658
1659				parcel_mgr.mCurrentParcelSelection->mWholeParcelSelected = TRUE;
1660			}
1661
1662			// Request access list information for this land
1663			parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN);
1664
1665			// Request the media url filter list for this land
1666			parcel_mgr.requestParcelMediaURLFilter();
1667
1668			// Request dwell for this land, if it's not public land.
1669			parcel_mgr.mSelectedDwell = DWELL_NAN;
1670			if (0 != local_id)
1671			{
1672				parcel_mgr.sendParcelDwellRequest();
1673			}
1674
1675			parcel_mgr.mSelected = TRUE;
1676			parcel_mgr.notifyObservers();
1677		}
1678	}
1679	else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
1680			 sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID  ||
1681			 sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1682	{
1683		// We're about to collide with this parcel
1684		parcel_mgr.mRenderCollision = TRUE;
1685		parcel_mgr.mCollisionTimer.reset();
1686
1687		// Differentiate this parcel if we are banned from it.
1688		if (sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1689		{
1690			parcel_mgr.mCollisionBanned = BA_BANNED;
1691		}
1692		else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID)
1693		{
1694			parcel_mgr.mCollisionBanned = BA_NOT_IN_GROUP;
1695		}
1696		else 
1697		{
1698			parcel_mgr.mCollisionBanned = BA_NOT_ON_LIST;
1699
1700		}
1701
1702		S32 bitmap_size =	parcel_mgr.mParcelsPerEdge
1703							* parcel_mgr.mParcelsPerEdge
1704							/ 8;
1705		U8* bitmap = new U8[ bitmap_size ];
1706		msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1707
1708		parcel_mgr.resetSegments(parcel_mgr.mCollisionSegments);
1709		parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mCollisionSegments );
1710
1711		delete[] bitmap;
1712		bitmap = NULL;
1713
1714	}
1715	else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
1716	{
1717		LLViewerRegion *region = LLWorld::getInstance()->getRegion( msg->getSender() );
1718		if (region)
1719		{
1720			parcel_mgr.mHoverWestSouth = region->getPosGlobalFromRegion( aabb_min );
1721			parcel_mgr.mHoverEastNorth = region->getPosGlobalFromRegion( aabb_max );
1722		}
1723		else
1724		{
1725			parcel_mgr.mHoverWestSouth.clearVec();
1726			parcel_mgr.mHoverEastNorth.clearVec();
1727		}
1728	}
1729	else
1730	{
1731		// Check for video
1732		LLViewerParcelMedia::update(parcel);
1733
1734		// Then check for music
1735		if (gAudiop)
1736		{
1737			if (parcel)
1738			{
1739				std::string music_url_raw = parcel->getMusicURL();
1740
1741				// Trim off whitespace from front and back
1742				std::string music_url = music_url_raw;
1743				LLStringUtil::trim(music_url);
1744
1745				// If there is a new music URL and it's valid, play it.
1746				if (music_url.size() > 12)
1747				{
1748					if (music_url.substr(0,7) == "http://")
1749					{
1750						optionally_start_music(music_url);
1751					}
1752					else
1753					{
1754						llinfos << "Stopping parcel music (invalid audio stream URL)" << llendl;
1755						// clears the URL 
1756						// null value causes fade out
1757						LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
1758					}
1759				}
1760				else if (!gAudiop->getInternetStreamURL().empty())
1761				{
1762					llinfos << "Stopping parcel music (parcel stream URL is empty)" << llendl;
1763					// null value causes fade out
1764					LLV

Large files files are truncated, but you can click here to view the full file