diff options
Diffstat (limited to 'indra/newview/llviewerregion.cpp')
-rw-r--r-- | indra/newview/llviewerregion.cpp | 1301 |
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 ®ion) +{ + 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; +} + |