"README.md" did not exist on "cf3ded4491751231056b220525970e125d813e6a"
Newer
Older
/**
* @file llviewerparcelmgr.cpp
* @brief Viewer-side representation of owned land
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* 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
*/
#include "llviewerprecompiledheaders.h"
#include "llviewerparcelmgr.h"
// Library includes
#include "indra_constants.h"
#include "llcachename.h"
#include "llgl.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llfloaterreg.h"
brad kittenbrink
committed
#include "llagentaccess.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"
Josh Bell
committed
#include "llsdutil.h"
brad kittenbrink
committed
#include "llslurl.h"
#include "llviewertexture.h"
#include "llviewertexturelist.h"
#include "llviewerparceloverlay.h"
#include "llviewerregion.h"
#include "llworld.h"
#include "roles_constants.h"
Jonathan Yap
committed
#include "llvieweraudio.h"
// Globals
U8* LLViewerParcelMgr::sPackedOverlay = NULL;
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),
Jonathan Yap
committed
mSelectedDwell(DWELL_NAN),
andreykproductengine
committed
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(8192.f / PARCEL_GRID_STEP_METERS); // 8192 is the maximum region size on Aurora
mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
resetSegments(mHighlightSegments);
mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
resetSegments(mCollisionSegments);
James Cook
committed
// 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");
mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png");
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;
}
mParcelsPerEdge = S32(REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS);
mTeleportInProgress = TRUE; // the initial parcel update is treated like teleport
void LLViewerParcelMgr::init(F32 region_size)
{
mParcelsPerEdge = S32(region_size / PARCEL_GRID_STEP_METERS);
}
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;
Bryan O'Sullivan
committed
delete[] sPackedOverlay;
sPackedOverlay = NULL;
delete[] mAgentParcelOverlay;
mAgentParcelOverlay = NULL;
sBlockedImage = NULL;
sPassImage = NULL;
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();
LL_INFOS() << "ban id " << (*cit).first << 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;
Jonathan Yap
committed
F32 dwell = DWELL_NAN;
if (mCurrentParcelSelection->mSelectedMultipleOwners)
area = mCurrentParcelSelection->getClaimableArea();
}
else
{
area = getSelectedArea();
}
if (mCurrentParcel->getForSale())
price = mCurrentParcel->getSalePrice();
price = area * mCurrentParcel->getClaimPricePerMeter();
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);
}
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 );
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
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 );
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
mEastNorth += LLVector3d(getSelectionRegion()->getWidth()/REGION_WIDTH_METERS * PARCEL_GRID_STEP_METERS, getSelectionRegion()->getWidth()/REGION_WIDTH_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);
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();
}
// ...y isn't more than one meter away
F32 delta_y = getSelectionHeight();
if (delta_y * delta_y <= 1.f * 1.f)
{
mSelected = FALSE;
notifyObservers();
}
// 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;
LLNotificationsUtil::add("CantSelectLandFromMultipleRegions");
}
// 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);
mCurrentParcelSelection->mWholeParcelSelected = snap_selection;
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();
Jonathan Yap
committed
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);
Steven Bennetts
committed
notifyObservers(); // Notify observers *after* changing the parcel selection
}
}
void LLViewerParcelMgr::addObserver(LLParcelObserver* observer)
{
Richard Linden
committed
mObservers.push_back(observer);
}
void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer)
{
Richard Linden
committed
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()
{
Richard Linden
committed
std::vector<LLParcelObserver*> observers;
S32 count = mObservers.size();
Richard Linden
committed
observers.push_back(mObservers.at(i));
Richard Linden
committed
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;
}
// Return whether the agent can build on the land they are on
bool LLViewerParcelMgr::allowAgentBuild() const
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
{
Sergei Litovchuk
committed
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);
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
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()
{
Richard Nelson
committed
if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
{
// 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()
{
// check for expiration
if (mCollisionTimer.getElapsedTimeF32() > PARCEL_COLLISION_DRAW_SECS)
{
mRenderCollision = FALSE;
}
if (mRenderCollision && gSavedSettings.getBOOL("ShowBanLines"))
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;
mCurrentParcel->mBanList.clear();
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");
LL_INFOS() << "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 );
LLNotificationsUtil::add("CannotSetLandOwnerMultipleRegions");
LL_INFOS() << "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())