/** * @file llworldmap.cpp * @brief Underlying data representation for map of the world * * $LicenseInfo:firstyear=2003&license=viewergpl$ * * Copyright (c) 2003-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llworldmap.h" #include "llregionhandle.h" #include "message.h" #include "llappviewer.h" // for gPacificDaylightTime #include "llagent.h" #include "llmapresponders.h" #include "llviewercontrol.h" #include "llfloaterworldmap.h" #include "lltracker.h" #include "llviewertexturelist.h" #include "llviewerregion.h" #include "llregionflags.h" #include "hippogridmanager.h" bool LLWorldMap::sGotMapURL = false; const F32 AGENTS_UPDATE_TIMER = 60.0; // Seconds between 2 agent requests for a region const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes // For DEV-17507, do lazy image loading in llworldmapview.cpp instead, // limiting requests to currently visible regions and minimizing the // number of textures being requested simultaneously. // // Uncomment IMMEDIATE_IMAGE_LOAD to restore the old behavior // //#define IMMEDIATE_IMAGE_LOAD LLItemInfo::LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id, S32 extra, S32 extra2) : mName(name), mToolTip(""), mPosGlobal(global_x, global_y, 40.0), mID(id), mSelected(FALSE), mExtra(extra), mExtra2(extra2) { mRegionHandle = to_region_handle(mPosGlobal); } LLSimInfo::LLSimInfo(U64 handle) : mHandle(handle), mName(), mAgentsUpdateTime(0), mShowAgentLocations(FALSE), mAccess(0x0), mRegionFlags(0x0), mWaterHeight(0.f), mAlpha(-1.f) { } LLVector3d LLSimInfo::getGlobalPos(const LLVector3& local_pos) const { LLVector3d pos = from_region_handle(mHandle); pos.mdV[VX] += local_pos.mV[VX]; pos.mdV[VY] += local_pos.mV[VY]; pos.mdV[VZ] += local_pos.mV[VZ]; return pos; } LLVector3d LLSimInfo::getGlobalOrigin() const { return from_region_handle(mHandle); } LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const { LLVector3d sim_origin = from_region_handle(mHandle); return LLVector3(global_pos - sim_origin); } void LLSimInfo::clearImage() { if (!mOverlayImage.isNull()) { mOverlayImage->setBoostLevel(0); mOverlayImage = NULL; } } void LLSimInfo::dropImagePriority() { if (!mOverlayImage.isNull()) { mOverlayImage->setBoostLevel(0); } } // Update the agent count for that region void LLSimInfo::updateAgentCount(F64 time) { if ((time - mAgentsUpdateTime > AGENTS_UPDATE_TIMER) || mFirstAgentRequest) { LLWorldMap::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, mHandle); mAgentsUpdateTime = time; mFirstAgentRequest = false; } } bool LLSimInfo::isName(const std::string& name) const { return (LLStringUtil::compareInsensitive(name, mName) == 0); } //--------------------------------------------------------------------------- // World Map //--------------------------------------------------------------------------- LLWorldMap::LLWorldMap() : mIsTrackingUnknownLocation( FALSE ), mInvalidLocation( FALSE ), mIsTrackingDoubleClick( FALSE ), mIsTrackingCommit( FALSE ), mUnknownLocation( 0, 0, 0 ), mRequestLandForSale(true), mCurrentMap(0), mMinX(U32_MAX), mMaxX(U32_MIN), mMinY(U32_MAX), mMaxY(U32_MIN), mNeighborMap(NULL), mTelehubCoverageMap(NULL), mNeighborMapWidth(0), mNeighborMapHeight(0), mSLURLRegionName(), mSLURLRegionHandle(0), mSLURL(), mSLURLCallback(0), mSLURLTeleport(false) { for (S32 map=0; map REQUEST_ITEMS_TIMER) { mRequestTimer.reset(); mTelehubs.clear(); mInfohubs.clear(); mPGEvents.clear(); mMatureEvents.clear(); mAdultEvents.clear(); mLandForSale.clear(); } // mAgentLocationsMap.clear(); // persists // mNumAgents.clear(); // persists } void LLWorldMap::clearImageRefs() { // We clear the reference to the images we're holding. // Images hold by the world mipmap first mWorldMipmap.reset(); // Images hold by the region map LLSimInfo* sim_info = NULL; for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { sim_info = it->second; if(sim_info) { if (sim_info->mCurrentImage) { sim_info->mCurrentImage->setBoostLevel(0); sim_info->mCurrentImage = NULL; } sim_info->clearImage(); } } } // Doesn't clear the already-loaded sim infos, just re-requests them void LLWorldMap::clearSimFlags() { for (S32 map=0; map::const_iterator it; for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) { const U64 handle = (*it).first; LLSimInfo* info = (*it).second; if(handle == findhandle) { return info; } U32 x = 0, y = 0; from_region_handle(findhandle, &x, &y); U32 checkRegionX, checkRegionY; from_region_handle(handle, &checkRegionX, &checkRegionY); if(x >= checkRegionX && x < (checkRegionX + info->getSizeX()) && y >= checkRegionY && y < (checkRegionY + info->getSizeY())) { return info; } } return NULL; } LLSimInfo* LLWorldMap::simInfoFromName(const std::string& sim_name) { LLSimInfo* sim_info = NULL; if (!sim_name.empty()) { // Iterate through the entire sim info map and compare the name sim_info_map_t::iterator it; for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { sim_info = it->second; if (sim_info && sim_info->isName(sim_name) ) { // break out of loop if success break; } } // If we got to the end, we haven't found the sim. Reset the ouput value to NULL. if (it == mSimInfoMap.end()) sim_info = NULL; } return sim_info; } bool LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global, std::string & outSimName ) { LLSimInfo* sim_info = simInfoFromPosGlobal(pos_global); if (sim_info) { outSimName = sim_info->getName(); } else { outSimName = "(unknown region)"; } return (sim_info != NULL); } void LLWorldMap::setCurrentLayer(S32 layer, bool request_layer) { //TODO: we only have 1 layer -SG mCurrentMap = layer; if (!mMapLoaded[layer] || request_layer) { sendMapLayerRequest(); } if (mTelehubs.size() == 0 || mInfohubs.size() == 0) { // Request for telehubs sendItemRequest(MAP_ITEM_TELEHUB); } if (mPGEvents.size() == 0) { // Request for events sendItemRequest(MAP_ITEM_PG_EVENT); } if (mMatureEvents.size() == 0) { // Request for events (mature) sendItemRequest(MAP_ITEM_MATURE_EVENT); } if (mAdultEvents.size() == 0) { // Request for events (adult) sendItemRequest(MAP_ITEM_ADULT_EVENT); } if (mLandForSale.size() == 0) { // Request for Land For Sale sendItemRequest(MAP_ITEM_LAND_FOR_SALE); } if (mLandForSaleAdult.size() == 0) { // Request for Land For Sale sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT); } clearImageRefs(); clearSimFlags(); } void LLWorldMap::sendItemRequest(U32 type, U64 handle) { LLMessageSystem* msg = gMessageSystem; S32 layer = mCurrentMap; msg->newMessageFast(_PREHASH_MapItemRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addU32Fast(_PREHASH_Flags, layer); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim msg->nextBlockFast(_PREHASH_RequestData); msg->addU32Fast(_PREHASH_ItemType, type); msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim gAgent.sendReliableMessage(); } // public void LLWorldMap::sendMapLayerRequest() { if (!gAgent.getRegion()) return; LLSD body; body["Flags"] = mCurrentMap; std::string url = gAgent.getRegion()->getCapability( gAgent.isGodlike() ? "MapLayerGod" : "MapLayer"); if (!url.empty()) { llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; LLHTTPClient::post(url, body, new LLMapLayerResponder()); } else { llinfos << "LLWorldMap::sendMapLayerRequest via message system" << llendl; LLMessageSystem* msg = gMessageSystem; S32 layer = mCurrentMap; // Request for layer msg->newMessageFast(_PREHASH_MapLayerRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addU32Fast(_PREHASH_Flags, layer); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim gAgent.sendReliableMessage(); if (mRequestLandForSale) { msg->newMessageFast(_PREHASH_MapLayerRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addU32Fast(_PREHASH_Flags, 2); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim gAgent.sendReliableMessage(); } } } // public void LLWorldMap::sendNamedRegionRequest(std::string region_name) { LLMessageSystem* msg = gMessageSystem; S32 layer = mCurrentMap; // Request for layer msg->newMessageFast(_PREHASH_MapNameRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addU32Fast(_PREHASH_Flags, layer); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim msg->nextBlockFast(_PREHASH_NameData); msg->addStringFast(_PREHASH_Name, region_name); gAgent.sendReliableMessage(); } // public void LLWorldMap::sendNamedRegionRequest(std::string region_name, url_callback_t callback, const std::string& callback_url, bool teleport) // immediately teleport when result returned { mSLURLRegionName = region_name; mSLURLRegionHandle = 0; mSLURL = callback_url; mSLURLCallback = callback; mSLURLTeleport = teleport; sendNamedRegionRequest(region_name); } void LLWorldMap::sendHandleRegionRequest(U64 region_handle, url_callback_t callback, const std::string& callback_url, bool teleport) // immediately teleport when result returned { mSLURLRegionName.clear(); mSLURLRegionHandle = region_handle; mSLURL = callback_url; mSLURLCallback = callback; mSLURLTeleport = teleport; U32 global_x; U32 global_y; from_region_handle(region_handle, &global_x, &global_y); U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS); U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS); sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true); } // public void LLWorldMap::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { S32 layer = mCurrentMap; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MapBlockRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); U32 flags = layer; flags |= (return_nonexistent ? 0x10000 : 0); msg->addU32Fast(_PREHASH_Flags, flags); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim msg->nextBlockFast(_PREHASH_PositionData); msg->addU16Fast(_PREHASH_MinX, min_x); msg->addU16Fast(_PREHASH_MinY, min_y); msg->addU16Fast(_PREHASH_MaxX, max_x); msg->addU16Fast(_PREHASH_MaxY, max_y); gAgent.sendReliableMessage(); if (mRequestLandForSale) { msg->newMessageFast(_PREHASH_MapBlockRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->addU32Fast(_PREHASH_Flags, 2); msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim msg->nextBlockFast(_PREHASH_PositionData); msg->addU16Fast(_PREHASH_MinX, min_x); msg->addU16Fast(_PREHASH_MinY, min_y); msg->addU16Fast(_PREHASH_MaxX, max_x); msg->addU16Fast(_PREHASH_MaxY, max_y); gAgent.sendReliableMessage(); } } // public static void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) { llinfos << "LLWorldMap::processMapLayerReply from message system" << llendl; U32 agent_flags; msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); if (agent_flags != (U32)LLWorldMap::getInstance()->mCurrentMap) { llwarns << "Invalid or out of date map image type returned!" << llendl; return; } LLUUID image_id; //U32 left, right, top, bottom; S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_LayerData); LLWorldMap::getInstance()->mMapLayers[agent_flags].clear(); // bool use_web_map_tiles = useWebMapTiles(); BOOL adjust = FALSE; for (S32 block=0; blockgetUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block); U32 left, right, top, bottom; msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Left, left, block); msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Right, right, block); msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Top, top, block); msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Bottom, bottom, block); // if (use_web_map_tiles) // { // new_layer.LayerImage = loadObjectsTile(left, bottom); // no good... Maybe using of level 2 and higher web maps ? // } // else // { new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, MIPMAP_TRUE, LLViewerTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); // } gGL.getTexUnit(0)->bind(new_layer.LayerImage.get()); new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP); new_layer.LayerExtents.mLeft = left; new_layer.LayerExtents.mRight = right; new_layer.LayerExtents.mBottom = bottom; new_layer.LayerExtents.mTop = top; F32 x_meters = F32(left*REGION_WIDTH_UNITS); F32 y_meters = F32(bottom*REGION_WIDTH_UNITS); adjust = LLWorldMap::getInstance()->extendAABB(U32(x_meters), U32(y_meters), U32(x_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getWidth()), U32(y_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getHeight())) || adjust; LLWorldMap::getInstance()->mMapLayers[agent_flags].push_back(new_layer); } LLWorldMap::getInstance()->mMapLoaded[agent_flags] = TRUE; if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); } // public static bool LLWorldMap::useWebMapTiles() { return gSavedSettings.getBOOL("UseWebMapTiles") && (( gHippoGridManager->getConnectedGrid()->isSecondLife() || sGotMapURL) && LLWorldMap::getInstance()->mCurrentMap == 0); } // public static LLPointer LLWorldMap::loadObjectsTile(U32 grid_x, U32 grid_y) { // Get the grid coordinates std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", 1, grid_x, grid_y); LLPointer img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl,TRUE,LLViewerTexture::BOOST_MAP,LLViewerTexture::LOD_TEXTURE); img->setBoostLevel(LLViewerTexture::BOOST_MAP); // Return the smart pointer return img; } // public static void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) { U32 agent_flags; msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); if ((S32)agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES) { llwarns << "Invalid map image type returned! " << agent_flags << llendl; return; } S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); bool found_null_sim = false; #ifdef IMMEDIATE_IMAGE_LOAD bool use_web_map_tiles = useWebMapTiles(); #endif BOOL adjust = FALSE; for (S32 block=0; blockgetU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block); msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block); msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, accesscode, block); msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block); msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block); msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block); msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block); if(msg->getNumberOfBlocksFast(_PREHASH_Size) > 0) { msg->getU16Fast(_PREHASH_Size, _PREHASH_SizeX, x_size, block); msg->getU16Fast(_PREHASH_Size, _PREHASH_SizeY, y_size, block); } if(x_size == 0 || (x_size % 16) != 0|| (y_size % 16) != 0) { x_size = 256; y_size = 256; } U32 x_meters = x_regions * REGION_WIDTH_UNITS; U32 y_meters = y_regions * REGION_WIDTH_UNITS; U64 handle = to_region_handle(x_meters, y_meters); if (accesscode == 255) { // This region doesn't exist if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation && LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters && LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 && LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters && LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256) { // We were tracking this location, but it doesn't exist LLWorldMap::getInstance()->mInvalidLocation = TRUE; } found_null_sim = true; } else { adjust = LLWorldMap::getInstance()->extendAABB(x_meters, y_meters, x_meters+REGION_WIDTH_UNITS, y_meters+REGION_WIDTH_UNITS) || adjust; //LL_INFOS("World Map") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL; // Insert the region in the region map of the world map // Loading the LLSimInfo object with what we got and insert it in the map LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); if (siminfo == NULL) { siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle); } siminfo->setName( name ); siminfo->setAccess( accesscode ); siminfo->setRegionFlags( region_flags ); siminfo->setWaterHeight((F32) water_height); siminfo->setMapImageID( image_id, agent_flags ); siminfo->setSize( x_size, y_size ); #ifdef IMMEDIATE_IMAGE_LOAD if (use_web_map_tiles) { siminfo->mCurrentImage = loadObjectsTile((U32)x_regions, (U32)y_regions); } else { siminfo->mCurrentImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE); } gGL.getTexUnit(0)->bind(siminfo->mCurrentImage.get()); siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP); #endif if (siminfo->mMapImageID[2].notNull()) { #ifdef IMMEDIATE_IMAGE_LOAD siminfo->mOverlayImage = LLViewerTextureManager::getFetchedTextureURL(siminfo->mMapImageID[2]); #endif } else { siminfo->mOverlayImage = NULL; } if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation && LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters && LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 && LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters && LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256) { if (siminfo->isDown()) { // We were tracking this location, but it doesn't exist LLWorldMap::getInstance()->mInvalidLocation = true; } else { // We were tracking this location, and it does exist bool is_tracking_dbl = LLWorldMap::getInstance()->mIsTrackingDoubleClick == TRUE; gFloaterWorldMap->trackLocation(LLWorldMap::getInstance()->mUnknownLocation); if (is_tracking_dbl) { LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); gAgent.teleportViaLocation( pos_global ); } } } } if(LLWorldMap::getInstance()->mSLURLCallback != NULL) { // Server returns definitive capitalization, SLURL might not have that. if ((LLStringUtil::compareInsensitive(LLWorldMap::getInstance()->mSLURLRegionName, name)==0) || (LLWorldMap::getInstance()->mSLURLRegionHandle == handle)) { url_callback_t callback = LLWorldMap::getInstance()->mSLURLCallback; LLWorldMap::getInstance()->mSLURLCallback = NULL; LLWorldMap::getInstance()->mSLURLRegionName.clear(); LLWorldMap::getInstance()->mSLURLRegionHandle = 0; callback(handle, LLWorldMap::getInstance()->mSLURL, image_id, LLWorldMap::getInstance()->mSLURLTeleport); } } if( gAgent.mPendingLure && (U16)(gAgent.mPendingLure->mPosGlobal.mdV[0] / REGION_WIDTH_UNITS) == x_regions && (U16)(gAgent.mPendingLure->mPosGlobal.mdV[1] / REGION_WIDTH_UNITS) == y_regions ) { gAgent.onFoundLureDestination(); } } if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); gFloaterWorldMap->updateSims(found_null_sim); } // public static void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**) { U32 type; msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type); S32 num_blocks = msg->getNumberOfBlocks("Data"); for (S32 block=0; blockgetU32Fast(_PREHASH_Data, _PREHASH_X, X, block); msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block); msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block); msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block); msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block); F32 world_x = (F32)X; X /= REGION_WIDTH_UNITS; F32 world_y = (F32)Y; Y /= REGION_WIDTH_UNITS; LLItemInfo new_item(world_x, world_y, name, uuid, extra, extra2); LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(new_item.getRegionHandle()); switch (type) { case MAP_ITEM_TELEHUB: // telehubs { // Telehub color, store in extra as 4 U8's U8 *color = (U8 *)&new_item.mExtra; F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f; F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f; F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f; F32 add_amt = (X % 2) ? 0.15f : -0.15f; add_amt += (Y % 2) ? -0.15f : 0.15f; color[0] = U8((red + add_amt) * 255); color[1] = U8((green + add_amt) * 255); color[2] = U8((blue + add_amt) * 255); color[3] = 255; // extra2 specifies whether this is an infohub or a telehub. if (extra2) { LLWorldMap::getInstance()->mInfohubs.push_back(new_item); } else { LLWorldMap::getInstance()->mTelehubs.push_back(new_item); } break; } case MAP_ITEM_PG_EVENT: // events case MAP_ITEM_MATURE_EVENT: case MAP_ITEM_ADULT_EVENT: { struct tm* timep; // Convert to Pacific, based on server's opinion of whether // it's daylight savings time there. timep = utc_to_pacific_time(extra, gPacificDaylightTime); S32 display_hour = timep->tm_hour % 12; if (display_hour == 0) display_hour = 12; new_item.setTooltip( llformat( "%d:%02d %s", display_hour, timep->tm_min, (timep->tm_hour < 12 ? "AM" : "PM") ) ); // HACK: store Z in extra2 new_item.setElevation((F64)extra2); if (type == MAP_ITEM_PG_EVENT) { LLWorldMap::getInstance()->mPGEvents.push_back(new_item); } else if (type == MAP_ITEM_MATURE_EVENT) { LLWorldMap::getInstance()->mMatureEvents.push_back(new_item); } else if (type == MAP_ITEM_ADULT_EVENT) { LLWorldMap::getInstance()->mAdultEvents.push_back(new_item); } break; } case MAP_ITEM_LAND_FOR_SALE: // land for sale case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale { new_item.setTooltip(llformat("%d sq. m. %s%d", new_item.mExtra, gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), new_item.mExtra2)); if (type == MAP_ITEM_LAND_FOR_SALE) { LLWorldMap::getInstance()->mLandForSale.push_back(new_item); } else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT) { LLWorldMap::getInstance()->mLandForSaleAdult.push_back(new_item); } break; } case MAP_ITEM_CLASSIFIED: // classifieds { //DEPRECATED: no longer used break; } case MAP_ITEM_AGENT_LOCATIONS: // agent locations { if (!siminfo) { llinfos << "siminfo missing for " << new_item.getGlobalPosition().mdV[0] << ", " << new_item.getGlobalPosition().mdV[1] << llendl; break; } // llinfos << "New Location " << new_item.mName << llendl; item_info_list_t& agentcounts = LLWorldMap::getInstance()->mAgentLocationsMap[new_item.getRegionHandle()]; // Find the last item in the list with a different name and erase them item_info_list_t::iterator lastiter; for (lastiter = agentcounts.begin(); lastiter!=agentcounts.end(); ++lastiter) { const LLItemInfo& info = *lastiter; if (info.isName(new_item.getName())) { break; } } if (lastiter != agentcounts.begin()) { agentcounts.erase(agentcounts.begin(), lastiter); } // Now append the new location if (new_item.mExtra > 0) { agentcounts.push_back(new_item); } break; } default: break; }; } } void LLWorldMap::dump() { for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { U64 handle = (*it).first; LLSimInfo* info = (*it).second; U32 x_pos, y_pos; from_region_handle(handle, &x_pos, &y_pos); llinfos << x_pos << "," << y_pos << " " << info->getName() << " " << (S32)info->getAccess() << " " << std::hex << info->getRegionFlags() << std::dec << " " << info->getWaterHeight() //<< " " << info->mTelehubName //<< " " << info->mTelehubPosition << llendl; if (info->mCurrentImage) { llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel() << " fullwidth " << info->mCurrentImage->getWidth(0) << " fullheight " << info->mCurrentImage->getHeight(0) << " maxvirt " << info->mCurrentImage->getMaxVirtualSize() << " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel() << llendl; } } } BOOL LLWorldMap::extendAABB(U32 min_x, U32 min_y, U32 max_x, U32 max_y) { BOOL rv = FALSE; if (min_x < mMinX) { rv = TRUE; mMinX = min_x; } if (min_y < mMinY) { rv = TRUE; mMinY = min_y; } if (max_x > mMaxX) { rv = TRUE; mMaxX = max_x; } if (max_y > mMaxY) { rv = TRUE; mMaxY = max_y; } lldebugs << "World map aabb: (" << mMinX << ", " << mMinY << "), (" << mMaxX << ", " << mMaxY << ")" << llendl; return rv; } U32 LLWorldMap::getWorldWidth() const { return mMaxX - mMinX; } U32 LLWorldMap::getWorldHeight() const { return mMaxY - mMinY; } BOOL LLWorldMap::coveredByTelehub(LLSimInfo* infop) { /*if (!mTelehubCoverageMap) { return FALSE; } U32 x_pos, y_pos; from_region_handle(infop->mHandle, &x_pos, &y_pos); x_pos /= REGION_WIDTH_UNITS; y_pos /= REGION_WIDTH_UNITS; S32 index = x_pos - (mMinX / REGION_WIDTH_UNITS - 1) + (mNeighborMapWidth * (y_pos - (mMinY / REGION_WIDTH_UNITS - 1))); return mTelehubCoverageMap[index] != 0; */ return FALSE; } void LLWorldMap::updateTelehubCoverage() { /*S32 neighbor_width = getWorldWidth() / REGION_WIDTH_UNITS + 2; S32 neighbor_height = getWorldHeight() / REGION_WIDTH_UNITS + 2; if (neighbor_width > mNeighborMapWidth || neighbor_height > mNeighborMapHeight) { mNeighborMapWidth = neighbor_width; mNeighborMapHeight = neighbor_height; delete mNeighborMap; delete mTelehubCoverageMap; mNeighborMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; mTelehubCoverageMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; } memset(mNeighborMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); memset(mTelehubCoverageMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); // leave 1 sim border S32 min_x = (mMinX / REGION_WIDTH_UNITS) - 1; S32 min_y = (mMinY / REGION_WIDTH_UNITS) - 1; std::map::const_iterator it; for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { U64 handle = (*it).first; //LLSimInfo* info = (*it).second; U32 x_pos, y_pos; from_region_handle(handle, &x_pos, &y_pos); x_pos /= REGION_WIDTH_UNITS; y_pos /= REGION_WIDTH_UNITS; x_pos -= min_x; y_pos -= min_y; S32 index = x_pos + (mNeighborMapWidth * y_pos); mNeighborMap[index - 1]++; mNeighborMap[index + 1]++; mNeighborMap[index - mNeighborMapWidth]++; mNeighborMap[index + mNeighborMapWidth]++; } for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { U64 handle = (*it).first; LLSimInfo* info = (*it).second; U32 x_pos, y_pos; from_region_handle(handle, &x_pos, &y_pos); x_pos /= REGION_WIDTH_UNITS; y_pos /= REGION_WIDTH_UNITS; x_pos -= min_x; y_pos -= min_y; S32 index = x_pos + (mNeighborMapWidth * y_pos); if (!info->mTelehubName.empty() && mNeighborMap[index]) { S32 x_start = llmax(0, S32(x_pos - 5)); S32 x_span = llmin(mNeighborMapWidth - 1, (S32)(x_pos + 5)) - x_start + 1; S32 y_start = llmax(0, (S32)y_pos - 5); S32 y_end = llmin(mNeighborMapHeight - 1, (S32)(y_pos + 5)); for (S32 y_index = y_start; y_index <= y_end; y_index++) { memset(&mTelehubCoverageMap[x_start + y_index * mNeighborMapWidth], 0xff, sizeof(U8) * x_span); } } } for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { U64 handle = (*it).first; //LLSimInfo* info = (*it).second; U32 x_pos, y_pos; from_region_handle(handle, &x_pos, &y_pos); x_pos /= REGION_WIDTH_UNITS; y_pos /= REGION_WIDTH_UNITS; S32 index = x_pos - min_x + (mNeighborMapWidth * (y_pos - min_y)); mTelehubCoverageMap[index] *= mNeighborMap[index]; }*/ } // Drop priority of all images being fetched by the map void LLWorldMap::dropImagePriorities() { // Drop the download of tiles priority to nil mWorldMipmap.dropBoostLevels(); // Same for the "land for sale" tiles per region for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { LLSimInfo* info = it->second; info->dropImagePriority(); } } LLPointer LLSimInfo::getLandForSaleImage () { if (mOverlayImage.isNull() && mMapImageID[2].notNull()) { // Fetch the image if it hasn't been done yet (unlikely but...) mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID[2], MIPMAP_TRUE, LLViewerTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP); } if (!mOverlayImage.isNull()) { // Boost the fetch level when we try to access that image mOverlayImage->setBoostLevel(LLViewerTexture::BOOST_MAP); } return mOverlayImage; }