aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerparcelmgr.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerparcelmgr.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llviewerparcelmgr.cpp2580
1 files changed, 2580 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerparcelmgr.cpp b/linden/indra/newview/llviewerparcelmgr.cpp
new file mode 100644
index 0000000..af910e8
--- /dev/null
+++ b/linden/indra/newview/llviewerparcelmgr.cpp
@@ -0,0 +1,2580 @@
1/**
2 * @file llviewerparcelmgr.cpp
3 * @brief Viewer-side representation of owned land
4 *
5 * Copyright (c) 2002-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 "llviewerparcelmgr.h"
31
32// Library includes
33#include "audioengine.h"
34#include "indra_constants.h"
35#include "llcachename.h"
36#include "llgl.h"
37#include "llmediaengine.h"
38#include "llparcel.h"
39#include "llsecondlifeurls.h"
40#include "message.h"
41
42// Viewer includes
43#include "llagent.h"
44#include "llfloatergroupinfo.h"
45#include "llviewerwindow.h"
46#include "llviewercontrol.h"
47#include "llfirstuse.h"
48#include "llfloaterbuyland.h"
49#include "llfloatergroups.h"
50#include "llfloaterhtml.h"
51#include "llfloatersellland.h"
52#include "llfloatertools.h"
53#include "llnotify.h"
54#include "llresmgr.h"
55#include "llstatusbar.h"
56#include "llui.h"
57#include "llviewerimagelist.h"
58#include "llviewermenu.h"
59#include "llviewerparceloverlay.h"
60#include "llviewerregion.h"
61//#include "llwebbrowserctrl.h"
62#include "llworld.h"
63#include "lloverlaybar.h"
64#include "roles_constants.h"
65
66const F32 PARCEL_COLLISION_DRAW_SECS = 1.f;
67
68// Globals
69LLViewerParcelMgr *gParcelMgr = NULL;
70
71U8* LLViewerParcelMgr::sPackedOverlay = NULL;
72
73LLUUID gCurrentMovieID = LLUUID::null;
74
75// Local functions
76void optionally_start_music(const LLString& music_url);
77void callback_start_music(S32 option, void* data);
78void optionally_prepare_video(const LLParcel *parcelp);
79void callback_prepare_video(S32 option, void* data);
80void prepare_video(const LLParcel *parcelp);
81void start_video(const LLParcel *parcelp);
82void stop_video();
83void callback_god_force_owner(S32 option, void* user_data);
84
85struct LLGodForceOwnerData
86{
87 LLUUID mOwnerID;
88 S32 mLocalID;
89 LLHost mHost;
90
91 LLGodForceOwnerData(
92 const LLUUID& owner_id,
93 S32 local_parcel_id,
94 const LLHost& host) :
95 mOwnerID(owner_id),
96 mLocalID(local_parcel_id),
97 mHost(host) {}
98};
99
100//
101// Methods
102//
103LLViewerParcelMgr::LLViewerParcelMgr()
104: mSelected(FALSE),
105 mSelectedMultipleOwners(FALSE),
106 mWholeParcelSelected(FALSE),
107 mWestSouth(),
108 mEastNorth(),
109 mSelectedDwell(0.f),
110 mAgentParcelSequenceID(-1),
111 mHoverWestSouth(),
112 mHoverEastNorth(),
113 mRenderCollision(FALSE),
114 mRenderSelection(TRUE),
115 mCollisionBanned(0),
116 mCollisionTimer(),
117 mMediaParcelId(0),
118 mMediaRegionId(0)
119{
120 mParcel = new LLParcel();
121 mAgentParcel = new LLParcel();
122 mHoverParcel = new LLParcel();
123 mCollisionParcel = new LLParcel();
124
125 mParcelsPerEdge = S32( REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS );
126 mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
127 resetSegments(mHighlightSegments);
128
129 mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)];
130 resetSegments(mCollisionSegments);
131
132 mBlockedImageID.set(gViewerArt.getString("noentrylines.tga"));
133 mBlockedImage = gImageList.getImage(mBlockedImageID, TRUE, TRUE);
134
135 mPassImageID.set(gViewerArt.getString("noentrypasslines.tga"));
136 mPassImage = gImageList.getImage(mPassImageID, TRUE, TRUE);
137
138 S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS;
139 sPackedOverlay = new U8[overlay_size];
140
141 mAgentParcelOverlay = new U8[mParcelsPerEdge * mParcelsPerEdge];
142 S32 i;
143 for (i = 0; i < mParcelsPerEdge * mParcelsPerEdge; i++)
144 {
145 mAgentParcelOverlay[i] = 0;
146 }
147}
148
149
150LLViewerParcelMgr::~LLViewerParcelMgr()
151{
152 delete mParcel;
153 mParcel = NULL;
154
155 delete mAgentParcel;
156 mAgentParcel = NULL;
157
158 delete mCollisionParcel;
159 mCollisionParcel = NULL;
160
161 delete mHoverParcel;
162 mHoverParcel = NULL;
163
164 delete[] mHighlightSegments;
165 mHighlightSegments = NULL;
166
167 delete[] mCollisionSegments;
168 mCollisionSegments = NULL;
169
170 // weird, this crashes if I use an array delete on it!
171 delete sPackedOverlay;
172 sPackedOverlay = NULL;
173
174 delete[] mAgentParcelOverlay;
175 mAgentParcelOverlay = NULL;
176}
177
178
179void LLViewerParcelMgr::destroyGL()
180{
181 mBlockedImage = NULL;
182 mPassImage = NULL;
183}
184
185
186void LLViewerParcelMgr::restoreGL()
187{
188 mBlockedImage = gImageList.getImage(mBlockedImageID, TRUE, TRUE);
189 mPassImage = gImageList.getImage(mPassImageID, TRUE, TRUE);
190}
191
192
193void LLViewerParcelMgr::dump()
194{
195 llinfos << "Parcel Manager Dump" << llendl;
196 llinfos << "mSelected " << S32(mSelected) << llendl;
197 llinfos << "Selected parcel: " << llendl;
198 llinfos << mWestSouth << " to " << mEastNorth << llendl;
199 mParcel->dump();
200 llinfos << "banning " << mParcel->mBanList.size() << llendl;
201
202 access_map_const_iterator cit = mParcel->mBanList.begin();
203 access_map_const_iterator end = mParcel->mBanList.end();
204 for ( ; cit != end; ++cit)
205 {
206 llinfos << "ban id " << (*cit).first << llendl;
207 }
208 llinfos << "Hover parcel:" << llendl;
209 mHoverParcel->dump();
210 llinfos << "Agent parcel:" << llendl;
211 mAgentParcel->dump();
212}
213
214
215LLViewerRegion* LLViewerParcelMgr::getSelectionRegion()
216{
217 if (!gWorldp) return NULL;
218
219 return gWorldp->getRegionFromPosGlobal( mWestSouth );
220}
221
222
223void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out,
224 S32* rent_out,
225 BOOL* for_sale_out,
226 F32* dwell_out)
227{
228 S32 area = 0;
229 S32 price = 0;
230 S32 rent = 0;
231 BOOL for_sale = FALSE;
232 F32 dwell = 0.f;
233
234 if (mSelected)
235 {
236 if (mSelectedMultipleOwners)
237 {
238 area = getClaimableArea();
239 }
240 else
241 {
242 area = getSelectedArea();
243 }
244
245 if (mParcel->getForSale())
246 {
247 price = mParcel->getSalePrice();
248 for_sale = TRUE;
249 }
250 else
251 {
252 price = area * mParcel->getClaimPricePerMeter();
253 for_sale = FALSE;
254 }
255
256 rent = mParcel->getTotalRent();
257
258 dwell = mSelectedDwell;
259 }
260
261 *area_out = area;
262 *claim_out = price;
263 *rent_out = rent;
264 *for_sale_out = for_sale;
265 *dwell_out = dwell;
266}
267
268void LLViewerParcelMgr::getPrimInfo(S32 &sw_max, S32 &sw_total, S32 &max, S32 &total, S32 &owner, S32 &group, S32 &other, S32& selected, F32 &parcel_object_bonus, S32 &other_clean)
269{
270 if (mSelected && mParcel)
271 {
272 sw_max = mParcel->getSimWideMaxPrimCapacity();
273 sw_total = mParcel->getSimWidePrimCount();
274 max = llround(mParcel->getMaxPrimCapacity()*mParcel->getParcelPrimBonus());
275 total = mParcel->getPrimCount();
276 owner = mParcel->getOwnerPrimCount();
277 group = mParcel->getGroupPrimCount();
278 other = mParcel->getOtherPrimCount();
279 selected = mParcel->getSelectedPrimCount();
280 parcel_object_bonus = mParcel->getParcelPrimBonus();
281 other_clean = mParcel->getCleanOtherTime();
282 }
283}
284
285BOOL LLViewerParcelMgr::getMultipleOwners() const
286{
287 return mSelectedMultipleOwners;
288}
289
290
291BOOL LLViewerParcelMgr::getWholeParcelSelected() const
292{
293 return mWholeParcelSelected;
294}
295
296
297S32 LLViewerParcelMgr::getClaimableArea() const
298{
299 const S32 UNIT_AREA = S32( PARCEL_GRID_STEP_METERS * PARCEL_GRID_STEP_METERS );
300 return mSelectedPublicCount * UNIT_AREA;
301}
302
303bool LLViewerParcelMgr::hasOthersSelected() const
304{
305 return mSelectedOtherCount != 0;
306}
307
308
309S32 LLViewerParcelMgr::getSelectedArea() const
310{
311 S32 rv = 0;
312 if(mSelected && mParcel && mWholeParcelSelected)
313 {
314 rv = mParcel->getArea();
315 }
316 else if(mSelected)
317 {
318 F64 width = mEastNorth.mdV[VX] - mWestSouth.mdV[VX];
319 F64 height = mEastNorth.mdV[VY] - mWestSouth.mdV[VY];
320 F32 area = (F32)(width * height);
321 rv = llround(area);
322 }
323 return rv;
324}
325
326void LLViewerParcelMgr::resetSegments(U8* segments)
327{
328 S32 i;
329 S32 count = (mParcelsPerEdge+1)*(mParcelsPerEdge+1);
330 for (i = 0; i < count; i++)
331 {
332 segments[i] = 0x0;
333 }
334}
335
336
337void LLViewerParcelMgr::writeHighlightSegments(F32 west, F32 south, F32 east,
338 F32 north)
339{
340 S32 x, y;
341 S32 min_x = llround( west / PARCEL_GRID_STEP_METERS );
342 S32 max_x = llround( east / PARCEL_GRID_STEP_METERS );
343 S32 min_y = llround( south / PARCEL_GRID_STEP_METERS );
344 S32 max_y = llround( north / PARCEL_GRID_STEP_METERS );
345
346 const S32 STRIDE = mParcelsPerEdge+1;
347
348 // south edge
349 y = min_y;
350 for (x = min_x; x < max_x; x++)
351 {
352 // exclusive OR means that writing to this segment twice
353 // will turn it off
354 mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
355 }
356
357 // west edge
358 x = min_x;
359 for (y = min_y; y < max_y; y++)
360 {
361 mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
362 }
363
364 // north edge - draw the south border on the y+1'th cell,
365 // which given C-style arrays, is item foo[max_y]
366 y = max_y;
367 for (x = min_x; x < max_x; x++)
368 {
369 mHighlightSegments[x + y*STRIDE] ^= SOUTH_MASK;
370 }
371
372 // east edge - draw west border on x+1'th cell
373 x = max_x;
374 for (y = min_y; y < max_y; y++)
375 {
376 mHighlightSegments[x + y*STRIDE] ^= WEST_MASK;
377 }
378}
379
380
381void LLViewerParcelMgr::writeSegmentsFromBitmap(U8* bitmap, U8* segments)
382{
383 S32 x;
384 S32 y;
385 const S32 IN_STRIDE = mParcelsPerEdge;
386 const S32 OUT_STRIDE = mParcelsPerEdge+1;
387
388 for (y = 0; y < IN_STRIDE; y++)
389 {
390 x = 0;
391 while( x < IN_STRIDE )
392 {
393 U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
394
395 S32 bit;
396 for (bit = 0; bit < 8; bit++)
397 {
398 if (byte & (1 << bit) )
399 {
400 S32 out = x+y*OUT_STRIDE;
401
402 // This and one above it
403 segments[out] ^= SOUTH_MASK;
404 segments[out+OUT_STRIDE] ^= SOUTH_MASK;
405
406 // This and one to the right
407 segments[out] ^= WEST_MASK;
408 segments[out+1] ^= WEST_MASK;
409 }
410 x++;
411 }
412 }
413 }
414}
415
416
417void LLViewerParcelMgr::writeAgentParcelFromBitmap(U8* bitmap)
418{
419 S32 x;
420 S32 y;
421 const S32 IN_STRIDE = mParcelsPerEdge;
422
423 for (y = 0; y < IN_STRIDE; y++)
424 {
425 x = 0;
426 while( x < IN_STRIDE )
427 {
428 U8 byte = bitmap[ (x + y*IN_STRIDE) / 8 ];
429
430 S32 bit;
431 for (bit = 0; bit < 8; bit++)
432 {
433 if (byte & (1 << bit) )
434 {
435 mAgentParcelOverlay[x+y*IN_STRIDE] = 1;
436 }
437 else
438 {
439 mAgentParcelOverlay[x+y*IN_STRIDE] = 0;
440 }
441 x++;
442 }
443 }
444 }
445}
446
447
448// Given a point, find the PARCEL_GRID_STEP x PARCEL_GRID_STEP block
449// containing it and select that.
450void LLViewerParcelMgr::selectParcelAt(const LLVector3d& pos_global)
451{
452 LLVector3d southwest = pos_global;
453 LLVector3d northeast = pos_global;
454
455 southwest -= LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
456 southwest.mdV[VX] = llround( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
457 southwest.mdV[VY] = llround( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
458
459 northeast += LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 );
460 northeast.mdV[VX] = llround( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS );
461 northeast.mdV[VY] = llround( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS );
462
463 // Snap to parcel
464 selectLand( southwest, northeast, TRUE );
465}
466
467
468// Tries to select the parcel inside the rectangle
469void LLViewerParcelMgr::selectParcelInRectangle()
470{
471 selectLand(mWestSouth, mEastNorth, TRUE);
472}
473
474
475void LLViewerParcelMgr::selectCollisionParcel()
476{
477 if (!gWorldp)
478 {
479 return;
480 }
481
482 // BUG: Claim to be in the agent's region
483 mWestSouth = gAgent.getRegion()->getOriginGlobal();
484 mEastNorth = mWestSouth;
485 mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0);
486
487 // BUG: must be in the sim you are in
488 LLMessageSystem *msg = gMessageSystem;
489 msg->newMessageFast(_PREHASH_ParcelPropertiesRequestByID);
490 msg->nextBlockFast(_PREHASH_AgentID);
491 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
492 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
493 msg->nextBlockFast(_PREHASH_ParcelData);
494 msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID );
495 msg->addS32Fast(_PREHASH_LocalID, mCollisionParcel->getLocalID() );
496 gAgent.sendReliableMessage();
497
498 mRequestResult = PARCEL_RESULT_NO_DATA;
499
500 // Hack: Copy some data over temporarily
501 mParcel->setName( mCollisionParcel->getName() );
502 mParcel->setDesc( mCollisionParcel->getDesc() );
503 mParcel->setPassPrice(mCollisionParcel->getPassPrice());
504 mParcel->setPassHours(mCollisionParcel->getPassHours());
505
506 // clear the list of segments to prevent flashing
507 resetSegments(mHighlightSegments);
508
509 mSelected = TRUE;
510 mWholeParcelSelected = TRUE;
511 notifyObservers();
512 return;
513}
514
515
516// snap_selection = auto-select the hit parcel, if there is exactly one
517void LLViewerParcelMgr::selectLand(const LLVector3d &corner1, const LLVector3d &corner2,
518 BOOL snap_selection)
519{
520 if (!gWorldp)
521 {
522 return;
523 }
524
525 sanitize_corners( corner1, corner2, mWestSouth, mEastNorth );
526
527 // ...x isn't more than one meter away
528 F32 delta_x = getSelectionWidth();
529 if (delta_x * delta_x <= 1.f * 1.f)
530 {
531 mSelected = FALSE;
532 notifyObservers();
533 return;
534 }
535
536 // ...y isn't more than one meter away
537 F32 delta_y = getSelectionHeight();
538 if (delta_y * delta_y <= 1.f * 1.f)
539 {
540 mSelected = FALSE;
541 notifyObservers();
542 return;
543 }
544
545 // Can't select across region boundary
546 // We need to pull in the upper right corner by a little bit to allow
547 // selection up to the x = 256 or y = 256 edge.
548 LLVector3d east_north_region_check( mEastNorth );
549 east_north_region_check.mdV[VX] -= 0.5;
550 east_north_region_check.mdV[VY] -= 0.5;
551
552 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal(mWestSouth);
553 LLViewerRegion *region_other = gWorldp->getRegionFromPosGlobal( east_north_region_check );
554
555 if(!region)
556 {
557 // just in case they somehow selected no land.
558 mSelected = FALSE;
559 return;
560 }
561
562 if (region != region_other)
563 {
564 LLNotifyBox::showXml("CantSelectLandFromMultipleRegions");
565 mSelected = FALSE;
566 notifyObservers();
567 return;
568 }
569
570 // Build region global copies of corners
571 LLVector3 wsb_region = region->getPosRegionFromGlobal( mWestSouth );
572 LLVector3 ent_region = region->getPosRegionFromGlobal( mEastNorth );
573
574 /*
575 // Check land to make sure all is either public, owned, or self
576 LLViewerParcelOverlay* overlay = region->getParcelOverlay();
577 if (!overlay)
578 {
579 llerrs << "No overlay in LLViewerParcelMgr::selectLand" << llendl;
580 return;
581 }
582
583 U8 start_ownership = overlay->ownership( wsb_region );
584 BOOL identical = TRUE;
585 S32 x_steps = S32( getSelectionWidth() / PARCEL_GRID_STEP_METERS );
586 S32 y_steps = S32( getSelectionHeight() / PARCEL_GRID_STEP_METERS );
587
588 for (S32 x = 0; x < x_steps && identical; x++ )
589 {
590 for (S32 y = 0; y < y_steps && identical; y++ )
591 {
592 // strange recomputation each time to avoid error accumulation
593 LLVector3 check = wsb_region;
594 check.mV[VX] += x * PARCEL_GRID_STEP_METERS;
595 check.mV[VY] += y * PARCEL_GRID_STEP_METERS;
596
597 identical = (start_ownership == overlay->ownership(check));
598 }
599 }
600
601 if (!identical)
602 {
603 add_chat("Can't select mix of your own, other people's and public land.", FALSE, "", FALSE, CHAT_SOURCE_SYSTEM);
604 add_chat("Try selecting a smaller piece of land.", FALSE, "", FALSE, CHAT_SOURCE_SYSTEM);
605 mSelected = FALSE;
606 notifyObservers();
607 return;
608 }
609 */
610
611 // Send request message
612 LLMessageSystem *msg = gMessageSystem;
613 msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
614 msg->nextBlockFast(_PREHASH_AgentData);
615 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
616 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
617 msg->nextBlockFast(_PREHASH_ParcelData);
618 msg->addS32Fast(_PREHASH_SequenceID, SELECTED_PARCEL_SEQ_ID );
619 msg->addF32Fast(_PREHASH_West, wsb_region.mV[VX] );
620 msg->addF32Fast(_PREHASH_South, wsb_region.mV[VY] );
621 msg->addF32Fast(_PREHASH_East, ent_region.mV[VX] );
622 msg->addF32Fast(_PREHASH_North, ent_region.mV[VY] );
623 msg->addBOOL("SnapSelection", snap_selection);
624 msg->sendReliable( region->getHost() );
625
626 mRequestResult = PARCEL_RESULT_NO_DATA;
627
628 // clear the list of segments to prevent flashing
629 resetSegments(mHighlightSegments);
630
631 mSelected = TRUE;
632 mWholeParcelSelected = snap_selection;
633 notifyObservers();
634 return;
635}
636
637
638void LLViewerParcelMgr::deselectLand()
639{
640 if (mSelected)
641 {
642 mSelected = FALSE;
643
644 // Invalidate the selected parcel
645 mParcel->setLocalID(-1);
646 mParcel->mAccessList.clear();
647 mParcel->mBanList.clear();
648 //mParcel->mRenterList.reset();
649
650 mSelectedDwell = 0.f;
651
652 notifyObservers();
653 }
654}
655
656
657void LLViewerParcelMgr::addObserver(LLParcelObserver* observer)
658{
659 mObservers.put(observer);
660}
661
662
663void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer)
664{
665 mObservers.removeObj(observer);
666}
667
668
669// Call this method when it's time to update everyone on a new state.
670// Copy the list because an observer could respond by removing itself
671// from the list.
672void LLViewerParcelMgr::notifyObservers()
673{
674 LLDynamicArray<LLParcelObserver*> observers;
675 S32 count = mObservers.count();
676 S32 i;
677 for(i = 0; i < count; ++i)
678 {
679 observers.put(mObservers.get(i));
680 }
681 for(i = 0; i < count; ++i)
682 {
683 observers.get(i)->changed();
684 }
685}
686
687
688//
689// ACCESSORS
690//
691BOOL LLViewerParcelMgr::selectionEmpty() const
692{
693 return !mSelected;
694}
695
696
697LLParcel *LLViewerParcelMgr::getSelectedParcel() const
698{
699 if (mSelected)
700 {
701 return mParcel;
702 }
703 else
704 {
705 return NULL;
706 }
707}
708
709
710LLParcel *LLViewerParcelMgr::getAgentParcel() const
711{
712 return mAgentParcel;
713}
714
715// Return whether the agent can build on the land they are on
716BOOL LLViewerParcelMgr::agentCanBuild() const
717{
718 if (mAgentParcel)
719 {
720 return gAgent.isGodlike()
721 || (mAgentParcel->getOwnerID() == gAgent.getID())
722 || (mAgentParcel->getAllowModify());
723 }
724 else
725 {
726 return gAgent.isGodlike();
727 }
728}
729
730BOOL LLViewerParcelMgr::agentCanTakeDamage() const
731{
732 return mAgentParcel->getAllowDamage();
733}
734
735BOOL LLViewerParcelMgr::agentCanFly() const
736{
737 return TRUE;
738}
739
740F32 LLViewerParcelMgr::agentDrawDistance() const
741{
742 return 512.f;
743}
744
745BOOL LLViewerParcelMgr::isOwnedAt(const LLVector3d& pos_global) const
746{
747 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal( pos_global );
748 if (!region) return FALSE;
749
750 LLViewerParcelOverlay* overlay = region->getParcelOverlay();
751 if (!overlay) return FALSE;
752
753 LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
754
755 return overlay->isOwned( pos_region );
756}
757
758BOOL LLViewerParcelMgr::isOwnedSelfAt(const LLVector3d& pos_global) const
759{
760 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal( pos_global );
761 if (!region) return FALSE;
762
763 LLViewerParcelOverlay* overlay = region->getParcelOverlay();
764 if (!overlay) return FALSE;
765
766 LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
767
768 return overlay->isOwnedSelf( pos_region );
769}
770
771BOOL LLViewerParcelMgr::isOwnedOtherAt(const LLVector3d& pos_global) const
772{
773 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal( pos_global );
774 if (!region) return FALSE;
775
776 LLViewerParcelOverlay* overlay = region->getParcelOverlay();
777 if (!overlay) return FALSE;
778
779 LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
780
781 return overlay->isOwnedOther( pos_region );
782}
783
784BOOL LLViewerParcelMgr::isSoundLocal(const LLVector3d& pos_global) const
785{
786 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal( pos_global );
787 if (!region) return FALSE;
788
789 LLViewerParcelOverlay* overlay = region->getParcelOverlay();
790 if (!overlay) return FALSE;
791
792 LLVector3 pos_region = region->getPosRegionFromGlobal( pos_global );
793
794 return overlay->isSoundLocal( pos_region );
795}
796
797BOOL LLViewerParcelMgr::canHearSound(const LLVector3d &pos_global) const
798{
799 BOOL in_agent_parcel = inAgentParcel(pos_global);
800
801 if (in_agent_parcel)
802 {
803 // In same parcel as the agent
804 return TRUE;
805 }
806 else
807 {
808 if (gParcelMgr->getAgentParcel()->getSoundLocal())
809 {
810 // Not in same parcel, and agent parcel only has local sound
811 return FALSE;
812 }
813 else if (gParcelMgr->isSoundLocal(pos_global))
814 {
815 // Not in same parcel, and target parcel only has local sound
816 return FALSE;
817 }
818 else
819 {
820 // Not in same parcel, but neither are local sound
821 return TRUE;
822 }
823 }
824}
825
826
827BOOL LLViewerParcelMgr::inAgentParcel(const LLVector3d &pos_global) const
828{
829 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal(pos_global);
830 if (region != gAgent.getRegion())
831 {
832 // Can't be in the agent parcel if you're not in the same region.
833 return FALSE;
834 }
835
836 LLVector3 pos_region = gAgent.getRegion()->getPosRegionFromGlobal(pos_global);
837 S32 row = S32(pos_region.mV[VY] / PARCEL_GRID_STEP_METERS);
838 S32 column = S32(pos_region.mV[VX] / PARCEL_GRID_STEP_METERS);
839
840 if (mAgentParcelOverlay[row*mParcelsPerEdge + column])
841 {
842 return TRUE;
843 }
844 else
845 {
846 return FALSE;
847 }
848}
849
850// Returns NULL when there is no valid data.
851LLParcel* LLViewerParcelMgr::getHoverParcel() const
852{
853 if (mHoverRequestResult == PARCEL_RESULT_SUCCESS)
854 {
855 return mHoverParcel;
856 }
857 else
858 {
859 return NULL;
860 }
861}
862
863// Returns NULL when there is no valid data.
864LLParcel* LLViewerParcelMgr::getCollisionParcel() const
865{
866 if (mRenderCollision)
867 {
868 return mCollisionParcel;
869 }
870 else
871 {
872 return NULL;
873 }
874}
875
876//
877// UTILITIES
878//
879
880void LLViewerParcelMgr::render()
881{
882 if (mSelected && mRenderSelection)
883 {
884 // Rendering is done in agent-coordinates, so need to supply
885 // an appropriate offset to the render code.
886 LLViewerRegion *regionp = gWorldp->getRegionFromPosGlobal( mWestSouth );
887 if (!regionp) return;
888
889 renderHighlightSegments(mHighlightSegments, regionp);
890 }
891}
892
893
894void LLViewerParcelMgr::renderParcelCollision()
895{
896 // check for expiration
897 if (mCollisionTimer.getElapsedTimeF32() > PARCEL_COLLISION_DRAW_SECS)
898 {
899 mRenderCollision = FALSE;
900 }
901
902 if (mRenderCollision)
903 {
904 LLViewerRegion* regionp = gAgent.getRegion();
905 BOOL use_pass = mCollisionParcel->getParcelFlag(PF_USE_PASS_LIST);
906 renderCollisionSegments(mCollisionSegments, use_pass, regionp);
907 }
908}
909
910
911void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
912{
913 if (!mSelected)
914 {
915 return;
916 }
917
918 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
919 if (!region) return;
920
921 LLMessageSystem *msg = gMessageSystem;
922
923
924 if (flags & AL_BAN)
925 {
926 mParcel->mBanList.clear();
927 }
928 if (flags & AL_ACCESS)
929 {
930 mParcel->mAccessList.clear();
931 }
932
933 // Only the headers differ
934 msg->newMessageFast(_PREHASH_ParcelAccessListRequest);
935 msg->nextBlockFast(_PREHASH_AgentData);
936 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
937 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
938 msg->nextBlockFast(_PREHASH_Data);
939 msg->addS32Fast(_PREHASH_SequenceID, 0);
940 msg->addU32Fast(_PREHASH_Flags, flags);
941 msg->addS32("LocalID", mParcel->getLocalID() );
942 msg->sendReliable( region->getHost() );
943}
944
945
946void LLViewerParcelMgr::sendParcelDwellRequest()
947{
948 if (!mSelected)
949 {
950 return;
951 }
952
953 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
954 if (!region) return;
955
956 LLMessageSystem *msg = gMessageSystem;
957
958 // Only the headers differ
959 msg->newMessage("ParcelDwellRequest");
960 msg->nextBlock("AgentData");
961 msg->addUUID("AgentID", gAgent.getID() );
962 msg->addUUID("SessionID", gAgent.getSessionID());
963 msg->nextBlock("Data");
964 msg->addS32("LocalID", mParcel->getLocalID());
965 msg->addUUID("ParcelID", LLUUID::null); // filled in on simulator
966 msg->sendReliable( region->getHost() );
967}
968
969
970void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id)
971{
972 if (!mSelected)
973 {
974 gViewerWindow->alertXml("CannotSetLandOwnerNothingSelected");
975 return;
976 }
977
978 llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl;
979
980 // BUG: Only works for the region containing mWestSouthBottom
981 LLVector3d east_north_region_check( mEastNorth );
982 east_north_region_check.mdV[VX] -= 0.5;
983 east_north_region_check.mdV[VY] -= 0.5;
984
985 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
986 if (!region)
987 {
988 // TODO: Add a force owner version of this alert.
989 gViewerWindow->alertXml("CannotContentifyNoRegion");
990 return;
991 }
992
993 // BUG: Make work for cross-region selections
994 LLViewerRegion *region2 = gWorldp->getRegionFromPosGlobal( east_north_region_check );
995 if (region != region2)
996 {
997 gViewerWindow->alertXml("CannotSetLandOwnerMultipleRegions");
998 return;
999 }
1000
1001 llinfos << "Region " << region->getOriginGlobal() << llendl;
1002
1003 LLGodForceOwnerData* data = new LLGodForceOwnerData(owner_id, mParcel->getLocalID(), region->getHost());
1004 if(mParcel->getAuctionID())
1005 {
1006 gViewerWindow->alertXml("ForceOwnerAuctionWarning",
1007 callback_god_force_owner,
1008 (void*)data);
1009 }
1010 else
1011 {
1012 callback_god_force_owner(0, (void*)data);
1013 }
1014}
1015
1016void callback_god_force_owner(S32 option, void* user_data)
1017{
1018 LLGodForceOwnerData* data = (LLGodForceOwnerData*)user_data;
1019 if(data && (0 == option))
1020 {
1021 LLMessageSystem* msg = gMessageSystem;
1022 msg->newMessage("ParcelGodForceOwner");
1023 msg->nextBlock("AgentData");
1024 msg->addUUID("AgentID", gAgent.getID());
1025 msg->addUUID("SessionID", gAgent.getSessionID());
1026 msg->nextBlock("Data");
1027 msg->addUUID("OwnerID", data->mOwnerID);
1028 msg->addS32( "LocalID", data->mLocalID);
1029 msg->sendReliable(data->mHost);
1030 }
1031 delete data;
1032}
1033
1034void LLViewerParcelMgr::sendParcelGodForceToContent()
1035{
1036 if (!mSelected)
1037 {
1038 gViewerWindow->alertXml("CannotContentifyNothingSelected");
1039 return;
1040 }
1041 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
1042 if (!region)
1043 {
1044 gViewerWindow->alertXml("CannotContentifyNoRegion");
1045 return;
1046 }
1047
1048 LLMessageSystem* msg = gMessageSystem;
1049 msg->newMessage("ParcelGodMarkAsContent");
1050 msg->nextBlock("AgentData");
1051 msg->addUUID("AgentID", gAgent.getID());
1052 msg->addUUID("SessionID", gAgent.getSessionID());
1053 msg->nextBlock("ParcelData");
1054 msg->addS32("LocalID", mParcel->getLocalID());
1055 msg->sendReliable(region->getHost());
1056}
1057
1058void LLViewerParcelMgr::sendParcelRelease()
1059{
1060 if (!mSelected)
1061 {
1062 gViewerWindow->alertXml("CannotReleaseLandNothingSelected");
1063 return;
1064 }
1065
1066 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
1067 if (!region)
1068 {
1069 gViewerWindow->alertXml("CannotReleaseLandNoRegion");
1070 return;
1071 }
1072
1073 //U32 flags = PR_NONE;
1074 //if (god_force) flags |= PR_GOD_FORCE;
1075
1076 LLMessageSystem* msg = gMessageSystem;
1077 msg->newMessage("ParcelRelease");
1078 msg->nextBlock("AgentData");
1079 msg->addUUID("AgentID", gAgent.getID() );
1080 msg->addUUID("SessionID", gAgent.getSessionID() );
1081 msg->nextBlock("Data");
1082 msg->addS32("LocalID", mParcel->getLocalID() );
1083 //msg->addU32("Flags", flags);
1084 msg->sendReliable( region->getHost() );
1085
1086 // Blitz selection, since the parcel might be non-rectangular, and
1087 // we won't have appropriate parcel information.
1088 deselectLand();
1089}
1090
1091class LLViewerParcelMgr::ParcelBuyInfo
1092{
1093public:
1094 LLUUID mAgent;
1095 LLUUID mSession;
1096 LLUUID mGroup;
1097 BOOL mIsGroupOwned;
1098 BOOL mRemoveContribution;
1099 BOOL mIsClaim;
1100 LLHost mHost;
1101
1102 // for parcel buys
1103 S32 mParcelID;
1104
1105 // for land claims
1106 F32 mWest;
1107 F32 mSouth;
1108 F32 mEast;
1109 F32 mNorth;
1110};
1111
1112LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy(
1113 const LLUUID& agent_id,
1114 const LLUUID& session_id,
1115 const LLUUID& group_id,
1116 BOOL is_group_owned,
1117 BOOL is_claim,
1118 BOOL remove_contribution)
1119{
1120 if (!mSelected || !mParcel)
1121 {
1122 gViewerWindow->alertXml("CannotBuyLandNothingSelected");
1123 return NULL;
1124 }
1125
1126 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
1127 if (!region)
1128 {
1129 gViewerWindow->alertXml("CannotBuyLandNoRegion");
1130 return NULL;
1131 }
1132
1133 if (is_claim)
1134 {
1135 llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl;
1136 llinfos << "Region " << region->getOriginGlobal() << llendl;
1137
1138 // BUG: Only works for the region containing mWestSouthBottom
1139 LLVector3d east_north_region_check( mEastNorth );
1140 east_north_region_check.mdV[VX] -= 0.5;
1141 east_north_region_check.mdV[VY] -= 0.5;
1142
1143 LLViewerRegion *region2 = gWorldp->getRegionFromPosGlobal( east_north_region_check );
1144
1145 if (region != region2)
1146 {
1147 gViewerWindow->alertXml("CantBuyLandAcrossMultipleRegions");
1148 return NULL;
1149 }
1150 }
1151
1152
1153 ParcelBuyInfo* info = new ParcelBuyInfo;
1154
1155 info->mAgent = agent_id;
1156 info->mSession = session_id;
1157 info->mGroup = group_id;
1158 info->mIsGroupOwned = is_group_owned;
1159 info->mIsClaim = is_claim;
1160 info->mRemoveContribution = remove_contribution;
1161 info->mHost = region->getHost();
1162
1163 if (!is_claim)
1164 {
1165 info->mParcelID = mParcel->getLocalID();
1166 }
1167 else
1168 {
1169 // BUG: Make work for cross-region selections
1170 LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
1171 LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
1172
1173 info->mWest = west_south_bottom_region.mV[VX];
1174 info->mSouth = west_south_bottom_region.mV[VY];
1175 info->mEast = east_north_top_region.mV[VX];
1176 info->mNorth = east_north_top_region.mV[VY];
1177 }
1178
1179 return info;
1180}
1181
1182void LLViewerParcelMgr::sendParcelBuy(ParcelBuyInfo* info)
1183{
1184 // send the message
1185 LLMessageSystem* msg = gMessageSystem;
1186 msg->newMessage(info->mIsClaim ? "ParcelClaim" : "ParcelBuy");
1187 msg->nextBlock("AgentData");
1188 msg->addUUID("AgentID", info->mAgent);
1189 msg->addUUID("SessionID", info->mSession);
1190 msg->nextBlock("Data");
1191 msg->addUUID("GroupID", info->mGroup);
1192 msg->addBOOL("IsGroupOwned", info->mIsGroupOwned);
1193 if (!info->mIsClaim)
1194 {
1195 msg->addBOOL("RemoveContribution", info->mRemoveContribution);
1196 msg->addS32("LocalID", info->mParcelID);
1197 }
1198 msg->addBOOL("Final", TRUE); // don't allow escrow buys
1199 if (info->mIsClaim)
1200 {
1201 msg->nextBlock("ParcelData");
1202 msg->addF32("West", info->mWest);
1203 msg->addF32("South", info->mSouth);
1204 msg->addF32("East", info->mEast);
1205 msg->addF32("North", info->mNorth);
1206 }
1207 msg->sendReliable(info->mHost);
1208}
1209
1210void LLViewerParcelMgr::deleteParcelBuy(ParcelBuyInfo*& info)
1211{
1212 delete info;
1213 info = NULL;
1214}
1215
1216void LLViewerParcelMgr::sendParcelDeed(const LLUUID& group_id)
1217{
1218 if (!mSelected || !mParcel)
1219 {
1220 gViewerWindow->alertXml("CannotDeedLandNothingSelected");
1221 return;
1222 }
1223 if(group_id.isNull())
1224 {
1225 gViewerWindow->alertXml("CannotDeedLandNoGroup");
1226 return;
1227 }
1228 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
1229 if (!region)
1230 {
1231 gViewerWindow->alertXml("CannotDeedLandNoRegion");
1232 return;
1233 }
1234
1235 LLMessageSystem* msg = gMessageSystem;
1236 msg->newMessage("ParcelDeedToGroup");
1237 msg->nextBlock("AgentData");
1238 msg->addUUID("AgentID", gAgent.getID() );
1239 msg->addUUID("SessionID", gAgent.getSessionID() );
1240 msg->nextBlock("Data");
1241 msg->addUUID("GroupID", group_id );
1242 msg->addS32("LocalID", mParcel->getLocalID() );
1243 //msg->addU32("JoinNeighbors", join);
1244 msg->sendReliable( region->getHost() );
1245}
1246
1247
1248/*
1249// *NOTE: We cannot easily make landmarks at global positions because
1250// global positions probably refer to a sim/local combination which
1251// can move over time. We could implement this by looking up the
1252// region global x,y, but it's easier to take it out for now.
1253void LLViewerParcelMgr::makeLandmarkAtSelection()
1254{
1255 // Don't create for parcels you don't own
1256 if (gAgent.getID() != mParcel->getOwnerID())
1257 {
1258 return;
1259 }
1260
1261 LLVector3d global_center(mWestSouth);
1262 global_center += mEastNorth;
1263 global_center *= 0.5f;
1264
1265 LLViewerRegion* region;
1266 region = gWorldp->getRegionFromPosGlobal(global_center);
1267
1268 LLVector3 west_south_bottom_region = region->getPosRegionFromGlobal( mWestSouth );
1269 LLVector3 east_north_top_region = region->getPosRegionFromGlobal( mEastNorth );
1270
1271 LLString name("My Land");
1272 char buffer[MAX_STRING];
1273 S32 pos_x = (S32)floor((west_south_bottom_region.mV[VX] + east_north_top_region.mV[VX]) / 2.0f);
1274 S32 pos_y = (S32)floor((west_south_bottom_region.mV[VY] + east_north_top_region.mV[VY]) / 2.0f);
1275 sprintf(buffer, "%s in %s (%d, %d)",
1276 name.c_str(),
1277 region->getName().c_str(),
1278 pos_x, pos_y);
1279 name.assign(buffer);
1280
1281 const char* desc = "Claimed land";
1282 create_landmark(name.c_str(), desc, global_center);
1283}
1284*/
1285
1286const char* LLViewerParcelMgr::getAgentParcelName() const
1287{
1288 return mAgentParcel->getName();
1289}
1290
1291
1292void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, BOOL want_reply_to_update)
1293{
1294 if (!parcel) return;
1295
1296 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
1297 if (!region) return;
1298
1299 LLMessageSystem *msg = gMessageSystem;
1300
1301 msg->newMessageFast(_PREHASH_ParcelPropertiesUpdate);
1302 msg->nextBlockFast(_PREHASH_AgentData);
1303 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
1304 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
1305 msg->nextBlockFast(_PREHASH_ParcelData);
1306 msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() );
1307
1308 U32 flags = 0x0;
1309 if (want_reply_to_update) flags |= 0x01;
1310 msg->addU32("Flags", flags);
1311
1312 parcel->packMessage(msg);
1313
1314 msg->sendReliable( region->getHost() );
1315}
1316
1317
1318void LLViewerParcelMgr::requestHoverParcelProperties(const LLVector3d& pos)
1319{
1320 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( pos );
1321 if (!region)
1322 {
1323 return;
1324 }
1325
1326 // Send a rectangle around the point.
1327 // This means the parcel sent back is at least a rectangle around the point,
1328 // which is more efficient for public land. Fewer requests are sent. JC
1329 LLVector3 wsb_region = region->getPosRegionFromGlobal( pos );
1330
1331 F32 west = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VX] / PARCEL_GRID_STEP_METERS );
1332 F32 south = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VY] / PARCEL_GRID_STEP_METERS );
1333
1334 F32 east = west + PARCEL_GRID_STEP_METERS;
1335 F32 north = south + PARCEL_GRID_STEP_METERS;
1336
1337 // Send request message
1338 LLMessageSystem *msg = gMessageSystem;
1339 msg->newMessageFast(_PREHASH_ParcelPropertiesRequest);
1340 msg->nextBlockFast(_PREHASH_AgentData);
1341 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
1342 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
1343 msg->nextBlockFast(_PREHASH_ParcelData);
1344 msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID );
1345 msg->addF32Fast(_PREHASH_West, west );
1346 msg->addF32Fast(_PREHASH_South, south );
1347 msg->addF32Fast(_PREHASH_East, east );
1348 msg->addF32Fast(_PREHASH_North, north );
1349 msg->addBOOL("SnapSelection", FALSE );
1350 msg->sendReliable( region->getHost() );
1351
1352 mHoverRequestResult = PARCEL_RESULT_NO_DATA;
1353}
1354
1355
1356// static
1357void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user)
1358{
1359 if (gNoRender)
1360 {
1361 return;
1362 }
1363
1364 // Extract the packed overlay information
1365 S32 packed_overlay_size = msg->getSizeFast(_PREHASH_ParcelData, _PREHASH_Data);
1366
1367 if (packed_overlay_size == 0)
1368 {
1369 llwarns << "Overlay size 0" << llendl;
1370 return;
1371 }
1372
1373 S32 parcels_per_edge = gParcelMgr->mParcelsPerEdge;
1374 S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS;
1375 if (packed_overlay_size != expected_size)
1376 {
1377 llwarns << "Got parcel overlay size " << packed_overlay_size
1378 << " expecting " << expected_size << llendl;
1379 return;
1380 }
1381
1382 S32 sequence_id;
1383 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id);
1384 msg->getBinaryDataFast(
1385 _PREHASH_ParcelData,
1386 _PREHASH_Data,
1387 sPackedOverlay,
1388 expected_size);
1389
1390 LLHost host = msg->getSender();
1391 LLViewerRegion *region = gWorldp->getRegion(host);
1392 if (region)
1393 {
1394 region->mParcelOverlay->uncompressLandOverlay( sequence_id, sPackedOverlay );
1395 }
1396}
1397
1398
1399// static
1400void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **user)
1401{
1402 S32 request_result;
1403 S32 sequence_id;
1404 BOOL snap_selection = FALSE;
1405 S32 self_count = 0;
1406 S32 other_count = 0;
1407 S32 public_count = 0;
1408 S32 local_id;
1409 LLUUID owner_id;
1410 BOOL is_group_owned;
1411 U32 auction_id = 0;
1412 BOOL is_reserved = FALSE;
1413 S32 claim_price_per_meter = 0;
1414 S32 rent_price_per_meter = 0;
1415 S32 claim_date = 0;
1416 LLVector3 aabb_min;
1417 LLVector3 aabb_max;
1418 S32 area = 0;
1419 S32 sw_max_prims = 0;
1420 S32 sw_total_prims = 0;
1421 //LLUUID buyer_id;
1422 U8 status = 0;
1423 S32 max_prims = 0;
1424 S32 total_prims = 0;
1425 S32 owner_prims = 0;
1426 S32 group_prims = 0;
1427 S32 other_prims = 0;
1428 S32 selected_prims = 0;
1429 F32 parcel_prim_bonus = 1.f;
1430 BOOL region_push_override = false;
1431 BOOL region_deny_anonymous_override = false;
1432 BOOL region_deny_identified_override = false;
1433 BOOL region_deny_transacted_override = false;
1434
1435 S32 other_clean_time = 0;
1436
1437 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result );
1438 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id );
1439
1440 if (request_result == PARCEL_RESULT_NO_DATA)
1441 {
1442 // no valid parcel data
1443 llinfos << "no valid parcel data" << llendl;
1444 return;
1445 }
1446
1447 // Decide where the data will go.
1448 LLParcel* parcel = NULL;
1449 if (sequence_id == SELECTED_PARCEL_SEQ_ID)
1450 {
1451 // ...selected parcels report this sequence id
1452 gParcelMgr->mRequestResult = PARCEL_RESULT_SUCCESS;
1453 parcel = gParcelMgr->mParcel;
1454 }
1455 else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
1456 {
1457 gParcelMgr->mHoverRequestResult = PARCEL_RESULT_SUCCESS;
1458 parcel = gParcelMgr->mHoverParcel;
1459 }
1460 else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
1461 sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID ||
1462 sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1463 {
1464 gParcelMgr->mHoverRequestResult = PARCEL_RESULT_SUCCESS;
1465 parcel = gParcelMgr->mCollisionParcel;
1466 }
1467 else if (sequence_id == 0 || sequence_id > gParcelMgr->mAgentParcelSequenceID)
1468 {
1469 // new agent parcel
1470 gParcelMgr->mAgentParcelSequenceID = sequence_id;
1471 parcel = gParcelMgr->mAgentParcel;
1472 }
1473 else
1474 {
1475 llinfos << "out of order agent parcel sequence id " << sequence_id
1476 << " last good " << gParcelMgr->mAgentParcelSequenceID
1477 << llendl;
1478 return;
1479 }
1480
1481 msg->getBOOL("ParcelData", "SnapSelection", snap_selection);
1482 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelfCount, self_count);
1483 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherCount, other_count);
1484 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_PublicCount, public_count);
1485 msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_LocalID, local_id );
1486 msg->getUUIDFast(_PREHASH_ParcelData, _PREHASH_OwnerID, owner_id);
1487 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_IsGroupOwned, is_group_owned);
1488 msg->getU32Fast(_PREHASH_ParcelData, _PREHASH_AuctionID, auction_id);
1489 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_ReservedNewbie, is_reserved);
1490 msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_ClaimDate, claim_date);
1491 msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_ClaimPrice, claim_price_per_meter);
1492 msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_RentPrice, rent_price_per_meter);
1493 msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMin, aabb_min);
1494 msg->getVector3Fast(_PREHASH_ParcelData, _PREHASH_AABBMax, aabb_max);
1495 msg->getS32Fast( _PREHASH_ParcelData, _PREHASH_Area, area );
1496 //msg->getUUIDFast( _PREHASH_ParcelData, _PREHASH_BuyerID, buyer_id);
1497 msg->getU8("ParcelData", "Status", status);
1498 msg->getS32("ParcelData", "SimWideMaxPrims", sw_max_prims );
1499 msg->getS32("ParcelData", "SimWideTotalPrims", sw_total_prims );
1500 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_MaxPrims, max_prims );
1501 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_TotalPrims, total_prims );
1502 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OwnerPrims, owner_prims );
1503 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_GroupPrims, group_prims );
1504 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_OtherPrims, other_prims );
1505 msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SelectedPrims, selected_prims );
1506 msg->getF32Fast(_PREHASH_ParcelData, _PREHASH_ParcelPrimBonus, parcel_prim_bonus );
1507 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionPushOverride, region_push_override );
1508 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyAnonymous, region_deny_anonymous_override );
1509 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyIdentified, region_deny_identified_override );
1510 msg->getBOOLFast(_PREHASH_ParcelData, _PREHASH_RegionDenyTransacted, region_deny_transacted_override );
1511
1512 msg->getS32("ParcelData", "OtherCleanTime", other_clean_time );
1513
1514 // Actually extract the data.
1515 if (parcel)
1516 {
1517 parcel->init(owner_id,
1518 FALSE, FALSE, FALSE,
1519 claim_date, claim_price_per_meter, rent_price_per_meter,
1520 area, other_prims, parcel_prim_bonus, is_group_owned);
1521 parcel->setLocalID(local_id);
1522 parcel->setAABBMin(aabb_min);
1523 parcel->setAABBMax(aabb_max);
1524
1525 parcel->setAuctionID(auction_id);
1526 parcel->setReservedForNewbie(is_reserved);
1527 parcel->setOwnershipStatus((LLParcel::EOwnershipStatus)status);
1528
1529 parcel->setSimWideMaxPrimCapacity(sw_max_prims);
1530 parcel->setSimWidePrimCount(sw_total_prims);
1531 parcel->setMaxPrimCapacity(max_prims);
1532 parcel->setOwnerPrimCount(owner_prims);
1533 parcel->setGroupPrimCount(group_prims);
1534 parcel->setOtherPrimCount(other_prims);
1535 parcel->setSelectedPrimCount(selected_prims);
1536 parcel->setParcelPrimBonus(parcel_prim_bonus);
1537
1538 parcel->setCleanOtherTime(other_clean_time);
1539 parcel->setRegionPushOverride(region_push_override);
1540 parcel->setRegionDenyAnonymousOverride(region_deny_anonymous_override);
1541 parcel->setRegionDenyIdentifiedOverride(region_deny_identified_override);
1542 parcel->setRegionDenyTransactedOverride(region_deny_transacted_override);
1543 parcel->unpackMessage(msg);
1544
1545 if (parcel == gParcelMgr->mAgentParcel)
1546 {
1547 S32 bitmap_size = gParcelMgr->mParcelsPerEdge
1548 * gParcelMgr->mParcelsPerEdge
1549 / 8;
1550 U8* bitmap = new U8[ bitmap_size ];
1551 msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1552
1553 gParcelMgr->writeAgentParcelFromBitmap(bitmap);
1554 delete[] bitmap;
1555 }
1556 }
1557
1558 // Handle updating selections, if necessary.
1559 if (sequence_id == SELECTED_PARCEL_SEQ_ID)
1560 {
1561 // Update selected counts
1562 gParcelMgr->mSelectedSelfCount = self_count;
1563 gParcelMgr->mSelectedOtherCount = other_count;
1564 gParcelMgr->mSelectedPublicCount = public_count;
1565
1566 gParcelMgr->mSelectedMultipleOwners =
1567 (request_result == PARCEL_RESULT_MULTIPLE);
1568
1569 // Select the whole parcel
1570 LLViewerRegion *region = gWorldp->getRegion( msg->getSender() );
1571 if (region)
1572 {
1573 if (!snap_selection)
1574 {
1575 // don't muck with the westsouth and eastnorth.
1576 // just highlight it
1577 LLVector3 west_south = region->getPosRegionFromGlobal(gParcelMgr->mWestSouth);
1578 LLVector3 east_north = region->getPosRegionFromGlobal(gParcelMgr->mEastNorth);
1579
1580 gParcelMgr->resetSegments(gParcelMgr->mHighlightSegments);
1581 gParcelMgr->writeHighlightSegments(
1582 west_south.mV[VX],
1583 west_south.mV[VY],
1584 east_north.mV[VX],
1585 east_north.mV[VY] );
1586 gParcelMgr->mWholeParcelSelected = FALSE;
1587 }
1588 else if (0 == local_id)
1589 {
1590 // this is public land, just highlight the selection
1591 gParcelMgr->mWestSouth = region->getPosGlobalFromRegion( aabb_min );
1592 gParcelMgr->mEastNorth = region->getPosGlobalFromRegion( aabb_max );
1593
1594 gParcelMgr->resetSegments(gParcelMgr->mHighlightSegments);
1595 gParcelMgr->writeHighlightSegments(
1596 aabb_min.mV[VX],
1597 aabb_min.mV[VY],
1598 aabb_max.mV[VX],
1599 aabb_max.mV[VY] );
1600 gParcelMgr->mWholeParcelSelected = TRUE;
1601 }
1602 else
1603 {
1604 gParcelMgr->mWestSouth = region->getPosGlobalFromRegion( aabb_min );
1605 gParcelMgr->mEastNorth = region->getPosGlobalFromRegion( aabb_max );
1606
1607 // Owned land, highlight the boundaries
1608 S32 bitmap_size = gParcelMgr->mParcelsPerEdge
1609 * gParcelMgr->mParcelsPerEdge
1610 / 8;
1611 U8* bitmap = new U8[ bitmap_size ];
1612 msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1613
1614 gParcelMgr->resetSegments(gParcelMgr->mHighlightSegments);
1615 gParcelMgr->writeSegmentsFromBitmap( bitmap, gParcelMgr->mHighlightSegments );
1616
1617 delete bitmap;
1618 bitmap = NULL;
1619
1620 gParcelMgr->mWholeParcelSelected = TRUE;
1621 }
1622
1623 // Request access list information for this land
1624 gParcelMgr->sendParcelAccessListRequest(AL_ACCESS | AL_BAN);
1625
1626 // Request dwell for this land, if it's not public land.
1627 gParcelMgr->mSelectedDwell = 0.f;
1628 if (0 != local_id)
1629 {
1630 gParcelMgr->sendParcelDwellRequest();
1631 }
1632
1633 gParcelMgr->mSelected = TRUE;
1634 gParcelMgr->notifyObservers();
1635 }
1636 }
1637 else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID ||
1638 sequence_id == COLLISION_NOT_ON_LIST_PARCEL_SEQ_ID ||
1639 sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1640 {
1641 // We're about to collide with this parcel
1642 gParcelMgr->mRenderCollision = TRUE;
1643 gParcelMgr->mCollisionTimer.reset();
1644
1645 // Differentiate this parcel if we are banned from it.
1646 if (sequence_id == COLLISION_BANNED_PARCEL_SEQ_ID)
1647 {
1648 gParcelMgr->mCollisionBanned = BA_BANNED;
1649 }
1650 else if (sequence_id == COLLISION_NOT_IN_GROUP_PARCEL_SEQ_ID)
1651 {
1652 gParcelMgr->mCollisionBanned = BA_NOT_IN_GROUP;
1653 }
1654 else
1655 {
1656 gParcelMgr->mCollisionBanned = BA_NOT_ON_LIST;
1657
1658 }
1659
1660 S32 bitmap_size = gParcelMgr->mParcelsPerEdge
1661 * gParcelMgr->mParcelsPerEdge
1662 / 8;
1663 U8* bitmap = new U8[ bitmap_size ];
1664 msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size);
1665
1666 gParcelMgr->resetSegments(gParcelMgr->mCollisionSegments);
1667 gParcelMgr->writeSegmentsFromBitmap( bitmap, gParcelMgr->mCollisionSegments );
1668
1669 delete bitmap;
1670 bitmap = NULL;
1671
1672 }
1673 else if (sequence_id == HOVERED_PARCEL_SEQ_ID)
1674 {
1675 LLViewerRegion *region = gWorldp->getRegion( msg->getSender() );
1676 if (region)
1677 {
1678 gParcelMgr->mHoverWestSouth = region->getPosGlobalFromRegion( aabb_min );
1679 gParcelMgr->mHoverEastNorth = region->getPosGlobalFromRegion( aabb_max );
1680 }
1681 else
1682 {
1683 gParcelMgr->mHoverWestSouth.clearVec();
1684 gParcelMgr->mHoverEastNorth.clearVec();
1685 }
1686 }
1687 else
1688 {
1689 // It's the agent parcel
1690 BOOL new_parcel = parcel ? FALSE : TRUE;
1691 if (parcel)
1692 {
1693 S32 parcelid = parcel->getLocalID();
1694 U64 regionid = gAgent.getRegion()->getHandle();
1695 if (parcelid != gParcelMgr->mMediaParcelId || regionid != gParcelMgr->mMediaRegionId)
1696 {
1697 gParcelMgr->mMediaParcelId = parcelid;
1698 gParcelMgr->mMediaRegionId = regionid;
1699 new_parcel = TRUE;
1700 }
1701 }
1702 // look for music.
1703 if (gAudiop)
1704 {
1705 if (parcel)
1706 {
1707 LLString music_url_raw = parcel->getMusicURL();
1708
1709 // Trim off whitespace from front and back
1710 LLString music_url = music_url_raw;
1711 LLString::trim(music_url);
1712
1713 // On entering a new parcel, stop the last stream if the
1714 // new parcel has a different music url. (Empty URL counts
1715 // as different.)
1716 const char* stream_url = gAudiop->getInternetStreamURL();
1717
1718 if (music_url.empty() || music_url != stream_url)
1719 {
1720 // URL is different from one currently playing.
1721 gAudiop->stopInternetStream();
1722
1723 // If there is a new music URL and it's valid, play it.
1724 if (music_url.size() > 12)
1725 {
1726 if (music_url.substr(0,7) == "http://")
1727 {
1728 optionally_start_music(music_url);
1729 }
1730 }
1731 else if (gAudiop->getInternetStreamURL()[0])
1732 {
1733 llinfos << "Stopping parcel music" << llendl;
1734 gAudiop->startInternetStream(NULL);
1735 }
1736 }
1737 }
1738 else
1739 {
1740 // Public land has no music
1741 gAudiop->stopInternetStream();
1742 }
1743 }//if gAudiop
1744
1745 // now check for video
1746 if (LLMediaEngine::getInstance ()->isAvailable ())
1747 {
1748 // we have a player
1749 if (parcel)
1750 {
1751 // we're in a parcel
1752 std::string mediaUrl = std::string ( parcel->getMediaURL () );
1753 LLString::trim(mediaUrl);
1754
1755 // something changed
1756 LLMediaEngine* me = LLMediaEngine::getInstance();
1757 if ( ( me->getUrl () != mediaUrl )
1758 || ( me->getImageUUID () != parcel->getMediaID () )
1759 || ( me->isAutoScaled () != parcel->getMediaAutoScale () ) )
1760 {
1761 BOOL video_was_playing = FALSE;
1762 LLMediaBase* renderer = me->getMediaRenderer();
1763 if (renderer && (renderer->isPlaying() || renderer->isLooping()))
1764 {
1765 video_was_playing = TRUE;
1766 }
1767
1768 stop_video();
1769
1770 if ( !mediaUrl.empty () )
1771 {
1772 // Someone has "changed the channel", changing the URL of a video
1773 // you were already watching. Do we want to automatically start playing? JC
1774 if (!new_parcel
1775 && gSavedSettings.getBOOL("AudioStreamingVideo")
1776 && video_was_playing)
1777 {
1778 start_video(parcel);
1779 }
1780 else
1781 {
1782 // "Prepare" the media engine, but don't auto-play. JC
1783 optionally_prepare_video(parcel);
1784 }
1785 }
1786 }
1787 }
1788 else
1789 {
1790 stop_video();
1791 }
1792 }
1793 else
1794 {
1795 // no audio player, do a first use dialog if their is media here
1796 if (parcel)
1797 {
1798 std::string mediaUrl = std::string ( parcel->getMediaURL () );
1799 if (!mediaUrl.empty ())
1800 {
1801 if (gSavedSettings.getWarning("QuickTimeInstalled"))
1802 {
1803 gSavedSettings.setWarning("QuickTimeInstalled", FALSE);
1804
1805 LLNotifyBox::showXml("NoQuickTime" );
1806 };
1807 }
1808 }
1809 }
1810
1811 };
1812}
1813
1814void optionally_start_music(const LLString& music_url)
1815{
1816 if (gSavedSettings.getWarning("FirstStreamingMusic"))
1817 {
1818 void* data = (void*)strdup(music_url.c_str());
1819 gViewerWindow->alertXml("ParcelCanPlayMusic",
1820 callback_start_music,
1821 (void*)data);
1822
1823 }
1824 else if (gSavedSettings.getBOOL("AudioStreamingMusic"))
1825 {
1826 // Make the user click the start button on the overlay bar. JC
1827 // llinfos << "Starting parcel music " << music_url << llendl;
1828
1829 // now only play music when you enter a new parcel if the control is in PLAY state
1830 // changed as part of SL-4878
1831 if ( gOverlayBar->getMusicRemoteControl ()->getTransportState () == LLMediaRemoteCtrl::Play )
1832 {
1833 if (gAudiop)
1834 {
1835 gAudiop->startInternetStream(music_url.c_str());
1836 }
1837 };
1838 }
1839}
1840
1841
1842void callback_start_music(S32 option, void* data)
1843{
1844 const char* music_url = (const char*)data;
1845
1846 if (0 == option)
1847 {
1848 gSavedSettings.setBOOL("AudioStreamingMusic", TRUE);
1849 llinfos << "Starting first parcel music " << music_url << llendl;
1850 if (gAudiop)
1851 {
1852 gAudiop->startInternetStream(music_url);
1853 LLMediaRemoteCtrl* ctrl = gOverlayBar->getMusicRemoteControl();
1854 ctrl->setTransportState( LLMediaRemoteCtrl::Play, FALSE );
1855 }
1856 }
1857 else
1858 {
1859 gSavedSettings.setBOOL("AudioStreamingMusic", FALSE);
1860 }
1861
1862 gSavedSettings.setWarning("FirstStreamingMusic", FALSE);
1863
1864 delete [] music_url;
1865 music_url = NULL;
1866}
1867
1868void prepare_video(const LLParcel *parcel)
1869{
1870 std::string mediaUrl;
1871 if (parcel->getParcelFlag(PF_URL_RAW_HTML))
1872 {
1873 mediaUrl = std::string("data:");
1874 mediaUrl.append(parcel->getMediaURL());
1875 }
1876 else
1877 {
1878 mediaUrl = std::string ( parcel->getMediaURL () );
1879 }
1880 LLMediaEngine::getInstance ()->setUrl ( mediaUrl );
1881 LLMediaEngine::getInstance ()->setImageUUID ( parcel->getMediaID () );
1882 LLMediaEngine::getInstance ()->setAutoScaled ( parcel->getMediaAutoScale () ? TRUE : FALSE ); // (U8 instead of BOOL for future expansion)
1883}
1884
1885void start_video(const LLParcel *parcel)
1886{
1887 prepare_video(parcel);
1888 std::string path( "" );
1889 LLMediaEngine::getInstance ()->convertImageAndLoadUrl ( true, false, path);
1890}
1891
1892void stop_video()
1893{
1894 // set up remote control so stop is selected
1895 LLMediaEngine::getInstance ()->stop ();
1896 if (gOverlayBar)
1897 {
1898 gOverlayBar->refresh ();
1899 }
1900
1901 if (LLMediaEngine::getInstance ()->isLoaded())
1902 {
1903 LLMediaEngine::getInstance ()->unload ();
1904
1905 gImageList.updateMovieImage(LLUUID::null, FALSE);
1906 gCurrentMovieID.setNull();
1907 }
1908
1909 LLMediaEngine::getInstance ()->setUrl ( "" );
1910 LLMediaEngine::getInstance ()->setImageUUID ( LLUUID::null );
1911
1912}
1913
1914void optionally_prepare_video(const LLParcel *parcelp)
1915{
1916 if (gSavedSettings.getWarning("FirstStreamingVideo"))
1917 {
1918 gViewerWindow->alertXml("ParcelCanPlayMedia",
1919 callback_prepare_video,
1920 (void*)parcelp);
1921 }
1922 else
1923 {
1924 llinfos << "Entering parcel " << parcelp->getLocalID() << " with video " << parcelp->getMediaURL() << llendl;
1925 prepare_video(parcelp);
1926 }
1927}
1928
1929
1930void callback_prepare_video(S32 option, void* data)
1931{
1932 const LLParcel *parcelp = (const LLParcel *)data;
1933
1934 if (0 == option)
1935 {
1936 gSavedSettings.setBOOL("AudioStreamingVideo", TRUE);
1937 llinfos << "Starting parcel video " << parcelp->getMediaURL() << " on parcel " << parcelp->getLocalID() << llendl;
1938 gMessageSystem->setHandlerFunc("ParcelMediaCommandMessage", LLMediaEngine::process_parcel_media);
1939 gMessageSystem->setHandlerFunc ( "ParcelMediaUpdate", LLMediaEngine::process_parcel_media_update );
1940 prepare_video(parcelp);
1941 }
1942 else
1943 {
1944 gMessageSystem->setHandlerFunc("ParcelMediaCommandMessage", null_message_callback);
1945 gMessageSystem->setHandlerFunc ( "ParcelMediaUpdate", null_message_callback );
1946 gSavedSettings.setBOOL("AudioStreamingVideo", FALSE);
1947 }
1948
1949 gSavedSettings.setWarning("FirstStreamingVideo", FALSE);
1950}
1951
1952// static
1953void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void **user)
1954{
1955 LLUUID agent_id;
1956 S32 sequence_id = 0;
1957 U32 message_flags = 0x0;
1958 S32 parcel_id = -1;
1959
1960 msg->getUUIDFast(_PREHASH_Data, _PREHASH_AgentID, agent_id);
1961 msg->getS32Fast( _PREHASH_Data, _PREHASH_SequenceID, sequence_id ); //ignored
1962 msg->getU32Fast( _PREHASH_Data, _PREHASH_Flags, message_flags);
1963 msg->getS32Fast( _PREHASH_Data, _PREHASH_LocalID, parcel_id);
1964
1965 LLParcel* parcel = gParcelMgr->mParcel;
1966 if (!parcel) return;
1967
1968 if (parcel_id != parcel->getLocalID())
1969 {
1970 llwarns << "processParcelAccessListReply for parcel " << parcel_id
1971 << " which isn't the selected parcel " << parcel->getLocalID()<< llendl;
1972 return;
1973 }
1974
1975 if (message_flags & AL_ACCESS)
1976 {
1977 parcel->unpackAccessEntries(msg, &(parcel->mAccessList) );
1978 }
1979 else if (message_flags & AL_BAN)
1980 {
1981 parcel->unpackAccessEntries(msg, &(parcel->mBanList) );
1982 }
1983 /*else if (message_flags & AL_RENTER)
1984 {
1985 parcel->unpackAccessEntries(msg, &(parcel->mRenterList) );
1986 }*/
1987
1988 gParcelMgr->notifyObservers();
1989}
1990
1991
1992// static
1993void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**)
1994{
1995 LLUUID agent_id;
1996 msg->getUUID("AgentData", "AgentID", agent_id);
1997
1998 S32 local_id;
1999 msg->getS32("Data", "LocalID", local_id);
2000
2001 LLUUID parcel_id;
2002 msg->getUUID("Data", "ParcelID", parcel_id);
2003
2004 F32 dwell;
2005 msg->getF32("Data", "Dwell", dwell);
2006
2007 if (local_id == gParcelMgr->mParcel->getLocalID())
2008 {
2009 gParcelMgr->mSelectedDwell = dwell;
2010 gParcelMgr->notifyObservers();
2011 }
2012}
2013
2014
2015void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which)
2016{
2017
2018 LLUUID transactionUUID;
2019 transactionUUID.generate();
2020
2021 if (!mSelected)
2022 {
2023 return;
2024 }
2025
2026 LLViewerRegion *region = gWorldp->getRegionFromPosGlobal( mWestSouth );
2027 if (!region) return;
2028
2029 LLMessageSystem* msg = gMessageSystem;
2030
2031 LLParcel* parcel = mParcel;
2032 if (!parcel) return;
2033
2034 if (which & AL_ACCESS)
2035 {
2036 S32 count = parcel->mAccessList.size();
2037 S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
2038 S32 sequence_id = 1;
2039 BOOL start_message = TRUE;
2040 BOOL initial = TRUE;
2041
2042 access_map_const_iterator cit = parcel->mAccessList.begin();
2043 access_map_const_iterator end = parcel->mAccessList.end();
2044 while ( (cit != end) || initial )
2045 {
2046 if (start_message)
2047 {
2048 msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
2049 msg->nextBlockFast(_PREHASH_AgentData);
2050 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
2051 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
2052 msg->nextBlockFast(_PREHASH_Data);
2053 msg->addU32Fast(_PREHASH_Flags, AL_ACCESS);
2054 msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
2055 msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
2056 msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
2057 msg->addS32Fast(_PREHASH_Sections, num_sections);
2058 start_message = FALSE;
2059
2060 if (initial && (cit == end))
2061 {
2062 // pack an empty block if there will be no data
2063 msg->nextBlockFast(_PREHASH_List);
2064 msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
2065 msg->addS32Fast(_PREHASH_Time, 0 );
2066 msg->addU32Fast(_PREHASH_Flags, 0 );
2067 }
2068
2069 initial = FALSE;
2070 sequence_id++;
2071
2072 }
2073
2074 while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
2075 {
2076
2077 const LLAccessEntry& entry = (*cit).second;
2078
2079 msg->nextBlockFast(_PREHASH_List);
2080 msg->addUUIDFast(_PREHASH_ID, entry.mID );
2081 msg->addS32Fast(_PREHASH_Time, entry.mTime );
2082 msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
2083 ++cit;
2084 }
2085
2086 start_message = TRUE;
2087 msg->sendReliable( region->getHost() );
2088 }
2089 }
2090
2091 if (which & AL_BAN)
2092 {
2093 S32 count = parcel->mBanList.size();
2094 S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
2095 S32 sequence_id = 1;
2096 BOOL start_message = TRUE;
2097 BOOL initial = TRUE;
2098
2099 access_map_const_iterator cit = parcel->mBanList.begin();
2100 access_map_const_iterator end = parcel->mBanList.end();
2101 while ( (cit != end) || initial )
2102 {
2103 if (start_message)
2104 {
2105 msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
2106 msg->nextBlockFast(_PREHASH_AgentData);
2107 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
2108 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
2109 msg->nextBlockFast(_PREHASH_Data);
2110 msg->addU32Fast(_PREHASH_Flags, AL_BAN);
2111 msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
2112 msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
2113 msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
2114 msg->addS32Fast(_PREHASH_Sections, num_sections);
2115 start_message = FALSE;
2116
2117 if (initial && (cit == end))
2118 {
2119 // pack an empty block if there will be no data
2120 msg->nextBlockFast(_PREHASH_List);
2121 msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
2122 msg->addS32Fast(_PREHASH_Time, 0 );
2123 msg->addU32Fast(_PREHASH_Flags, 0 );
2124 }
2125
2126 initial = FALSE;
2127 sequence_id++;
2128
2129 }
2130
2131 while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
2132 {
2133 const LLAccessEntry& entry = (*cit).second;
2134
2135 msg->nextBlockFast(_PREHASH_List);
2136 msg->addUUIDFast(_PREHASH_ID, entry.mID );
2137 msg->addS32Fast(_PREHASH_Time, entry.mTime );
2138 msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
2139 ++cit;
2140 }
2141
2142 start_message = TRUE;
2143 msg->sendReliable( region->getHost() );
2144 }
2145 }
2146}
2147
2148
2149void LLViewerParcelMgr::deedLandToGroup()
2150{
2151 char group_name[MAX_STRING];
2152 gCacheName->getGroupName(mParcel->getGroupID(), group_name);
2153 LLString::format_map_t args;
2154 args["[AREA]"] = llformat("%d", mParcel->getArea());
2155 args["[GROUP_NAME]"] = group_name;
2156 if(mParcel->getContributeWithDeed())
2157 {
2158 char first_name[DB_FIRST_NAME_BUF_SIZE];
2159 first_name[0] = '\0';
2160 char last_name[DB_FIRST_NAME_BUF_SIZE];
2161 last_name[0] = '\0';
2162 gCacheName->getName(mParcel->getOwnerID(), first_name, last_name);
2163 args["[FIRST_NAME]"] = first_name;
2164 args["[LAST_NAME]"] = last_name;
2165 gViewerWindow->alertXml("DeedLandToGroupWithContribution",args, deedAlertCB, NULL);
2166 }
2167 else
2168 {
2169 gViewerWindow->alertXml("DeedLandToGroup",args, deedAlertCB, NULL);
2170 }
2171}
2172
2173// static
2174void LLViewerParcelMgr::deedAlertCB(S32 option, void*)
2175{
2176 if (option == 0)
2177 {
2178 LLParcel* parcel = gParcelMgr->getSelectedParcel();
2179 LLUUID group_id;
2180 if(parcel)
2181 {
2182 group_id = parcel->getGroupID();
2183 }
2184 gParcelMgr->sendParcelDeed(group_id);
2185 }
2186}
2187
2188
2189void LLViewerParcelMgr::startReleaseLand()
2190{
2191 if (!mSelected)
2192 {
2193 gViewerWindow->alertXml("CannotReleaseLandNothingSelected");
2194 return;
2195 }
2196
2197 if (mRequestResult == PARCEL_RESULT_NO_DATA)
2198 {
2199 gViewerWindow->alertXml("CannotReleaseLandWatingForServer");
2200 return;
2201 }
2202
2203 if (mRequestResult == PARCEL_RESULT_MULTIPLE)
2204 {
2205 gViewerWindow->alertXml("CannotReleaseLandSelected");
2206 return;
2207 }
2208
2209 if (!isParcelOwnedByAgent(mParcel, GP_LAND_RELEASE)
2210 && !(gAgent.canManageEstate()))
2211 {
2212 gViewerWindow->alertXml("CannotReleaseLandDontOwn");
2213 return;
2214 }
2215
2216 LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0;
2217 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal(parcel_center);
2218 if (!region)
2219 {
2220 gViewerWindow->alertXml("CannotReleaseLandRegionNotFound");
2221 return;
2222 }
2223/*
2224 if ((region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
2225 && !gAgent.isGodlike())
2226 {
2227 LLStringBase<char>::format_map_t args;
2228 args["[REGION]"] = region->getName();
2229 gViewerWindow->alertXml("CannotReleaseLandNoTransfer", args);
2230 return;
2231 }
2232*/
2233
2234 if (!mWholeParcelSelected)
2235 {
2236 gViewerWindow->alertXml("CannotReleaseLandPartialSelection");
2237 return;
2238 }
2239
2240 // Compute claim price
2241 LLStringBase<char>::format_map_t args;
2242 args["[AREA]"] = llformat("%d",mParcel->getArea());
2243 gViewerWindow->alertXml("ReleaseLandWarning", args,
2244 releaseAlertCB, this);
2245}
2246
2247bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const
2248{
2249 if (!parcel)
2250 {
2251 return false;
2252 }
2253
2254 if (mSelected && parcel == mParcel)
2255 {
2256 if (mRequestResult == PARCEL_RESULT_NO_DATA)
2257 {
2258 return false;
2259 }
2260 }
2261
2262 const LLUUID& parcelOwner = parcel->getOwnerID();
2263 const LLUUID& authorizeBuyer = parcel->getAuthorizedBuyerID();
2264
2265 if (parcel->isPublic())
2266 {
2267 return true; // change this if want to make it gods only
2268 }
2269
2270 bool isForSale = parcel->getForSale()
2271 && ((parcel->getSalePrice() > 0) || (authorizeBuyer.notNull()));
2272
2273 bool isEmpowered
2274 = forGroup ? gAgent.hasPowerInActiveGroup(GP_LAND_DEED) == TRUE : true;
2275
2276 bool isOwner
2277 = parcelOwner == (forGroup ? gAgent.getGroupID() : gAgent.getID());
2278
2279 bool isAvailable
2280 = parcel->getReservedForNewbie()
2281 ? (!forGroup && gStatusBar->getSquareMetersCommitted() == 0)
2282 : true;
2283 // *TODO: should be based on never_owned_land, see SL-10728
2284
2285 bool isAuthorized
2286 = (authorizeBuyer.isNull() || (gAgent.getID() == authorizeBuyer));
2287
2288 return isForSale && !isOwner && isAuthorized && isAvailable && isEmpowered;
2289}
2290
2291
2292void LLViewerParcelMgr::startBuyLand(BOOL is_for_group)
2293{
2294 LLFloaterBuyLand::buyLand(getSelectionRegion(), mParcel, is_for_group == TRUE);
2295}
2296
2297void LLViewerParcelMgr::startSellLand()
2298{
2299 LLFloaterSellLand::sellLand(getSelectionRegion(), mParcel);
2300}
2301
2302void LLViewerParcelMgr::startDivideLand()
2303{
2304 if (!mSelected)
2305 {
2306 gViewerWindow->alertXml("CannotDivideLandNothingSelected");
2307 return;
2308 }
2309
2310 if (mWholeParcelSelected)
2311 {
2312 gViewerWindow->alertXml("CannotDivideLandPartialSelection");
2313 return;
2314 }
2315
2316 gViewerWindow->alertXml("LandDivideWarning",
2317 callbackDivideLand,
2318 this);
2319}
2320
2321// static
2322void LLViewerParcelMgr::callbackDivideLand(S32 option, void* data)
2323{
2324 LLViewerParcelMgr* self = (LLViewerParcelMgr*)data;
2325
2326 LLVector3d parcel_center = (self->mWestSouth + self->mEastNorth) / 2.0;
2327 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal(parcel_center);
2328 if (!region)
2329 {
2330 gViewerWindow->alertXml("CannotDivideLandNoRegion");
2331 return;
2332 }
2333
2334 if (0 == option)
2335 {
2336 LLVector3 west_south = region->getPosRegionFromGlobal(self->mWestSouth);
2337 LLVector3 east_north = region->getPosRegionFromGlobal(self->mEastNorth);
2338
2339 LLMessageSystem* msg = gMessageSystem;
2340 msg->newMessage("ParcelDivide");
2341 msg->nextBlock("AgentData");
2342 msg->addUUID("AgentID", gAgent.getID());
2343 msg->addUUID("SessionID", gAgent.getSessionID());
2344 msg->nextBlock("ParcelData");
2345 msg->addF32("West", west_south.mV[VX]);
2346 msg->addF32("South", west_south.mV[VY]);
2347 msg->addF32("East", east_north.mV[VX]);
2348 msg->addF32("North", east_north.mV[VY]);
2349 msg->sendReliable(region->getHost());
2350 }
2351}
2352
2353
2354void LLViewerParcelMgr::startJoinLand()
2355{
2356 if (!mSelected)
2357 {
2358 gViewerWindow->alertXml("CannotJoinLandNothingSelected");
2359 return;
2360 }
2361
2362 if (mWholeParcelSelected)
2363 {
2364 gViewerWindow->alertXml("CannotJoinLandEntireParcelSelected");
2365 return;
2366 }
2367
2368 if (!mSelectedMultipleOwners)
2369 {
2370 gViewerWindow->alertXml("CannotJoinLandSelection");
2371 return;
2372 }
2373
2374 gViewerWindow->alertXml("JoinLandWarning",
2375 callbackJoinLand,
2376 this);
2377}
2378
2379// static
2380void LLViewerParcelMgr::callbackJoinLand(S32 option, void* data)
2381{
2382 LLViewerParcelMgr* self = (LLViewerParcelMgr*)data;
2383
2384 LLVector3d parcel_center = (self->mWestSouth + self->mEastNorth) / 2.0;
2385 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal(parcel_center);
2386 if (!region)
2387 {
2388 gViewerWindow->alertXml("CannotJoinLandNoRegion");
2389 return;
2390 }
2391
2392 if (0 == option)
2393 {
2394 LLVector3 west_south = region->getPosRegionFromGlobal(self->mWestSouth);
2395 LLVector3 east_north = region->getPosRegionFromGlobal(self->mEastNorth);
2396
2397 LLMessageSystem* msg = gMessageSystem;
2398 msg->newMessage("ParcelJoin");
2399 msg->nextBlock("AgentData");
2400 msg->addUUID("AgentID", gAgent.getID());
2401 msg->addUUID("SessionID", gAgent.getSessionID());
2402 msg->nextBlock("ParcelData");
2403 msg->addF32("West", west_south.mV[VX]);
2404 msg->addF32("South", west_south.mV[VY]);
2405 msg->addF32("East", east_north.mV[VX]);
2406 msg->addF32("North", east_north.mV[VY]);
2407 msg->sendReliable(region->getHost());
2408 }
2409}
2410
2411
2412void LLViewerParcelMgr::startDeedLandToGroup()
2413{
2414 if (!mSelected || !mParcel)
2415 {
2416 gViewerWindow->alertXml("CannotDeedLandNothingSelected");
2417 return;
2418 }
2419
2420 if (mRequestResult == PARCEL_RESULT_NO_DATA)
2421 {
2422 gViewerWindow->alertXml("CannotDeedLandWaitingForServer");
2423 return;
2424 }
2425
2426 if (mRequestResult == PARCEL_RESULT_MULTIPLE)
2427 {
2428 gViewerWindow->alertXml("CannotDeedLandMultipleSelected");
2429 return;
2430 }
2431
2432 LLVector3d parcel_center = (mWestSouth + mEastNorth) / 2.0;
2433 LLViewerRegion* region = gWorldp->getRegionFromPosGlobal(parcel_center);
2434 if (!region)
2435 {
2436 gViewerWindow->alertXml("CannotDeedLandNoRegion");
2437 return;
2438 }
2439
2440 /*
2441 if(!gAgent.isGodlike())
2442 {
2443 if((region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
2444 && (mParcel->getOwnerID() != region->getOwner()))
2445 {
2446 LLStringBase<char>::format_map_t args;
2447 args["[REGION]"] = region->getName();
2448 gViewerWindow->alertXml("CannotDeedLandNoTransfer", args);
2449 return;
2450 }
2451 }
2452 */
2453
2454 deedLandToGroup();
2455}
2456void LLViewerParcelMgr::reclaimParcel()
2457{
2458 LLParcel* parcel = gParcelMgr->getSelectedParcel();
2459 LLViewerRegion* regionp = gParcelMgr->getSelectionRegion();
2460 if(parcel && parcel->getOwnerID().notNull()
2461 && (parcel->getOwnerID() != gAgent.getID())
2462 && regionp && (regionp->getOwner() == gAgent.getID()))
2463 {
2464 LLMessageSystem* msg = gMessageSystem;
2465 msg->newMessage("ParcelReclaim");
2466 msg->nextBlock("AgentData");
2467 msg->addUUID("AgentID", gAgent.getID());
2468 msg->addUUID("SessionID", gAgent.getSessionID());
2469 msg->nextBlock("Data");
2470 msg->addS32("LocalID", parcel->getLocalID());
2471 msg->sendReliable(regionp->getHost());
2472 }
2473}
2474
2475// static
2476void LLViewerParcelMgr::releaseAlertCB(S32 option, void *)
2477{
2478 if (option == 0)
2479 {
2480 // Send the release message, not a force
2481 gParcelMgr->sendParcelRelease();
2482 }
2483}
2484
2485void LLViewerParcelMgr::buyPass()
2486{
2487 LLParcel* parcel = getSelectedParcel();
2488 if (!parcel) return;
2489
2490 LLViewerRegion* region = getSelectionRegion();
2491 if (!region) return;
2492
2493 LLMessageSystem* msg = gMessageSystem;
2494 msg->newMessageFast(_PREHASH_ParcelBuyPass);
2495 msg->nextBlock("AgentData");
2496 msg->addUUID("AgentID", gAgent.getID());
2497 msg->addUUID("SessionID", gAgent.getSessionID());
2498 msg->nextBlockFast(_PREHASH_ParcelData);
2499 msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID() );
2500 msg->sendReliable( region->getHost() );
2501}
2502
2503//Tells whether we are allowed to buy a pass or not
2504BOOL LLViewerParcelMgr::isCollisionBanned()
2505{
2506 if ((mCollisionBanned == BA_ALLOWED) || (mCollisionBanned == BA_NOT_ON_LIST) || (mCollisionBanned == BA_NOT_IN_GROUP))
2507 return FALSE;
2508 else
2509 return TRUE;
2510}
2511
2512// This implementation should mirror LLSimParcelMgr::isParcelOwnedBy
2513// static
2514BOOL LLViewerParcelMgr::isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power)
2515{
2516 if (!parcelp)
2517 {
2518 return FALSE;
2519 }
2520
2521 // Gods can always assume ownership.
2522 if (gAgent.isGodlike())
2523 {
2524 return TRUE;
2525 }
2526
2527 // The owner of a parcel automatically gets all powersr.
2528 if (parcelp->getOwnerID() == gAgent.getID())
2529 {
2530 return TRUE;
2531 }
2532
2533 // Only gods can assume 'ownership' of public land.
2534 if (parcelp->isPublic())
2535 {
2536 return FALSE;
2537 }
2538
2539 // Return whether or not the agent has group_proxy_power powers in the
2540 // parcel's group.
2541 return gAgent.hasPowerInGroup(parcelp->getOwnerID(), group_proxy_power);
2542}
2543
2544// This implementation should mirror llSimParcelMgr::isParcelModifiableBy
2545// static
2546BOOL LLViewerParcelMgr::isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power)
2547{
2548 // If the agent can assume ownership, it is probably modifiable.
2549 BOOL rv = FALSE;
2550 if (parcelp)
2551 {
2552 // *NOTE: This should only work for leased parcels, but group owned
2553 // parcels cannot be OS_LEASED yet. Phoenix 2003-12-15.
2554 rv = isParcelOwnedByAgent(parcelp, group_proxy_power);
2555
2556 // ... except for the case that the parcel is not OS_LEASED for agent-owned parcels.
2557 if( (gAgent.getID() == parcelp->getOwnerID())
2558 && !gAgent.isGodlike()
2559 && (parcelp->getOwnershipStatus() != LLParcel::OS_LEASED) )
2560 {
2561 rv = FALSE;
2562 }
2563 }
2564 return rv;
2565}
2566
2567void sanitize_corners(const LLVector3d &corner1,
2568 const LLVector3d &corner2,
2569 LLVector3d &west_south_bottom,
2570 LLVector3d &east_north_top)
2571{
2572 west_south_bottom.mdV[VX] = llmin( corner1.mdV[VX], corner2.mdV[VX] );
2573 west_south_bottom.mdV[VY] = llmin( corner1.mdV[VY], corner2.mdV[VY] );
2574 west_south_bottom.mdV[VZ] = llmin( corner1.mdV[VZ], corner2.mdV[VZ] );
2575
2576 east_north_top.mdV[VX] = llmax( corner1.mdV[VX], corner2.mdV[VX] );
2577 east_north_top.mdV[VY] = llmax( corner1.mdV[VY], corner2.mdV[VY] );
2578 east_north_top.mdV[VZ] = llmax( corner1.mdV[VZ], corner2.mdV[VZ] );
2579}
2580