diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llworldmap.cpp | 934 |
1 files changed, 934 insertions, 0 deletions
diff --git a/linden/indra/newview/llworldmap.cpp b/linden/indra/newview/llworldmap.cpp new file mode 100644 index 0000000..6e010f7 --- /dev/null +++ b/linden/indra/newview/llworldmap.cpp | |||
@@ -0,0 +1,934 @@ | |||
1 | /** | ||
2 | * @file llworldmap.cpp | ||
3 | * @brief Underlying data representation for map of the world | ||
4 | * | ||
5 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llworldmap.h" | ||
31 | |||
32 | #include "llregionhandle.h" | ||
33 | #include "message.h" | ||
34 | |||
35 | #include "viewer.h" // for gPacificDaylightTime | ||
36 | #include "llagent.h" | ||
37 | #include "llmapresponders.h" | ||
38 | #include "llviewercontrol.h" | ||
39 | #include "llfloaterworldmap.h" | ||
40 | #include "lltracker.h" | ||
41 | #include "llviewerimagelist.h" | ||
42 | #include "llviewerregion.h" | ||
43 | #include "llregionflags.h" | ||
44 | |||
45 | LLWorldMap* gWorldMap = NULL; | ||
46 | |||
47 | const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes | ||
48 | |||
49 | LLItemInfo::LLItemInfo(F32 global_x, F32 global_y, | ||
50 | const std::string& name, | ||
51 | LLUUID id, | ||
52 | S32 extra, S32 extra2) | ||
53 | : mName(name), | ||
54 | mToolTip(""), | ||
55 | mPosGlobal(global_x, global_y, 40.0), | ||
56 | mID(id), | ||
57 | mSelected(FALSE), | ||
58 | mExtra(extra), | ||
59 | mExtra2(extra2) | ||
60 | { | ||
61 | mRegionHandle = to_region_handle(mPosGlobal); | ||
62 | } | ||
63 | |||
64 | LLSimInfo::LLSimInfo() | ||
65 | : mHandle(0), | ||
66 | mName(), | ||
67 | mAgentsUpdateTime(0), | ||
68 | mAccess(0x0), | ||
69 | mRegionFlags(0x0), | ||
70 | mWaterHeight(0.f), | ||
71 | mAlpha(-1.f) | ||
72 | { | ||
73 | } | ||
74 | |||
75 | |||
76 | LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const | ||
77 | { | ||
78 | LLVector3d pos = from_region_handle(mHandle); | ||
79 | pos.mdV[VX] += local_pos.mV[VX]; | ||
80 | pos.mdV[VY] += local_pos.mV[VY]; | ||
81 | pos.mdV[VZ] += local_pos.mV[VZ]; | ||
82 | return pos; | ||
83 | } | ||
84 | |||
85 | |||
86 | //--------------------------------------------------------------------------- | ||
87 | // World Map | ||
88 | //--------------------------------------------------------------------------- | ||
89 | |||
90 | LLWorldMap::LLWorldMap() : | ||
91 | mIsTrackingUnknownLocation( FALSE ), | ||
92 | mInvalidLocation( FALSE ), | ||
93 | mIsTrackingDoubleClick( FALSE ), | ||
94 | mIsTrackingCommit( FALSE ), | ||
95 | mUnknownLocation( 0, 0, 0 ), | ||
96 | mRequestLandForSale(true), | ||
97 | mCurrentMap(0), | ||
98 | mMinX(U32_MAX), | ||
99 | mMaxX(U32_MIN), | ||
100 | mMinY(U32_MAX), | ||
101 | mMaxY(U32_MIN), | ||
102 | mNeighborMap(NULL), | ||
103 | mTelehubCoverageMap(NULL), | ||
104 | mNeighborMapWidth(0), | ||
105 | mNeighborMapHeight(0) | ||
106 | { | ||
107 | for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map) | ||
108 | { | ||
109 | mMapLoaded[map] = FALSE; | ||
110 | mMapBlockLoaded[map] = new BOOL[MAP_BLOCK_RES*MAP_BLOCK_RES]; | ||
111 | for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx) | ||
112 | { | ||
113 | mMapBlockLoaded[map][idx] = FALSE; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | |||
119 | LLWorldMap::~LLWorldMap() | ||
120 | { | ||
121 | reset(); | ||
122 | for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map) | ||
123 | { | ||
124 | delete[] mMapBlockLoaded[map]; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | |||
129 | void LLWorldMap::reset() | ||
130 | { | ||
131 | for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer()); | ||
132 | mSimInfoMap.clear(); | ||
133 | |||
134 | for (S32 m=0; m<MAP_SIM_IMAGE_TYPES; ++m) | ||
135 | { | ||
136 | mMapLoaded[m] = FALSE; | ||
137 | } | ||
138 | |||
139 | clearSimFlags(); | ||
140 | |||
141 | eraseItems(); | ||
142 | |||
143 | mMinX = U32_MAX; | ||
144 | mMaxX = U32_MIN; | ||
145 | |||
146 | mMinY = U32_MAX; | ||
147 | mMaxY = U32_MIN; | ||
148 | |||
149 | delete [] mNeighborMap; | ||
150 | mNeighborMap = NULL; | ||
151 | delete [] mTelehubCoverageMap; | ||
152 | mTelehubCoverageMap = NULL; | ||
153 | |||
154 | mNeighborMapWidth = 0; | ||
155 | mNeighborMapHeight = 0; | ||
156 | } | ||
157 | |||
158 | void LLWorldMap::eraseItems() | ||
159 | { | ||
160 | if (mRequestTimer.getElapsedTimeF32() > REQUEST_ITEMS_TIMER) | ||
161 | { | ||
162 | mRequestTimer.reset(); | ||
163 | |||
164 | mTelehubs.clear(); | ||
165 | mInfohubs.clear(); | ||
166 | mPGEvents.clear(); | ||
167 | mMatureEvents.clear(); | ||
168 | mPopular.clear(); | ||
169 | mLandForSale.clear(); | ||
170 | mClassifieds.clear(); | ||
171 | } | ||
172 | // mAgentLocationsMap.clear(); // persists | ||
173 | // mNumAgents.clear(); // persists | ||
174 | } | ||
175 | |||
176 | |||
177 | void LLWorldMap::clearImageRefs() | ||
178 | { | ||
179 | for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
180 | { | ||
181 | LLSimInfo* info = (*it).second; | ||
182 | if (info->mCurrentImage) | ||
183 | { | ||
184 | info->mCurrentImage->setBoostLevel(0); | ||
185 | info->mCurrentImage = NULL; | ||
186 | } | ||
187 | if (info->mOverlayImage) | ||
188 | { | ||
189 | info->mOverlayImage->setBoostLevel(0); | ||
190 | info->mOverlayImage = NULL; | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | // Doesn't clear the already-loaded sim infos, just re-requests them | ||
196 | void LLWorldMap::clearSimFlags() | ||
197 | { | ||
198 | for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map) | ||
199 | { | ||
200 | for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx) | ||
201 | { | ||
202 | mMapBlockLoaded[map][idx] = FALSE; | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | |||
207 | LLSimInfo* LLWorldMap::simInfoFromPosGlobal(const LLVector3d& pos_global) | ||
208 | { | ||
209 | U64 handle = to_region_handle(pos_global); | ||
210 | return simInfoFromHandle(handle); | ||
211 | } | ||
212 | |||
213 | LLSimInfo* LLWorldMap::simInfoFromHandle(const U64 handle) | ||
214 | { | ||
215 | sim_info_map_t::iterator it = mSimInfoMap.find(handle); | ||
216 | if (it != mSimInfoMap.end()) | ||
217 | { | ||
218 | LLSimInfo* sim_info = (*it).second; | ||
219 | if (sim_info) | ||
220 | { | ||
221 | return sim_info; | ||
222 | } | ||
223 | } | ||
224 | return NULL; | ||
225 | } | ||
226 | |||
227 | |||
228 | LLSimInfo* LLWorldMap::simInfoFromName(const LLString& sim_name) | ||
229 | { | ||
230 | LLSimInfo* sim_info = NULL; | ||
231 | if (!sim_name.empty()) | ||
232 | { | ||
233 | for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
234 | { | ||
235 | sim_info = (*it).second; | ||
236 | if (sim_info | ||
237 | && (0 == LLString::compareInsensitive(sim_name.c_str(), sim_info->mName.c_str())) ) | ||
238 | { | ||
239 | break; | ||
240 | } | ||
241 | sim_info = NULL; | ||
242 | } | ||
243 | } | ||
244 | return sim_info; | ||
245 | } | ||
246 | |||
247 | LLString LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global) | ||
248 | { | ||
249 | U64 handle = to_region_handle(pos_global); | ||
250 | |||
251 | sim_info_map_t::iterator it = mSimInfoMap.find(handle); | ||
252 | if (it != mSimInfoMap.end()) | ||
253 | { | ||
254 | LLSimInfo* info = (*it).second; | ||
255 | return info->mName.c_str(); | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | return "(unknown region)"; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | void LLWorldMap::setCurrentLayer(S32 layer, bool request_layer) | ||
264 | { | ||
265 | mCurrentMap = layer; | ||
266 | if (!mMapLoaded[layer] || request_layer) | ||
267 | { | ||
268 | sendMapLayerRequest(); | ||
269 | sendItemRequest(MAP_ITEM_AGENT_COUNT); | ||
270 | } | ||
271 | |||
272 | if (mTelehubs.size() == 0 || | ||
273 | mInfohubs.size() == 0) | ||
274 | { | ||
275 | // Request for telehubs | ||
276 | sendItemRequest(MAP_ITEM_TELEHUB); | ||
277 | } | ||
278 | |||
279 | if (mPGEvents.size() == 0) | ||
280 | { | ||
281 | // Request for events | ||
282 | sendItemRequest(MAP_ITEM_PG_EVENT); | ||
283 | } | ||
284 | |||
285 | if (mMatureEvents.size() == 0) | ||
286 | { | ||
287 | // Request for events (mature) | ||
288 | sendItemRequest(MAP_ITEM_MATURE_EVENT); | ||
289 | } | ||
290 | |||
291 | if (mPopular.size() == 0) | ||
292 | { | ||
293 | // Request for popular | ||
294 | sendItemRequest(MAP_ITEM_POPULAR); | ||
295 | } | ||
296 | |||
297 | if (mLandForSale.size() == 0) | ||
298 | { | ||
299 | // Request for Land For Sale | ||
300 | sendItemRequest(MAP_ITEM_LAND_FOR_SALE); | ||
301 | } | ||
302 | |||
303 | if (mClassifieds.size() == 0) | ||
304 | { | ||
305 | sendItemRequest(MAP_ITEM_CLASSIFIED); | ||
306 | } | ||
307 | |||
308 | clearImageRefs(); | ||
309 | clearSimFlags(); | ||
310 | } | ||
311 | |||
312 | void LLWorldMap::sendItemRequest(U32 type, U64 handle) | ||
313 | { | ||
314 | LLMessageSystem* msg = gMessageSystem; | ||
315 | S32 layer = mCurrentMap; | ||
316 | |||
317 | msg->newMessageFast(_PREHASH_MapItemRequest); | ||
318 | msg->nextBlockFast(_PREHASH_AgentData); | ||
319 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
320 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
321 | msg->addU32Fast(_PREHASH_Flags, layer); | ||
322 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
323 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
324 | |||
325 | msg->nextBlockFast(_PREHASH_RequestData); | ||
326 | msg->addU32Fast(_PREHASH_ItemType, type); | ||
327 | msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim | ||
328 | |||
329 | gAgent.sendReliableMessage(); | ||
330 | } | ||
331 | |||
332 | // public | ||
333 | void LLWorldMap::sendMapLayerRequest() | ||
334 | { | ||
335 | LLSD body; | ||
336 | body["Flags"] = mCurrentMap; | ||
337 | std::string url = gAgent.getRegion()->getCapability( | ||
338 | gAgent.isGodlike() ? "MapLayerGod" : "MapLayer"); | ||
339 | |||
340 | if (!url.empty()) | ||
341 | { | ||
342 | llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; | ||
343 | LLHTTPClient::post(url, body, new LLMapLayerResponder()); | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | llinfos << "LLWorldMap::sendMapLayerRequest via message system" << llendl; | ||
348 | LLMessageSystem* msg = gMessageSystem; | ||
349 | S32 layer = mCurrentMap; | ||
350 | |||
351 | // Request for layer | ||
352 | msg->newMessageFast(_PREHASH_MapLayerRequest); | ||
353 | msg->nextBlockFast(_PREHASH_AgentData); | ||
354 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
355 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
356 | msg->addU32Fast(_PREHASH_Flags, layer); | ||
357 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
358 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
359 | gAgent.sendReliableMessage(); | ||
360 | |||
361 | if (mRequestLandForSale) | ||
362 | { | ||
363 | msg->newMessageFast(_PREHASH_MapLayerRequest); | ||
364 | msg->nextBlockFast(_PREHASH_AgentData); | ||
365 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
366 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
367 | msg->addU32Fast(_PREHASH_Flags, 2); | ||
368 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
369 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
370 | gAgent.sendReliableMessage(); | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | |||
375 | // public | ||
376 | void LLWorldMap::sendNamedRegionRequest(std::string region_name) | ||
377 | { | ||
378 | LLMessageSystem* msg = gMessageSystem; | ||
379 | S32 layer = mCurrentMap; | ||
380 | |||
381 | // Request for layer | ||
382 | msg->newMessageFast(_PREHASH_MapNameRequest); | ||
383 | msg->nextBlockFast(_PREHASH_AgentData); | ||
384 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
385 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
386 | msg->addU32Fast(_PREHASH_Flags, layer); | ||
387 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
388 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
389 | msg->nextBlockFast(_PREHASH_NameData); | ||
390 | msg->addStringFast(_PREHASH_Name, region_name); | ||
391 | gAgent.sendReliableMessage(); | ||
392 | } | ||
393 | |||
394 | // public | ||
395 | void LLWorldMap::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) | ||
396 | { | ||
397 | S32 layer = mCurrentMap; | ||
398 | LLMessageSystem* msg = gMessageSystem; | ||
399 | msg->newMessageFast(_PREHASH_MapBlockRequest); | ||
400 | msg->nextBlockFast(_PREHASH_AgentData); | ||
401 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
402 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
403 | U32 flags = layer; | ||
404 | flags |= (return_nonexistent ? 0x10000 : 0); | ||
405 | msg->addU32Fast(_PREHASH_Flags, flags); | ||
406 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
407 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
408 | msg->nextBlockFast(_PREHASH_PositionData); | ||
409 | msg->addU16Fast(_PREHASH_MinX, min_x); | ||
410 | msg->addU16Fast(_PREHASH_MinY, min_y); | ||
411 | msg->addU16Fast(_PREHASH_MaxX, max_x); | ||
412 | msg->addU16Fast(_PREHASH_MaxY, max_y); | ||
413 | gAgent.sendReliableMessage(); | ||
414 | |||
415 | if (mRequestLandForSale) | ||
416 | { | ||
417 | msg->newMessageFast(_PREHASH_MapBlockRequest); | ||
418 | msg->nextBlockFast(_PREHASH_AgentData); | ||
419 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
420 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
421 | msg->addU32Fast(_PREHASH_Flags, 2); | ||
422 | msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim | ||
423 | msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim | ||
424 | msg->nextBlockFast(_PREHASH_PositionData); | ||
425 | msg->addU16Fast(_PREHASH_MinX, min_x); | ||
426 | msg->addU16Fast(_PREHASH_MinY, min_y); | ||
427 | msg->addU16Fast(_PREHASH_MaxX, max_x); | ||
428 | msg->addU16Fast(_PREHASH_MaxY, max_y); | ||
429 | gAgent.sendReliableMessage(); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | // public static | ||
434 | void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) | ||
435 | { | ||
436 | llinfos << "LLWorldMap::processMapLayerReply from message system" << llendl; | ||
437 | |||
438 | U32 agent_flags; | ||
439 | msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); | ||
440 | |||
441 | if (agent_flags != (U32)gWorldMap->mCurrentMap) | ||
442 | { | ||
443 | llwarns << "Invalid or out of date map image type returned!" << llendl; | ||
444 | return; | ||
445 | } | ||
446 | |||
447 | LLUUID image_id; | ||
448 | //U32 left, right, top, bottom; | ||
449 | |||
450 | S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_LayerData); | ||
451 | |||
452 | gWorldMap->mMapLayers[agent_flags].clear(); | ||
453 | |||
454 | BOOL adjust = FALSE; | ||
455 | for (S32 block=0; block<num_blocks; ++block) | ||
456 | { | ||
457 | LLWorldMapLayer new_layer; | ||
458 | new_layer.LayerDefined = TRUE; | ||
459 | msg->getUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block); | ||
460 | new_layer.LayerImage = gImageList.getImage(new_layer.LayerImageID, MIPMAP_TRUE, FALSE); | ||
461 | new_layer.LayerImage->bindTexture(0); | ||
462 | new_layer.LayerImage->setClamp(TRUE, TRUE); | ||
463 | |||
464 | U32 left, right, top, bottom; | ||
465 | msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Left, left, block); | ||
466 | msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Right, right, block); | ||
467 | msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Top, top, block); | ||
468 | msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Bottom, bottom, block); | ||
469 | |||
470 | new_layer.LayerExtents.mLeft = left; | ||
471 | new_layer.LayerExtents.mRight = right; | ||
472 | new_layer.LayerExtents.mBottom = bottom; | ||
473 | new_layer.LayerExtents.mTop = top; | ||
474 | |||
475 | F32 x_meters = F32(left*REGION_WIDTH_UNITS); | ||
476 | F32 y_meters = F32(bottom*REGION_WIDTH_UNITS); | ||
477 | adjust = gWorldMap->extendAABB(U32(x_meters), U32(y_meters), | ||
478 | U32(x_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getWidth()), | ||
479 | U32(y_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getHeight())) || adjust; | ||
480 | |||
481 | gWorldMap->mMapLayers[agent_flags].push_back(new_layer); | ||
482 | } | ||
483 | |||
484 | gWorldMap->mMapLoaded[agent_flags] = TRUE; | ||
485 | if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); | ||
486 | } | ||
487 | |||
488 | // public static | ||
489 | void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) | ||
490 | { | ||
491 | U32 agent_flags; | ||
492 | msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); | ||
493 | |||
494 | if (agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES) | ||
495 | { | ||
496 | llwarns << "Invalid map image type returned! " << agent_flags << llendl; | ||
497 | return; | ||
498 | } | ||
499 | |||
500 | S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); | ||
501 | |||
502 | bool found_null_sim = false; | ||
503 | |||
504 | BOOL adjust = FALSE; | ||
505 | for (S32 block=0; block<num_blocks; ++block) | ||
506 | { | ||
507 | U16 x_regions; | ||
508 | U16 y_regions; | ||
509 | char name[MAX_STRING]; | ||
510 | U8 access; | ||
511 | U32 region_flags; | ||
512 | U8 water_height; | ||
513 | U8 agents; | ||
514 | LLUUID image_id; | ||
515 | msg->getU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block); | ||
516 | msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block); | ||
517 | msg->getStringFast(_PREHASH_Data, _PREHASH_Name, MAX_STRING, name, block); | ||
518 | msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, access, block); | ||
519 | msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block); | ||
520 | msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block); | ||
521 | msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block); | ||
522 | msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block); | ||
523 | |||
524 | U32 x_meters = x_regions * REGION_WIDTH_UNITS; | ||
525 | U32 y_meters = y_regions * REGION_WIDTH_UNITS; | ||
526 | |||
527 | if (access == 255) | ||
528 | { | ||
529 | // This region doesn't exist | ||
530 | if (gWorldMap->mIsTrackingUnknownLocation && | ||
531 | gWorldMap->mUnknownLocation.mdV[0] >= x_meters && | ||
532 | gWorldMap->mUnknownLocation.mdV[0] < x_meters + 256 && | ||
533 | gWorldMap->mUnknownLocation.mdV[1] >= y_meters && | ||
534 | gWorldMap->mUnknownLocation.mdV[1] < y_meters + 256) | ||
535 | { | ||
536 | // We were tracking this location, but it doesn't exist | ||
537 | gWorldMap->mInvalidLocation = TRUE; | ||
538 | } | ||
539 | |||
540 | found_null_sim = true; | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | adjust = gWorldMap->extendAABB(x_meters, | ||
545 | y_meters, | ||
546 | x_meters+REGION_WIDTH_UNITS, | ||
547 | y_meters+REGION_WIDTH_UNITS) || adjust; | ||
548 | U64 handle = to_region_handle(x_meters, y_meters); | ||
549 | |||
550 | // llinfos << "Map sim " << name << " image layer " << agent_flags << " ID " << image_id.getString() << llendl; | ||
551 | |||
552 | LLSimInfo* siminfo = new LLSimInfo(); | ||
553 | sim_info_map_t::iterator iter = gWorldMap->mSimInfoMap.find(handle); | ||
554 | if (iter != gWorldMap->mSimInfoMap.end()) | ||
555 | { | ||
556 | LLSimInfo* oldinfo = iter->second; | ||
557 | for (S32 image=0; image<MAP_SIM_IMAGE_TYPES; ++image) | ||
558 | { | ||
559 | siminfo->mMapImageID[image] = oldinfo->mMapImageID[image]; | ||
560 | } | ||
561 | delete oldinfo; | ||
562 | } | ||
563 | gWorldMap->mSimInfoMap[handle] = siminfo; | ||
564 | |||
565 | siminfo->mHandle = handle; | ||
566 | siminfo->mName.assign( name ); | ||
567 | siminfo->mAccess = access; | ||
568 | siminfo->mRegionFlags = region_flags; | ||
569 | siminfo->mWaterHeight = (F32) water_height; | ||
570 | siminfo->mMapImageID[agent_flags] = image_id; | ||
571 | siminfo->mCurrentImage = gImageList.getImage(siminfo->mMapImageID[gWorldMap->mCurrentMap], MIPMAP_TRUE, FALSE); | ||
572 | siminfo->mCurrentImage->bindTexture(0); | ||
573 | siminfo->mCurrentImage->setClamp(TRUE, TRUE); | ||
574 | |||
575 | if (siminfo->mMapImageID[2].notNull()) | ||
576 | { | ||
577 | siminfo->mOverlayImage = gImageList.getImage(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE); | ||
578 | } | ||
579 | else | ||
580 | { | ||
581 | siminfo->mOverlayImage = NULL; | ||
582 | } | ||
583 | |||
584 | if (gWorldMap->mIsTrackingUnknownLocation && | ||
585 | gWorldMap->mUnknownLocation.mdV[0] >= x_meters && | ||
586 | gWorldMap->mUnknownLocation.mdV[0] < x_meters + 256 && | ||
587 | gWorldMap->mUnknownLocation.mdV[1] >= y_meters && | ||
588 | gWorldMap->mUnknownLocation.mdV[1] < y_meters + 256) | ||
589 | { | ||
590 | if (siminfo->mAccess == SIM_ACCESS_DOWN) | ||
591 | { | ||
592 | // We were tracking this location, but it doesn't exist | ||
593 | gWorldMap->mInvalidLocation = true; | ||
594 | } | ||
595 | else | ||
596 | { | ||
597 | // We were tracking this location, and it does exist | ||
598 | bool is_tracking_dbl = gWorldMap->mIsTrackingDoubleClick == TRUE; | ||
599 | gFloaterWorldMap->trackLocation(gWorldMap->mUnknownLocation); | ||
600 | if (is_tracking_dbl) | ||
601 | { | ||
602 | LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); | ||
603 | gAgent.teleportViaLocation( pos_global ); | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | } | ||
608 | } | ||
609 | if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); | ||
610 | gFloaterWorldMap->updateSims(found_null_sim); | ||
611 | } | ||
612 | |||
613 | // public static | ||
614 | void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**) | ||
615 | { | ||
616 | U32 type; | ||
617 | msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type); | ||
618 | |||
619 | S32 num_blocks = msg->getNumberOfBlocks("Data"); | ||
620 | |||
621 | for (S32 block=0; block<num_blocks; ++block) | ||
622 | { | ||
623 | U32 X, Y; | ||
624 | char name[MAX_STRING]; | ||
625 | S32 extra, extra2; | ||
626 | LLUUID uuid; | ||
627 | msg->getU32Fast(_PREHASH_Data, _PREHASH_X, X, block); | ||
628 | msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block); | ||
629 | msg->getStringFast(_PREHASH_Data, _PREHASH_Name, MAX_STRING, name, block); | ||
630 | msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block); | ||
631 | msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block); | ||
632 | msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block); | ||
633 | |||
634 | F32 world_x = (F32)X; | ||
635 | X /= REGION_WIDTH_UNITS; | ||
636 | F32 world_y = (F32)Y; | ||
637 | Y /= REGION_WIDTH_UNITS; | ||
638 | |||
639 | LLItemInfo new_item(world_x, world_y, name, uuid, extra, extra2); | ||
640 | LLSimInfo* siminfo = gWorldMap->simInfoFromHandle(new_item.mRegionHandle); | ||
641 | |||
642 | switch (type) | ||
643 | { | ||
644 | case MAP_ITEM_TELEHUB: // telehubs | ||
645 | { | ||
646 | // Telehub color, store in extra as 4 U8's | ||
647 | U8 *color = (U8 *)&new_item.mExtra; | ||
648 | |||
649 | F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f; | ||
650 | F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f; | ||
651 | F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f; | ||
652 | F32 add_amt = (X % 2) ? 0.15f : -0.15f; | ||
653 | add_amt += (Y % 2) ? -0.15f : 0.15f; | ||
654 | color[0] = U8((red + add_amt) * 255); | ||
655 | color[1] = U8((green + add_amt) * 255); | ||
656 | color[2] = U8((blue + add_amt) * 255); | ||
657 | color[3] = 255; | ||
658 | |||
659 | // extra2 specifies whether this is an infohub or a telehub. | ||
660 | if (extra2) | ||
661 | { | ||
662 | gWorldMap->mInfohubs.push_back(new_item); | ||
663 | } | ||
664 | else | ||
665 | { | ||
666 | gWorldMap->mTelehubs.push_back(new_item); | ||
667 | } | ||
668 | |||
669 | break; | ||
670 | } | ||
671 | case MAP_ITEM_PG_EVENT: // events | ||
672 | case MAP_ITEM_MATURE_EVENT: | ||
673 | { | ||
674 | char buffer[32]; | ||
675 | struct tm* timep; | ||
676 | // Convert to Pacific, based on server's opinion of whether | ||
677 | // it's daylight savings time there. | ||
678 | timep = utc_to_pacific_time(extra, gPacificDaylightTime); | ||
679 | |||
680 | S32 display_hour = timep->tm_hour % 12; | ||
681 | if (display_hour == 0) display_hour = 12; | ||
682 | |||
683 | sprintf(buffer, "%d:%02d %s", | ||
684 | display_hour, | ||
685 | timep->tm_min, | ||
686 | (timep->tm_hour < 12 ? "AM" : "PM") ); | ||
687 | new_item.mToolTip.assign( buffer ); | ||
688 | |||
689 | // HACK: store Z in extra2 | ||
690 | new_item.mPosGlobal.mdV[VZ] = (F64)extra2; | ||
691 | if (type == MAP_ITEM_PG_EVENT) | ||
692 | { | ||
693 | gWorldMap->mPGEvents.push_back(new_item); | ||
694 | } | ||
695 | else | ||
696 | { | ||
697 | gWorldMap->mMatureEvents.push_back(new_item); | ||
698 | } | ||
699 | break; | ||
700 | } | ||
701 | case MAP_ITEM_POPULAR: // popular | ||
702 | { | ||
703 | new_item.mPosGlobal.mdV[VZ] = (F64)extra2; | ||
704 | gWorldMap->mPopular.push_back(new_item); | ||
705 | break; | ||
706 | } | ||
707 | case MAP_ITEM_LAND_FOR_SALE: // land for sale | ||
708 | { | ||
709 | new_item.mToolTip = llformat("%d sq. m. L$%d", new_item.mExtra, new_item.mExtra2); | ||
710 | gWorldMap->mLandForSale.push_back(new_item); | ||
711 | break; | ||
712 | } | ||
713 | case MAP_ITEM_CLASSIFIED: // classifieds | ||
714 | { | ||
715 | // HACK: Z-height is in Extra2 field. | ||
716 | new_item.mPosGlobal.mdV[VZ] = (F64)extra2; | ||
717 | gWorldMap->mClassifieds.push_back(new_item); | ||
718 | break; | ||
719 | } | ||
720 | case MAP_ITEM_AGENT_COUNT: // agent counts | ||
721 | { | ||
722 | // We only ever receive one per region, i.e. this update superceeds any others | ||
723 | gWorldMap->mNumAgents[new_item.mRegionHandle] = new_item.mExtra; | ||
724 | break; | ||
725 | } | ||
726 | case MAP_ITEM_AGENT_LOCATIONS: // agent locations | ||
727 | { | ||
728 | if (!siminfo) | ||
729 | { | ||
730 | llinfos << "siminfo missing for " << new_item.mPosGlobal.mdV[0] << ", " << new_item.mPosGlobal.mdV[1] << llendl; | ||
731 | break; | ||
732 | } | ||
733 | // llinfos << "New Location " << new_item.mName << llendl; | ||
734 | |||
735 | item_info_list_t& agentcounts = gWorldMap->mAgentLocationsMap[new_item.mRegionHandle]; | ||
736 | |||
737 | // Find the last item in the list with a different name and erase them | ||
738 | item_info_list_t::iterator lastiter; | ||
739 | for (lastiter = agentcounts.begin(); lastiter!=agentcounts.end(); ++lastiter) | ||
740 | { | ||
741 | const LLItemInfo& info = *lastiter; | ||
742 | if (info.mName == new_item.mName) | ||
743 | { | ||
744 | break; | ||
745 | } | ||
746 | } | ||
747 | if (lastiter != agentcounts.begin()) | ||
748 | { | ||
749 | agentcounts.erase(agentcounts.begin(), lastiter); | ||
750 | } | ||
751 | // Now append the new location | ||
752 | if (new_item.mExtra > 0) | ||
753 | { | ||
754 | agentcounts.push_back(new_item); | ||
755 | } | ||
756 | break; | ||
757 | } | ||
758 | default: | ||
759 | break; | ||
760 | }; | ||
761 | } | ||
762 | } | ||
763 | |||
764 | void LLWorldMap::dump() | ||
765 | { | ||
766 | for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
767 | { | ||
768 | U64 handle = (*it).first; | ||
769 | LLSimInfo* info = (*it).second; | ||
770 | |||
771 | U32 x_pos, y_pos; | ||
772 | from_region_handle(handle, &x_pos, &y_pos); | ||
773 | |||
774 | llinfos << x_pos << "," << y_pos | ||
775 | << " " << info->mName.c_str() | ||
776 | << " " << (S32)info->mAccess | ||
777 | << " " << std::hex << info->mRegionFlags << std::dec | ||
778 | << " " << info->mWaterHeight | ||
779 | //<< " " << info->mTelehubName | ||
780 | //<< " " << info->mTelehubPosition | ||
781 | << llendl; | ||
782 | |||
783 | if (info->mCurrentImage) | ||
784 | { | ||
785 | llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel() | ||
786 | << " fullwidth " << info->mCurrentImage->getWidth(0) | ||
787 | << " fullheight " << info->mCurrentImage->getHeight(0) | ||
788 | << " maxvirt " << info->mCurrentImage->mMaxVirtualSize | ||
789 | << " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel() | ||
790 | << llendl; | ||
791 | } | ||
792 | } | ||
793 | } | ||
794 | |||
795 | |||
796 | BOOL LLWorldMap::extendAABB(U32 min_x, U32 min_y, U32 max_x, U32 max_y) | ||
797 | { | ||
798 | BOOL rv = FALSE; | ||
799 | if (min_x < mMinX) | ||
800 | { | ||
801 | rv = TRUE; | ||
802 | mMinX = min_x; | ||
803 | } | ||
804 | if (min_y < mMinY) | ||
805 | { | ||
806 | rv = TRUE; | ||
807 | mMinY = min_y; | ||
808 | } | ||
809 | if (max_x > mMaxX) | ||
810 | { | ||
811 | rv = TRUE; | ||
812 | mMaxX = max_x; | ||
813 | } | ||
814 | if (max_y > mMaxY) | ||
815 | { | ||
816 | rv = TRUE; | ||
817 | mMaxY = max_y; | ||
818 | } | ||
819 | lldebugs << "World map aabb: (" << mMinX << ", " << mMinY << "), (" | ||
820 | << mMaxX << ", " << mMaxY << ")" << llendl; | ||
821 | return rv; | ||
822 | } | ||
823 | |||
824 | |||
825 | U32 LLWorldMap::getWorldWidth() const | ||
826 | { | ||
827 | return mMaxX - mMinX; | ||
828 | } | ||
829 | |||
830 | |||
831 | U32 LLWorldMap::getWorldHeight() const | ||
832 | { | ||
833 | return mMaxY - mMinY; | ||
834 | } | ||
835 | |||
836 | BOOL LLWorldMap::coveredByTelehub(LLSimInfo* infop) | ||
837 | { | ||
838 | /*if (!mTelehubCoverageMap) | ||
839 | { | ||
840 | return FALSE; | ||
841 | } | ||
842 | U32 x_pos, y_pos; | ||
843 | from_region_handle(infop->mHandle, &x_pos, &y_pos); | ||
844 | x_pos /= REGION_WIDTH_UNITS; | ||
845 | y_pos /= REGION_WIDTH_UNITS; | ||
846 | |||
847 | S32 index = x_pos - (mMinX / REGION_WIDTH_UNITS - 1) + (mNeighborMapWidth * (y_pos - (mMinY / REGION_WIDTH_UNITS - 1))); | ||
848 | return mTelehubCoverageMap[index] != 0; */ | ||
849 | return FALSE; | ||
850 | } | ||
851 | |||
852 | void LLWorldMap::updateTelehubCoverage() | ||
853 | { | ||
854 | /*S32 neighbor_width = getWorldWidth() / REGION_WIDTH_UNITS + 2; | ||
855 | S32 neighbor_height = getWorldHeight() / REGION_WIDTH_UNITS + 2; | ||
856 | if (neighbor_width > mNeighborMapWidth || neighbor_height > mNeighborMapHeight) | ||
857 | { | ||
858 | mNeighborMapWidth = neighbor_width; | ||
859 | mNeighborMapHeight = neighbor_height; | ||
860 | delete mNeighborMap; | ||
861 | delete mTelehubCoverageMap; | ||
862 | |||
863 | mNeighborMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; | ||
864 | mTelehubCoverageMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; | ||
865 | } | ||
866 | |||
867 | memset(mNeighborMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); | ||
868 | memset(mTelehubCoverageMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); | ||
869 | |||
870 | // leave 1 sim border | ||
871 | S32 min_x = (mMinX / REGION_WIDTH_UNITS) - 1; | ||
872 | S32 min_y = (mMinY / REGION_WIDTH_UNITS) - 1; | ||
873 | |||
874 | std::map<U64, LLSimInfo*>::const_iterator it; | ||
875 | for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
876 | { | ||
877 | U64 handle = (*it).first; | ||
878 | //LLSimInfo* info = (*it).second; | ||
879 | |||
880 | U32 x_pos, y_pos; | ||
881 | from_region_handle(handle, &x_pos, &y_pos); | ||
882 | x_pos /= REGION_WIDTH_UNITS; | ||
883 | y_pos /= REGION_WIDTH_UNITS; | ||
884 | x_pos -= min_x; | ||
885 | y_pos -= min_y; | ||
886 | |||
887 | S32 index = x_pos + (mNeighborMapWidth * y_pos); | ||
888 | mNeighborMap[index - 1]++; | ||
889 | mNeighborMap[index + 1]++; | ||
890 | mNeighborMap[index - mNeighborMapWidth]++; | ||
891 | mNeighborMap[index + mNeighborMapWidth]++; | ||
892 | } | ||
893 | |||
894 | for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
895 | { | ||
896 | U64 handle = (*it).first; | ||
897 | LLSimInfo* info = (*it).second; | ||
898 | |||
899 | U32 x_pos, y_pos; | ||
900 | from_region_handle(handle, &x_pos, &y_pos); | ||
901 | x_pos /= REGION_WIDTH_UNITS; | ||
902 | y_pos /= REGION_WIDTH_UNITS; | ||
903 | x_pos -= min_x; | ||
904 | y_pos -= min_y; | ||
905 | |||
906 | S32 index = x_pos + (mNeighborMapWidth * y_pos); | ||
907 | |||
908 | if (!info->mTelehubName.empty() && mNeighborMap[index]) | ||
909 | { | ||
910 | S32 x_start = llmax(0, S32(x_pos - 5)); | ||
911 | S32 x_span = llmin(mNeighborMapWidth - 1, (S32)(x_pos + 5)) - x_start + 1; | ||
912 | S32 y_start = llmax(0, (S32)y_pos - 5); | ||
913 | S32 y_end = llmin(mNeighborMapHeight - 1, (S32)(y_pos + 5)); | ||
914 | for (S32 y_index = y_start; y_index <= y_end; y_index++) | ||
915 | { | ||
916 | memset(&mTelehubCoverageMap[x_start + y_index * mNeighborMapWidth], 0xff, sizeof(U8) * x_span); | ||
917 | } | ||
918 | } | ||
919 | } | ||
920 | |||
921 | for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) | ||
922 | { | ||
923 | U64 handle = (*it).first; | ||
924 | //LLSimInfo* info = (*it).second; | ||
925 | |||
926 | U32 x_pos, y_pos; | ||
927 | from_region_handle(handle, &x_pos, &y_pos); | ||
928 | x_pos /= REGION_WIDTH_UNITS; | ||
929 | y_pos /= REGION_WIDTH_UNITS; | ||
930 | |||
931 | S32 index = x_pos - min_x + (mNeighborMapWidth * (y_pos - min_y)); | ||
932 | mTelehubCoverageMap[index] *= mNeighborMap[index]; | ||
933 | }*/ | ||
934 | } | ||