PageRenderTime 22ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llinventory/lllandmark.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 278 lines | 212 code | 26 blank | 40 comment | 37 complexity | 92b1bdfc2ffd369524d9aeec47382b1d MD5 | raw file
  1/** 
  2 * @file lllandmark.cpp
  3 * @brief Landmark asset class
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "lllandmark.h"
 29
 30#include <errno.h>
 31
 32#include "message.h"
 33#include "llregionhandle.h"
 34
 35std::pair<LLUUID, U64> LLLandmark::mLocalRegion;
 36LLLandmark::region_map_t LLLandmark::mRegions;
 37LLLandmark::region_callback_map_t LLLandmark::sRegionCallbackMap;
 38
 39LLLandmark::LLLandmark() :
 40	mGlobalPositionKnown(false)
 41{
 42}
 43
 44LLLandmark::LLLandmark(const LLVector3d& pos) :
 45	mGlobalPositionKnown(true),
 46	mGlobalPos( pos )
 47{
 48}
 49
 50bool LLLandmark::getGlobalPos(LLVector3d& pos)
 51{
 52	if(mGlobalPositionKnown)
 53	{
 54		pos = mGlobalPos;
 55	}
 56	else if(mRegionID.notNull())
 57	{
 58		F32 g_x = -1.0;
 59		F32 g_y = -1.0;
 60		if(mRegionID == mLocalRegion.first)
 61		{
 62			from_region_handle(mLocalRegion.second, &g_x, &g_y);
 63		}
 64		else
 65		{
 66			region_map_t::iterator it = mRegions.find(mRegionID);
 67			if(it != mRegions.end())
 68			{
 69				from_region_handle((*it).second.mRegionHandle, &g_x, &g_y);
 70			}
 71		}
 72		if((g_x > 0.f) && (g_y > 0.f))
 73		{
 74			pos.mdV[0] = g_x + mRegionPos.mV[0];
 75			pos.mdV[1] = g_y + mRegionPos.mV[1];
 76			pos.mdV[2] = mRegionPos.mV[2];
 77			setGlobalPos(pos);
 78		}
 79	}
 80	return mGlobalPositionKnown;
 81}
 82
 83void LLLandmark::setGlobalPos(const LLVector3d& pos)
 84{
 85	mGlobalPos = pos;
 86	mGlobalPositionKnown = true;
 87}
 88
 89bool LLLandmark::getRegionID(LLUUID& region_id)
 90{
 91	if(mRegionID.notNull())
 92	{
 93		region_id = mRegionID;
 94		return true;
 95	}
 96	return false;
 97}
 98
 99LLVector3 LLLandmark::getRegionPos() const
100{
101	return mRegionPos;
102}
103
104
105// static
106LLLandmark* LLLandmark::constructFromString(const char *buffer)
107{
108	const char* cur = buffer;
109	S32 chars_read = 0;
110	S32 count = 0;
111	U32 version = 0;
112
113	// read version 
114	count = sscanf( cur, "Landmark version %u\n%n", &version, &chars_read );
115	if(count != 1)
116	{
117		goto error;
118	}
119
120	if(version == 1)
121	{
122		LLVector3d pos;
123		cur += chars_read;
124		// read position
125		count = sscanf( cur, "position %lf %lf %lf\n%n", pos.mdV+VX, pos.mdV+VY, pos.mdV+VZ, &chars_read );
126		if( count != 3 )
127		{
128			goto error;
129		}
130		cur += chars_read;
131		// llinfos << "Landmark read: " << pos << llendl;
132		
133		return new LLLandmark(pos);
134	}
135	else if(version == 2)
136	{
137		// *NOTE: Changing the buffer size will require changing the
138		// scanf call below.
139		char region_id_str[MAX_STRING];	/* Flawfinder: ignore */
140		LLVector3 pos;
141		cur += chars_read;
142		count = sscanf(	/* Flawfinder: ignore */
143			cur,
144			"region_id %254s\n%n",
145			region_id_str, &chars_read);
146		if(count != 1) goto error;
147		cur += chars_read;
148		count = sscanf(cur, "local_pos %f %f %f\n%n", pos.mV+VX, pos.mV+VY, pos.mV+VZ, &chars_read);
149		if(count != 3) goto error;
150		cur += chars_read;
151		LLLandmark* lm = new LLLandmark;
152		lm->mRegionID.set(region_id_str);
153		lm->mRegionPos = pos;
154		return lm;
155	}
156
157 error:
158	llinfos << "Bad Landmark Asset: bad _DATA_ block." << llendl;
159	return NULL;
160}
161
162
163// static
164void LLLandmark::registerCallbacks(LLMessageSystem* msg)
165{
166	msg->setHandlerFunc("RegionIDAndHandleReply", &processRegionIDAndHandle);
167}
168
169// static
170void LLLandmark::requestRegionHandle(
171	LLMessageSystem* msg,
172	const LLHost& upstream_host,
173	const LLUUID& region_id,
174	region_handle_callback_t callback)
175{
176	if(region_id.isNull())
177	{
178		// don't bother with checking - it's 0.
179		lldebugs << "requestRegionHandle: null" << llendl;
180		if(callback)
181		{
182			const U64 U64_ZERO = 0;
183			callback(region_id, U64_ZERO);
184		}
185	}
186	else
187	{
188		if(region_id == mLocalRegion.first)
189		{
190			lldebugs << "requestRegionHandle: local" << llendl;
191			if(callback)
192			{
193				callback(region_id, mLocalRegion.second);
194			}
195		}
196		else
197		{
198			region_map_t::iterator it = mRegions.find(region_id);
199			if(it == mRegions.end())
200			{
201				lldebugs << "requestRegionHandle: upstream" << llendl;
202				if(callback)
203				{
204					region_callback_map_t::value_type vt(region_id, callback);
205					sRegionCallbackMap.insert(vt);
206				}
207				lldebugs << "Landmark requesting information about: "
208						 << region_id << llendl;
209				msg->newMessage("RegionHandleRequest");
210				msg->nextBlock("RequestBlock");
211				msg->addUUID("RegionID", region_id);
212				msg->sendReliable(upstream_host);
213			}
214			else if(callback)
215			{
216				// we have the answer locally - just call the callack.
217				lldebugs << "requestRegionHandle: ready" << llendl;
218				callback(region_id, (*it).second.mRegionHandle);
219			}
220		}
221	}
222
223	// As good a place as any to expire old entries.
224	expireOldEntries();
225}
226
227// static
228void LLLandmark::setRegionHandle(const LLUUID& region_id, U64 region_handle)
229{
230	mLocalRegion.first = region_id;
231	mLocalRegion.second = region_handle;
232}
233
234
235// static
236void LLLandmark::processRegionIDAndHandle(LLMessageSystem* msg, void**)
237{
238	LLUUID region_id;
239	msg->getUUID("ReplyBlock", "RegionID", region_id);
240	mRegions.erase(region_id);
241	CacheInfo info;
242	const F32 CACHE_EXPIRY_SECONDS = 60.0f * 10.0f; // ten minutes
243	info.mTimer.setTimerExpirySec(CACHE_EXPIRY_SECONDS);
244	msg->getU64("ReplyBlock", "RegionHandle", info.mRegionHandle);
245	region_map_t::value_type vt(region_id, info);
246	mRegions.insert(vt);
247
248#if LL_DEBUG
249	U32 grid_x, grid_y;
250	grid_from_region_handle(info.mRegionHandle, &grid_x, &grid_y);
251	lldebugs << "Landmark got reply for region: " << region_id << " "
252			 << grid_x << "," << grid_y << llendl;
253#endif
254
255	// make all the callbacks here.
256	region_callback_map_t::iterator it;
257	while((it = sRegionCallbackMap.find(region_id)) != sRegionCallbackMap.end())
258	{
259		(*it).second(region_id, info.mRegionHandle);
260		sRegionCallbackMap.erase(it);
261	}
262}
263
264// static
265void LLLandmark::expireOldEntries()
266{
267	for(region_map_t::iterator it = mRegions.begin(); it != mRegions.end(); )
268	{
269		if((*it).second.mTimer.hasExpired())
270		{
271			mRegions.erase(it++);
272		}
273		else
274		{
275			++it;
276		}
277	}
278}