phoenix-firestorm/indra/llinventory/lllandmark.cpp

323 lines
8.9 KiB
C++

/**
* @file lllandmark.cpp
* @brief Landmark asset class
*
* $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 "linden_common.h"
#include "lllandmark.h"
#include <errno.h>
#include "message.h"
#include "llregionhandle.h"
std::pair<LLUUID, U64> LLLandmark::mLocalRegion;
LLLandmark::region_map_t LLLandmark::mRegions;
LLLandmark::region_callback_map_t LLLandmark::sRegionCallbackMap;
LLLandmark::LLLandmark() :
mGlobalPositionKnown(false)
{
}
LLLandmark::LLLandmark(const LLVector3d& pos) :
mGlobalPositionKnown(true),
mGlobalPos( pos )
{
}
bool LLLandmark::getGlobalPos(LLVector3d& pos)
{
if(mGlobalPositionKnown)
{
pos = mGlobalPos;
}
else if(mRegionID.notNull())
{
F32 g_x = -1.0;
F32 g_y = -1.0;
if(mRegionID == mLocalRegion.first)
{
from_region_handle(mLocalRegion.second, &g_x, &g_y);
}
else
{
region_map_t::iterator it = mRegions.find(mRegionID);
if(it != mRegions.end())
{
from_region_handle((*it).second.mRegionHandle, &g_x, &g_y);
}
}
if((g_x > 0.f) && (g_y > 0.f))
{
pos.mdV[0] = g_x + mRegionPos.mV[0];
pos.mdV[1] = g_y + mRegionPos.mV[1];
pos.mdV[2] = mRegionPos.mV[2];
setGlobalPos(pos);
}
}
return mGlobalPositionKnown;
}
void LLLandmark::setGlobalPos(const LLVector3d& pos)
{
mGlobalPos = pos;
mGlobalPositionKnown = true;
}
bool LLLandmark::getRegionID(LLUUID& region_id)
{
if(mRegionID.notNull())
{
region_id = mRegionID;
return true;
}
return false;
}
LLVector3 LLLandmark::getRegionPos() const
{
return mRegionPos;
}
// static
LLLandmark* LLLandmark::constructFromString(const char *buffer, const S32 buffer_size)
{
S32 chars_read = 0;
S32 chars_read_total = 0;
S32 count = 0;
U32 version = 0;
bool bad_block = false;
LLLandmark* result = NULL;
// read version
count = sscanf( buffer, "Landmark version %u\n%n", &version, &chars_read );
chars_read_total += chars_read;
if (count != 1
|| chars_read_total >= buffer_size)
{
bad_block = true;
}
if (!bad_block)
{
switch (version)
{
case 1:
{
LLVector3d pos;
// read position
count = sscanf(buffer + chars_read_total, "position %lf %lf %lf\n%n", pos.mdV + VX, pos.mdV + VY, pos.mdV + VZ, &chars_read);
if (count != 3)
{
bad_block = true;
}
else
{
LL_DEBUGS("Landmark") << "Landmark read: " << pos << LL_ENDL;
result = new LLLandmark(pos);
}
break;
}
case 2:
{
// *NOTE: Changing the buffer size will require changing the
// scanf call below.
char region_id_str[MAX_STRING];
LLVector3 pos;
LLUUID region_id;
count = sscanf( buffer + chars_read_total,
"region_id %254s\n%n",
region_id_str,
&chars_read);
chars_read_total += chars_read;
if (count != 1
|| chars_read_total >= buffer_size
|| !LLUUID::validate(region_id_str))
{
bad_block = true;
}
if (!bad_block)
{
region_id.set(region_id_str);
if (region_id.isNull())
{
bad_block = true;
}
}
if (!bad_block)
{
count = sscanf(buffer + chars_read_total, "local_pos %f %f %f\n%n", pos.mV + VX, pos.mV + VY, pos.mV + VZ, &chars_read);
if (count != 3)
{
bad_block = true;
}
else
{
result = new LLLandmark;
result->mRegionID = region_id;
result->mRegionPos = pos;
}
}
break;
}
default:
{
LL_INFOS("Landmark") << "Encountered Unknown landmark version " << version << LL_ENDL;
break;
}
}
}
if (bad_block)
{
LL_INFOS("Landmark") << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL;
}
return result;
}
// static
void LLLandmark::registerCallbacks(LLMessageSystem* msg)
{
msg->setHandlerFunc("RegionIDAndHandleReply", &processRegionIDAndHandle);
}
// static
void LLLandmark::requestRegionHandle(
LLMessageSystem* msg,
const LLHost& upstream_host,
const LLUUID& region_id,
region_handle_callback_t callback)
{
if(region_id.isNull())
{
// don't bother with checking - it's 0.
LL_DEBUGS("Landmark") << "requestRegionHandle: null" << LL_ENDL;
if(callback)
{
const U64 U64_ZERO = 0;
callback(region_id, U64_ZERO);
}
}
else
{
if(region_id == mLocalRegion.first)
{
LL_DEBUGS("Landmark") << "requestRegionHandle: local" << LL_ENDL;
if(callback)
{
callback(region_id, mLocalRegion.second);
}
}
else
{
region_map_t::iterator it = mRegions.find(region_id);
if(it == mRegions.end())
{
LL_DEBUGS("Landmark") << "requestRegionHandle: upstream" << LL_ENDL;
if(callback)
{
region_callback_map_t::value_type vt(region_id, callback);
sRegionCallbackMap.insert(vt);
}
LL_DEBUGS("Landmark") << "Landmark requesting information about: "
<< region_id << LL_ENDL;
msg->newMessage("RegionHandleRequest");
msg->nextBlock("RequestBlock");
msg->addUUID("RegionID", region_id);
msg->sendReliable(upstream_host);
}
else if(callback)
{
// we have the answer locally - just call the callack.
LL_DEBUGS("Landmark") << "requestRegionHandle: ready" << LL_ENDL;
callback(region_id, (*it).second.mRegionHandle);
}
}
}
// As good a place as any to expire old entries.
expireOldEntries();
}
// static
void LLLandmark::setRegionHandle(const LLUUID& region_id, U64 region_handle)
{
mLocalRegion.first = region_id;
mLocalRegion.second = region_handle;
}
// static
void LLLandmark::processRegionIDAndHandle(LLMessageSystem* msg, void**)
{
LLUUID region_id;
msg->getUUID("ReplyBlock", "RegionID", region_id);
mRegions.erase(region_id);
CacheInfo info;
const F32 CACHE_EXPIRY_SECONDS = 60.0f * 10.0f; // ten minutes
info.mTimer.setTimerExpirySec(CACHE_EXPIRY_SECONDS);
msg->getU64("ReplyBlock", "RegionHandle", info.mRegionHandle);
region_map_t::value_type vt(region_id, info);
mRegions.insert(vt);
#if LL_DEBUG
U32 grid_x, grid_y;
grid_from_region_handle(info.mRegionHandle, &grid_x, &grid_y);
LL_DEBUGS() << "Landmark got reply for region: " << region_id << " "
<< grid_x << "," << grid_y << LL_ENDL;
#endif
// make all the callbacks here.
region_callback_map_t::iterator it;
while((it = sRegionCallbackMap.find(region_id)) != sRegionCallbackMap.end())
{
(*it).second(region_id, info.mRegionHandle);
sRegionCallbackMap.erase(it);
}
}
// static
void LLLandmark::expireOldEntries()
{
for(region_map_t::iterator it = mRegions.begin(); it != mRegions.end(); )
{
if((*it).second.mTimer.hasExpired())
{
mRegions.erase(it++);
}
else
{
++it;
}
}
}