diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llviewerparcelmgr.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
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
+}
|