diff options
Diffstat (limited to 'linden/indra/newview/llfloateravatarlist.cpp')
-rw-r--r-- | linden/indra/newview/llfloateravatarlist.cpp | 1471 |
1 files changed, 1471 insertions, 0 deletions
diff --git a/linden/indra/newview/llfloateravatarlist.cpp b/linden/indra/newview/llfloateravatarlist.cpp new file mode 100644 index 0000000..2346e94 --- /dev/null +++ b/linden/indra/newview/llfloateravatarlist.cpp | |||
@@ -0,0 +1,1471 @@ | |||
1 | /** | ||
2 | * @file llfloateravatarlist.cpp | ||
3 | * @brief Avatar list/radar floater | ||
4 | * | ||
5 | * @author Dale Glass <dale@daleglass.net>, (C) 2007 | ||
6 | */ | ||
7 | |||
8 | /** | ||
9 | * Rewritten by jcool410 | ||
10 | * Removed usage of globals | ||
11 | * Removed TrustNET | ||
12 | * Added utilization of "minimap" data | ||
13 | * Heavily modified by Henri Beauchamp (the laggy spying tool becomes a true, | ||
14 | * low lag radar) | ||
15 | */ | ||
16 | |||
17 | #include "llviewerprecompiledheaders.h" | ||
18 | |||
19 | #include "llavatarconstants.h" | ||
20 | #include "llfloateravatarlist.h" | ||
21 | |||
22 | #include "llcachename.h" | ||
23 | #include "lluictrlfactory.h" | ||
24 | #include "llviewerwindow.h" | ||
25 | #include "llscrolllistctrl.h" | ||
26 | #include "llradiogroup.h" | ||
27 | #include "llviewercontrol.h" | ||
28 | |||
29 | #include "llvoavatar.h" | ||
30 | #include "llimview.h" | ||
31 | #include "llfloateravatarinfo.h" | ||
32 | #include "llregionflags.h" | ||
33 | #include "llfloaterreporter.h" | ||
34 | #include "llagent.h" | ||
35 | #include "llviewerregion.h" | ||
36 | #include "lltracker.h" | ||
37 | #include "llviewerstats.h" | ||
38 | #include "llerror.h" | ||
39 | #include "llchat.h" | ||
40 | #include "llfloaterchat.h" | ||
41 | #include "llviewermessage.h" | ||
42 | #include "llweb.h" | ||
43 | #include "llviewerobjectlist.h" | ||
44 | #include "llmutelist.h" | ||
45 | #include "llcallbacklist.h" | ||
46 | #include "llviewermenu.h" | ||
47 | |||
48 | #include <time.h> | ||
49 | #include <string.h> | ||
50 | |||
51 | #include <map> | ||
52 | |||
53 | |||
54 | #include "llworld.h" | ||
55 | |||
56 | #include "llsdutil.h" | ||
57 | |||
58 | /** | ||
59 | * @brief How long to keep people who are gone in the list and in memory. | ||
60 | */ | ||
61 | const F32 DEAD_KEEP_TIME = 10.0f; | ||
62 | |||
63 | extern U32 gFrameCount; | ||
64 | |||
65 | typedef enum e_radar_alert_type | ||
66 | { | ||
67 | ALERT_TYPE_SIM = 0, | ||
68 | ALERT_TYPE_DRAW = 1, | ||
69 | ALERT_TYPE_SHOUTRANGE = 2, | ||
70 | ALERT_TYPE_CHATRANGE = 3 | ||
71 | } ERadarAlertType; | ||
72 | |||
73 | void announce(std::string msg) | ||
74 | { | ||
75 | //llinfos << "Radar broadcasting key: " << key.asString() << " - on channel " << gSavedSettings.getS32("RadarChatKeysChannel") << llendl; | ||
76 | gMessageSystem->newMessage("ScriptDialogReply"); | ||
77 | gMessageSystem->nextBlock("AgentData"); | ||
78 | gMessageSystem->addUUID("AgentID", gAgent.getID()); | ||
79 | gMessageSystem->addUUID("SessionID", gAgent.getSessionID()); | ||
80 | gMessageSystem->nextBlock("Data"); | ||
81 | gMessageSystem->addUUID("ObjectID", gAgent.getID()); | ||
82 | gMessageSystem->addS32("ChatChannel", gSavedSettings.getS32("RadarChatKeysChannel")); | ||
83 | gMessageSystem->addS32("ButtonIndex", 1); | ||
84 | gMessageSystem->addString("ButtonLabel", msg); | ||
85 | gAgent.sendReliableMessage(); | ||
86 | } | ||
87 | |||
88 | void chat_avatar_status(std::string name, LLUUID key, ERadarAlertType type, bool entering) | ||
89 | { | ||
90 | if (gSavedSettings.getBOOL("RadarChatAlerts")) | ||
91 | { | ||
92 | LLChat chat; | ||
93 | switch(type) | ||
94 | { | ||
95 | case ALERT_TYPE_SIM: | ||
96 | if (gSavedSettings.getBOOL("MiniMapNotifySimRange")) | ||
97 | { | ||
98 | chat.mText = name+" has "+(entering ? "entered" : "left")+" the sim."; | ||
99 | } | ||
100 | break; | ||
101 | case ALERT_TYPE_DRAW: | ||
102 | if (gSavedSettings.getBOOL("RadarAlertDraw")) | ||
103 | { | ||
104 | chat.mText = name+" has "+(entering ? "entered" : "left")+" draw distance."; | ||
105 | } | ||
106 | break; | ||
107 | case ALERT_TYPE_SHOUTRANGE: | ||
108 | if (gSavedSettings.getBOOL("RadarAlertShoutRange")) | ||
109 | { | ||
110 | chat.mText = name+" has "+(entering ? "entered" : "left")+" shout range."; | ||
111 | } | ||
112 | break; | ||
113 | case ALERT_TYPE_CHATRANGE: | ||
114 | if (gSavedSettings.getBOOL("MiniMapNotifyChatRange")) | ||
115 | { | ||
116 | chat.mText = name+" has "+(entering ? "entered" : "left")+" chat range."; | ||
117 | } | ||
118 | break; | ||
119 | } | ||
120 | if (chat.mText != "") | ||
121 | { | ||
122 | chat.mSourceType = CHAT_SOURCE_SYSTEM; | ||
123 | LLFloaterChat::addChat(chat); | ||
124 | } | ||
125 | } | ||
126 | if (type == ALERT_TYPE_SIM && entering && gSavedSettings.getBOOL("RadarChatKeys")) | ||
127 | { | ||
128 | announce(key.asString()); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string &name, const LLVector3d &position) : | ||
133 | mID(id), mName(name), mDisplayName(name), mPosition(position), mDrawPosition(), mMarked(FALSE), | ||
134 | mFocused(FALSE), mUpdateTimer(), mFrame(gFrameCount), mInSimFrame(U32_MAX), mInDrawFrame(U32_MAX), | ||
135 | mInChatFrame(U32_MAX), mInShoutFrame(U32_MAX) | ||
136 | { | ||
137 | } | ||
138 | |||
139 | void LLAvatarListEntry::setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange) | ||
140 | { | ||
141 | if (drawn) | ||
142 | { | ||
143 | mDrawPosition = position; | ||
144 | } | ||
145 | else if (mInDrawFrame == U32_MAX) | ||
146 | { | ||
147 | mDrawPosition.setZero(); | ||
148 | } | ||
149 | |||
150 | mPosition = position; | ||
151 | |||
152 | mFrame = gFrameCount; | ||
153 | if (this_sim) | ||
154 | { | ||
155 | if (mInSimFrame == U32_MAX) | ||
156 | { | ||
157 | chat_avatar_status(mName, mID, ALERT_TYPE_SIM, true); | ||
158 | } | ||
159 | mInSimFrame = mFrame; | ||
160 | } | ||
161 | if (drawn) | ||
162 | { | ||
163 | if (mInDrawFrame == U32_MAX) | ||
164 | { | ||
165 | chat_avatar_status(mName, mID, ALERT_TYPE_DRAW, true); | ||
166 | } | ||
167 | mInDrawFrame = mFrame; | ||
168 | } | ||
169 | if (shoutrange) | ||
170 | { | ||
171 | if (mInShoutFrame == U32_MAX) | ||
172 | { | ||
173 | chat_avatar_status(mName, mID, ALERT_TYPE_SHOUTRANGE, true); | ||
174 | } | ||
175 | mInShoutFrame = mFrame; | ||
176 | } | ||
177 | if (chatrange) | ||
178 | { | ||
179 | if (mInChatFrame == U32_MAX) | ||
180 | { | ||
181 | chat_avatar_status(mName, mID, ALERT_TYPE_CHATRANGE, true); | ||
182 | } | ||
183 | mInChatFrame = mFrame; | ||
184 | } | ||
185 | |||
186 | mUpdateTimer.start(); | ||
187 | } | ||
188 | |||
189 | bool LLAvatarListEntry::getAlive() | ||
190 | { | ||
191 | U32 current = gFrameCount; | ||
192 | if (mInSimFrame != U32_MAX && (current - mInSimFrame) >= 2) | ||
193 | { | ||
194 | mInSimFrame = U32_MAX; | ||
195 | chat_avatar_status(mName, mID, ALERT_TYPE_SIM, false); | ||
196 | } | ||
197 | if (mInDrawFrame != U32_MAX && (current - mInDrawFrame) >= 2) | ||
198 | { | ||
199 | mInDrawFrame = U32_MAX; | ||
200 | chat_avatar_status(mName, mID, ALERT_TYPE_DRAW, false); | ||
201 | } | ||
202 | if (mInShoutFrame != U32_MAX && (current - mInShoutFrame) >= 2) | ||
203 | { | ||
204 | mInShoutFrame = U32_MAX; | ||
205 | chat_avatar_status(mName, mID, ALERT_TYPE_SHOUTRANGE, false); | ||
206 | } | ||
207 | if (mInChatFrame != U32_MAX && (current - mInChatFrame) >= 2) | ||
208 | { | ||
209 | mInChatFrame = U32_MAX; | ||
210 | chat_avatar_status(mName, mID, ALERT_TYPE_CHATRANGE, false); | ||
211 | } | ||
212 | return ((current - mFrame) <= 2); | ||
213 | } | ||
214 | |||
215 | F32 LLAvatarListEntry::getEntryAgeSeconds() | ||
216 | { | ||
217 | return mUpdateTimer.getElapsedTimeF32(); | ||
218 | } | ||
219 | |||
220 | BOOL LLAvatarListEntry::isDead() | ||
221 | { | ||
222 | return getEntryAgeSeconds() > DEAD_KEEP_TIME; | ||
223 | } | ||
224 | |||
225 | LLFloaterAvatarList* LLFloaterAvatarList::sInstance = NULL; | ||
226 | |||
227 | LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar")) | ||
228 | { | ||
229 | llassert_always(sInstance == NULL); | ||
230 | sInstance = this; | ||
231 | mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3; | ||
232 | } | ||
233 | |||
234 | LLFloaterAvatarList::~LLFloaterAvatarList() | ||
235 | { | ||
236 | gIdleCallbacks.deleteFunction(LLFloaterAvatarList::callbackIdle); | ||
237 | sInstance = NULL; | ||
238 | } | ||
239 | |||
240 | //static | ||
241 | void LLFloaterAvatarList::toggle(void*) | ||
242 | { | ||
243 | #ifdef LL_RRINTERFACE_H //MK | ||
244 | if (gRRenabled && gAgent.mRRInterface.mContainsShownames) | ||
245 | { | ||
246 | if (sInstance && sInstance->getVisible()) | ||
247 | { | ||
248 | sInstance->close(false); | ||
249 | } | ||
250 | } | ||
251 | #endif //mk | ||
252 | if (sInstance) | ||
253 | { | ||
254 | if (sInstance->getVisible()) | ||
255 | { | ||
256 | sInstance->close(false); | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | sInstance->open(); | ||
261 | } | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | showInstance(); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | //static | ||
270 | void LLFloaterAvatarList::showInstance() | ||
271 | { | ||
272 | #ifdef LL_RRINTERFACE_H //MK | ||
273 | if (gRRenabled && gAgent.mRRInterface.mContainsShownames) | ||
274 | { | ||
275 | return; | ||
276 | } | ||
277 | #endif //mk | ||
278 | if (sInstance) | ||
279 | { | ||
280 | if (!sInstance->getVisible()) | ||
281 | { | ||
282 | sInstance->open(); | ||
283 | } | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | sInstance = new LLFloaterAvatarList(); | ||
288 | LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_radar.xml"); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | void LLFloaterAvatarList::draw() | ||
293 | { | ||
294 | LLFloater::draw(); | ||
295 | } | ||
296 | |||
297 | void LLFloaterAvatarList::onOpen() | ||
298 | { | ||
299 | gSavedSettings.setBOOL("ShowRadar", TRUE); | ||
300 | sInstance->setVisible(TRUE); | ||
301 | } | ||
302 | |||
303 | void LLFloaterAvatarList::onClose(bool app_quitting) | ||
304 | { | ||
305 | sInstance->setVisible(FALSE); | ||
306 | if (!app_quitting) | ||
307 | { | ||
308 | gSavedSettings.setBOOL("ShowRadar", FALSE); | ||
309 | } | ||
310 | if (!gSavedSettings.getBOOL("RadarKeepOpen") || app_quitting) | ||
311 | { | ||
312 | destroy(); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | BOOL LLFloaterAvatarList::postBuild() | ||
317 | { | ||
318 | // Default values | ||
319 | mTracking = FALSE; | ||
320 | mUpdate = TRUE; | ||
321 | |||
322 | // Hide them until some other way is found | ||
323 | // Users may not expect to find a Ban feature on the Eject button | ||
324 | childSetVisible("estate_ban_btn", false); | ||
325 | |||
326 | // Set callbacks | ||
327 | childSetAction("profile_btn", onClickProfile, this); | ||
328 | childSetAction("im_btn", onClickIM, this); | ||
329 | childSetAction("offer_btn", onClickTeleportOffer, this); | ||
330 | childSetAction("track_btn", onClickTrack, this); | ||
331 | childSetAction("mark_btn", onClickMark, this); | ||
332 | childSetAction("focus_btn", onClickFocus, this); | ||
333 | childSetAction("prev_in_list_btn", onClickPrevInList, this); | ||
334 | childSetAction("next_in_list_btn", onClickNextInList, this); | ||
335 | childSetAction("prev_marked_btn", onClickPrevMarked, this); | ||
336 | childSetAction("next_marked_btn", onClickNextMarked, this); | ||
337 | |||
338 | childSetAction("get_key_btn", onClickGetKey, this); | ||
339 | |||
340 | childSetAction("freeze_btn", onClickFreeze, this); | ||
341 | childSetAction("eject_btn", onClickEject, this); | ||
342 | childSetAction("mute_btn", onClickMute, this); | ||
343 | childSetAction("ar_btn", onClickAR, this); | ||
344 | childSetAction("teleport_btn", onClickTeleport, this); | ||
345 | childSetAction("estate_eject_btn", onClickEjectFromEstate, this); | ||
346 | |||
347 | childSetAction("send_keys_btn", onClickSendKeys, this); | ||
348 | |||
349 | getChild<LLRadioGroup>("update_rate")->setSelectedIndex(gSavedSettings.getU32("RadarUpdateRate")); | ||
350 | childSetCommitCallback("update_rate", onCommitUpdateRate, this); | ||
351 | |||
352 | // Get a pointer to the scroll list from the interface | ||
353 | mAvatarList = getChild<LLScrollListCtrl>("avatar_list"); | ||
354 | mAvatarList->sortByColumn("distance", TRUE); | ||
355 | mAvatarList->setCommitOnSelectionChange(TRUE); | ||
356 | childSetCommitCallback("avatar_list", onSelectName, this); | ||
357 | refreshAvatarList(); | ||
358 | |||
359 | gIdleCallbacks.addFunction(LLFloaterAvatarList::callbackIdle); | ||
360 | |||
361 | return TRUE; | ||
362 | } | ||
363 | |||
364 | void LLFloaterAvatarList::updateAvatarList() | ||
365 | { | ||
366 | if (sInstance != this) return; | ||
367 | |||
368 | #ifdef LL_RRINTERFACE_H //MK | ||
369 | if (gRRenabled && gAgent.mRRInterface.mContainsShownames) | ||
370 | { | ||
371 | close(); | ||
372 | } | ||
373 | #endif //mk | ||
374 | |||
375 | //llinfos << "radar refresh: updating map" << llendl; | ||
376 | |||
377 | // Check whether updates are enabled | ||
378 | LLCheckboxCtrl* check = getChild<LLCheckboxCtrl>("update_enabled_cb"); | ||
379 | if (check && !check->getValue()) | ||
380 | { | ||
381 | mUpdate = FALSE; | ||
382 | refreshTracker(); | ||
383 | return; | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | mUpdate = TRUE; | ||
388 | } | ||
389 | |||
390 | LLVector3d mypos = gAgent.getPositionGlobal(); | ||
391 | |||
392 | { | ||
393 | std::vector<LLUUID> avatar_ids; | ||
394 | std::vector<LLUUID> sorted_avatar_ids; | ||
395 | std::vector<LLVector3d> positions; | ||
396 | |||
397 | LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, F32_MAX); | ||
398 | |||
399 | sorted_avatar_ids = avatar_ids; | ||
400 | std::sort(sorted_avatar_ids.begin(), sorted_avatar_ids.end()); | ||
401 | |||
402 | for (std::vector<LLCharacter*>::const_iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) | ||
403 | { | ||
404 | LLUUID avid = (*iter)->getID(); | ||
405 | |||
406 | if (!std::binary_search(sorted_avatar_ids.begin(), sorted_avatar_ids.end(), avid)) | ||
407 | { | ||
408 | avatar_ids.push_back(avid); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | size_t i; | ||
413 | size_t count = avatar_ids.size(); | ||
414 | |||
415 | for (i = 0; i < count; ++i) | ||
416 | { | ||
417 | std::string name, first, last; | ||
418 | const LLUUID &avid = avatar_ids[i]; | ||
419 | |||
420 | LLVector3d position; | ||
421 | LLViewerObject *obj = gObjectList.findObject(avid); | ||
422 | |||
423 | if (obj) | ||
424 | { | ||
425 | LLVOAvatar* avatarp = dynamic_cast<LLVOAvatar*>(obj); | ||
426 | |||
427 | if (avatarp == NULL) | ||
428 | { | ||
429 | continue; | ||
430 | } | ||
431 | |||
432 | // Skip if avatar is dead(what's that?) | ||
433 | // or if the avatar is ourselves. | ||
434 | if (avatarp->isDead() || avatarp->isSelf()) | ||
435 | { | ||
436 | continue; | ||
437 | } | ||
438 | |||
439 | // Get avatar data | ||
440 | position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); | ||
441 | name = avatarp->getFullname(); | ||
442 | |||
443 | // Apparently, sometimes the name comes out empty, with a " " name. This is because | ||
444 | // getFullname concatenates first and last name with a " " in the middle. | ||
445 | // This code will avoid adding a nameless entry to the list until it acquires a name. | ||
446 | |||
447 | //duped for lower section | ||
448 | if (name.empty() || (name.compare(" ") == 0))// || (name.compare(gCacheName->getDefaultName()) == 0)) | ||
449 | { | ||
450 | if (gCacheName->getName(avid, first, last)) | ||
451 | { | ||
452 | name = first + " " + last; | ||
453 | } | ||
454 | else | ||
455 | { | ||
456 | continue; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | #ifdef LL_DISPLAY_NAMES | ||
461 | std::string display_name = name; | ||
462 | if (LLAvatarName::sOmitResidentAsLastName) | ||
463 | { | ||
464 | LLStringUtil::replaceString(display_name, " Resident", ""); | ||
465 | } | ||
466 | if (LLAvatarNameCache::useDisplayNames()) | ||
467 | { | ||
468 | LLAvatarName avatar_name; | ||
469 | if (LLAvatarNameCache::get(avid, &avatar_name)) | ||
470 | { | ||
471 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
472 | { | ||
473 | display_name = avatar_name.mDisplayName; | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | display_name = avatar_name.getNames(); | ||
478 | } | ||
479 | } | ||
480 | } | ||
481 | #endif | ||
482 | |||
483 | if (avid.isNull()) | ||
484 | { | ||
485 | //llinfos << "Key empty for avatar " << name << llendl; | ||
486 | continue; | ||
487 | } | ||
488 | |||
489 | if (mAvatars.count(avid) > 0) | ||
490 | { | ||
491 | // Avatar already in list, update position | ||
492 | F32 dist = (F32)(position - mypos).magVec(); | ||
493 | mAvatars[avid].setPosition(position, (avatarp->getRegion() == gAgent.getRegion()), true, dist < 20.0, dist < 100.0); | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | // Avatar not there yet, add it | ||
498 | LLAvatarListEntry entry(avid, name, position); | ||
499 | mAvatars[avid] = entry; | ||
500 | } | ||
501 | #ifdef LL_DISPLAY_NAMES | ||
502 | // update avatar display name. | ||
503 | mAvatars[avid].setDisplayName(display_name); | ||
504 | #endif | ||
505 | } | ||
506 | else | ||
507 | { | ||
508 | if (i < positions.size()) | ||
509 | { | ||
510 | position = positions[i]; | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | continue; | ||
515 | } | ||
516 | |||
517 | if (gCacheName->getName(avid, first, last)) | ||
518 | { | ||
519 | name = first + " " + last; | ||
520 | } | ||
521 | else | ||
522 | { | ||
523 | //name = gCacheName->getDefaultName(); | ||
524 | continue; //prevent (Loading...) | ||
525 | } | ||
526 | |||
527 | #ifdef LL_DISPLAY_NAMES | ||
528 | std::string display_name = name; | ||
529 | if (LLAvatarName::sOmitResidentAsLastName) | ||
530 | { | ||
531 | LLStringUtil::replaceString(display_name, " Resident", ""); | ||
532 | } | ||
533 | if (LLAvatarNameCache::useDisplayNames()) | ||
534 | { | ||
535 | LLAvatarName avatar_name; | ||
536 | if (LLAvatarNameCache::get(avid, &avatar_name)) | ||
537 | { | ||
538 | if (LLAvatarNameCache::useDisplayNames() == 2) | ||
539 | { | ||
540 | display_name = avatar_name.mDisplayName; | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | display_name = avatar_name.getNames(); | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | #endif | ||
549 | |||
550 | if (mAvatars.count(avid) > 0) | ||
551 | { | ||
552 | // Avatar already in list, update position | ||
553 | F32 dist = (F32)(position - mypos).magVec(); | ||
554 | mAvatars[avid].setPosition(position, gAgent.getRegion()->pointInRegionGlobal(position), false, dist < 20.0, dist < 100.0); | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | // Avatar not there yet, add it | ||
559 | LLAvatarListEntry entry(avid, name, position); | ||
560 | mAvatars[avid] = entry; | ||
561 | } | ||
562 | #ifdef LL_DISPLAY_NAMES | ||
563 | // update avatar display name. | ||
564 | mAvatars[avid].setDisplayName(display_name); | ||
565 | #endif | ||
566 | } | ||
567 | } | ||
568 | } | ||
569 | |||
570 | // llinfos << "radar refresh: done" << llendl; | ||
571 | |||
572 | expireAvatarList(); | ||
573 | refreshAvatarList(); | ||
574 | refreshTracker(); | ||
575 | } | ||
576 | |||
577 | void LLFloaterAvatarList::expireAvatarList() | ||
578 | { | ||
579 | // llinfos << "radar: expiring" << llendl; | ||
580 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
581 | std::queue<LLUUID> delete_queue; | ||
582 | |||
583 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
584 | { | ||
585 | LLAvatarListEntry *entry = &iter->second; | ||
586 | |||
587 | if (!entry->getAlive() && entry->isDead()) | ||
588 | { | ||
589 | //llinfos << "radar: expiring avatar " << entry->getDisplayName() << llendl; | ||
590 | LLUUID av_id = entry->getID(); | ||
591 | delete_queue.push(av_id); | ||
592 | if (av_id == mTrackedAvatar) | ||
593 | { | ||
594 | stopTracker(); | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | |||
599 | while (!delete_queue.empty()) | ||
600 | { | ||
601 | mAvatars.erase(delete_queue.front()); | ||
602 | delete_queue.pop(); | ||
603 | } | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Redraws the avatar list | ||
608 | * Only does anything if the avatar list is visible. | ||
609 | * @author Dale Glass | ||
610 | */ | ||
611 | void LLFloaterAvatarList::refreshAvatarList() | ||
612 | { | ||
613 | // Don't update list when interface is hidden | ||
614 | if (!sInstance->getVisible()) return; | ||
615 | |||
616 | // We rebuild the list fully each time it's refreshed | ||
617 | // The assumption is that it's faster to refill it and sort than | ||
618 | // to rebuild the whole list. | ||
619 | LLDynamicArray<LLUUID> selected = mAvatarList->getSelectedIDs(); | ||
620 | S32 scrollpos = mAvatarList->getScrollPos(); | ||
621 | |||
622 | mAvatarList->deleteAllItems(); | ||
623 | |||
624 | LLVector3d mypos = gAgent.getPositionGlobal(); | ||
625 | LLVector3d posagent; | ||
626 | posagent.setVec(gAgent.getPositionAgent()); | ||
627 | LLVector3d simpos = mypos - posagent; | ||
628 | |||
629 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
630 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
631 | { | ||
632 | LLSD element; | ||
633 | LLUUID av_id; | ||
634 | |||
635 | LLAvatarListEntry *entry = &iter->second; | ||
636 | |||
637 | // Skip if avatar hasn't been around | ||
638 | if (entry->isDead()) | ||
639 | { | ||
640 | continue; | ||
641 | } | ||
642 | |||
643 | av_id = entry->getID(); | ||
644 | |||
645 | LLVector3d position = entry->getPosition(); | ||
646 | BOOL UnknownAltitude = false; | ||
647 | |||
648 | LLVector3d delta = position - mypos; | ||
649 | F32 distance = (F32)delta.magVec(); | ||
650 | if (position.mdV[VZ] == 0.0) | ||
651 | { | ||
652 | UnknownAltitude = true; | ||
653 | distance = 9000.0; | ||
654 | } | ||
655 | delta.mdV[2] = 0.0f; | ||
656 | F32 side_distance = (F32)delta.magVec(); | ||
657 | |||
658 | // HACK: Workaround for an apparent bug: | ||
659 | // sometimes avatar entries get stuck, and are registered | ||
660 | // by the client as perpetually moving in the same direction. | ||
661 | // this makes sure they get removed from the visible list eventually | ||
662 | |||
663 | //jcool410 -- this fucks up seeing dueds thru minimap data > 1024m away, so, lets just say > 2048m to the side is bad | ||
664 | //aka 8 sims | ||
665 | if (side_distance > 2048.0f) | ||
666 | { | ||
667 | continue; | ||
668 | } | ||
669 | |||
670 | if (av_id.isNull()) | ||
671 | { | ||
672 | //llwarns << "Avatar with null key somehow got into the list!" << llendl; | ||
673 | continue; | ||
674 | } | ||
675 | |||
676 | element["id"] = av_id; | ||
677 | |||
678 | element["columns"][LIST_MARK]["column"] = "marked"; | ||
679 | element["columns"][LIST_MARK]["type"] = "text"; | ||
680 | if (entry->isMarked()) | ||
681 | { | ||
682 | element["columns"][LIST_MARK]["value"] = "X"; | ||
683 | element["columns"][LIST_MARK]["color"] = LLColor4::blue.getValue(); | ||
684 | element["columns"][LIST_MARK]["font-style"] = "BOLD"; | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | element["columns"][LIST_MARK]["value"] = ""; | ||
689 | } | ||
690 | |||
691 | element["columns"][LIST_AVATAR_NAME]["column"] = "avatar_name"; | ||
692 | element["columns"][LIST_AVATAR_NAME]["type"] = "text"; | ||
693 | element["columns"][LIST_AVATAR_NAME]["value"] = entry->getDisplayName().c_str(); | ||
694 | if (entry->getEntryAgeSeconds() > 1.0f) | ||
695 | { | ||
696 | element["columns"][LIST_AVATAR_NAME]["font-style"] = "ITALIC"; | ||
697 | } | ||
698 | else if (entry->isFocused()) | ||
699 | { | ||
700 | element["columns"][LIST_AVATAR_NAME]["font-style"] = "BOLD"; | ||
701 | } | ||
702 | if (LLMuteList::getInstance()->isMuted(av_id)) | ||
703 | { | ||
704 | element["columns"][LIST_AVATAR_NAME]["color"] = LLColor4::red2.getValue(); | ||
705 | } | ||
706 | else if (is_agent_friend(av_id)) | ||
707 | { | ||
708 | element["columns"][LIST_AVATAR_NAME]["color"] = LLColor4::green3.getValue(); | ||
709 | } | ||
710 | |||
711 | char temp[32]; | ||
712 | LLColor4 color = LLColor4::black; | ||
713 | element["columns"][LIST_DISTANCE]["column"] = "distance"; | ||
714 | element["columns"][LIST_DISTANCE]["type"] = "text"; | ||
715 | if (UnknownAltitude) | ||
716 | { | ||
717 | strcpy(temp, "?"); | ||
718 | if (entry->isDrawn()) | ||
719 | { | ||
720 | color = LLColor4::green2; | ||
721 | } | ||
722 | } | ||
723 | else | ||
724 | { | ||
725 | if (distance < 100.0) | ||
726 | { | ||
727 | snprintf(temp, sizeof(temp), "%.1f", distance); | ||
728 | if (distance > 20.0f) | ||
729 | { | ||
730 | color = LLColor4::yellow1; | ||
731 | } | ||
732 | else | ||
733 | { | ||
734 | color = LLColor4::red; | ||
735 | } | ||
736 | } | ||
737 | else | ||
738 | { | ||
739 | if (entry->isDrawn()) | ||
740 | { | ||
741 | color = LLColor4::green2; | ||
742 | } | ||
743 | snprintf(temp, sizeof(temp), "%d", (S32)distance); | ||
744 | } | ||
745 | } | ||
746 | element["columns"][LIST_DISTANCE]["value"] = temp; | ||
747 | element["columns"][LIST_DISTANCE]["color"] = color.getValue(); | ||
748 | |||
749 | position = position - simpos; | ||
750 | |||
751 | S32 x = (S32)position.mdV[VX]; | ||
752 | S32 y = (S32)position.mdV[VY]; | ||
753 | if (x >= 0 && x <= 256 && y >= 0 && y <= 256) | ||
754 | { | ||
755 | snprintf(temp, sizeof(temp), "%d, %d", x, y); | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | temp[0] = '\0'; | ||
760 | if (y < 0) | ||
761 | { | ||
762 | strcat(temp, "S"); | ||
763 | } | ||
764 | else if (y > 256) | ||
765 | { | ||
766 | strcat(temp, "N"); | ||
767 | } | ||
768 | if (x < 0) | ||
769 | { | ||
770 | strcat(temp, "W"); | ||
771 | } | ||
772 | else if (x > 256) | ||
773 | { | ||
774 | strcat(temp, "E"); | ||
775 | } | ||
776 | } | ||
777 | element["columns"][LIST_POSITION]["column"] = "position"; | ||
778 | element["columns"][LIST_POSITION]["type"] = "text"; | ||
779 | element["columns"][LIST_POSITION]["value"] = temp; | ||
780 | |||
781 | element["columns"][LIST_ALTITUDE]["column"] = "altitude"; | ||
782 | element["columns"][LIST_ALTITUDE]["type"] = "text"; | ||
783 | if (UnknownAltitude) | ||
784 | { | ||
785 | strcpy(temp, "?"); | ||
786 | } | ||
787 | else | ||
788 | { | ||
789 | snprintf(temp, sizeof(temp), "%d", (S32)position.mdV[VZ]); | ||
790 | } | ||
791 | element["columns"][LIST_ALTITUDE]["value"] = temp; | ||
792 | |||
793 | // Add to list | ||
794 | mAvatarList->addElement(element, ADD_BOTTOM); | ||
795 | } | ||
796 | |||
797 | // finish | ||
798 | mAvatarList->sortItems(); | ||
799 | mAvatarList->selectMultiple(selected); | ||
800 | mAvatarList->setScrollPos(scrollpos); | ||
801 | |||
802 | // llinfos << "radar refresh: done" << llendl; | ||
803 | |||
804 | } | ||
805 | |||
806 | // static | ||
807 | void LLFloaterAvatarList::onClickIM(void* userdata) | ||
808 | { | ||
809 | //llinfos << "LLFloaterFriends::onClickIM()" << llendl; | ||
810 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
811 | |||
812 | LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs(); | ||
813 | if (ids.size() > 0) | ||
814 | { | ||
815 | if (ids.size() == 1) | ||
816 | { | ||
817 | // Single avatar | ||
818 | LLUUID agent_id = ids[0]; | ||
819 | |||
820 | char buffer[MAX_STRING]; | ||
821 | snprintf(buffer, MAX_STRING, "%s", self->mAvatars[agent_id].getName().c_str()); | ||
822 | gIMMgr->setFloaterOpen(TRUE); | ||
823 | gIMMgr->addSession(buffer, IM_NOTHING_SPECIAL, agent_id); | ||
824 | } | ||
825 | else | ||
826 | { | ||
827 | // Group IM | ||
828 | LLUUID session_id; | ||
829 | session_id.generate(); | ||
830 | gIMMgr->setFloaterOpen(TRUE); | ||
831 | gIMMgr->addSession("Avatars Conference", IM_SESSION_CONFERENCE_START, ids[0], ids); | ||
832 | } | ||
833 | } | ||
834 | } | ||
835 | |||
836 | void LLFloaterAvatarList::onClickTeleportOffer(void *userdata) | ||
837 | { | ||
838 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
839 | |||
840 | LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs(); | ||
841 | if (ids.size() > 0) | ||
842 | { | ||
843 | handle_lure(ids); | ||
844 | } | ||
845 | } | ||
846 | |||
847 | void LLFloaterAvatarList::onClickTrack(void *userdata) | ||
848 | { | ||
849 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
850 | |||
851 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
852 | if (!item) return; | ||
853 | |||
854 | LLUUID agent_id = item->getUUID(); | ||
855 | |||
856 | if (self->mTracking && self->mTrackedAvatar == agent_id) { | ||
857 | self->stopTracker(); | ||
858 | } | ||
859 | else | ||
860 | { | ||
861 | self->mTracking = TRUE; | ||
862 | self->mTrackedAvatar = agent_id; | ||
863 | // trackAvatar only works for friends allowing you to see them on map... | ||
864 | // LLTracker::trackAvatar(agent_id, self->mAvatars[agent_id].getDisplayName()); | ||
865 | std::string name = self->mAvatars[agent_id].getDisplayName(); | ||
866 | if (!self->mUpdate) | ||
867 | { | ||
868 | name += "\n(last known position)"; | ||
869 | } | ||
870 | LLTracker::trackLocation(self->mAvatars[agent_id].getPosition(), name, ""); | ||
871 | } | ||
872 | } | ||
873 | |||
874 | void LLFloaterAvatarList::stopTracker() | ||
875 | { | ||
876 | LLTracker::stopTracking(NULL); | ||
877 | mTracking = FALSE; | ||
878 | } | ||
879 | |||
880 | void LLFloaterAvatarList::refreshTracker() | ||
881 | { | ||
882 | if (!mTracking) return; | ||
883 | |||
884 | if (LLTracker::isTracking(NULL)) | ||
885 | { | ||
886 | LLVector3d pos; | ||
887 | if (mUpdate) | ||
888 | { | ||
889 | pos = mAvatars[mTrackedAvatar].getPosition(); | ||
890 | } | ||
891 | else | ||
892 | { | ||
893 | LLViewerObject *obj = gObjectList.findObject(mTrackedAvatar); | ||
894 | if (!obj) | ||
895 | { | ||
896 | stopTracker(); | ||
897 | return; | ||
898 | } | ||
899 | LLVOAvatar* avatarp = dynamic_cast<LLVOAvatar*>(obj); | ||
900 | if (!avatarp) | ||
901 | { | ||
902 | stopTracker(); | ||
903 | return; | ||
904 | } | ||
905 | pos = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); | ||
906 | } | ||
907 | if (pos != LLTracker::getTrackedPositionGlobal()) | ||
908 | { | ||
909 | std::string name = mAvatars[mTrackedAvatar].getDisplayName(); | ||
910 | LLTracker::trackLocation(pos, name, ""); | ||
911 | } | ||
912 | } | ||
913 | else | ||
914 | { | ||
915 | stopTracker(); | ||
916 | } | ||
917 | } | ||
918 | |||
919 | LLAvatarListEntry * LLFloaterAvatarList::getAvatarEntry(LLUUID avatar) | ||
920 | { | ||
921 | if (avatar.isNull()) | ||
922 | { | ||
923 | return NULL; | ||
924 | } | ||
925 | |||
926 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
927 | |||
928 | iter = mAvatars.find(avatar); | ||
929 | if (iter == mAvatars.end()) | ||
930 | { | ||
931 | return NULL; | ||
932 | } | ||
933 | |||
934 | return &iter->second; | ||
935 | } | ||
936 | |||
937 | //static | ||
938 | void LLFloaterAvatarList::onClickMark(void *userdata) | ||
939 | { | ||
940 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
941 | LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs(); | ||
942 | |||
943 | for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr) | ||
944 | { | ||
945 | LLUUID avid = *itr; | ||
946 | LLAvatarListEntry *entry = self->getAvatarEntry(avid); | ||
947 | if (entry != NULL) | ||
948 | { | ||
949 | entry->toggleMark(); | ||
950 | } | ||
951 | } | ||
952 | } | ||
953 | |||
954 | void LLFloaterAvatarList::onClickFocus(void *userdata) | ||
955 | { | ||
956 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
957 | |||
958 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
959 | if (item) | ||
960 | { | ||
961 | self->mFocusedAvatar = item->getUUID(); | ||
962 | self->focusOnCurrent(); | ||
963 | } | ||
964 | } | ||
965 | |||
966 | void LLFloaterAvatarList::removeFocusFromAll() | ||
967 | { | ||
968 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
969 | |||
970 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
971 | { | ||
972 | LLAvatarListEntry *entry = &iter->second; | ||
973 | entry->setFocus(FALSE); | ||
974 | } | ||
975 | } | ||
976 | |||
977 | void LLFloaterAvatarList::focusOnCurrent() | ||
978 | { | ||
979 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
980 | LLAvatarListEntry *entry; | ||
981 | |||
982 | if (mAvatars.size() == 0) | ||
983 | { | ||
984 | return; | ||
985 | } | ||
986 | |||
987 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
988 | { | ||
989 | entry = &iter->second; | ||
990 | |||
991 | if (entry->isDead()) | ||
992 | continue; | ||
993 | |||
994 | if (entry->getID() == mFocusedAvatar) | ||
995 | { | ||
996 | removeFocusFromAll(); | ||
997 | entry->setFocus(TRUE); | ||
998 | gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT); | ||
999 | return; | ||
1000 | } | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | void LLFloaterAvatarList::focusOnPrev(BOOL marked_only) | ||
1005 | { | ||
1006 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
1007 | LLAvatarListEntry *prev = NULL; | ||
1008 | LLAvatarListEntry *entry; | ||
1009 | |||
1010 | if (mAvatars.size() == 0) | ||
1011 | { | ||
1012 | return; | ||
1013 | } | ||
1014 | |||
1015 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
1016 | { | ||
1017 | entry = &iter->second; | ||
1018 | |||
1019 | if (entry->isDead()) | ||
1020 | continue; | ||
1021 | |||
1022 | if (prev != NULL && entry->getID() == mFocusedAvatar) | ||
1023 | { | ||
1024 | break; | ||
1025 | } | ||
1026 | |||
1027 | if ((!marked_only && entry->isDrawn()) || entry->isMarked()) | ||
1028 | { | ||
1029 | prev = entry; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | if (prev != NULL) | ||
1034 | { | ||
1035 | removeFocusFromAll(); | ||
1036 | prev->setFocus(TRUE); | ||
1037 | mFocusedAvatar = prev->getID(); | ||
1038 | gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT); | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | void LLFloaterAvatarList::focusOnNext(BOOL marked_only) | ||
1043 | { | ||
1044 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
1045 | BOOL found = FALSE; | ||
1046 | LLAvatarListEntry *next = NULL; | ||
1047 | LLAvatarListEntry *entry; | ||
1048 | |||
1049 | if (mAvatars.size() == 0) | ||
1050 | { | ||
1051 | return; | ||
1052 | } | ||
1053 | |||
1054 | for (iter = mAvatars.begin(); iter != mAvatars.end(); iter++) | ||
1055 | { | ||
1056 | entry = &iter->second; | ||
1057 | |||
1058 | if (entry->isDead()) | ||
1059 | continue; | ||
1060 | |||
1061 | if (next == NULL && ((!marked_only && entry->isDrawn()) || entry->isMarked())) | ||
1062 | { | ||
1063 | next = entry; | ||
1064 | } | ||
1065 | |||
1066 | if (found && ((!marked_only && entry->isDrawn()) || entry->isMarked())) | ||
1067 | { | ||
1068 | next = entry; | ||
1069 | break; | ||
1070 | } | ||
1071 | |||
1072 | if (entry->getID() == mFocusedAvatar) | ||
1073 | { | ||
1074 | found = TRUE; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | if (next != NULL) | ||
1079 | { | ||
1080 | removeFocusFromAll(); | ||
1081 | next->setFocus(TRUE); | ||
1082 | mFocusedAvatar = next->getID(); | ||
1083 | gAgent.lookAtObject(mFocusedAvatar, CAMERA_POSITION_OBJECT); | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | //static | ||
1088 | void LLFloaterAvatarList::onClickPrevInList(void *userdata) | ||
1089 | { | ||
1090 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1091 | self->focusOnPrev(FALSE); | ||
1092 | } | ||
1093 | |||
1094 | //static | ||
1095 | void LLFloaterAvatarList::onClickNextInList(void *userdata) | ||
1096 | { | ||
1097 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1098 | self->focusOnNext(FALSE); | ||
1099 | } | ||
1100 | |||
1101 | //static | ||
1102 | void LLFloaterAvatarList::onClickPrevMarked(void *userdata) | ||
1103 | { | ||
1104 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1105 | self->focusOnPrev(TRUE); | ||
1106 | } | ||
1107 | |||
1108 | //static | ||
1109 | void LLFloaterAvatarList::onClickNextMarked(void *userdata) | ||
1110 | { | ||
1111 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1112 | self->focusOnNext(TRUE); | ||
1113 | } | ||
1114 | |||
1115 | //static | ||
1116 | void LLFloaterAvatarList::onClickGetKey(void *userdata) | ||
1117 | { | ||
1118 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1119 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
1120 | |||
1121 | if (NULL == item) return; | ||
1122 | |||
1123 | LLUUID agent_id = item->getUUID(); | ||
1124 | |||
1125 | char buffer[UUID_STR_LENGTH]; /*Flawfinder: ignore*/ | ||
1126 | agent_id.toString(buffer); | ||
1127 | |||
1128 | gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer)); | ||
1129 | } | ||
1130 | |||
1131 | void LLFloaterAvatarList::onClickSendKeys(void *userdata) | ||
1132 | { | ||
1133 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1134 | std::map<LLUUID, LLAvatarListEntry>::iterator iter; | ||
1135 | LLAvatarListEntry *entry; | ||
1136 | |||
1137 | if (self->mAvatars.size() == 0) | ||
1138 | return; | ||
1139 | |||
1140 | for (iter = self->mAvatars.begin(); iter != self->mAvatars.end(); iter++) | ||
1141 | { | ||
1142 | entry = &iter->second; | ||
1143 | |||
1144 | if (!entry->isDead() && entry->isInSim()) | ||
1145 | announce(entry->getID().asString()); | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | static void send_freeze(const LLUUID& avatar_id, bool freeze) | ||
1150 | { | ||
1151 | U32 flags = 0x0; | ||
1152 | if (!freeze) | ||
1153 | { | ||
1154 | // unfreeze | ||
1155 | flags |= 0x1; | ||
1156 | } | ||
1157 | |||
1158 | LLMessageSystem* msg = gMessageSystem; | ||
1159 | LLViewerObject* avatar = gObjectList.findObject(avatar_id); | ||
1160 | |||
1161 | if (avatar) | ||
1162 | { | ||
1163 | msg->newMessage("FreezeUser"); | ||
1164 | msg->nextBlock("AgentData"); | ||
1165 | msg->addUUID("AgentID", gAgent.getID()); | ||
1166 | msg->addUUID("SessionID", gAgent.getSessionID()); | ||
1167 | msg->nextBlock("Data"); | ||
1168 | msg->addUUID("TargetID", avatar_id); | ||
1169 | msg->addU32("Flags", flags); | ||
1170 | msg->sendReliable( avatar->getRegion()->getHost()); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | static void send_eject(const LLUUID& avatar_id, bool ban) | ||
1175 | { | ||
1176 | LLMessageSystem* msg = gMessageSystem; | ||
1177 | LLViewerObject* avatar = gObjectList.findObject(avatar_id); | ||
1178 | |||
1179 | if (avatar) | ||
1180 | { | ||
1181 | U32 flags = 0x0; | ||
1182 | if (ban) | ||
1183 | { | ||
1184 | // eject and add to ban list | ||
1185 | flags |= 0x1; | ||
1186 | } | ||
1187 | |||
1188 | msg->newMessage("EjectUser"); | ||
1189 | msg->nextBlock("AgentData"); | ||
1190 | msg->addUUID("AgentID", gAgent.getID()); | ||
1191 | msg->addUUID("SessionID", gAgent.getSessionID()); | ||
1192 | msg->nextBlock("Data"); | ||
1193 | msg->addUUID("TargetID", avatar_id); | ||
1194 | msg->addU32("Flags", flags); | ||
1195 | msg->sendReliable( avatar->getRegion()->getHost()); | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | static void send_estate_message( | ||
1200 | const char* request, | ||
1201 | const LLUUID &target) | ||
1202 | { | ||
1203 | |||
1204 | LLMessageSystem* msg = gMessageSystem; | ||
1205 | LLUUID invoice; | ||
1206 | |||
1207 | // This seems to provide an ID so that the sim can say which request it's | ||
1208 | // replying to. I think this can be ignored for now. | ||
1209 | invoice.generate(); | ||
1210 | |||
1211 | llinfos << "Sending estate request '" << request << "'" << llendl; | ||
1212 | msg->newMessage("EstateOwnerMessage"); | ||
1213 | msg->nextBlockFast(_PREHASH_AgentData); | ||
1214 | msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); | ||
1215 | msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); | ||
1216 | msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used | ||
1217 | msg->nextBlock("MethodData"); | ||
1218 | msg->addString("Method", request); | ||
1219 | msg->addUUID("Invoice", invoice); | ||
1220 | |||
1221 | // Agent id | ||
1222 | msg->nextBlock("ParamList"); | ||
1223 | msg->addString("Parameter", gAgent.getID().asString().c_str()); | ||
1224 | |||
1225 | // Target | ||
1226 | msg->nextBlock("ParamList"); | ||
1227 | msg->addString("Parameter", target.asString().c_str()); | ||
1228 | |||
1229 | msg->sendReliable(gAgent.getRegion()->getHost()); | ||
1230 | } | ||
1231 | |||
1232 | static void cmd_freeze(const LLUUID& avatar, const std::string &name) { send_freeze(avatar, true); } | ||
1233 | static void cmd_unfreeze(const LLUUID& avatar, const std::string &name) { send_freeze(avatar, false); } | ||
1234 | static void cmd_eject(const LLUUID& avatar, const std::string &name) { send_eject(avatar, false); } | ||
1235 | static void cmd_ban(const LLUUID& avatar, const std::string &name) { send_eject(avatar, true); } | ||
1236 | static void cmd_profile(const LLUUID& avatar, const std::string &name) { LLFloaterAvatarInfo::showFromDirectory(avatar); } | ||
1237 | static void cmd_estate_eject(const LLUUID &avatar, const std::string &name){ send_estate_message("teleporthomeuser", avatar); } | ||
1238 | |||
1239 | void LLFloaterAvatarList::doCommand(void (*func)(const LLUUID &avatar, const std::string &name)) | ||
1240 | { | ||
1241 | LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs(); | ||
1242 | |||
1243 | for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr) | ||
1244 | { | ||
1245 | LLUUID avid = *itr; | ||
1246 | LLAvatarListEntry *entry = getAvatarEntry(avid); | ||
1247 | if (entry != NULL) | ||
1248 | { | ||
1249 | llinfos << "Executing command on " << entry->getDisplayName() << llendl; | ||
1250 | func(avid, entry->getName()); | ||
1251 | } | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | std::string LLFloaterAvatarList::getSelectedNames(const std::string& separator) | ||
1256 | { | ||
1257 | std::string ret = ""; | ||
1258 | |||
1259 | LLDynamicArray<LLUUID> ids = mAvatarList->getSelectedIDs(); | ||
1260 | for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr) | ||
1261 | { | ||
1262 | LLUUID avid = *itr; | ||
1263 | LLAvatarListEntry *entry = getAvatarEntry(avid); | ||
1264 | if (entry != NULL) | ||
1265 | { | ||
1266 | if (!ret.empty()) ret += separator; | ||
1267 | ret += entry->getName(); | ||
1268 | } | ||
1269 | } | ||
1270 | |||
1271 | return ret; | ||
1272 | } | ||
1273 | |||
1274 | std::string LLFloaterAvatarList::getSelectedName() | ||
1275 | { | ||
1276 | LLUUID id = getSelectedID(); | ||
1277 | LLAvatarListEntry *entry = getAvatarEntry(id); | ||
1278 | if (entry) | ||
1279 | { | ||
1280 | return entry->getName(); | ||
1281 | } | ||
1282 | return ""; | ||
1283 | } | ||
1284 | |||
1285 | LLUUID LLFloaterAvatarList::getSelectedID() | ||
1286 | { | ||
1287 | LLScrollListItem *item = mAvatarList->getFirstSelected(); | ||
1288 | if (item) return item->getUUID(); | ||
1289 | return LLUUID::null; | ||
1290 | } | ||
1291 | |||
1292 | //static | ||
1293 | void LLFloaterAvatarList::callbackFreeze(const LLSD& notification, const LLSD& response) | ||
1294 | { | ||
1295 | S32 option = LLNotification::getSelectedOption(notification, response); | ||
1296 | |||
1297 | LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; | ||
1298 | |||
1299 | if (option == 0) | ||
1300 | { | ||
1301 | self->doCommand(cmd_freeze); | ||
1302 | } | ||
1303 | else if (option == 1) | ||
1304 | { | ||
1305 | self->doCommand(cmd_unfreeze); | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | //static | ||
1310 | void LLFloaterAvatarList::callbackEject(const LLSD& notification, const LLSD& response) | ||
1311 | { | ||
1312 | S32 option = LLNotification::getSelectedOption(notification, response); | ||
1313 | |||
1314 | LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; | ||
1315 | |||
1316 | if (option == 0) | ||
1317 | { | ||
1318 | self->doCommand(cmd_eject); | ||
1319 | } | ||
1320 | else if (option == 1) | ||
1321 | { | ||
1322 | self->doCommand(cmd_ban); | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1326 | //static | ||
1327 | void LLFloaterAvatarList::callbackEjectFromEstate(const LLSD& notification, const LLSD& response) | ||
1328 | { | ||
1329 | S32 option = LLNotification::getSelectedOption(notification, response); | ||
1330 | |||
1331 | LLFloaterAvatarList *self = LLFloaterAvatarList::sInstance; | ||
1332 | |||
1333 | if (option == 0) | ||
1334 | { | ||
1335 | self->doCommand(cmd_estate_eject); | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1339 | //static | ||
1340 | void LLFloaterAvatarList::callbackIdle(void *userdata) { | ||
1341 | if (LLFloaterAvatarList::sInstance != NULL) | ||
1342 | { | ||
1343 | // Do not update at every frame: this would be insane ! | ||
1344 | if (gFrameCount % LLFloaterAvatarList::sInstance->mUpdateRate == 0) | ||
1345 | { | ||
1346 | LLFloaterAvatarList::sInstance->updateAvatarList(); | ||
1347 | } | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | void LLFloaterAvatarList::onClickFreeze(void *userdata) | ||
1352 | { | ||
1353 | LLSD args; | ||
1354 | LLSD payload; | ||
1355 | args["AVATAR_NAME"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames(); | ||
1356 | LLNotifications::instance().add("FreezeAvatarFullname", args, payload, callbackFreeze); | ||
1357 | } | ||
1358 | |||
1359 | //static | ||
1360 | void LLFloaterAvatarList::onClickEject(void *userdata) | ||
1361 | { | ||
1362 | LLSD args; | ||
1363 | LLSD payload; | ||
1364 | args["AVATAR_NAME"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames(); | ||
1365 | LLNotifications::instance().add("EjectAvatarFullname", args, payload, callbackEject); | ||
1366 | } | ||
1367 | |||
1368 | //static | ||
1369 | void LLFloaterAvatarList::onClickMute(void *userdata) | ||
1370 | { | ||
1371 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1372 | |||
1373 | LLDynamicArray<LLUUID> ids = self->mAvatarList->getSelectedIDs(); | ||
1374 | if (ids.size() > 0) | ||
1375 | { | ||
1376 | for (LLDynamicArray<LLUUID>::iterator itr = ids.begin(); itr != ids.end(); ++itr) | ||
1377 | { | ||
1378 | LLUUID agent_id = *itr; | ||
1379 | |||
1380 | std::string agent_name; | ||
1381 | if (gCacheName->getFullName(agent_id, agent_name)) | ||
1382 | { | ||
1383 | if (LLMuteList::getInstance()->isMuted(agent_id)) | ||
1384 | { | ||
1385 | LLMute mute(agent_id, agent_name, LLMute::AGENT); | ||
1386 | LLMuteList::getInstance()->remove(mute); | ||
1387 | } | ||
1388 | else | ||
1389 | { | ||
1390 | LLMute mute(agent_id, agent_name, LLMute::AGENT); | ||
1391 | LLMuteList::getInstance()->add(mute); | ||
1392 | } | ||
1393 | } | ||
1394 | } | ||
1395 | } | ||
1396 | } | ||
1397 | |||
1398 | //static | ||
1399 | void LLFloaterAvatarList::onClickEjectFromEstate(void *userdata) | ||
1400 | { | ||
1401 | LLSD args; | ||
1402 | LLSD payload; | ||
1403 | args["EVIL_USER"] = ((LLFloaterAvatarList*)userdata)->getSelectedNames(); | ||
1404 | LLNotifications::instance().add("EstateKickUser", args, payload, callbackEjectFromEstate); | ||
1405 | } | ||
1406 | |||
1407 | //static | ||
1408 | void LLFloaterAvatarList::onClickAR(void *userdata) | ||
1409 | { | ||
1410 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1411 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
1412 | if (item) | ||
1413 | { | ||
1414 | LLUUID agent_id = item->getUUID(); | ||
1415 | LLAvatarListEntry *entry = self->getAvatarEntry(agent_id); | ||
1416 | if (entry) | ||
1417 | { | ||
1418 | LLFloaterReporter::showFromObject(entry->getID()); | ||
1419 | } | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | // static | ||
1424 | void LLFloaterAvatarList::onClickProfile(void* userdata) | ||
1425 | { | ||
1426 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1427 | self->doCommand(cmd_profile); | ||
1428 | } | ||
1429 | |||
1430 | //static | ||
1431 | void LLFloaterAvatarList::onClickTeleport(void* userdata) | ||
1432 | { | ||
1433 | LLFloaterAvatarList *self = (LLFloaterAvatarList*)userdata; | ||
1434 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
1435 | if (item) | ||
1436 | { | ||
1437 | LLUUID agent_id = item->getUUID(); | ||
1438 | LLAvatarListEntry *entry = self->getAvatarEntry(agent_id); | ||
1439 | if (entry) | ||
1440 | { | ||
1441 | // llinfos << "Trying to teleport to " << entry->getDisplayName() << " at " << entry->getPosition() << llendl; | ||
1442 | gAgent.teleportViaLocation(entry->getPosition()); | ||
1443 | } | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1447 | void LLFloaterAvatarList::onSelectName(LLUICtrl*, void* userdata) | ||
1448 | { | ||
1449 | LLFloaterAvatarList* self = (LLFloaterAvatarList*)userdata; | ||
1450 | |||
1451 | LLScrollListItem *item = self->mAvatarList->getFirstSelected(); | ||
1452 | if (item) | ||
1453 | { | ||
1454 | LLUUID agent_id = item->getUUID(); | ||
1455 | LLAvatarListEntry *entry = self->getAvatarEntry(agent_id); | ||
1456 | if (entry) | ||
1457 | { | ||
1458 | BOOL enabled = entry->isDrawn(); | ||
1459 | self->childSetEnabled("focus_btn", enabled); | ||
1460 | self->childSetEnabled("prev_in_list_btn", enabled); | ||
1461 | self->childSetEnabled("next_in_list_btn", enabled); | ||
1462 | } | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | void LLFloaterAvatarList::onCommitUpdateRate(LLUICtrl*, void* userdata) | ||
1467 | { | ||
1468 | LLFloaterAvatarList* self = (LLFloaterAvatarList*)userdata; | ||
1469 | |||
1470 | self->mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3; | ||
1471 | } | ||