summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerregion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerregion.cpp')
-rw-r--r--indra/newview/llviewerregion.cpp1301
1 files changed, 1301 insertions, 0 deletions
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
new file mode 100644
index 0000000000..bcbc81ce5c
--- /dev/null
+++ b/indra/newview/llviewerregion.cpp
@@ -0,0 +1,1301 @@
+/**
+ * @file llviewerregion.cpp
+ * @brief Implementation of the LLViewerRegion class.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerregion.h"
+
+#include "indra_constants.h"
+#include "llmath.h"
+#include "llhttpclient.h"
+#include "llregionflags.h"
+#include "llregionhandle.h"
+#include "llsdmessagesystem.h"
+#include "llsurface.h"
+#include "message.h"
+//#include "vmath.h"
+#include "v3math.h"
+#include "v4math.h"
+
+#include "llagent.h"
+#include "llcallingcard.h"
+#include "lldir.h"
+#include "lleventpoll.h"
+#include "llfloatergodtools.h"
+#include "llfloaterregioninfo.h"
+#include "llhttpnode.h"
+#include "llnetmap.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparceloverlay.h"
+#include "llvlmanager.h"
+#include "llvlcomposition.h"
+#include "llvocache.h"
+#include "llvoclouds.h"
+#include "llworld.h"
+
+extern BOOL gNoRender;
+
+const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region
+const S16 MAX_MAP_DIST = 10;
+
+
+
+
+LLViewerRegion::LLViewerRegion(const U64 &handle,
+ const LLHost &host,
+ const U32 grids_per_region_edge,
+ const U32 grids_per_patch_edge,
+ const F32 region_width_meters)
+: mCenterGlobal(),
+ mHandle(handle),
+ mHost( host ),
+ mTimeDilation(1.0f),
+ mName(""),
+ mZoning(""),
+ mOwnerID(),
+ mIsEstateManager(FALSE),
+ mCompositionp(NULL),
+ mRegionFlags( REGION_FLAGS_DEFAULT ),
+ mSimAccess( SIM_ACCESS_MIN ),
+ mBillableFactor(1.0),
+ mMaxTasks(MAX_TASKS_PER_REGION),
+ mCacheLoaded(FALSE),
+ mCacheMap(),
+ mCacheEntriesCount(0),
+ mCacheID(),
+ mEventPoll(NULL)
+{
+ mWidth = region_width_meters;
+
+ mOriginGlobal = from_region_handle(handle);
+
+ mLandp = new LLSurface('l', NULL);
+ if (!gNoRender)
+ {
+ // Create the composition layer for the surface
+ mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge);
+ mCompositionp->setSurface(mLandp);
+
+ // Create the surfaces
+ mLandp->setRegion(this);
+ mLandp->create(grids_per_region_edge,
+ grids_per_patch_edge,
+ mOriginGlobal,
+ mWidth);
+ }
+
+ if (!gNoRender)
+ {
+ mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters);
+ }
+ else
+ {
+ mParcelOverlay = NULL;
+ }
+
+ setOriginGlobal(from_region_handle(handle));
+ calculateCenterGlobal();
+
+ // Create the object lists
+ initStats();
+
+ mCacheStart.append(mCacheEnd);
+
+}
+
+
+void LLViewerRegion::initStats()
+{
+ mLastNetUpdate.reset();
+ mPacketsIn = 0;
+ mBitsIn = 0;
+ mLastBitsIn = 0;
+ mLastPacketsIn = 0;
+ mPacketsOut = 0;
+ mLastPacketsOut = 0;
+ mPacketsLost = 0;
+ mLastPacketsLost = 0;
+ mPingDelay = 0;
+ mAlive = FALSE; // can become false if circuit disconnects
+}
+
+
+
+LLViewerRegion::~LLViewerRegion()
+{
+ gVLManager.cleanupData(this);
+ // Can't do this on destruction, because the neighbor pointers might be invalid.
+ // This should be reference counted...
+ disconnectAllNeighbors();
+ mCloudLayer.destroy();
+ gWorldPointer->mPartSim.cleanupRegion(this);
+
+ gObjectList.killObjects(this);
+
+ delete mCompositionp;
+ delete mParcelOverlay;
+ delete mLandp;
+ delete mEventPoll;
+
+ saveCache();
+}
+
+
+void LLViewerRegion::loadCache()
+{
+ if (mCacheLoaded)
+ {
+ return;
+ }
+
+ // Presume success. If it fails, we don't want to try again.
+ mCacheLoaded = TRUE;
+
+ LLVOCacheEntry *entry;
+
+ char filename[256];
+ sprintf(filename, "%s%sobjects_%d_%d.slc",
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),
+ gDirUtilp->getDirDelimiter().c_str(),
+ U32(mHandle>>32)/REGION_WIDTH_UNITS,
+ U32(mHandle)/REGION_WIDTH_UNITS );
+
+ FILE *fp = LLFile::fopen(filename, "rb");
+ if (!fp)
+ {
+ // might not have a file, which is normal
+ return;
+ }
+
+ U32 zero;
+ fread(&zero, 1, sizeof(U32), fp);
+ if (zero)
+ {
+ // a non-zero value here means bad things!
+ // skip reading the cached values
+ llinfos << "Cache file invalid" << llendl;
+ fclose(fp);
+ return;
+ }
+
+ U32 version;
+ fread(&version, 1, sizeof(U32), fp);
+ if (version != INDRA_OBJECT_CACHE_VERSION)
+ {
+ // a version mismatch here means we've changed the binary format!
+ // skip reading the cached values
+ llinfos << "Cache version changed, discarding" << llendl;
+ fclose(fp);
+ return;
+ }
+
+ LLUUID cache_id;
+ fread(&cache_id.mData, UUID_BYTES, sizeof(U8), fp);
+ if (mCacheID != cache_id)
+ {
+ llinfos << "Cache ID doesn't match for this region, discarding"
+ << llendl;
+ fclose(fp);
+ return;
+ }
+
+ S32 num_entries;
+ fread(&num_entries, 1, sizeof(S32), fp);
+ S32 i;
+ for (i = 0; i < num_entries; i++)
+ {
+ entry = new LLVOCacheEntry(fp);
+ if (!entry->getLocalID())
+ {
+ llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+ delete entry;
+ entry = NULL;
+ break;
+ }
+ mCacheEnd.insert(*entry);
+ mCacheMap[entry->getLocalID()] = entry;
+ mCacheEntriesCount++;
+ }
+
+ fclose(fp);
+}
+
+
+void LLViewerRegion::saveCache()
+{
+ if (!mCacheLoaded)
+ {
+ return;
+ }
+
+ S32 num_entries = mCacheEntriesCount;
+ if (0 == num_entries)
+ {
+ return;
+ }
+
+ char filename[256];
+ sprintf(filename, "%s%sobjects_%d_%d.slc",
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),
+ gDirUtilp->getDirDelimiter().c_str(),
+ U32(mHandle>>32)/REGION_WIDTH_UNITS,
+ U32(mHandle)/REGION_WIDTH_UNITS );
+
+ FILE *fp = LLFile::fopen(filename, "wb");
+ if (!fp)
+ {
+ llwarns << "Unable to write cache file " << filename << llendl;
+ return;
+ }
+
+ // write out zero to indicate a version cache file
+ U32 zero = 0;
+ fwrite(&zero, 1, sizeof(U32), fp);
+
+ // write out version number
+ U32 version = INDRA_OBJECT_CACHE_VERSION;
+ fwrite(&version, 1, sizeof(U32), fp);
+
+ // write the cache id for this sim
+ fwrite(&mCacheID.mData, UUID_BYTES, sizeof(U8), fp);
+
+ fwrite(&num_entries, 1, sizeof(S32), fp);
+
+ LLVOCacheEntry *entry;
+
+ for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext())
+ {
+ entry->writeToFile(fp);
+ }
+
+ mCacheMap.removeAllData();
+ mCacheEnd.unlink();
+ mCacheEnd.init();
+ mCacheStart.deleteAll();
+ mCacheStart.init();
+
+ fclose(fp);
+}
+
+void LLViewerRegion::sendMessage()
+{
+ gMessageSystem->sendMessage(mHost);
+}
+
+void LLViewerRegion::sendReliableMessage()
+{
+ gMessageSystem->sendReliable(mHost);
+}
+
+
+void LLViewerRegion::setAllowDamage(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_ALLOW_DAMAGE;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_ALLOW_DAMAGE;
+ }
+}
+
+
+void LLViewerRegion::setAllowLandmark(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_ALLOW_LANDMARK;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_ALLOW_LANDMARK;
+ }
+}
+
+void LLViewerRegion::setAllowSetHome(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_ALLOW_SET_HOME;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_ALLOW_SET_HOME;
+ }
+}
+
+void LLViewerRegion::setResetHomeOnTeleport(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_RESET_HOME_ON_TELEPORT;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_RESET_HOME_ON_TELEPORT;
+ }
+}
+
+void LLViewerRegion::setSunFixed(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_SUN_FIXED;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_SUN_FIXED;
+ }
+}
+
+void LLViewerRegion::setBlockFly(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_BLOCK_FLY;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_BLOCK_FLY;
+ }
+}
+
+void LLViewerRegion::setAllowDirectTeleport(BOOL b)
+{
+ if (b)
+ {
+ mRegionFlags |= REGION_FLAGS_ALLOW_DIRECT_TELEPORT;
+ }
+ else
+ {
+ mRegionFlags &= ~REGION_FLAGS_ALLOW_DIRECT_TELEPORT;
+ }
+}
+
+void LLViewerRegion::setWaterHeight(F32 water_level)
+{
+ mLandp->setWaterHeight(water_level);
+}
+
+F32 LLViewerRegion::getWaterHeight() const
+{
+ return mLandp->getWaterHeight();
+}
+
+void LLViewerRegion::setRegionFlags(U32 flags)
+{
+ mRegionFlags = flags;
+}
+
+
+void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global)
+{
+ mOriginGlobal = origin_global;
+ mLandp->setOriginGlobal(origin_global);
+ mWind.setOriginGlobal(origin_global);
+ mCloudLayer.setOriginGlobal(origin_global);
+ calculateCenterGlobal();
+}
+
+
+void LLViewerRegion::setTimeDilation(F32 time_dilation)
+{
+ mTimeDilation = time_dilation;
+}
+
+
+LLVector3 LLViewerRegion::getOriginAgent() const
+{
+ return gAgent.getPosAgentFromGlobal(mOriginGlobal);
+}
+
+
+LLVector3 LLViewerRegion::getCenterAgent() const
+{
+ return gAgent.getPosAgentFromGlobal(mCenterGlobal);
+}
+
+
+void LLViewerRegion::setRegionNameAndZone(const char* name_and_zone)
+{
+ LLString name_zone(name_and_zone);
+ std::string::size_type pipe_pos = name_zone.find('|');
+ S32 length = name_zone.size();
+ if (pipe_pos != std::string::npos)
+ {
+ mName = name_zone.substr(0, pipe_pos);
+ mZoning = name_zone.substr(pipe_pos+1, length-(pipe_pos+1));
+ }
+ else
+ {
+ mName = name_zone;
+ mZoning = "";
+ }
+
+ LLString::stripNonprintable(mName);
+ LLString::stripNonprintable(mZoning);
+}
+
+BOOL LLViewerRegion::canManageEstate() const
+{
+ return gAgent.isGodlike()
+ || isEstateManager()
+ || gAgent.getID() == getOwner();
+}
+
+const char* LLViewerRegion::getSimAccessString() const
+{
+ return accessToString(mSimAccess);
+}
+
+
+// static
+std::string LLViewerRegion::regionFlagsToString(U32 flags)
+{
+ std::string result;
+
+ if (flags & REGION_FLAGS_SANDBOX)
+ {
+ result += "Sandbox";
+ }
+
+ if (flags & REGION_FLAGS_ALLOW_DAMAGE)
+ {
+ result += " Not Safe";
+ }
+
+ return result;
+}
+
+char* SIM_ACCESS_STR[] = { "Free Trial",
+ "PG",
+ "Mature",
+ "Offline",
+ "Unknown" };
+
+// static
+const char* LLViewerRegion::accessToString(U8 access)
+{
+ switch(access)
+ {
+ case SIM_ACCESS_TRIAL:
+ return SIM_ACCESS_STR[0];
+
+ case SIM_ACCESS_PG:
+ return SIM_ACCESS_STR[1];
+
+ case SIM_ACCESS_MATURE:
+ return SIM_ACCESS_STR[2];
+
+ case SIM_ACCESS_DOWN:
+ return SIM_ACCESS_STR[3];
+
+ case SIM_ACCESS_MIN:
+ default:
+ return SIM_ACCESS_STR[4];
+ }
+}
+
+// static
+U8 LLViewerRegion::stringToAccess(const char* access_str)
+{
+ U8 access = SIM_ACCESS_MIN;
+ if (0 == strcmp(access_str, SIM_ACCESS_STR[0]))
+ {
+ access = SIM_ACCESS_TRIAL;
+ }
+ else if (0 == strcmp(access_str, SIM_ACCESS_STR[1]))
+ {
+ access = SIM_ACCESS_PG;
+ }
+ else if (0 == strcmp(access_str, SIM_ACCESS_STR[2]))
+ {
+ access = SIM_ACCESS_MATURE;
+ }
+ return access;
+}
+
+// static
+const char* LLViewerRegion::accessToShortString(U8 access)
+{
+ switch(access)
+ {
+ case SIM_ACCESS_PG:
+ return "PG";
+
+ case SIM_ACCESS_TRIAL:
+ return "TR";
+
+ case SIM_ACCESS_MATURE:
+ return "M";
+
+ case SIM_ACCESS_MIN:
+ default:
+ return "U";
+ }
+}
+
+// static
+void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**)
+{
+ // send it to 'observers'
+ LLFloaterGodTools::processRegionInfo(msg);
+ LLFloaterRegionInfo::processRegionInfo(msg);
+}
+
+
+
+S32 LLViewerRegion::renderPropertyLines()
+{
+ if (mParcelOverlay)
+ {
+ return mParcelOverlay->renderPropertyLines();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// This gets called when the height field changes.
+void LLViewerRegion::dirtyHeights()
+{
+ // Property lines need to be reconstructed when the land changes.
+ if (mParcelOverlay)
+ {
+ mParcelOverlay->setDirty();
+ }
+}
+
+BOOL LLViewerRegion::idleUpdate(LLTimer &timer, const F32 max_time)
+{
+ BOOL done = mLandp->idleUpdate();
+
+ if (mParcelOverlay)
+ {
+ mParcelOverlay->idleUpdate();
+ }
+
+ return done;
+}
+
+
+// As above, but forcibly do the update.
+void LLViewerRegion::forceUpdate()
+{
+ mLandp->idleUpdate();
+
+ if (mParcelOverlay)
+ {
+ mParcelOverlay->idleUpdate(true);
+ }
+}
+
+void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction)
+{
+ mLandp->connectNeighbor(neighborp->mLandp, direction);
+ mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction);
+}
+
+
+void LLViewerRegion::disconnectAllNeighbors()
+{
+ mLandp->disconnectAllNeighbors();
+ mCloudLayer.disconnectAllNeighbors();
+}
+
+
+F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const
+{
+ if (x >= 256)
+ {
+ if (y >= 256)
+ {
+ LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 256.f, 0.f);
+ LLViewerRegion *regionp = gWorldPointer->getRegionFromPosGlobal(center);
+ if (regionp)
+ {
+ // OK, we need to do some hackery here - different simulators no longer use
+ // the same composition values, necessarily.
+ // If we're attempting to blend, then we want to make the fractional part of
+ // this region match the fractional of the adjacent. For now, just minimize
+ // the delta.
+ F32 our_comp = getComposition()->getValueScaled(255, 255);
+ F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, y - 256.f);
+ while (llabs(our_comp - adj_comp) >= 1.f)
+ {
+ if (our_comp > adj_comp)
+ {
+ adj_comp += 1.f;
+ }
+ else
+ {
+ adj_comp -= 1.f;
+ }
+ }
+ return adj_comp;
+ }
+ }
+ else
+ {
+ LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 0, 0.f);
+ LLViewerRegion *regionp = gWorldPointer->getRegionFromPosGlobal(center);
+ if (regionp)
+ {
+ // OK, we need to do some hackery here - different simulators no longer use
+ // the same composition values, necessarily.
+ // If we're attempting to blend, then we want to make the fractional part of
+ // this region match the fractional of the adjacent. For now, just minimize
+ // the delta.
+ F32 our_comp = getComposition()->getValueScaled(255.f, (F32)y);
+ F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, (F32)y);
+ while (llabs(our_comp - adj_comp) >= 1.f)
+ {
+ if (our_comp > adj_comp)
+ {
+ adj_comp += 1.f;
+ }
+ else
+ {
+ adj_comp -= 1.f;
+ }
+ }
+ return adj_comp;
+ }
+ }
+ }
+ else if (y >= 256)
+ {
+ LLVector3d center = getCenterGlobal() + LLVector3d(0.f, 256.f, 0.f);
+ LLViewerRegion *regionp = gWorldPointer->getRegionFromPosGlobal(center);
+ if (regionp)
+ {
+ // OK, we need to do some hackery here - different simulators no longer use
+ // the same composition values, necessarily.
+ // If we're attempting to blend, then we want to make the fractional part of
+ // this region match the fractional of the adjacent. For now, just minimize
+ // the delta.
+ F32 our_comp = getComposition()->getValueScaled((F32)x, 255.f);
+ F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - 256.f);
+ while (llabs(our_comp - adj_comp) >= 1.f)
+ {
+ if (our_comp > adj_comp)
+ {
+ adj_comp += 1.f;
+ }
+ else
+ {
+ adj_comp -= 1.f;
+ }
+ }
+ return adj_comp;
+ }
+ }
+
+ return getComposition()->getValueScaled((F32)x, (F32)y);
+}
+
+
+// ---------------- Friends ----------------
+
+std::ostream& operator<<(std::ostream &s, const LLViewerRegion &region)
+{
+ s << "{ ";
+ s << region.mHost;
+ s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n";
+ s << "}";
+ return s;
+}
+
+
+// ---------------- Protected Member Functions ----------------
+
+void LLViewerRegion::calculateCenterGlobal()
+{
+ mCenterGlobal = mOriginGlobal;
+ mCenterGlobal.mdV[VX] += 0.5 * mWidth;
+ mCenterGlobal.mdV[VY] += 0.5 * mWidth;
+ if (mLandp)
+ {
+ mCenterGlobal.mdV[VZ] = 0.5*mLandp->getMinZ() + mLandp->getMaxZ();
+ }
+ else
+ {
+ mCenterGlobal.mdV[VZ] = F64( getWaterHeight() );
+ }
+}
+
+
+
+void LLViewerRegion::updateNetStats()
+{
+ F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32();
+
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost);
+ if (!cdp)
+ {
+ mAlive = FALSE;
+ return;
+ }
+
+ mAlive = TRUE;
+ mDeltaTime = dt;
+
+ mLastPacketsIn = mPacketsIn;
+ mLastBitsIn = mBitsIn;
+ mLastPacketsOut = mPacketsOut;
+ mLastPacketsLost = mPacketsLost;
+
+ mPacketsIn = cdp->getPacketsIn();
+ mBitsIn = 8 * cdp->getBytesIn();
+ mPacketsOut = cdp->getPacketsOut();
+ mPacketsLost = cdp->getPacketsLost();
+ mPingDelay = cdp->getPingDelay();
+
+ mBitStat.addValue(mBitsIn - mLastBitsIn);
+ mPacketsStat.addValue(mPacketsIn - mLastPacketsIn);
+ mPacketsLostStat.addValue(mPacketsLost);
+}
+
+
+U32 LLViewerRegion::getPacketsLost() const
+{
+ LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost);
+ if (!cdp)
+ {
+ llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl;
+ return 0;
+ }
+ else
+ {
+ return cdp->getPacketsLost();
+ }
+}
+
+BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const
+{
+ LLVector3 pos_region = getPosRegionFromGlobal(point_global);
+
+ if (pos_region.mV[VX] < 0)
+ {
+ return FALSE;
+ }
+ if (pos_region.mV[VX] >= mWidth)
+ {
+ return FALSE;
+ }
+ if (pos_region.mV[VY] < 0)
+ {
+ return FALSE;
+ }
+ if (pos_region.mV[VY] >= mWidth)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const
+{
+ LLVector3 pos_region;
+ pos_region.setVec(point_global - mOriginGlobal);
+ return pos_region;
+}
+
+LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) const
+{
+ LLVector3d pos_region_d;
+ pos_region_d.setVec(pos_region);
+ return pos_region_d + mOriginGlobal;
+}
+
+LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const
+{
+ LLVector3d pos_global = getPosGlobalFromRegion(pos_region);
+
+ return gAgent.getPosAgentFromGlobal(pos_global);
+}
+
+LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) const
+{
+ return getPosRegionFromGlobal(gAgent.getPosGlobalFromAgent(pos_agent));
+}
+
+F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos)
+{
+ return mLandp->resolveHeightRegion( region_pos );
+}
+
+BOOL LLViewerRegion::isOwnedSelf(const LLVector3& pos)
+{
+ return mParcelOverlay->isOwnedSelf(pos);
+}
+
+// Owned by a group you belong to? (officer or member)
+BOOL LLViewerRegion::isOwnedGroup(const LLVector3& pos)
+{
+ return mParcelOverlay->isOwnedGroup(pos);
+}
+
+void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
+{
+ //llinfos << "CoarseLocationUpdate" << llendl;
+ mMapAvatars.reset();
+
+ U8 x_pos = 0;
+ U8 y_pos = 0;
+ U8 z_pos = 0;
+
+ U32 pos = 0x0;
+
+ S16 agent_index;
+ S16 target_index;
+ msg->getS16Fast(_PREHASH_Index, _PREHASH_You, agent_index);
+ msg->getS16Fast(_PREHASH_Index, _PREHASH_Prey, target_index);
+
+ S32 count = msg->getNumberOfBlocksFast(_PREHASH_Location);
+ for(S32 i = 0; i < count; i++)
+ {
+ msg->getU8Fast(_PREHASH_Location, _PREHASH_X, x_pos, i);
+ msg->getU8Fast(_PREHASH_Location, _PREHASH_Y, y_pos, i);
+ msg->getU8Fast(_PREHASH_Location, _PREHASH_Z, z_pos, i);
+
+ //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos
+ // << " Z: " << (S32)(z_pos * 4)
+ // << llendl;
+
+ // treat the target specially for the map, and don't add you
+ // or the target
+ if(i == target_index)
+ {
+ LLVector3d global_pos(mOriginGlobal);
+ global_pos.mdV[VX] += (F64)(x_pos);
+ global_pos.mdV[VY] += (F64)(y_pos);
+ global_pos.mdV[VZ] += (F64)(z_pos) * 4.0;
+ LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
+ }
+ else if( i != agent_index)
+ {
+ pos = 0x0;
+ pos |= x_pos;
+ pos <<= 8;
+ pos |= y_pos;
+ pos <<= 8;
+ pos |= z_pos;
+ mMapAvatars.put(pos);
+ }
+ }
+}
+
+LLString LLViewerRegion::getInfoString()
+{
+ char tmp_buf[256];
+ LLString info;
+
+ info = "Region: ";
+ getHost().getString(tmp_buf, 256);
+ info += tmp_buf;
+ info += ":";
+ info += getName();
+ info += "\n";
+
+ U32 x, y;
+ from_region_handle(getHandle(), &x, &y);
+ sprintf(tmp_buf, "%d:%d", x, y);
+ info += "Handle:";
+ info += tmp_buf;
+ info += "\n";
+ return info;
+}
+
+
+void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
+{
+ U32 local_id = objectp->getLocalID();
+ U32 crc = objectp->getCRC();
+
+ LLVOCacheEntry *entry = mCacheMap.getIfThere(local_id);
+
+ if (entry)
+ {
+ // we've seen this object before
+ if (entry->getCRC() == crc)
+ {
+ // Record a hit
+ entry->recordDupe();
+ }
+ else
+ {
+ // Update the cache entry
+ mCacheMap.removeData(local_id);
+ delete entry;
+ entry = new LLVOCacheEntry(local_id, crc, dp);
+ mCacheEnd.insert(*entry);
+ mCacheMap[local_id] = entry;
+ }
+ }
+ else
+ {
+ // we haven't seen this object before
+
+ // Create new entry and add to map
+ if (mCacheEntriesCount > MAX_OBJECT_CACHE_ENTRIES)
+ {
+ entry = mCacheStart.getNext();
+ mCacheMap.removeData(entry->getLocalID());
+ delete entry;
+ mCacheEntriesCount--;
+ }
+ entry = new LLVOCacheEntry(local_id, crc, dp);
+
+ mCacheEnd.insert(*entry);
+ mCacheMap[local_id] = entry;
+ mCacheEntriesCount++;
+ }
+ return ;
+}
+
+// Get data packer for this object, if we have cached data
+// AND the CRC matches. JC
+LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc)
+{
+ llassert(mCacheLoaded);
+
+ LLVOCacheEntry *entry = mCacheMap.getIfThere(local_id);
+
+ if (entry)
+ {
+ // we've seen this object before
+ if (entry->getCRC() == crc)
+ {
+ // Record a hit
+ entry->recordHit();
+ return entry->getDP(crc);
+ }
+ else
+ {
+ // llinfos << "CRC miss for " << local_id << llendl;
+ mCacheMissCRC.put(local_id);
+ }
+ }
+ else
+ {
+ // llinfos << "Cache miss for " << local_id << llendl;
+ mCacheMissFull.put(local_id);
+ }
+ return NULL;
+}
+
+void LLViewerRegion::addCacheMissFull(const U32 local_id)
+{
+ mCacheMissFull.put(local_id);
+}
+
+void LLViewerRegion::requestCacheMisses()
+{
+ S32 full_count = mCacheMissFull.count();
+ S32 crc_count = mCacheMissCRC.count();
+ if (full_count == 0 && crc_count == 0) return;
+
+ LLMessageSystem* msg = gMessageSystem;
+ BOOL start_new_message = TRUE;
+ S32 blocks = 0;
+ S32 i;
+
+ const U8 CACHE_MISS_TYPE_FULL = 0;
+ const U8 CACHE_MISS_TYPE_CRC = 1;
+
+ // Send full cache miss updates. For these, we KNOW we don't
+ // have a viewer object.
+ for (i = 0; i < full_count; i++)
+ {
+ if (start_new_message)
+ {
+ msg->newMessageFast(_PREHASH_RequestMultipleObjects);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ start_new_message = FALSE;
+ }
+
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_FULL);
+ msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]);
+ blocks++;
+
+ if (blocks >= 255)
+ {
+ sendReliableMessage();
+ start_new_message = TRUE;
+ blocks = 0;
+ }
+ }
+
+ // Send CRC miss updates. For these, we _might_ have a viewer object,
+ // but probably not.
+ for (i = 0; i < crc_count; i++)
+ {
+ if (start_new_message)
+ {
+ msg->newMessageFast(_PREHASH_RequestMultipleObjects);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ start_new_message = FALSE;
+ }
+
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_CRC);
+ msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]);
+ blocks++;
+
+ if (blocks >= 255)
+ {
+ sendReliableMessage();
+ start_new_message = TRUE;
+ blocks = 0;
+ }
+ }
+
+ // finish any pending message
+ if (!start_new_message)
+ {
+ sendReliableMessage();
+ }
+ mCacheMissFull.reset();
+ mCacheMissCRC.reset();
+
+ // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
+}
+
+void LLViewerRegion::dumpCache()
+{
+ const S32 BINS = 4;
+ S32 hit_bin[BINS];
+ S32 change_bin[BINS];
+
+ S32 i;
+ for (i = 0; i < BINS; ++i)
+ {
+ hit_bin[i] = 0;
+ change_bin[i] = 0;
+ }
+
+ LLVOCacheEntry *entry;
+
+ for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext())
+ {
+ S32 hits = entry->getHitCount();
+ S32 changes = entry->getCRCChangeCount();
+
+ hits = llclamp(hits, 0, BINS-1);
+ changes = llclamp(changes, 0, BINS-1);
+
+ hit_bin[hits]++;
+ change_bin[changes]++;
+ }
+
+ llinfos << "Count " << mCacheEntriesCount << llendl;
+ for (i = 0; i < BINS; i++)
+ {
+ llinfos << "Hits " << i << " " << hit_bin[i] << llendl;
+ }
+ for (i = 0; i < BINS; i++)
+ {
+ llinfos << "Changes " << i << " " << change_bin[i] << llendl;
+ }
+}
+
+void LLViewerRegion::unpackRegionHandshake()
+{
+ LLMessageSystem *msg = gMessageSystem;
+
+ const S32 SIM_NAME_BUF = 256;
+ U32 region_flags;
+ U8 sim_access;
+ char sim_name[SIM_NAME_BUF];
+ LLUUID sim_owner;
+ BOOL is_estate_manager;
+ F32 water_height;
+ F32 billable_factor;
+ LLUUID cache_id;
+
+ msg->getU32 ("RegionInfo", "RegionFlags", region_flags);
+ msg->getU8 ("RegionInfo", "SimAccess", sim_access);
+ msg->getString ("RegionInfo", "SimName", SIM_NAME_BUF, sim_name);
+ msg->getUUID ("RegionInfo", "SimOwner", sim_owner);
+ msg->getBOOL ("RegionInfo", "IsEstateManager", is_estate_manager);
+ msg->getF32 ("RegionInfo", "WaterHeight", water_height);
+ msg->getF32 ("RegionInfo", "BillableFactor", billable_factor);
+ msg->getUUID ("RegionInfo", "CacheID", cache_id );
+
+ setRegionFlags(region_flags);
+ setSimAccess(sim_access);
+ setRegionNameAndZone(sim_name);
+ setOwner(sim_owner);
+ setIsEstateManager(is_estate_manager);
+ setWaterHeight(water_height);
+ setBillableFactor(billable_factor);
+ setCacheID(cache_id);
+
+ LLVLComposition *compp = getComposition();
+ if (compp)
+ {
+ LLUUID tmp_id;
+
+ msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id);
+ compp->setDetailTextureID(0, tmp_id);
+ msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id);
+ compp->setDetailTextureID(1, tmp_id);
+ msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id);
+ compp->setDetailTextureID(2, tmp_id);
+ msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id);
+ compp->setDetailTextureID(3, tmp_id);
+
+ F32 tmp_f32;
+ msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32);
+ compp->setStartHeight(0, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32);
+ compp->setStartHeight(1, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32);
+ compp->setStartHeight(2, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32);
+ compp->setStartHeight(3, tmp_f32);
+
+ msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32);
+ compp->setHeightRange(0, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32);
+ compp->setHeightRange(1, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32);
+ compp->setHeightRange(2, tmp_f32);
+ msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32);
+ compp->setHeightRange(3, tmp_f32);
+
+ // If this is an UPDATE (params already ready, we need to regenerate
+ // all of our terrain stuff, by
+ if (compp->getParamsReady())
+ {
+ getLand().dirtyAllPatches();
+ }
+ else
+ {
+ compp->setParamsReady();
+ }
+ }
+
+
+ // Now that we have the name, we can load the cache file
+ // off disk.
+ loadCache();
+
+ // After loading cache, signal that simulator can start
+ // sending data.
+ // TODO: Send all upstream viewer->sim handshake info here.
+ LLHost host = msg->getSender();
+ msg->newMessage("RegionHandshakeReply");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->nextBlock("RegionInfo");
+ msg->addU32("Flags", 0x0 );
+ msg->sendReliable(host);
+}
+
+
+
+class BaseCapabilitiesComplete : public LLHTTPClient::Responder
+{
+public:
+ BaseCapabilitiesComplete(LLViewerRegion* region)
+ : mRegion(region)
+ { }
+
+ void error(U32 statusNum, const std::string& reason)
+ {
+ llinfos << "BaseCapabilitiesComplete::error "
+ << statusNum << ": " << reason << llendl;
+ }
+
+ void result(const LLSD& content)
+ {
+ LLSD::map_const_iterator iter;
+ for(iter = content.beginMap(); iter != content.endMap(); ++iter)
+ {
+ mRegion->setCapability(iter->first, iter->second);
+ llinfos << "BaseCapabilitiesComplete::result got capability for "
+ << iter->first << llendl;
+ }
+ }
+
+ static boost::intrusive_ptr<BaseCapabilitiesComplete> build(
+ LLViewerRegion* region)
+ {
+ return boost::intrusive_ptr<BaseCapabilitiesComplete>(
+ new BaseCapabilitiesComplete(region));
+ }
+
+private:
+ LLViewerRegion* mRegion;
+};
+
+
+void LLViewerRegion::setSeedCapability(const std::string& url)
+{
+ delete mEventPoll;
+ mEventPoll = NULL;
+
+ mCapabilities.clear();
+ setCapability("Seed", url);
+
+ LLSD capabilityNames = LLSD::emptyArray();
+ capabilityNames.append("MapLayer");
+ capabilityNames.append("MapLayerGod");
+ capabilityNames.append("NewAgentInventory");
+ capabilityNames.append("EventQueueGet");
+ LLHTTPClient::post(url, capabilityNames, BaseCapabilitiesComplete::build(this));
+}
+
+static
+LLEventPoll* createViewerEventPoll(const std::string& url)
+{
+ static LLHTTPNode eventRoot;
+ static bool eventRootServicesAdded = false;
+ if (!eventRootServicesAdded)
+ {
+ LLSDMessageSystem::useServices();
+ LLHTTPRegistrar::buildAllServices(eventRoot);
+ eventRootServicesAdded = true;
+ }
+
+ return new LLEventPoll(url, eventRoot);
+}
+
+
+void LLViewerRegion::setCapability(const std::string& name, const std::string& url)
+{
+ mCapabilities[name] = url;
+
+ if (name == "EventQueueGet")
+ {
+ delete mEventPoll;
+ mEventPoll = NULL;
+ mEventPoll = createViewerEventPoll(url);
+ }
+}
+
+std::string LLViewerRegion::getCapability(const std::string& name) const
+{
+ CapabilityMap::const_iterator iter = mCapabilities.find(name);
+ if(iter == mCapabilities.end())
+ {
+ return "";
+ }
+ return iter->second;
+}
+