diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h index e4da9bb9a..95d5a124b 100644 --- a/indra/llappearance/llavatarjoint.h +++ b/indra/llappearance/llavatarjoint.h @@ -52,7 +52,7 @@ public: virtual ~LLAvatarJoint(); // Gets the validity of this joint - BOOL getValid() { return mValid; } + bool getValid() const { return mValid; } // Sets the validity of this joint virtual void setValid( BOOL valid, BOOL recursive=FALSE ); diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 98dbd90fe..7f3f486ca 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -491,7 +491,7 @@ void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake) { mCurWeight = new_weight; - const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); if (info->mNumColors <= 0) { diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index fc8fe1936..062fe50d6 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -38,7 +38,6 @@ LLStringTable LLCharacter::sVisualParamNames(1024); std::vector< LLCharacter* > LLCharacter::sInstances; -BOOL LLCharacter::sAllowInstancesChange = TRUE ; //----------------------------------------------------------------------------- // LLCharacter() @@ -51,7 +50,6 @@ LLCharacter::LLCharacter() mAppearanceSerialNum( 0 ), mSkeletonSerialNum( 0 ) { - llassert_always(sAllowInstancesChange) ; sInstances.push_back(this); mMotionController.setCharacter( this ); @@ -75,8 +73,6 @@ LLCharacter::~LLCharacter() bool erased = vector_replace_with_last(sInstances,this); llassert_always(erased) ; - - llassert_always(sAllowInstancesChange) ; } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 93cf461c9..340b96a5e 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -267,7 +267,6 @@ public: void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } static std::vector< LLCharacter* > sInstances; - static BOOL sAllowInstancesChange ; //debug use virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; } const LLVector3& getHoverOffset() const { return mHoverOffset; } diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index fab4f11eb..d600936d8 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -32,15 +32,6 @@ class LLUUID; -// At 45 Hz collisions seem stable and objects seem -// to settle down at a reasonable rate. -// JC 3/18/2003 - -// const F32 PHYSICS_TIMESTEP = 1.f / 45.f; -// This must be a #define due to anal retentive restrictions on const expressions -// CG 2008-06-05 -#define PHYSICS_TIMESTEP (1.f / 45.f) - const F32 COLLISION_TOLERANCE = 0.1f; const F32 HALF_COLLISION_TOLERANCE = 0.05f; @@ -265,7 +256,7 @@ const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants -const S32 MAX_AGENT_ATTACHMENTS = 38; +const U32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; // god levels diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 4f8ec6756..becf99092 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -265,10 +265,10 @@ int LLFile::remove_nowarn(const std::string& filename) return rc; } -int LLFile::remove(const std::string& filename) +int LLFile::remove(const std::string& filename, int supress_error) { int rc = LLFile::remove_nowarn(filename); - return warnif("remove", filename, rc); + return warnif("remove", filename, rc, supress_error); } int LLFile::rename_nowarn(const std::string& filename, const std::string& newname) @@ -285,10 +285,10 @@ int LLFile::rename_nowarn(const std::string& filename, const std::string& newnam return rc; } -int LLFile::rename(const std::string& filename, const std::string& newname) +int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) { int rc = LLFile::rename_nowarn(filename, newname); - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); } int LLFile::stat(const std::string& filename, llstat* filestatus) diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index eacbacca1..f6bcf8728 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -45,6 +45,7 @@ typedef FILE LLFILE; typedef struct _stat llstat; #else typedef struct stat llstat; +#include #endif #ifndef S_ISREG @@ -77,8 +78,8 @@ public: static int mkdir(const std::string& filename, int perms = 0700); static int rmdir(const std::string& filename); - static int remove(const std::string& filename); - static int rename(const std::string& filename,const std::string& newname); + static int remove(const std::string& filename, int supress_error = 0); + static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); static int stat(const std::string& filename,llstat* file_status); static bool isdir(const std::string& filename); static bool isfile(const std::string& filename); diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 3562c044f..dc1236fce 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -815,6 +815,26 @@ std::string LLStringOps::getDatetimeCode (std::string key) } +std::string LLStringOps::getReadableNumber(F64 num) +{ + if (fabs(num)>=1e9) + { + return llformat("%.2lfB", num / 1e9); + } + else if (fabs(num)>=1e6) + { + return llformat("%.2lfM", num / 1e6); + } + else if (fabs(num)>=1e3) + { + return llformat("%.2lfK", num / 1e3); + } + else + { + return llformat("%.2lf", num); + } +} + namespace LLStringFn { // NOTE - this restricts output to ascii diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 41c38fe13..091849277 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -210,6 +210,9 @@ public: static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} static std::string getDatetimeCode (std::string key); + + // Express a value like 1234567 as "1.23M" + static std::string getReadableNumber(F64 num); }; /** diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 41d1fdee9..48cad96da 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -18,17 +18,18 @@ set(llmath_SOURCE_FILES llcoordframe.cpp llline.cpp llmatrix3a.cpp + llmatrix4a.cpp llmodularmath.cpp llperlin.cpp llquaternion.cpp + llrigginginfo.cpp llrect.cpp - llrigginginfo.cpp - llsdutil_math.cpp llsphere.cpp llvector4a.cpp llvolume.cpp llvolumemgr.cpp llvolumeoctree.cpp + llsdutil_math.cpp m3math.cpp m4math.cpp raytrace.cpp @@ -68,8 +69,7 @@ set(llmath_HEADER_FILES llquaternion2.h llquaternion2.inl llrect.h - llrigginginfo.h - llsdutil_math.h + llrigginginfo.h llsimdmath.h llsimdtypes.h llsimdtypes.inl @@ -81,6 +81,7 @@ set(llmath_HEADER_FILES llvolume.h llvolumemgr.h llvolumeoctree.h + llsdutil_math.h m3math.h m4math.h raytrace.h diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp new file mode 100644 index 000000000..fe8f0b98f --- /dev/null +++ b/indra/llmath/llmatrix4a.cpp @@ -0,0 +1,80 @@ +/** +* @file llmatrix4a.cpp +* @brief Functions for vectorized matrix/vector operations +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llmath.h" +#include "llmatrix4a.h" + +// Convert a bounding box into other coordinate system. Should give +// the same results as transforming every corner of the bounding box +// and extracting the bounding box of that, although that's not +// necessarily the fastest way to implement. +void matMulBoundBox(const LLMatrix4a &mat, const LLVector4a *in_extents, LLVector4a *out_extents) +{ + //get 8 corners of bounding box + LLVector4Logical mask[6]; + + for (U32 i = 0; i < 6; ++i) + { + mask[i].clear(); + } + + mask[0].setElement<2>(); //001 + mask[1].setElement<1>(); //010 + mask[2].setElement<1>(); //011 + mask[2].setElement<2>(); + mask[3].setElement<0>(); //100 + mask[4].setElement<0>(); //101 + mask[4].setElement<2>(); + mask[5].setElement<0>(); //110 + mask[5].setElement<1>(); + + LLVector4a v[8]; + + v[6] = in_extents[0]; + v[7] = in_extents[1]; + + for (U32 i = 0; i < 6; ++i) + { + v[i].setSelectWithMask(mask[i], in_extents[0], in_extents[1]); + } + + LLVector4a tv[8]; + + //transform bounding box into drawable space + for (U32 i = 0; i < 8; ++i) + { + mat.affineTransform(v[i], tv[i]); + } + + //find bounding box + out_extents[0] = out_extents[1] = tv[0]; + + for (U32 i = 1; i < 8; ++i) + { + out_extents[0].setMin(out_extents[0], tv[i]); + out_extents[1].setMax(out_extents[1], tv[i]); + } +} diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index a0906af1a..562b45e31 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -544,7 +544,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 { // Generate an n-sided "circular" path. // 0 is (1,0), and we go counter-clockwise along a circular path from there. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 scale = 0.5f; F32 t, t_step, t_first, t_fraction, ang, ang_step; LLVector4a pt1,pt2; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 43c94a5e5..88e91e8d1 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -369,3 +369,39 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) return FALSE; } + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ + LLVector3 offset; + for (S32 k=0; k<3; k++) + { + offset[k] = 0; + if (pos[k] < box[0][k]) + { + offset[k] = pos[k] - box[0][k]; + } + else if (pos[k] > box[1][k]) + { + offset[k] = pos[k] - box[1][k]; + } + } + return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ + if (!box[0].isFinite() || !box[1].isFinite()) + { + return false; + } + LLVector3 zero_vec; + zero_vec.clear(); + if ((box[0] != zero_vec) || (box[1] != zero_vec)) + { + return true; + } + return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 9403135a5..71ca661dd 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -163,6 +163,8 @@ LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Retu LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box); inline LLVector3::LLVector3(void) { diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index 4aba5cae7..f0d82bc3b 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -63,7 +63,6 @@ void LLXfer::init (S32 chunk_size) mXferSize = 0; mStatus = e_LL_XFER_UNINITIALIZED; - mNext = NULL; mWaitingForACK = FALSE; mCallback = NULL; @@ -99,7 +98,22 @@ void LLXfer::cleanup () S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) { - LL_WARNS() << "undifferentiated LLXfer::startSend for " << getFileName() << LL_ENDL; + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::startSend for " << getFileName() << LL_ENDL; + return (-1); +} + +/////////////////////////////////////////////////////////// + +void LLXfer::closeFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::closeFileHandle for " << getFileName() << LL_ENDL; +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer::reopenFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::reopenFileHandle for " << getFileName() << LL_ENDL; return (-1); } @@ -115,7 +129,7 @@ void LLXfer::setXferSize (S32 xfer_size) S32 LLXfer::startDownload() { - LL_WARNS() << "undifferentiated LLXfer::startDownload for " << getFileName() + LL_WARNS("Xfer") << "undifferentiated LLXfer::startDownload for " << getFileName() << LL_ENDL; return (-1); } @@ -140,7 +154,7 @@ S32 LLXfer::receiveData (char *datap, S32 data_size) } else { - LL_ERRS() << "NULL data passed in receiveData" << LL_ENDL; + LL_ERRS("Xfer") << "NULL data passed in receiveData" << LL_ENDL; } } @@ -163,7 +177,7 @@ S32 LLXfer::flush() S32 LLXfer::suck(S32 start_position) { - LL_WARNS() << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; + LL_WARNS("Xfer") << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; return (-1); } @@ -196,7 +210,7 @@ void LLXfer::sendPacket(S32 packet_num) if (fdata_size < 0) { - LL_WARNS() << "negative data size in xfer send, aborting" << LL_ENDL; + LL_WARNS("Xfer") << "negative data size in xfer send, aborting" << LL_ENDL; abort(LL_ERR_EOF); return; } @@ -248,7 +262,12 @@ void LLXfer::sendPacket(S32 packet_num) gMessageSystem->nextBlockFast(_PREHASH_DataPacket); gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size); - gMessageSystem->sendMessage(mRemoteHost); + S32 sent_something = gMessageSystem->sendMessage(mRemoteHost); + if (sent_something == 0) + { + abort(LL_ERR_CIRCUIT_GONE); + return; + } ACKTimer.reset(); mWaitingForACK = TRUE; @@ -289,12 +308,12 @@ S32 LLXfer::processEOF() if (LL_ERR_NOERR == mCallbackResult) { - LL_INFOS() << "xfer from " << mRemoteHost << " complete: " << getFileName() + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " complete: " << getFileName() << LL_ENDL; } else { - LL_INFOS() << "xfer from " << mRemoteHost << " failed, code " + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " failed, code " << mCallbackResult << ": " << getFileName() << LL_ENDL; } @@ -323,15 +342,18 @@ void LLXfer::abort (S32 result_code) { mCallbackResult = result_code; - LL_INFOS() << "Aborting xfer from " << mRemoteHost << " named " << getFileName() + LL_INFOS("Xfer") << "Aborting xfer from " << mRemoteHost << " named " << getFileName() << " - error: " << result_code << LL_ENDL; + if (result_code != LL_ERR_CIRCUIT_GONE) + { gMessageSystem->newMessageFast(_PREHASH_AbortXfer); gMessageSystem->nextBlockFast(_PREHASH_XferID); gMessageSystem->addU64Fast(_PREHASH_ID, mID); gMessageSystem->addS32Fast(_PREHASH_Result, result_code); gMessageSystem->sendMessage(mRemoteHost); + } mStatus = e_LL_XFER_ABORTED; } diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index edf5eeb82..064278afd 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -54,7 +54,6 @@ class LLXfer S32 mChunkSize; public: - LLXfer *mNext; U64 mID; S32 mPacketNum; @@ -90,7 +89,9 @@ class LLXfer void init(S32 chunk_size); virtual void cleanup(); - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual void sendPacket(S32 packet_num); virtual void sendNextPacket(); virtual void resendLastPacket(); diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 257a13f27..41d7dcd6c 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -98,16 +98,16 @@ void LLXfer_File::cleanup () mFp = NULL; } - LLFile::remove(mTempFilename); + LLFile::remove(mTempFilename, ENOENT); if (mDeleteLocalOnCompletion) { - LL_DEBUGS() << "Removing file: " << mLocalFilename << LL_ENDL; - LLFile::remove(mLocalFilename); + LL_DEBUGS("Xfer") << "Removing file: " << mLocalFilename << LL_ENDL; + LLFile::remove(mLocalFilename, ENOENT); } else { - LL_DEBUGS() << "Keeping local file: " << mLocalFilename << LL_ENDL; + LL_DEBUGS("Xfer") << "Keeping local file: " << mLocalFilename << LL_ENDL; } LLXfer::cleanup(); @@ -139,7 +139,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, mCallbackDataHandle = user_data; mCallbackResult = LL_ERR_NOERR; - LL_INFOS() << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; + LL_INFOS("Xfer") << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; if (mBuffer) { @@ -182,7 +182,7 @@ S32 LLXfer_File::startDownload() } else { - LL_WARNS() << "Couldn't create file to be received!" << LL_ENDL; + LL_WARNS("Xfer") << "Couldn't create file to be received!" << LL_ENDL; retval = -1; } @@ -223,7 +223,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) } else { - LL_INFOS() << "Warning: " << mLocalFilename << " not found." << LL_ENDL; + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found." << LL_ENDL; return (LL_ERR_FILE_NOT_FOUND); } @@ -232,6 +232,36 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) return (retval); } +/////////////////////////////////////////////////////////// +void LLXfer_File::closeFileHandle() +{ + if (mFp) + { + fclose(mFp); + mFp = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_File::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mFp == NULL) + { + mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + if (mFp == NULL) + { + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + /////////////////////////////////////////////////////////// S32 LLXfer_File::getMaxBufferSize () @@ -279,18 +309,21 @@ S32 LLXfer_File::flush() { if (mFp) { - LL_ERRS() << "Overwriting open file pointer!" << LL_ENDL; + LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ if (mFp) { - if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength) + S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp); + if (write_size != mBufferLength) { - LL_WARNS() << "Short write" << LL_ENDL; + LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength + << " but wrote " << write_size + << LL_ENDL; } -// LL_INFOS() << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; +// LL_INFOS("Xfer") << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; fclose(mFp); mFp = NULL; @@ -298,7 +331,7 @@ S32 LLXfer_File::flush() } else { - LL_WARNS() << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; + LL_WARNS("Xfer") << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; retval = LL_ERR_CANNOT_OPEN_FILE; } } @@ -321,7 +354,7 @@ S32 LLXfer_File::processEOF() mCallbackResult = flushval; } - LLFile::remove(mLocalFilename); + LLFile::remove(mLocalFilename, ENOENT); if (!mCallbackResult) { @@ -329,18 +362,18 @@ S32 LLXfer_File::processEOF() { #if !LL_WINDOWS S32 error_number = errno; - LL_INFOS() << "Rename failure (" << error_number << ") - " + LL_INFOS("Xfer") << "Rename failure (" << error_number << ") - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; if(EXDEV == error_number) { if(copy_file(mTempFilename, mLocalFilename) == 0) { - LL_INFOS() << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; + LL_INFOS("Xfer") << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; unlink(mTempFilename.c_str()); } else { - LL_WARNS() << "Copy failure - " << mTempFilename << " to " + LL_WARNS("Xfer") << "Copy failure - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; } } @@ -354,11 +387,11 @@ S32 LLXfer_File::processEOF() //LL_WARNS() << "File " << mLocalFilename << " does " // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - LL_WARNS() << "Rename fatally failed, can only handle EXDEV (" + LL_WARNS("Xfer") << "Rename fatally failed, can only handle EXDEV (" << EXDEV << ")" << LL_ENDL; } #else - LL_WARNS() << "Rename failure - " << mTempFilename << " to " + LL_WARNS("Xfer") << "Rename failure - " << mTempFilename << " to " << mLocalFilename << LL_ENDL; #endif } diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index a37dda673..ab9374549 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -61,8 +61,10 @@ class LLXfer_File : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index 3bea08f2e..78a3e4f55 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -80,28 +80,6 @@ void LLXfer_Mem::setXferSize (S32 xfer_size) /////////////////////////////////////////////////////////// -U64 LLXfer_Mem::registerXfer(U64 xfer_id, const void *datap, const S32 length) -{ - mID = xfer_id; - - if (datap) - { - setXferSize(length); - if (mBuffer) - { - memcpy(mBuffer,datap,length); /* Flawfinder : ignore */ - mBufferLength = length; - } - else - { - xfer_id = 0; - } - } - - mStatus = e_LL_XFER_REGISTERED; - return (xfer_id); -} - S32 LLXfer_Mem::startSend (U64 xfer_id, const LLHost &remote_host) { S32 retval = LL_ERR_NOERR; // presume success diff --git a/indra/llmessage/llxfer_mem.h b/indra/llmessage/llxfer_mem.h index b5adf837d..d07779de8 100644 --- a/indra/llmessage/llxfer_mem.h +++ b/indra/llmessage/llxfer_mem.h @@ -53,7 +53,6 @@ class LLXfer_Mem : public LLXfer virtual void cleanup(); virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); - virtual U64 registerXfer(U64 xfer_id, const void *datap, const S32 length); virtual void setXferSize (S32 data_size); virtual S32 initializeRequest(U64 xfer_id, diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index 4a378d1d3..988bb7513 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -79,8 +79,20 @@ void LLXfer_VFile::init (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType void LLXfer_VFile::cleanup () { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - file.remove(); + if (mTempID.notNull() && + mDeleteTempFile) + { + if (mVFS->getExists(mTempID, mType)) + { + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + file.remove(); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete VFS file " << mTempID << "." << LLAssetType::lookup(mType) + << ", mRemoteID is " << mRemoteID << LL_ENDL; + } + } delete mVFile; mVFile = NULL; @@ -118,7 +130,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType)); - LL_INFOS() << "Requesting " << mName << LL_ENDL; + LL_INFOS("Xfer") << "Requesting " << mName << LL_ENDL; if (mBuffer) { @@ -131,6 +143,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mBufferLength = 0; mPacketNum = 0; mTempID.generate(); + mDeleteTempFile = TRUE; mStatus = e_LL_XFER_PENDING; return retval; } @@ -140,7 +153,8 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, S32 LLXfer_VFile::startDownload() { S32 retval = 0; // presume success - LLVFile file(mVFS, mTempID, mType, LLVFile::APPEND); + + // Don't need to create the file here, it will happen when data arrives gMessageSystem->newMessageFast(_PREHASH_RequestXfer); gMessageSystem->nextBlockFast(_PREHASH_XferID); @@ -184,6 +198,8 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) if (mVFile->getSize() <= 0) { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() VFS file " << mLocalID << "." << LLAssetType::lookup(mType) + << " has unexpected file size of " << mVFile->getSize() << LL_ENDL; delete mVFile; mVFile = NULL; @@ -198,6 +214,7 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } else { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; retval = LL_ERR_FILE_NOT_FOUND; } @@ -205,6 +222,41 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } /////////////////////////////////////////////////////////// + +void LLXfer_VFile::closeFileHandle() +{ + if (mVFile) + { + delete mVFile; + mVFile = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_VFile::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mVFile == NULL) + { + if (mVFS->getExists(mLocalID, mType)) + { + mVFile = new LLVFile(mVFS, mLocalID, mType, LLVFile::READ); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + +/////////////////////////////////////////////////////////// + void LLXfer_VFile::setXferSize (S32 xfer_size) { LLXfer::setXferSize(xfer_size); @@ -236,8 +288,8 @@ S32 LLXfer_VFile::suck(S32 start_position) // grab a buffer from the right place in the file if (! mVFile->seek(start_position, 0)) { - LL_WARNS() << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; - LL_WARNS() << "While sending file " << mLocalID << LL_ENDL; + LL_WARNS("Xfer") << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; + LL_WARNS("Xfer") << "While sending file " << mLocalID << LL_ENDL; return -1; } @@ -288,12 +340,31 @@ S32 LLXfer_VFile::processEOF() if (!mCallbackResult) { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - if (! file.rename(mLocalID, mType)) + if (mVFS->getExists(mTempID, mType)) { - LL_INFOS() << "copy from temp file failed: unable to rename to " << mLocalID << LL_ENDL; + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + if (!file.rename(mLocalID, mType)) + { + LL_WARNS("Xfer") << "VFS rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; + } + else + { + #ifdef VFS_SPAM + // Debugging spam + LL_INFOS("Xfer") << "VFS rename of temp file done: renamed " << mTempID << " to " << mLocalID + << " LLVFile size is " << file.getSize() + << LL_ENDL; + #endif + + // Rename worked: the original file is gone. Clear mDeleteTempFile + // so we don't attempt to delete the file in cleanup() + mDeleteTempFile = FALSE; + } + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming VFS file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; } - } if (mVFile) diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 048bf49dc..5bf9a5cfb 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -47,6 +47,8 @@ class LLXfer_VFile : public LLXfer std::string mName; + BOOL mDeleteTempFile; + public: LLXfer_VFile (); LLXfer_VFile (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type); @@ -66,8 +68,10 @@ class LLXfer_VFile : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 0ab67b8dd..4cea886c8 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -44,9 +44,15 @@ const S32 LL_PACKET_RETRY_LIMIT = 10; // packet retransmission limit const S32 LL_DEFAULT_MAX_SIMULTANEOUS_XFERS = 10; const S32 LL_DEFAULT_MAX_REQUEST_FIFO_XFERS = 1000; -#define LL_XFER_PROGRESS_MESSAGES 0 -#define LL_XFER_TEST_REXMIT 0 +// Kills the connection if a viewer download queue hits this many requests backed up +// Also set in simulator.xml at "hard_limit_outgoing_xfers_per_circuit" +const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500; +// Use this to show sending some ConfirmXferPacket messages +//#define LL_XFER_PROGRESS_MESSAGES 1 + +// Use this for lots of diagnostic spam +//#define LL_XFER_DIAGNOISTIC_LOGGING 1 /////////////////////////////////////////////////////////// @@ -66,10 +72,10 @@ LLXferManager::~LLXferManager () void LLXferManager::init (LLVFS *vfs) { - mSendList = NULL; - mReceiveList = NULL; + cleanup(); setMaxOutgoingXfersPerCircuit(LL_DEFAULT_MAX_SIMULTANEOUS_XFERS); + setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS); setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); mVFS = vfs; @@ -83,29 +89,14 @@ void LLXferManager::init (LLVFS *vfs) void LLXferManager::cleanup () { - LLXfer *xferp; - LLXfer *delp; - for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - delp = mSendList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mSendList = NULL; + for_each(mSendList.begin(), mSendList.end(), DeletePointer()); + mSendList.clear(); - delp = mReceiveList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mReceiveList = NULL; + for_each(mReceiveList.begin(), mReceiveList.end(), DeletePointer()); + mReceiveList.clear(); } /////////////////////////////////////////////////////////// @@ -122,6 +113,11 @@ void LLXferManager::setMaxOutgoingXfersPerCircuit(S32 max_num) mMaxOutgoingXfersPerCircuit = max_num; } +void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num) +{ + mHardLimitOutgoingXfersPerCircuit = max_num; +} + void LLXferManager::setUseAckThrottling(const BOOL use) { mUseAckThrottling = use; @@ -140,6 +136,11 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) F32 actual_rate = llmax(min_bps*1.1f, bps); LL_DEBUGS("AppInit") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; LL_DEBUGS("AppInit") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; + LL_INFOS("Xfer") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + mAckThrottle.setRate(actual_rate); } @@ -148,45 +149,71 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) void LLXferManager::updateHostStatus() { - LLXfer *xferp; - LLHostStatus *host_statusp = NULL; - + // Clear the outgoing host list for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - - for (xferp = mSendList; xferp; xferp = xferp->mNext) + + // Loop through all outgoing xfers and re-build mOutgoingHosts + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) { + LLHostStatus *host_statusp = NULL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { - host_statusp = *iter; - if (host_statusp->mHost == xferp->mRemoteHost) - { + if ((*iter)->mHost == (*send_iter)->mRemoteHost) + { // Already have this host + host_statusp = *iter; break; } } if (!host_statusp) - { + { // Don't have this host, so add it host_statusp = new LLHostStatus(); if (host_statusp) { - host_statusp->mHost = xferp->mRemoteHost; + host_statusp->mHost = (*send_iter)->mRemoteHost; mOutgoingHosts.push_front(host_statusp); } } if (host_statusp) - { - if (xferp->mStatus == e_LL_XFER_PENDING) + { // Do the accounting + if ((*send_iter)->mStatus == e_LL_XFER_PENDING) { host_statusp->mNumPending++; } - else if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + else if ((*send_iter)->mStatus == e_LL_XFER_IN_PROGRESS) { host_statusp->mNumActive++; } } - } + +#ifdef LL_XFER_DIAGNOISTIC_LOGGING + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) + { + LLXfer * xferp = *send_iter; + LL_INFOS("Xfer") << "xfer to host " << xferp->mRemoteHost + << " is " << xferp->mXferSize << " bytes" + << ", status " << (S32)(xferp->mStatus) + << ", waiting for ACK: " << (S32)(xferp->mWaitingForACK) + << " in frame " << (S32) LLFrameTimer::getFrameCount() + << LL_ENDL; + } + + for (status_list_t::iterator iter = mOutgoingHosts.begin(); + iter != mOutgoingHosts.end(); ++iter) + { + LL_INFOS("Xfer") << "LLXfer host " << (*iter)->mHost.getIPandPort() + << " has " << (*iter)->mNumActive + << " active, " << (*iter)->mNumPending + << " pending" + << " in frame " << (S32) LLFrameTimer::getFrameCount() + << LL_ENDL; + } +#endif // LL_XFER_DIAGNOISTIC_LOGGING + } /////////////////////////////////////////////////////////// @@ -196,27 +223,28 @@ void LLXferManager::printHostStatus() LLHostStatus *host_statusp = NULL; if (!mOutgoingHosts.empty()) { - LL_INFOS() << "Outgoing Xfers:" << LL_ENDL; + LL_INFOS("Xfer") << "Outgoing Xfers:" << LL_ENDL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { host_statusp = *iter; - LL_INFOS() << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; + LL_INFOS("Xfer") << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; } } } /////////////////////////////////////////////////////////// -LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) +LLXfer * LLXferManager::findXferByID(U64 id, xfer_list_t & xfer_list) { - LLXfer *xferp; - for (xferp = list_head; xferp; xferp = xferp->mNext) + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - if (xferp->mID == id) + if ((*iter)->mID == id) { - return(xferp); + return(*iter); } } return(NULL); @@ -225,29 +253,34 @@ LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) /////////////////////////////////////////////////////////// -void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) +// WARNING: this invalidates iterators from xfer_list +void LLXferManager::removeXfer(LLXfer *delp, xfer_list_t & xfer_list) { - // This function assumes that delp will only occur in the list - // zero or one times. if (delp) - { - if (*list_head == delp) + { + std::string direction = "send"; + if (&xfer_list == &mReceiveList) { - *list_head = delp->mNext; - delete (delp); + direction = "receive"; } - else + + // This assumes that delp will occur in the list once at most + // Find the pointer in the list + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - LLXfer *xferp = *list_head; - while (xferp->mNext) + if ((*iter) == delp) { - if (xferp->mNext == delp) - { - xferp->mNext = delp->mNext; - delete (delp); - break; - } - xferp = xferp->mNext; + LL_DEBUGS("Xfer") << "Deleting xfer to host " << (*iter)->mRemoteHost + << " of " << (*iter)->mXferSize << " bytes" + << ", status " << (S32)((*iter)->mStatus) + << " from the " << direction << " list" + << LL_ENDL; + + xfer_list.erase(iter); + delete (delp); + break; } } } @@ -255,24 +288,7 @@ void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) /////////////////////////////////////////////////////////// -U32 LLXferManager::numActiveListEntries(LLXfer *list_head) -{ - U32 num_entries = 0; - - while (list_head) - { - if (list_head->mStatus == e_LL_XFER_IN_PROGRESS) - { - num_entries++; - } - list_head = list_head->mNext; - } - return(num_entries); -} - -/////////////////////////////////////////////////////////// - -S32 LLXferManager::numPendingXfers(const LLHost &host) +LLHostStatus * LLXferManager::findHostStatus(const LLHost &host) { LLHostStatus *host_statusp = NULL; @@ -282,26 +298,32 @@ S32 LLXferManager::numPendingXfers(const LLHost &host) host_statusp = *iter; if (host_statusp->mHost == host) { - return (host_statusp->mNumPending); + return (host_statusp); } } return 0; } +/////////////////////////////////////////////////////////// + +S32 LLXferManager::numPendingXfers(const LLHost &host) +{ + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) + { + return host_statusp->mNumPending; + } + return 0; +} + /////////////////////////////////////////////////////////// S32 LLXferManager::numActiveXfers(const LLHost &host) { - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - return (host_statusp->mNumActive); - } + return host_statusp->mNumActive; } return 0; } @@ -372,36 +394,7 @@ BOOL LLXferManager::isLastPacket(S32 packet_num) /////////////////////////////////////////////////////////// -U64 LLXferManager::registerXfer(const void *datap, const S32 length) -{ - LLXfer *xferp; - U64 xfer_id = getNextID(); - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mSendList; - mSendList = xferp; - - xfer_id = ((LLXfer_Mem *)xferp)->registerXfer(xfer_id, datap,length); - - if (!xfer_id) - { - removeXfer(xferp,&mSendList); - } - } - else - { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; - xfer_id = 0; - } - - return(xfer_id); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::requestFile(const std::string& local_filename, +U64 LLXferManager::requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -411,28 +404,34 @@ void LLXferManager::requestFile(const std::string& local_filename, BOOL is_priority, BOOL use_big_packets) { - LLXfer *xferp; + LLXfer_File* file_xfer_p = NULL; - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) + // First check to see if it's already requested + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (((LLXfer_File*)xferp)->matchesRemoteFilename(remote_filename, remote_path)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - + if ((*iter)->getXferTypeTag() == LLXfer::XFER_FILE) { - // cout << "requested a xfer already in progress" << endl; - return; + file_xfer_p = (LLXfer_File*)(*iter); + if (file_xfer_p->matchesLocalFilename(local_filename) + && file_xfer_p->matchesRemoteFilename(remote_filename, remote_path) + && (remote_host == file_xfer_p->mRemoteHost) + && (callback == file_xfer_p->mCallback) + && (user_data == file_xfer_p->mCallbackDataHandle)) + { + // Already have the request (already in progress) + return (*iter)->mID; + } } } + U64 xfer_id = 0; + S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1; - xferp = (LLXfer *) new LLXfer_File(chunk_size); - if (xferp) + file_xfer_p = new LLXfer_File(chunk_size); + if (file_xfer_p) { - addToList(xferp, mReceiveList, is_priority); + addToList(file_xfer_p, mReceiveList, is_priority); // Remove any file by the same name that happens to be lying // around. @@ -441,10 +440,11 @@ void LLXferManager::requestFile(const std::string& local_filename, if(delete_remote_on_completion && (remote_filename.substr(remote_filename.length()-4) == ".tmp")) { - LLFile::remove(local_filename); + LLFile::remove(local_filename, ENOENT); } - ((LLXfer_File *)xferp)->initializeRequest( - getNextID(), + xfer_id = getNextID(); + file_xfer_p->initializeRequest( + xfer_id, local_filename, remote_filename, remote_path, @@ -455,36 +455,9 @@ void LLXferManager::requestFile(const std::string& local_filename, } else { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; - } -} - -void LLXferManager::requestFile(const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*,S32,void**,S32,LLExtStat), - void** user_data, - BOOL is_priority) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_Mem *)xferp)->initializeRequest(getNextID(), - remote_filename, - remote_path, - remote_host, - delete_remote_on_completion, - callback, user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } + return xfer_id; } void LLXferManager::requestVFile(const LLUUID& local_id, @@ -495,28 +468,46 @@ void LLXferManager::requestVFile(const LLUUID& local_id, void** user_data, BOOL is_priority) { - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_VFILE - && (((LLXfer_VFile*)xferp)->matchesLocalFile(local_id, type)) - && (((LLXfer_VFile*)xferp)->matchesRemoteFile(remote_id, type)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) + LLXfer_VFile * xfer_p = NULL; + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) + { // Find any matching existing requests + if ((*iter)->getXferTypeTag() == LLXfer::XFER_VFILE) { - // cout << "requested a xfer already in progress" << endl; - return; + xfer_p = (LLXfer_VFile*) (*iter); + if (xfer_p->matchesLocalFile(local_id, type) + && xfer_p->matchesRemoteFile(remote_id, type) + && (remote_host == xfer_p->mRemoteHost) + && (callback == xfer_p->mCallback) + && (user_data == xfer_p->mCallbackDataHandle)) + + { // Have match, don't add a duplicate + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Dropping duplicate xfer request for " << remote_id + << " on " << remote_host.getIPandPort() + << " local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + return; + } } } - xferp = (LLXfer *) new LLXfer_VFile(); - if (xferp) + xfer_p = new LLXfer_VFile(); + if (xfer_p) { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_VFile *)xferp)->initializeRequest(getNextID(), + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Starting file xfer for " << remote_id + << " type " << LLAssetType::lookupHumanReadable(type) + << " from " << xfer_p->mRemoteHost.getIPandPort() + << ", local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + addToList(xfer_p, mReceiveList, is_priority); + ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(), vfs, local_id, remote_id, @@ -528,78 +519,18 @@ void LLXferManager::requestVFile(const LLUUID& local_id, } else { - LL_ERRS() << "Xfer allocation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } } -/* -void LLXferManager::requestXfer( - const std::string& local_filename, - BOOL delete_remote_on_completion, - U64 xfer_id, - const LLHost &remote_host, - void (*callback)(void **,S32), - void **user_data) -{ - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (xfer_id == xferp->mID) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - - { - // cout << "requested a xfer already in progress" << endl; - return; - } - } - - xferp = (LLXfer *) new LLXfer_File(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_File *)xferp)->initializeRequest(xfer_id,local_filename,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; - } -} - -void LLXferManager::requestXfer(U64 xfer_id, const LLHost &remote_host, BOOL delete_remote_on_completion, void (*callback)(void *,S32,void **,S32),void **user_data) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_Mem *)xferp)->initializeRequest(xfer_id,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; - } -} -*/ /////////////////////////////////////////////////////////// void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user_data*/) { // there's sometimes an extra 4 bytes added to an xfer payload const S32 BUF_SIZE = LL_XFER_LARGE_PAYLOAD + 4; - char fdata_buf[LL_XFER_LARGE_PAYLOAD + 4]; /* Flawfinder : ignore */ + char fdata_buf[BUF_SIZE]; /* Flawfinder : ignore */ S32 fdata_size; U64 id; S32 packetnum; @@ -609,14 +540,24 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetnum); fdata_size = mesgsys->getSizeFast(_PREHASH_DataPacket,_PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, 0, 0, BUF_SIZE); - - xferp = findXfer(id, mReceiveList); - - if (!xferp) + if (fdata_size < 0 || + fdata_size > BUF_SIZE) { char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_WARNS() << "received xfer data from " << mesgsys->getSender() + LL_WARNS("Xfer") << "Received invalid xfer data size of " << fdata_size + << " in packet number " << packetnum + << " from " << mesgsys->getSender() + << " for xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) + << LL_ENDL; + return; + } + mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, fdata_size, 0, BUF_SIZE); + + xferp = findXferByID(id, mReceiveList); + if (!xferp) + { + char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ + LL_WARNS("Xfer") << "received xfer data from " << mesgsys->getSender() << " for non-existent xfer id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL; return; @@ -629,11 +570,11 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user // confirm it if it was a resend of the last one, since the confirmation might have gotten dropped if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1)) { - LL_INFOS() << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); + LL_INFOS("Xfer") << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); } else { - LL_INFOS() << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; + LL_INFOS("Xfer") << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; } return; } @@ -658,7 +599,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (result == LL_ERR_CANNOT_OPEN_FILE) { xferp->abort(LL_ERR_CANNOT_OPEN_FILE); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); return; } @@ -683,7 +624,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (isLastPacket(packetnum)) { xferp->processEOF(); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); } } @@ -692,7 +633,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host) { -#if LL_XFER_PROGRESS_MESSAGES +#ifdef LL_XFER_PROGRESS_MESSAGES if (!(packetnum % 50)) { cout << "confirming xfer packet #" << packetnum << endl; @@ -703,6 +644,7 @@ void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 pac mesgsys->addU64Fast(_PREHASH_ID, id); mesgsys->addU32Fast(_PREHASH_Packet, packetnum); + // Ignore a circuit failure here, we'll catch it with another message mesgsys->sendMessage(remote_host); } @@ -741,6 +683,28 @@ bool LLXferManager::validateFileForTransfer(const std::string& filename) return find_and_remove(mExpectedTransfers, filename); } +/* Present in fireengine, not used by viewer +void LLXferManager::expectVFileForRequest(const std::string& filename) +{ + mExpectedVFileRequests.insert(filename); +} + +bool LLXferManager::validateVFileForRequest(const std::string& filename) +{ + return find_and_remove(mExpectedVFileRequests, filename); +} + +void LLXferManager::expectVFileForTransfer(const std::string& filename) +{ + mExpectedVFileTransfers.insert(filename); +} + +bool LLXferManager::validateVFileForTransfer(const std::string& filename) +{ + return find_and_remove(mExpectedVFileTransfers, filename); +} +*/ + static bool remove_prefix(std::string& filename, const std::string& prefix) { if (std::equal(prefix.begin(), prefix.end(), filename.begin())) @@ -802,7 +766,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS() << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) + LL_INFOS("Xfer") << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " << mesgsys->getSender() << LL_ENDL; mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); @@ -820,36 +784,45 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user LLXfer *xferp; if (uuid != LLUUID::null) - { + { // Request for an asset - use a VFS file if(NULL == LLAssetType::lookup(type)) { - LL_WARNS() << "Invalid type for xfer request: " << uuid << ":" + LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":" << type_s16 << " to " << mesgsys->getSender() << LL_ENDL; return; } - LL_INFOS() << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; - if (! mVFS) { - LL_WARNS() << "Attempt to send VFile w/o available VFS" << LL_ENDL; + LL_WARNS("Xfer") << "Attempt to send VFile w/o available VFS" << LL_ENDL; return; } + /* Present in fireengine, not used by viewer + if (!validateVFileForTransfer(uuid.asString())) + { + // it is up to the app sending the file to mark it for expected + // transfer before the request arrives or it will be dropped + LL_WARNS("Xfer") << "SECURITY: Unapproved VFile '" << uuid << "'" << LL_ENDL; + return; + } + */ + + LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; + xferp = (LLXfer *)new LLXfer_VFile(mVFS, uuid, type); if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else if (!local_filename.empty()) - { + { // Was given a file name to send // See DEV-21775 for detailed security issues if (local_path == LL_PATH_NONE) @@ -868,7 +841,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_NONE: if(!validateFileForTransfer(local_filename)) { - LL_WARNS() << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; return; } break; @@ -876,13 +849,13 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_CACHE: if(!verify_cache_filename(local_filename)) { - LL_WARNS() << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; return; } break; default: - LL_WARNS() << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; + LL_WARNS("Xfer") << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; return; } @@ -897,7 +870,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user { expanded_filename = local_filename; } - LL_INFOS() << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; + LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; BOOL delete_local_on_completion = FALSE; mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion); @@ -907,23 +880,22 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - LL_ERRS() << "Xfer allcoation error" << LL_ENDL; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else - { + { // no uuid or filename - use the ID sent char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - LL_INFOS() << "starting memory transfer: " + LL_INFOS("Xfer") << "starting memory transfer: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " << mesgsys->getSender() << LL_ENDL; - xferp = findXfer(id, mSendList); + xferp = findXferByID(id, mSendList); if (xferp) { @@ -931,7 +903,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user } else { - LL_INFOS() << "Warning: " << U64_BUF << " not found." << LL_ENDL; + LL_INFOS("Xfer") << "Warning: xfer ID " << U64_BUF << " not found." << LL_ENDL; result = LL_ERR_FILE_NOT_FOUND; } } @@ -941,11 +913,11 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { xferp->abort(result); - removeXfer(xferp,&mSendList); + removeXfer(xferp, mSendList); } else // can happen with a memory transfer not found { - LL_INFOS() << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; + LL_INFOS("Xfer") << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; mesgsys->newMessageFast(_PREHASH_AbortXfer); mesgsys->nextBlockFast(_PREHASH_XferID); @@ -955,24 +927,86 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->sendMessage(mesgsys->getSender()); } } - else if(xferp && (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit)) + else if(xferp) { - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); -// LL_INFOS() << "***STARTING XFER IMMEDIATELY***" << LL_ENDL; - } - else - { - if(xferp) + // Figure out how many transfers the host has requested + LLHostStatus *host_statusp = findHostStatus(xferp->mRemoteHost); + if (host_statusp) { - LL_INFOS() << " queueing xfer request, " << numPendingXfers(xferp->mRemoteHost) << " ahead of this one" << LL_ENDL; + if (host_statusp->mNumActive < mMaxOutgoingXfersPerCircuit) + { // Not many transfers in progress already, so start immediately + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + LL_DEBUGS("Xfer") << "Starting xfer ID " << U64_to_str(id) << " immediately" << LL_ENDL; + } + else if (mHardLimitOutgoingXfersPerCircuit == 0 || + (host_statusp->mNumActive + host_statusp->mNumPending) < mHardLimitOutgoingXfersPerCircuit) + { // Must close the file handle and wait for earlier ones to complete + LL_INFOS("Xfer") << " queueing xfer request id " << U64_to_str(id) << ", " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + xferp->closeFileHandle(); // Close the file handle until we're ready to send again + } + else if (mHardLimitOutgoingXfersPerCircuit > 0) + { // Way too many requested ... it's time to stop being nice and kill the circuit + xferp->closeFileHandle(); // Close the file handle in any case + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(xferp->mRemoteHost); + if (cdp) + { + if (cdp->getTrusted()) + { // Trusted internal circuit - don't kill it + LL_WARNS("Xfer") << "Trusted circuit to " << xferp->mRemoteHost << " has too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + } + else + { // Untrusted circuit - time to stop messing around and kill it + LL_WARNS("Xfer") << "Killing circuit to " << xferp->mRemoteHost << " for having too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } + else + { // WTF? Why can't we find a circuit? Try to kill it off + LL_WARNS("Xfer") << "Backlog with circuit to " << xferp->mRemoteHost << " with too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << " but no LLCircuitData found???" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } } else { - LL_WARNS() << "LLXferManager::processFileRequest() - no xfer found!" - << LL_ENDL; + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no LLHostStatus found for id " << U64_to_str(id) + << " host " << xferp->mRemoteHost << LL_ENDL; } } + else + { + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no xfer found for id " << U64_to_str(id) << LL_ENDL; + } +} + +/////////////////////////////////////////////////////////// + +// Return true if host is in a transfer-flood sitation. Same check for both internal and external hosts +bool LLXferManager::isHostFlooded(const LLHost & host) +{ + bool flooded = false; + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) + { + flooded = (mHardLimitOutgoingXfersPerCircuit > 0 && + (host_statusp->mNumActive + host_statusp->mNumPending) >= (S32)(mHardLimitOutgoingXfersPerCircuit * 0.8f)); + } + + return flooded; } @@ -986,7 +1020,7 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetNum); - LLXfer* xferp = findXfer(id, mSendList); + LLXfer* xferp = findXferByID(id, mSendList); if (xferp) { // cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl; @@ -997,91 +1031,105 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use } else { - removeXfer(xferp, &mSendList); + removeXfer(xferp, mSendList); } } } /////////////////////////////////////////////////////////// -void LLXferManager::retransmitUnackedPackets () +// Called from LLMessageSystem::processAcks() +void LLXferManager::retransmitUnackedPackets() { LLXfer *xferp; - LLXfer *delp; - xferp = mReceiveList; - while(xferp) + + xfer_list_t::iterator iter = mReceiveList.begin(); + while (iter != mReceiveList.end()) { + xferp = (*iter); if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) { // if the circuit dies, abort if (! gMessageSystem->mCircuitInfo.isCircuitAlive( xferp->mRemoteHost )) { - LL_INFOS() << "Xfer found in progress on dead circuit, aborting" << LL_ENDL; + LL_WARNS("Xfer") << "Xfer found in progress on dead circuit, aborting transfer to " + << xferp->mRemoteHost.getIPandPort() + << LL_ENDL; xferp->mCallbackResult = LL_ERR_CIRCUIT_GONE; xferp->processEOF(); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mReceiveList); + + iter = mReceiveList.erase(iter); // iter is set to next one after the deletion point + delete (xferp); continue; } } - xferp = xferp->mNext; + ++iter; } - xferp = mSendList; + // Re-build mOutgoingHosts data updateHostStatus(); + F32 et; - while (xferp) + iter = mSendList.begin(); + while (iter != mSendList.end()) { + xferp = (*iter); if (xferp->mWaitingForACK && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_PACKET_TIMEOUT)) { if (xferp->mRetries > LL_PACKET_RETRY_LIMIT) { - LL_INFOS() << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; + LL_INFOS("Xfer") << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else { - LL_INFOS() << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; + LL_INFOS("Xfer") << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; xferp->resendLastPacket(); - xferp = xferp->mNext; } } else if ((xferp->mStatus == e_LL_XFER_REGISTERED) && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_XFER_REGISTRATION_TIMEOUT)) { - LL_INFOS() << "registered xfer never requested, xfer dropped" << LL_ENDL; + LL_INFOS("Xfer") << "registered xfer never requested, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_ABORTED) { - LL_WARNS() << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + LL_WARNS("Xfer") << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_PENDING) { -// LL_INFOS() << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; +// LL_INFOS("Xfer") << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; if (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit) { -// LL_INFOS() << "bumping pending xfer to active" << LL_ENDL; - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); - } - xferp = xferp->mNext; + if (xferp->reopenFileHandle()) + { + LL_WARNS("Xfer") << "Error re-opening file handle for xfer ID " << U64_to_str(xferp->mID) + << " to host " << xferp->mRemoteHost << LL_ENDL; + xferp->abort(LL_ERR_CANNOT_OPEN_FILE); + iter = mSendList.erase(iter); + delete xferp; + continue; + } + else + { // No error re-opening the file, send the first packet + LL_DEBUGS("Xfer") << "Moving pending xfer ID " << U64_to_str(xferp->mID) << " to active" << LL_ENDL; + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + } + } } - else - { - xferp = xferp->mNext; - } - } + ++iter; + } // end while() loop // // HACK - if we're using xfer confirm throttling, throttle our xfer confirms here @@ -1094,15 +1142,38 @@ void LLXferManager::retransmitUnackedPackets () { break; } - //LL_INFOS() << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; + //LL_INFOS("Xfer") << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; LLXferAckInfo ack_info = mXferAckQueue.front(); mXferAckQueue.pop_front(); - //LL_INFOS() << "Sending confirm packet" << LL_ENDL; + //LL_INFOS("Xfer") << "Sending confirm packet" << LL_ENDL; sendConfirmPacket(gMessageSystem, ack_info.mID, ack_info.mPacketNum, ack_info.mRemoteHost); mAckThrottle.throttleOverflow(1000.f*8.f); // Assume 1000 bytes/packet } } +/////////////////////////////////////////////////////////// + +void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) +{ + LLXfer * xferp = findXferByID(xfer_id, mReceiveList); + if (xferp) + { + if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + { + // causes processAbort(); + xferp->abort(result_code); + } + else + { + xferp->mCallbackResult = result_code; + xferp->processEOF(); //should notify requester + removeXfer(xferp, mReceiveList); + } + // Since already removed or marked as aborted no need + // to wait for processAbort() to start new download + startPendingDownloads(); + } +} /////////////////////////////////////////////////////////// @@ -1115,12 +1186,12 @@ void LLXferManager::processAbort (LLMessageSystem *mesgsys, void ** /*user_data* mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Result, result_code); - xferp = findXfer(id, mReceiveList); + xferp = findXferByID(id, mReceiveList); if (xferp) { xferp->mCallbackResult = result_code; xferp->processEOF(); - removeXfer(xferp, &mReceiveList); + removeXfer(xferp, mReceiveList); startPendingDownloads(); } } @@ -1136,27 +1207,29 @@ void LLXferManager::startPendingDownloads() // requests get pushed toward the back. Thus, if we didn't do a // stateful iteration, it would be possible for old requests to // never start. - LLXfer* xferp = mReceiveList; + LLXfer* xferp; std::list pending_downloads; S32 download_count = 0; S32 pending_count = 0; - while(xferp) + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); + ++iter) { + xferp = (*iter); if(xferp->mStatus == e_LL_XFER_PENDING) - { + { // Count and accumulate pending downloads ++pending_count; pending_downloads.push_front(xferp); } else if(xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { + { // Count downloads in progress ++download_count; } - xferp = xferp->mNext; } S32 start_count = mMaxIncomingXfers - download_count; - LL_DEBUGS() << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " + LL_DEBUGS("Xfer") << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " << download_count << " XFER_PENDING: " << pending_count << " startring " << llmin(start_count, pending_count) << LL_ENDL; @@ -1181,29 +1254,15 @@ void LLXferManager::startPendingDownloads() /////////////////////////////////////////////////////////// -void LLXferManager::addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority) +void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority) { if(is_priority) { - xferp->mNext = NULL; - LLXfer* next = head; - if(next) - { - while(next->mNext) - { - next = next->mNext; - } - next->mNext = xferp; - } - else - { - head = xferp; - } + xfer_list.push_back(xferp); } else { - xferp->mNext = head; - head = xferp; + xfer_list.push_front(xferp); } } diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index b3d110e7a..45ae2ffdd 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -77,6 +77,7 @@ class LLXferManager protected: S32 mMaxOutgoingXfersPerCircuit; + S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection S32 mMaxIncomingXfers; BOOL mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth @@ -92,19 +93,22 @@ class LLXferManager HIGH_PRIORITY = TRUE, }; - LLXfer *mSendList; - LLXfer *mReceiveList; + // Linked FIFO list, add to the front and pull from back + typedef std::deque xfer_list_t; + xfer_list_t mSendList; + xfer_list_t mReceiveList; typedef std::list status_list_t; status_list_t mOutgoingHosts; - private: protected: // implementation methods virtual void startPendingDownloads(); - virtual void addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority); + virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority); std::multiset mExpectedTransfers; // files that are authorized to transfer out std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of + std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out + std::multiset mExpectedVFileRequests; // files that are authorized to be downloaded on top of public: LLXferManager(LLVFS *vfs); @@ -117,14 +121,17 @@ class LLXferManager void setAckThrottleBPS(const F32 bps); // list management routines - virtual LLXfer *findXfer(U64 id, LLXfer *list_head); - virtual void removeXfer (LLXfer *delp, LLXfer **list_head); - virtual U32 numActiveListEntries(LLXfer *list_head); + virtual LLXfer *findXferByID(U64 id, xfer_list_t & xfer_list); + virtual void removeXfer (LLXfer *delp, xfer_list_t & xfer_list); + + LLHostStatus * findHostStatus(const LLHost &host); virtual S32 numActiveXfers(const LLHost &host); virtual S32 numPendingXfers(const LLHost &host); + virtual void changeNumActiveXfers(const LLHost &host, S32 delta); virtual void setMaxOutgoingXfersPerCircuit (S32 max_num); + virtual void setHardLimitOutgoingXfersPerCircuit(S32 max_num); virtual void setMaxIncomingXfers(S32 max_num); virtual void updateHostStatus(); virtual void printHostStatus(); @@ -136,11 +143,9 @@ class LLXferManager virtual S32 decodePacketNum(S32 packet_num); virtual BOOL isLastPacket(S32 packet_num); - virtual U64 registerXfer(const void *datap, const S32 length); - // file requesting routines // .. to file - virtual void requestFile(const std::string& local_filename, + virtual U64 requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -148,7 +153,7 @@ class LLXferManager void (*callback)(void**,S32,LLExtStat), void** user_data, BOOL is_priority = FALSE, BOOL use_big_packets = FALSE); - + /* // .. to memory virtual void requestFile(const std::string& remote_filename, ELLPath remote_path, @@ -157,7 +162,7 @@ class LLXferManager void (*callback)(void*, S32, void**, S32, LLExtStat), void** user_data, BOOL is_priority = FALSE); - + */ // vfile requesting // .. to vfile virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id, @@ -180,18 +185,15 @@ class LLXferManager virtual void expectFileForRequest(const std::string& filename); virtual bool validateFileForRequest(const std::string& filename); -/* -// xfer request (may be memory or file) -// .. to file - virtual void requestXfer(const char *local_filename, U64 xfer_id, - BOOL delete_remote_on_completion, - const LLHost &remote_host, void (*callback)(void **,S32),void **user_data); -// .. to memory - virtual void requestXfer(U64 xfer_id, - const LLHost &remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void *, S32, void **, S32),void **user_data); -*/ + /** + Same idea but for VFiles, kept separate to avoid namespace overlap + */ + /* Present in fireengine, not used by viewer + virtual void expectVFileForTransfer(const std::string& filename); + virtual bool validateVFileForTransfer(const std::string& filename); + virtual void expectVFileForRequest(const std::string& filename); + virtual bool validateVFileForRequest(const std::string& filename); + */ virtual void processReceiveData (LLMessageSystem *mesgsys, void **user_data); virtual void sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host); @@ -202,7 +204,10 @@ class LLXferManager virtual void retransmitUnackedPackets (); // error handling + void abortRequestById(U64 xfer_id, S32 result_code); virtual void processAbort (LLMessageSystem *mesgsys, void **user_data); + + virtual bool isHostFlooded(const LLHost & host); }; extern LLXferManager* gXferManager; diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 7999d2b0f..a67a95f69 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -505,7 +505,7 @@ protected: U32 mMiscFlags; // home for misc bools static LLVolumeMgr* sVolumeManager; - +public: enum { NO_LOD = -1 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 261e3f67f..d745fd1bf 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -482,6 +482,7 @@ set(viewer_SOURCE_FILES lltoolselectrect.cpp lltoolview.cpp lltracker.cpp + lluiavatar.cpp lluploaddialog.cpp lluploadfloaterobservers.cpp llurl.cpp @@ -1020,6 +1021,7 @@ set(viewer_HEADER_FILES lltracker.h lltranslate.h lluiconstants.h + lluiavatar.h lluploaddialog.h lluploadfloaterobservers.h llurl.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 558c9bcf6..64a51ac3a 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4481,8 +4481,7 @@ void LLAgent::stopCurrentAnimations() // re-assert at least the default standing animation, because // viewers get confused by avs with no associated anims. - sendAnimationRequest(ANIM_AGENT_STAND, - ANIM_REQUEST_START); + sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); } } diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 9cb42959d..7f55b00c9 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -863,8 +863,8 @@ void LLWearableHoldingPattern::onAllComplete() << mResolved << " wearable items " << LL_ENDL; LLAppearanceMgr::instance().updateAgentWearables(this); -// // Restore attachment pos overrides for the attachments that -// // are remaining in the outfit. + // Restore attachment pos overrides for the attachments that + // are remaining in the outfit. // for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); // it != objects_to_retain.end(); // ++it) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f83a3bae5..1950f5194 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -255,12 +255,12 @@ LLPumpIO* gServicePump = NULL; BOOL gPacificDaylightTime = FALSE; -U64 gFrameTime = 0; -F32 gFrameTimeSeconds = 0.f; -F32 gFrameIntervalSeconds = 0.f; +U64MicrosecondsImplicit gFrameTime = 0; +F32SecondsImplicit gFrameTimeSeconds = 0.f; +F32SecondsImplicit gFrameIntervalSeconds = 0.f; F32 gFPSClamped = 10.f; // Pretend we start at target rate. F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds U32 gFrameStalls = 0; const F64 FRAME_STALL_THRESHOLD = 1.0; @@ -1341,7 +1341,8 @@ bool LLAppViewer::mainLoop() || (!gFocusMgr.getAppHasFocus() && !AIFilePicker::activePicker) ) { // Sleep if we're not rendering, or the window is minimized. - S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000); + static LLCachedControl s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000); // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads // of equal priority on Windows if (milliseconds_to_sleep > 0) @@ -1368,7 +1369,7 @@ bool LLAppViewer::mainLoop() ms_sleep(500); } - const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds, 0.005); // 50ms/second, no more than 5ms/frame + const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds.value(), 0.005); // 50ms/second, no more than 5ms/frame idleTimer.reset(); while(1) { diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 777f06207..e646aa2b5 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -271,6 +271,7 @@ public: // consts from viewer.h const S32 AGENT_UPDATES_PER_SECOND = 10; +const S32 AGENT_FORCE_UPDATES_PER_SECOND = 1; // Globals with external linkage. From viewer.h // *NOTE:Mani - These will be removed as the Viewer App Cleanup project continues. @@ -303,13 +304,13 @@ extern LLPumpIO* gServicePump; // Is the Pacific time zone (aka server time zone) // currently in daylight savings time? extern BOOL gPacificDaylightTime; - -extern U64 gFrameTime; // The timestamp of the most-recently-processed frame -extern F32 gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... -extern F32 gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds +extern U64MicrosecondsImplicit gStartTime; +extern U64MicrosecondsImplicit gFrameTime; // The timestamp of the most-recently-processed frame +extern F32SecondsImplicit gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... +extern F32SecondsImplicit gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds extern F32 gFPSClamped; // Frames per second, smoothed, weighted toward last frame extern F32 gFrameDTClamped; -extern U64 gStartTime; + extern U32 gFrameStalls; extern LLTimer gRenderStartTime; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 360c1d977..1b107c406 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -512,7 +512,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled) if (isState(ACTIVE) && !isState(ACTIVE_CHILD) && !mVObjp->isAttachment() && - !mVObjp->isFlexible()) + !mVObjp->isFlexible() && + !mVObjp->isAnimatedObject()) { clearState(ACTIVE | ANIMATED_CHILD); @@ -939,9 +940,7 @@ void LLDrawable::updateSpatialExtents() if (mVObjp) { const LLVector4a* exts = getSpatialExtents(); - LLVector4a extents[2]; - extents[0] = exts[0]; - extents[1] = exts[1]; + LLVector4a extents[2] = { exts[0], exts[1] }; mVObjp->updateSpatialExtents(extents[0], extents[1]); setSpatialExtents(extents[0], extents[1]); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 8843dad39..c3afcdbd6 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1510,13 +1510,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; @@ -1729,7 +1723,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) LLVOVolume* vobj = drawable->getVOVolume(); - if (!vobj) + if (!vobj || vobj->isNoLOD()) { continue; } @@ -1742,13 +1736,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 52727dd6c..9112aa9fd 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -44,7 +44,7 @@ #include "llperlin.h" extern bool gShiftFrame; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; extern LLPipeline gPipeline; LLSurfacePatch::LLSurfacePatch() diff --git a/indra/newview/lluiavatar.cpp b/indra/newview/lluiavatar.cpp new file mode 100644 index 000000000..e4e266c92 --- /dev/null +++ b/indra/newview/lluiavatar.cpp @@ -0,0 +1,61 @@ +/** + * @file lluiavatar.cpp + * @brief Implementation for special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lluiavatar.h" +#include "llagent.h" // Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" + +LLUIAvatar::LLUIAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp) +{ + mIsDummy = TRUE; + mIsUIAvatar = true; +} + +// virtual +LLUIAvatar::~LLUIAvatar() +{ +} + +// virtual +void LLUIAvatar::initInstance() +{ + LLVOAvatar::initInstance(); + + createDrawable( &gPipeline ); + setPositionAgent(LLVector3::zero); + slamPosition(); + updateJointLODs(); + updateGeometry(mDrawable); + + mInitFlags |= 1<<3; +} diff --git a/indra/newview/lluiavatar.h b/indra/newview/lluiavatar.h new file mode 100644 index 000000000..bcdffedef --- /dev/null +++ b/indra/newview/lluiavatar.h @@ -0,0 +1,44 @@ +/** + * @file lluiavatar.h + * @brief Special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UIAVATAR_H +#define LL_UIAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLUIAvatar: + public LLVOAvatar +{ + LOG_CLASS(LLUIAvatar); + +public: + LLUIAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual void initInstance(); // Called after construction to initialize the class. + virtual ~LLUIAvatar(); +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 742d5f7d6..80aaac6cb 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6053,24 +6053,33 @@ class LLAvatarAddFriend : public view_listener_t class LLAvatarResetSkeleton: public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLVOAvatar* avatar = NULL; + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + avatar = obj->getAvatar(); + } if(avatar) - { - avatar->resetSkeleton(false); - } - return true; - } + { + avatar->resetSkeleton(false); + } + return true; + } }; - class LLAvatarResetSkeletonAndAnimations : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - if (avatar) + LLVOAvatar* avatar = NULL; + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj) + { + avatar = obj->getAvatar(); + } + if(avatar) { avatar->resetSkeleton(true); } @@ -6078,6 +6087,19 @@ class LLAvatarResetSkeletonAndAnimations : public view_listener_t } }; +class LLAvatarEnableResetSkeleton: public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (obj && obj->getAvatar()) + { + return true; + } + return false; + } +}; + bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) { S32 option = LLNotification::getSelectedOption(notification, response); @@ -6869,9 +6891,10 @@ class LLAttachmentEnableDrop : public view_listener_t LLViewerJointAttachment* attachment = NULL; LLInventoryItem* item = NULL; - if (object) + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState()); + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); if (attachment) @@ -9451,7 +9474,8 @@ void initialize_menus() addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); addMenu(new LLObjectEnableMute(), "Avatar.EnableMute"); addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); - addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeletonAndAnimations"); + addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); + addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); addMenu(new LLAvatarCopyUUID(), "Avatar.CopyUUID"); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 838364bfb..9892b7987 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -107,7 +107,7 @@ //#define DEBUG_UPDATE_TYPE BOOL LLViewerObject::sVelocityInterpolate = TRUE; -BOOL LLViewerObject::sPingInterpolate = TRUE; +BOOL LLViewerObject::sPingInterpolate = TRUE; U32 LLViewerObject::sNumZombieObjects = 0; S32 LLViewerObject::sNumObjects = 0; @@ -123,6 +123,17 @@ F64Seconds LLViewerObject::sMaxUpdateInterpolationTime(3.0); // For motion inte F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motion interpolation: after Y seconds with no updates, taper off motion prediction +// The maximum size of an object extra parameters binary (packed) block +#define MAX_OBJECT_PARAMS_SIZE 1024 + +// At 45 Hz collisions seem stable and objects seem +// to settle down at a reasonable rate. +// JC 3/18/2003 + +const F32 PHYSICS_TIMESTEP = 1.f / 45.f; +const U32 MAX_INV_FILE_READ_FAILS = 25; +const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16; + static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); // static @@ -224,6 +235,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mRenderMedia(FALSE), mBestUpdatePrecision(0), mText(), + + mHudTextColor(LLColor4::white), mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), @@ -234,9 +247,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), - mRegionp( regionp ), - mInventoryPending(FALSE), + mInvRequestState(INVENTORY_REQUEST_STOPPED), + mInvRequestXFerId(0), mInventoryDirty(FALSE), + mRegionp(regionp), mDead(FALSE), mOrphaned(FALSE), mUserSelected(FALSE), @@ -247,7 +261,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mRotTime(0.f), mAngularVelocityRot(), mPreviousRotation(), - mState(0), + mAttachmentState(0), mMedia(NULL), mClickAction(0), mObjectCost(0), @@ -320,7 +334,7 @@ LLViewerObject::~LLViewerObject() for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; mNameValuePairs.clear(); - + delete[] mData; mData = NULL; @@ -338,18 +352,18 @@ void LLViewerObject::deleteTEImages() { delete[] mTEImages; mTEImages = NULL; - + if (mTENormalMaps != NULL) { delete[] mTENormalMaps; mTENormalMaps = NULL; } - + if (mTESpecularMaps != NULL) { delete[] mTESpecularMaps; mTESpecularMaps = NULL; - } + } } void LLViewerObject::markDead() @@ -357,7 +371,7 @@ void LLViewerObject::markDead() if (!mDead) { //LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL; - + // if (isSelected()) { @@ -386,6 +400,10 @@ void LLViewerObject::markDead() // Mark itself as dead mDead = TRUE; + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } gObjectList.cleanupReferences(this); LLViewerObject *childp; @@ -400,7 +418,7 @@ void LLViewerObject::markDead() } else { - // make sure avatar is no longer parented, + // make sure avatar is no longer parented, // so we can properly set it's position childp->setDrawableParent(NULL); ((LLVOAvatar*)childp)->getOffObject(); @@ -475,8 +493,8 @@ void LLViewerObject::dump() const LL_INFOS() << "PositionAgent: " << getPositionAgent() << LL_ENDL; LL_INFOS() << "PositionGlobal: " << getPositionGlobal() << LL_ENDL; LL_INFOS() << "Velocity: " << getVelocity() << LL_ENDL; - if (mDrawable.notNull() && - mDrawable->getNumFaces() && + if (mDrawable.notNull() && + mDrawable->getNumFaces() && mDrawable->getFace(0)) { LLFacePool *poolp = mDrawable->getFace(0)->getPool(); @@ -570,6 +588,37 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) } } +BOOL LLViewerObject::isAnySelected() const +{ + bool any_selected = isSelected(); + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + const LLViewerObject* child = *iter; + any_selected = any_selected || child->isSelected(); + } + return any_selected; +} + +void LLViewerObject::setSelected(BOOL sel) +{ + mUserSelected = sel; + static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); + if(use_new_target_omega) + { + resetRot(); + } + else + { + mRotTime = 0.f; + } + + if (!sel) + { + setAllTESelected(false); + } +} + // This method returns true if the object is over land owned by the // agent. bool LLViewerObject::isReturnable() @@ -578,7 +627,7 @@ bool LLViewerObject::isReturnable() { return false; } - + // [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a // Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us if ( (rlv_handler_t::isEnabled()) && @@ -598,19 +647,19 @@ bool LLViewerObject::isReturnable() } bool result = (mRegionp && mRegionp->objectIsReturnable(getPositionRegion(), boxes)) ? 1 : 0; - + if ( !result ) - { + { //Get list of neighboring regions relative to this vo's region std::vector uniqueRegions; mRegionp->getNeighboringRegions( uniqueRegions ); - + //Build aabb's - for root and all children std::vector returnables; typedef std::vector::iterator RegionIt; RegionIt regionStart = uniqueRegions.begin(); RegionIt regionEnd = uniqueRegions.end(); - + for (; regionStart != regionEnd; ++regionStart ) { LLViewerRegion* pTargetRegion = *regionStart; @@ -620,26 +669,26 @@ bool LLViewerObject::isReturnable() //Add it's children for (child_list_t::iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { - LLViewerObject* pChild = *iter; + LLViewerObject* pChild = *iter; buildReturnablesForChildrenVO( returnables, pChild, pTargetRegion ); } - } - - //TBD#Eventually create a region -> box list map + } + + //TBD#Eventually create a region -> box list map typedef std::vector::iterator ReturnablesIt; ReturnablesIt retCurrentIt = returnables.begin(); ReturnablesIt retEndIt = returnables.end(); - + for ( ; retCurrentIt !=retEndIt; ++retCurrentIt ) { boxes.clear(); LLViewerRegion* pRegion = (*retCurrentIt).pRegion; - boxes.push_back( (*retCurrentIt).box ); + boxes.push_back( (*retCurrentIt).box ); bool retResult = pRegion && pRegion->childrenObjectReturnable( boxes ) && pRegion->canManageEstate(); if ( retResult ) - { + { result = true; break; } @@ -654,9 +703,9 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vectormChildList.begin(); iter != pChild->mChildList.end(); iter++) { @@ -667,20 +716,20 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vector& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion ) { - + LLVector3 targetRegionPos; - targetRegionPos.setVec( pChild->getPositionGlobal() ); - - LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, - pChild->getScale() * 0.5f).getAxisAligned(); - + targetRegionPos.setVec( pChild->getPositionGlobal() ); + + LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, + pChild->getScale() * 0.5f).getAxisAligned(); + LLVector3 edgeA = targetRegionPos + childBBox.getMinLocal(); LLVector3 edgeB = targetRegionPos + childBBox.getMaxLocal(); - + LLVector3d edgeAd, edgeBd; edgeAd.setVec(edgeA); edgeBd.setVec(edgeB); - + //Only add the box when either of the extents are in a neighboring region if ( pTargetRegion->pointInRegionGlobal( edgeAd ) || pTargetRegion->pointInRegionGlobal( edgeBd ) ) { @@ -709,7 +758,7 @@ BOOL LLViewerObject::setParent(LLViewerObject* parent) { if (mParent != parent) { - LLViewerObject* old_parent = (LLViewerObject*)mParent ; + LLViewerObject* old_parent = (LLViewerObject*)mParent ; BOOL ret = LLPrimitive::setParent(parent); if (ret && old_parent && parent) { @@ -730,7 +779,7 @@ void LLViewerObject::addChild(LLViewerObject *childp) return; } } - + if (!isAvatar()) { // propagate selection properties @@ -740,9 +789,18 @@ void LLViewerObject::addChild(LLViewerObject *childp) if (childp->setParent(this)) { mChildList.push_back(childp); + childp->afterReparent(); } } +void LLViewerObject::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ +} + +void LLViewerObject::afterReparent() +{ +} + void LLViewerObject::removeChild(LLViewerObject *childp) { for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) @@ -758,12 +816,12 @@ void LLViewerObject::removeChild(LLViewerObject *childp) if(childp->getParent() == this) { - childp->setParent(NULL); + childp->setParent(NULL); } break; } } - + if (childp->isSelected()) { LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); @@ -850,8 +908,8 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE ; } LLDrawable* old_parent = mDrawable->mParent; - mDrawable->mParent = parentp; - + mDrawable->mParent = parentp; + if (parentp && mDrawable->isActive()) { parentp->makeActive(); @@ -873,7 +931,7 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) mDrawable->movePartition(); }*/ } - + return ret; } @@ -901,7 +959,7 @@ void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) U32 LLViewerObject::checkMediaURL(const std::string &media_url) { - U32 retval = (U32)0x0; + U32 retval = (U32)0x0; if (!mMedia && !media_url.empty()) { retval |= MEDIA_URL_ADDED; @@ -917,23 +975,23 @@ U32 LLViewerObject::checkMediaURL(const std::string &media_url) retval |= MEDIA_URL_REMOVED; delete mMedia; mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. - { - /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && - LLTextureEntry::getVersionFromMediaVersionString(media_url) == - LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) */ - { - // If the media URL is different and WE were not the one who - // changed it, mark dirty. - retval |= MEDIA_URL_UPDATED; - } - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - return retval; + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; } U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, @@ -943,7 +1001,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { U32 retval = 0x0; - + // If region is removed from the list it is also deleted. if (!LLWorld::instance().isRegionListed(mRegionp)) { @@ -952,14 +1010,15 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } // Coordinates of objects on simulators are region-local. - U64 region_handle; - mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + U64 region_handle = 0; + if(mesgsys != NULL) { + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); if(regionp != mRegionp && regionp && mRegionp)//region cross { - //this is the redundant position and region update, but it is necessary in case the viewer misses the following + //this is the redundant position and region update, but it is necessary in case the viewer misses the following //position and region update messages from sim. //this redundant update should not cause any problems. LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); @@ -968,10 +1027,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } else { + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } mRegionp = regionp ; } - } - + } + if (!mRegionp) { U32 x, y; @@ -984,10 +1054,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, F32 time_dilation = 1.f; if(mesgsys != NULL) { - U16 time_dilation16; - mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); - time_dilation = ((F32) time_dilation16) / 65535.f; - mRegionp->setTimeDilation(time_dilation); + U16 time_dilation16; + mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); + time_dilation = ((F32) time_dilation16) / 65535.f; + mRegionp->setTimeDilation(time_dilation); } // this will be used to determine if we've really changed position @@ -1016,6 +1086,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, parent_id = cur_parentp->mLocalID; } + if (!dp) { switch(update_type) @@ -1047,7 +1118,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); mTotalCRC = crc; @@ -1078,8 +1149,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mFlags |= flags; U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; // ...new objects that should come in selected need to be added to the selected list mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); @@ -1121,17 +1192,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Setup object text if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } //Cache for reset on debug infodisplay toggle. mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, mHudTextString, block_num ); - + LLColor4U coloru; mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); @@ -1149,7 +1215,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText->setObjectText(mHudTextString); } // [/RLVa:KB] - + setChanged(MOVED | SILHOUETTE); } else if (mText.notNull()) @@ -1160,8 +1226,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, std::string media_url; mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - retval |= checkMediaURL(media_url); - + retval |= checkMediaURL(media_url); + // // Unpack particle system data // @@ -1237,7 +1303,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U8 state; dp->unpackU8(state, "State"); - mState = state; + mAttachmentState = state; switch(update_type) { @@ -1298,7 +1364,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { gFloaterTools->dirty(); } - + dp->unpackU32(crc, "CRC"); mTotalCRC = crc; dp->unpackU8(material, "Material"); @@ -1403,12 +1469,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText = NULL; } - std::string media_url; + std::string media_url; if (value & 0x200) { dp->unpackString(media_url, "MediaURL"); } - retval |= checkMediaURL(media_url); + retval |= checkMediaURL(media_url); // // Unpack particle system data @@ -1421,7 +1487,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { deleteParticleSource(); } - + // Mark all extra parameters not used std::map::iterator iter; for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) @@ -1477,13 +1543,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Preload these five flags for every object. // Finer shades require the object to be selected, and the selection manager // stores the extended permission info. - U32 flags; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); - // keep local flags and overwrite remote-controlled flags - mFlags = (mFlags & FLAGS_LOCAL) | flags; - - // ...new objects that should come in selected need to be added to the selected list - mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + if(mesgsys != NULL) + { + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + loadFlags(flags); + } } break; @@ -1491,7 +1556,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; } } - // // Fix object parenting. // @@ -1511,10 +1575,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { // No parent now, new parent in message -> attach to that parent if possible LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); @@ -1525,7 +1600,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { static std::map state_map; std::map::iterator it = state_map.find(getID()); - + if(it != state_map.end() && (!it->second && sent_parentp)) { it->second = sent_parentp != NULL; @@ -1544,7 +1619,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, this->removeChild(sent_parentp); sent_parentp->setDrawableParent(NULL); } - + if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) { // @@ -1584,7 +1659,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) ) { // Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar()) - S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState()); + S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getAttachmentState()); if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) { // If this will end up on an "add locked" attachment point then treat the attach as a user action @@ -1611,7 +1686,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { sent_parentp->addChild(this); } - + // Show particles, icon and HUD hideExtraDisplayItems( FALSE ); @@ -1623,11 +1698,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // No corresponding viewer object for the parent, put the various // pieces on the orphan list. // - + //parent_id - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } gObjectList.orphanize(this, parent_id, ip, port); // Hide particles, icon and HUD @@ -1665,12 +1749,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, else { LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } sent_parentp = gObjectList.findObject(parent_uuid); - + if (isAvatar()) { // This logic is meant to handle the case where a sitting avatar has reached a new sim @@ -1689,8 +1784,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // Switching parents, but we don't know the new parent. // - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } // We're an orphan, flag things appropriately. gObjectList.orphanize(this, parent_id, ip, port); @@ -1774,13 +1879,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.normQuat(); - if (sPingInterpolate) - { + if (sPingInterpolate && mesgsys != NULL) + { LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); if (cdp) { F32 ping_delay = 0.5f * time_dilation * ( ((F32)cdp->getPingDelay().valueInUnits()) + gFrameDTClamped); - LLVector3 diff = getVelocity() * ping_delay; + LLVector3 diff = getVelocity() * ping_delay; new_pos_parent += diff; } else @@ -1795,18 +1900,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // - // If we're going to skip this message, why are we + // If we're going to skip this message, why are we // doing all the parenting, etc above? - U32 packet_id = mesgsys->getCurrentRecvPacketID(); - if (packet_id < mLatestRecvPacketID && - mLatestRecvPacketID - packet_id < 65536) + if(mesgsys != NULL) { - //skip application of this message, it's old - return retval; + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + mLatestRecvPacketID = packet_id; } - mLatestRecvPacketID = packet_id; - // Set the change flags for scale if (new_scale != getScale()) { @@ -1828,7 +1935,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, ||(this_update_precision > mBestUpdatePrecision)))) { mBestUpdatePrecision = this_update_precision; - + LLVector3 diff = new_pos_parent - test_pos_parent ; F32 mag_sqr = diff.magVecSquared() ; if(std::isfinite(mag_sqr)) @@ -1837,7 +1944,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } else { - LL_WARNS() << "Can not move the object/avatar to an infinite location!" << LL_ENDL ; + LL_WARNS() << "Can not move the object/avatar to an infinite location!" << LL_ENDL ; retval |= INVALID_UPDATE ; } @@ -1902,7 +2009,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } } - if ( gShowObjectUpdates ) { LLColor4 color; @@ -1923,7 +2029,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, llassert(accel_mag_sq >= 0.f); llassert(getAngularVelocity().magVecSquared() >= 0.f); - if ((MAG_CUTOFF >= vel_mag_sq) && + if ((MAG_CUTOFF >= vel_mag_sq) && (MAG_CUTOFF >= accel_mag_sq) && (MAG_CUTOFF >= getAngularVelocity().magVecSquared())) { @@ -1934,16 +2040,16 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mStatic = FALSE; } -// BUG: This code leads to problems during group rotate and any scale operation. -// Small discepencies between the simulator and viewer representations cause the -// selection center to creep, leading to objects moving around the wrong center. -// -// Removing this, however, means that if someone else drags an object you have -// selected, your selection center and dialog boxes will be wrong. It also means -// that higher precision information on selected objects will be ignored. -// -// I believe the group rotation problem is fixed. JNC 1.21.2002 -// + // BUG: This code leads to problems during group rotate and any scale operation. + // Small discepencies between the simulator and viewer representations cause the + // selection center to creep, leading to objects moving around the wrong center. + // + // Removing this, however, means that if someone else drags an object you have + // selected, your selection center and dialog boxes will be wrong. It also means + // that higher precision information on selected objects will be ignored. + // + // I believe the group rotation problem is fixed. JNC 1.21.2002 + // // Additionally, if any child is selected, need to update the dialogs and selection // center. BOOL needs_refresh = mUserSelected; @@ -1963,7 +2069,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // LLSelectMgr::getInstance()->updateSelectionCenter(); dialog_refresh_all(); - } + } // Mark update time as approx. now, with the ping delay. @@ -1998,13 +2104,13 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data, U32 block_num, S32& this_update_precision, LLVector3& new_pos_parent, LLQuaternion& new_rot, LLVector3& new_angv, LLVector3& test_pos_parent) { // Aurora Sim - //const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); + //const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); const F32 size = mRegionp->getWidth(); // Aurora Sim const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); - U8 data[60+16]; // This needs to match the largest size below. + U8 data[MAX_OBJECT_PARAMS_SIZE]; // This needs to match the largest size below. #ifdef LL_BIG_ENDIAN U16 valswizzle[4]; #endif @@ -2013,7 +2119,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data LLVector4 collision_plane; S32 length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_PARAMS_SIZE); switch (length) { @@ -2069,7 +2175,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2080,7 +2186,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2091,7 +2197,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2102,7 +2208,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data U16_to_F32(val[VZ], -size, size)); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2114,7 +2220,7 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); #ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); val = valswizzle; #else val = (U16 *)&data[count]; @@ -2165,7 +2271,9 @@ void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data break; } - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, mState, block_num); + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; } BOOL LLViewerObject::isActive() const @@ -2173,7 +2281,21 @@ BOOL LLViewerObject::isActive() const return TRUE; } +//load flags from cache or from message +void LLViewerObject::loadFlags(U32 flags) +{ + if(flags == (U32)(-1)) + { + return; //invalid + } + // keep local flags and overwrite remote-controlled flags + mFlags = (mFlags & FLAGS_LOCAL) | flags; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + return; +} void LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { @@ -2214,10 +2336,10 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object // updates represents the average velocity of the last timestep, rather than the final velocity. // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically - // + // // *TODO: should also wrap linear accel/velocity in check // to see if object is selected, instead of explicitly - // zeroing it out + // zeroing it out F32 dt = dt_seconds; F64Seconds time_since_last_update = time - mLastMessageUpdateSecs; @@ -2228,26 +2350,26 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con LLVector3 accel = getAcceleration(); LLVector3 vel = getVelocity(); - + if (sMaxUpdateInterpolationTime <= (F64Seconds)0.0) { // Old code path ... unbounded, simple interpolation if (!(accel.isExactlyZero() && vel.isExactlyZero())) { - LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; - - // region local + LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + + // region local setPositionRegion(pos + getPositionRegion()); - setVelocity(vel + accel*dt); - + setVelocity(vel + accel*dt); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); } } else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving { // Object is moving, and hasn't been too long since we got an update from the server - + // Calculate predicted position and velocity - LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; LLVector3 new_v = accel * dt; if (time_since_last_update > sPhaseOutUpdateInterpolationTime && @@ -2281,13 +2403,13 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con } else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) { // Last update was already phased out a bit - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - time_since_last_interpolation); //LL_INFOS() << "Continuing motion phase out of " << (F32) phase_out << LL_ENDL; } else { // Phase out from full value - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); //LL_INFOS() << "Starting motion phase out of " << (F32) phase_out << LL_ENDL; } @@ -2313,7 +2435,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con min_height += (0.5f * getScale().mV[VZ]); } else - { // This will put the object underground, but we can't tell if it will stop + { // This will put the object underground, but we can't tell if it will stop // at ground level or not min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); } @@ -2333,11 +2455,11 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); if (clip_pos_global != new_pos_global) { // Was clipped, so this means we hit a edge where there is no region to enter - + //LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) // << " from " << new_pos << LL_ENDL; new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); - + // Stop motion and get server update for bouncing on the edge new_v.clear(); setAcceleration(LLVector3::zero); @@ -2350,11 +2472,11 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // Set new position and velocity setPositionRegion(new_pos); - setVelocity(new_v); - + setVelocity(new_v); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); - } + } // Update the last time we did anything mLastInterpUpdateSecs = time; @@ -2588,6 +2710,11 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) } } +BOOL LLViewerObject::isInventoryPending() +{ + return mInvRequestState != INVENTORY_REQUEST_STOPPED; +} + void LLViewerObject::clearInventoryListeners() { for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); @@ -2626,7 +2753,7 @@ void LLViewerObject::requestInventory() void LLViewerObject::fetchInventoryFromServer() { - if (!mInventoryPending) + if (!isInventoryPending()) { delete mInventory; LLMessageSystem* msg = gMessageSystem; @@ -2639,10 +2766,16 @@ void LLViewerObject::fetchInventoryFromServer() msg->sendReliable(mRegionp->getHost()); // this will get reset by dirtyInventory or doInventoryCallback - mInventoryPending = TRUE; + mInvRequestState = INVENTORY_REQUEST_PENDING; } } +// virtual +bool LLViewerObject::isAnimatedObject() const +{ + return false; +} + struct LLFilenameAndTask { LLUUID mTaskID; @@ -2711,13 +2844,27 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) delete ft; return; } - gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), ft->mFilename, LL_PATH_CACHE, object->mRegionp->getHost(), TRUE, &LLViewerObject::processTaskInvFile, (void**)ft, LLXferManager::HIGH_PRIORITY); + if (object->mInvRequestState == INVENTORY_XFER) + { + if (new_id > 0 && new_id != object->mInvRequestXFerId) + { + // we started new download. + gXferManager->abortRequestById(object->mInvRequestXFerId, -1); + object->mInvRequestXFerId = new_id; + } + } + else + { + object->mInvRequestState = INVENTORY_XFER; + object->mInvRequestXFerId = new_id; + } } void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) @@ -2768,9 +2915,10 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) { std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); - llifstream ifs(filename_and_local_path); + llifstream ifs(filename_and_local_path.c_str()); if(ifs.good()) { + U32 fail_count = 0; char buffer[MAX_STRING]; /* Flawfinder: ignore */ // *NOTE: This buffer size is hard coded into scanf() below. char keyword[MAX_STRING]; /* Flawfinder: ignore */ @@ -2785,8 +2933,14 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) while(ifs.good()) { ifs.getline(buffer, MAX_STRING); - if (sscanf(buffer, " %254s", keyword) < 1) continue; - if(0 == strcmp("inv_item", keyword)) + if (sscanf(buffer, " %254s", keyword) == EOF) /* Flawfinder: ignore */ + { + // Blank file? + LL_WARNS() << "Issue reading from file '" + << filename << "'" << LL_ENDL; + break; + } + else if(0 == strcmp("inv_item", keyword)) { LLPointer inv = new LLViewerInventoryItem; inv->importLegacyStream(ifs); @@ -2799,9 +2953,17 @@ BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) inv->rename("Contents"); mInventory->push_front(inv); } + else if (fail_count >= MAX_INV_FILE_READ_FAILS) + { + LL_WARNS() << "Encountered too many unknowns while reading from file: '" + << filename << "'" << LL_ENDL; + break; + } else { - LL_WARNS() << "Unknown token in inventory file '" + // Is there really a point to continue processing? We already failing to display full inventory + fail_count++; + LL_WARNS_ONCE() << "Unknown token while reading from inventory file. Token: '" << keyword << "'" << LL_ENDL; } } @@ -2840,7 +3002,10 @@ void LLViewerObject::doInventoryCallback() mInventoryCallbacks.erase(curiter); } } - mInventoryPending = FALSE; + + // release inventory loading state + mInvRequestXFerId = 0; + mInvRequestState = INVENTORY_REQUEST_STOPPED; } void LLViewerObject::removeInventory(const LLUUID& item_id) @@ -2955,7 +3120,7 @@ LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) rv = *it; break; } - } + } } return rv; } @@ -3010,7 +3175,7 @@ LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& ass break; } } - } + } } return rv; } @@ -3033,7 +3198,7 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) { //volumes calculate pixel area and angle per face return; } - + LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); LLVector3 pos_agent = getRenderPosition(); @@ -3089,7 +3254,7 @@ void LLViewerObject::updateGL() void LLViewerObject::updateFaceSize(S32 idx) { - + } LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) @@ -3102,7 +3267,7 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) LLPrimitive::setScale(scale); if (mDrawable.notNull()) { - //encompass completely sheared objects by taking + //encompass completely sheared objects by taking //the most extreme point possible (<1,1,0.5>) mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); updateDrawable(damped); @@ -3146,8 +3311,17 @@ void LLViewerObject::setLinksetCost(F32 cost) { mLinksetCost = cost; mCostStale = false; - - if (isSelected()) + + BOOL needs_refresh = isSelected(); + child_list_t::iterator iter = mChildList.begin(); + while(iter != mChildList.end() && !needs_refresh) + { + LLViewerObject* child = *iter; + needs_refresh = child->isSelected(); + iter++; + } + + if (needs_refresh) { gFloaterTools->dirty(); } @@ -3168,7 +3342,7 @@ void LLViewerObject::setLinksetPhysicsCost(F32 cost) { mLinksetPhysicsCost = cost; mCostStale = false; - + if (isSelected()) { gFloaterTools->dirty(); @@ -3182,7 +3356,7 @@ F32 LLViewerObject::getObjectCost() { gObjectList.updateObjectCost(this); } - + return mObjectCost; } @@ -3202,7 +3376,7 @@ F32 LLViewerObject::getPhysicsCost() { gObjectList.updateObjectCost(this); } - + return mPhysicsCost; } @@ -3241,7 +3415,7 @@ void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax size.load3(getScale().mV); newMin.setSub(center, size); newMax.setAdd(center, size); - + mDrawable->setPositionGroup(center); } @@ -3254,7 +3428,7 @@ F32 LLViewerObject::getBinRadius() diff.setSub(ext[1], ext[0]); return diff.getLength3().getF32(); } - + return getScale().magVec(); } @@ -3315,7 +3489,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) S32 tex_count = getNumTEs(); for (i = 0; i < tex_count; i++) { - getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); + getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } if (isSculpted() && !isMesh()) @@ -3324,7 +3498,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) LLUUID sculpt_id = sculpt_params->getSculptTexture(); LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } - + if (boost_children) { for (child_list_t::iterator iter = mChildList.begin(); @@ -3433,7 +3607,7 @@ BOOL LLViewerObject::removeNVPair(const std::string& name) gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); gMessageSystem->nextBlockFast(_PREHASH_TaskData); gMessageSystem->addUUIDFast(_PREHASH_ID, mID); - + gMessageSystem->nextBlockFast(_PREHASH_NameValueData); gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); @@ -3491,7 +3665,7 @@ void LLViewerObject::updatePositionCaches() const } const LLVector3d LLViewerObject::getPositionGlobal() const -{ +{ // If region is removed from the list it is also deleted. if(mRegionp && LLWorld::instance().isRegionListed(mRegionp)) { @@ -3500,14 +3674,14 @@ const LLVector3d LLViewerObject::getPositionGlobal() const if (isAttachment()) { position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); - } + } return position_global; } else { LLVector3d position_global(getPosition()); return position_global; - } + } } const LLVector3 &LLViewerObject::getPositionAgent() const @@ -3588,11 +3762,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const const LLQuaternion LLViewerObject::getRenderRotation() const { LLQuaternion ret; - if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject()) { return ret; } - + if (mDrawable.isNull() || mDrawable->isStatic()) { ret = getRotationEdit(); @@ -3608,7 +3782,7 @@ const LLQuaternion LLViewerObject::getRenderRotation() const ret = LLQuaternion(LLMatrix4(mDrawable->getWorldMatrix().getF32ptr())); } } - + return ret; } @@ -3655,7 +3829,7 @@ void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BO new_pos = new_pos * ~parentp->getRotationRegion(); } LLViewerObject::setPosition(new_pos); - + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) { // we have changed the position of an attachment, so we need to clamp it @@ -3692,7 +3866,7 @@ void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) { setChanged(TRANSLATED | SILHOUETTE); } - + LLXform::setPosition(pos); updateDrawable(damped); if (isRoot()) @@ -3726,7 +3900,7 @@ void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped LLQuaternion invRotation = mDrawable->getRotation(); invRotation.transQuat(); - + delta_pos = delta_pos * invRotation; // *FIX: is this right? Shouldn't we be calling the @@ -3797,7 +3971,7 @@ void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) setPositionRegion(pos_region, damped); } -// identical to setPositionRegion() except it checks for child-joints +// identical to setPositionRegion() except it checks for child-joints // and doesn't also move the joint-parent // TODO -- implement similar intelligence for joint-parents toward // their joint-children @@ -3816,14 +3990,14 @@ void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) LLViewerObject::setPosition(pos_edit, damped); mPositionRegion = pos_edit; mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } + } } LLViewerObject* LLViewerObject::getRootEdit() const { const LLViewerObject* root = this; - while (root->mParent + while (root->mParent && !((LLViewerObject*)root->mParent)->isAvatar()) { root = (LLViewerObject*)root->mParent; @@ -3960,10 +4134,10 @@ void LLViewerObject::setNumTEs(const U8 num_tes) { LLPointer *new_images; new_images = new LLPointer[num_tes]; - + LLPointer *new_normmaps; new_normmaps = new LLPointer[num_tes]; - + LLPointer *new_specmaps; new_specmaps = new LLPointer[num_tes]; for (i = 0; i < num_tes; i++) @@ -3989,7 +4163,7 @@ void LLViewerObject::setNumTEs(const U8 num_tes) } deleteTEImages(); - + mTEImages = new_images; mTENormalMaps = new_normmaps; mTESpecularMaps = new_specmaps; @@ -4152,7 +4326,7 @@ S32 LLViewerObject::setTENormalMapCore(const U8 te, LLViewerTexture *image) mat->setNormalID(uuid); } } - changeTENormalMap(te,image); + changeTENormalMap(te,image); return retval; } @@ -4173,14 +4347,14 @@ S32 LLViewerObject::setTESpecularMapCore(const U8 te, LLViewerTexture *image) if (mat) { mat->setSpecularID(uuid); - } + } } changeTESpecularMap(te, image); return retval; } //virtual -void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) { if(index < 0 || index >= getNumTEs()) { @@ -4425,7 +4599,7 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams); LL_DEBUGS("Material") << "Changing material params for te " << (S32)te << ", object " << mID - << " (" << retval << ")" + << " (" << retval << ")" << LL_ENDL; setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); @@ -4570,7 +4744,7 @@ bool LLViewerObject::isImageAlphaBlended(const U8 te) const LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const { // llassert(mTEImages); - + if (face < getNumTEs()) { LLViewerTexture* image = mTENormalMaps[face]; @@ -4583,16 +4757,16 @@ LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); } } - + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; - + return NULL; } LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const { // llassert(mTEImages); - + if (face < getNumTEs()) { LLViewerTexture* image = mTESpecularMaps[face]; @@ -4605,9 +4779,9 @@ LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); } } - + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; - + return NULL; } @@ -4627,7 +4801,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const { avatar_parent = (LLViewerObject*)root_edit->getParent(); } - + if (avatar_parent && avatar_parent->isAvatar() && root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) { @@ -4640,7 +4814,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const position_agent = getPositionAgent(); rot = getRotationRegion(); } - + return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); } @@ -4725,12 +4899,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text) if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } mText->setColor(utf8text.empty() ? mHudTextColor : LLColor4::white ); mText->setString(utf8text.empty() ? mHudTextString : utf8text ); @@ -4738,6 +4907,16 @@ void LLViewerObject::setDebugText(const std::string &utf8text) mText->setDoFade(utf8text.empty()); updateText(); } +void LLViewerObject::initHudText() +{ + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); +} + // std::string LLViewerObject::getDebugText() { @@ -4771,8 +4950,8 @@ void LLViewerObject::clearIcon() } } -LLViewerObject* LLViewerObject::getSubParent() -{ +LLViewerObject* LLViewerObject::getSubParent() +{ return (LLViewerObject*) getParent(); } @@ -4795,7 +4974,7 @@ void LLViewerObject::updateText() { LLVector3 up_offset(0,0,0); up_offset.mV[2] = getScale().mV[VZ]*0.6f; - + if (mDrawable.notNull()) { mText->setPositionAgent(getRenderPosition() + up_offset); @@ -4813,7 +4992,13 @@ LLVOAvatar* LLViewerObject::asAvatar() return NULL; } -// If this object is directly or indirectly parented by an avatar, return it. +// If this object is directly or indirectly parented by an avatar, +// return it. Normally getAvatar() is the correct function to call; +// it will give the avatar used for skinning. The exception is with +// animated objects that are also attachments; in that case, +// getAvatar() will return the control avatar, used for skinning, and +// getAvatarAncestor will return the avatar to which the object is +// attached. LLVOAvatar* LLViewerObject::getAvatarAncestor() { LLViewerObject *pobj = (LLViewerObject*) getParent(); @@ -4843,7 +5028,7 @@ void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, LLPointer pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); mPartSourcep = pss; - + if (mPartSourcep) { mPartSourcep->setOwnerUUID(owner_id); @@ -4975,20 +5160,20 @@ void LLViewerObject::updateDrawable(BOOL force_damped) if (!isChanged(MOVED)) { //most common case, having an empty if case here makes for better branch prediction } - else if (mDrawable.notNull() && + else if (mDrawable.notNull() && !mDrawable->isState(LLDrawable::ON_MOVE_LIST)) { - BOOL damped_motion = + BOOL damped_motion = !isChanged(SHIFTED) && // not shifted between regions this frame and... ( force_damped || // ...forced into damped motion by application logic or... ( !isSelected() && // ...not selected and... ( mDrawable->isRoot() || // ... is root or ... (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... - ) && + ) && getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... getVelocity().isExactlyZero() && // ...is not moving physically and... mDrawable->getGeneration() != -1 // ...was not created this frame. - ) + ) ); gPipeline.markMoved(mDrawable, damped_motion); } @@ -5007,7 +5192,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow { return; } - + if (audio_uuid.isNull()) { if (!mAudioSourcep || (flags & LL_SOUND_FLAG_STOP && !mAudioSourcep->isLoop())) @@ -5025,7 +5210,7 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow mAudioSourcep = NULL; } else if (flags & LL_SOUND_FLAG_STOP) - { + { // Just shut off the sound mAudioSourcep->play(LLUUID::null); } @@ -5040,14 +5225,14 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow } // don't clean up before previous sound is done. Solves: SL-33486 - if ( mAudioSourcep && mAudioSourcep->isDone() ) + if ( mAudioSourcep && mAudioSourcep->isDone() ) { gAudiop->cleanupAudioSource(mAudioSourcep); mAudioSourcep = NULL; } if (mAudioSourcep && mAudioSourcep->isMuted() && - mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) { //LL_INFOS() << "Already having this sound as muted sound, ignoring" << LL_ENDL; return; @@ -5129,31 +5314,36 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para LLNetworkData* new_block = NULL; switch (param_type) { - case LLNetworkData::PARAMS_FLEXIBLE: - { - new_block = new LLFlexibleObjectData(); - break; - } - case LLNetworkData::PARAMS_LIGHT: - { - new_block = new LLLightParams(); - break; - } - case LLNetworkData::PARAMS_SCULPT: - { - new_block = new LLSculptParams(); - break; - } - case LLNetworkData::PARAMS_LIGHT_IMAGE: - { - new_block = new LLLightImageParams(); - break; - } - default: - { - LL_INFOS() << "Unknown param type. (" << llformat("0x%2x",param_type) << ")" << LL_ENDL; - break; - } + case LLNetworkData::PARAMS_FLEXIBLE: + { + new_block = new LLFlexibleObjectData(); + break; + } + case LLNetworkData::PARAMS_LIGHT: + { + new_block = new LLLightParams(); + break; + } + case LLNetworkData::PARAMS_SCULPT: + { + new_block = new LLSculptParams(); + break; + } + case LLNetworkData::PARAMS_LIGHT_IMAGE: + { + new_block = new LLLightImageParams(); + break; + } + case LLNetworkData::PARAMS_EXTENDED_MESH: + { + new_block = new LLExtendedMeshParams(); + break; + } + default: + { + LL_INFOS() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL; + break; + } }; if (new_block) @@ -5328,25 +5518,45 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) } } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ + BOOL matches = FALSE; + if (mDrawable) + { + matches = mDrawable->isState(state); + } + if (recursive) + { + for (child_list_t::const_iterator iter = mChildList.begin(); + (iter != mChildList.end()) && matches; iter++) + { + LLViewerObject* child = *iter; + matches &= child->isDrawableState(state, recursive); + } + } + + return matches; +} + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// RN: these functions assume a 2-level hierarchy +// RN: these functions assume a 2-level hierarchy //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Owned by anyone? BOOL LLViewerObject::permAnyOwner() const -{ +{ if (isRootEdit()) { - return flagObjectAnyOwner(); + return flagObjectAnyOwner(); } else { return ((LLViewerObject*)getParent())->permAnyOwner(); } -} +} // Owned by this viewer? BOOL LLViewerObject::permYouOwner() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5354,12 +5564,12 @@ BOOL LLViewerObject::permYouOwner() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectYouOwner(); + return flagObjectYouOwner(); #endif } else @@ -5369,11 +5579,11 @@ BOOL LLViewerObject::permYouOwner() const } // Owned by a group? -BOOL LLViewerObject::permGroupOwner() const -{ +BOOL LLViewerObject::permGroupOwner() const +{ if (isRootEdit()) { - return flagObjectGroupOwned(); + return flagObjectGroupOwned(); } else { @@ -5383,7 +5593,7 @@ BOOL LLViewerObject::permGroupOwner() const // Can the owner edit BOOL LLViewerObject::permOwnerModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5391,12 +5601,12 @@ BOOL LLViewerObject::permOwnerModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectOwnerModify(); + return flagObjectOwnerModify(); #endif } else @@ -5407,7 +5617,7 @@ BOOL LLViewerObject::permOwnerModify() const // Can edit BOOL LLViewerObject::permModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5415,12 +5625,12 @@ BOOL LLViewerObject::permModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectModify(); + return flagObjectModify(); #endif } else @@ -5431,7 +5641,7 @@ BOOL LLViewerObject::permModify() const // Can copy BOOL LLViewerObject::permCopy() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5439,7 +5649,7 @@ BOOL LLViewerObject::permCopy() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } @@ -5463,12 +5673,12 @@ BOOL LLViewerObject::permMove() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectMove(); + return flagObjectMove(); #endif } else @@ -5479,7 +5689,7 @@ BOOL LLViewerObject::permMove() const // Can be transferred BOOL LLViewerObject::permTransfer() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5487,12 +5697,12 @@ BOOL LLViewerObject::permTransfer() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectTransfer(); + return flagObjectTransfer(); #endif } else @@ -5529,6 +5739,17 @@ void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) } } +void LLViewerObject::recursiveMarkForUpdate(BOOL priority) +{ + for (LLViewerObject::child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->markForUpdate(priority); + } + markForUpdate(priority); +} + void LLViewerObject::markForUpdate(BOOL priority) { if (mDrawable.notNull()) @@ -5559,7 +5780,18 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) { LL_WARNS() << "viewer object set region to NULL" << LL_ENDL; } - + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } + mLatestRecvPacketID = 0; mRegionp = regionp; @@ -5676,13 +5908,13 @@ void LLViewerObject::setPhysicsRestitution(F32 restitution) } U8 LLViewerObject::getPhysicsShapeType() const -{ +{ if (mPhysicsShapeUnknown) { gObjectList.updatePhysicsFlags(this); } - return mPhysicsShapeType; + return mPhysicsShapeType; } void LLViewerObject::applyAngularVelocity(F32 dt) @@ -5699,7 +5931,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) angle = omega * dt; ang_vel *= 1.f/omega; - + // calculate the delta increment based on the object's angular velocity dQ.setQuat(angle, ang_vel); @@ -5709,7 +5941,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) // accumulate the angular velocity rotations to re-apply in the case of an object update mAngularVelocityRot *= dQ; } - + // Just apply the delta increment to the current rotation setRotation(getRotation()*dQ); setChanged(MOVED | SILHOUETTE); @@ -5728,25 +5960,9 @@ void LLViewerObject::resetRot() } } -//virtual -void LLViewerObject::setSelected(BOOL sel) -{ - mUserSelected = sel; - - static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); - if(use_new_target_omega) - { - resetRot(); - } - else - { - mRotTime = 0.f; - } -} - U32 LLViewerObject::getPartitionType() const -{ - return LLViewerRegion::PARTITION_NONE; +{ + return LLViewerRegion::PARTITION_NONE; } void LLViewerObject::dirtySpatialGroup(BOOL priority) const @@ -5810,7 +6026,7 @@ void LLViewerObject::saveUnselectedChildrenPosition(std::vector& posi LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - positions.push_back(childp->getPositionEdit()); + positions.push_back(childp->getPositionEdit()); } } @@ -5830,15 +6046,15 @@ void LLViewerObject::saveUnselectedChildrenRotation(std::vector& r LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - rotations.push_back(childp->getRotationEdit()); - } + rotations.push_back(childp->getRotationEdit()); + } } return ; } //counter-rotation -void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, +void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) { if(mChildList.empty()) @@ -5859,30 +6075,30 @@ void LLViewerObject::resetChildrenRotationAndPosition(const std::vectorsetRotation(rotations[index] * inv_rotation); childp->setPosition((positions[index] - offset) * inv_rotation); - LLManip::rebuild(childp); + LLManip::rebuild(childp); } else //avatar { LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; LLQuaternion reset_rot = rotations[index] * inv_rotation ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; - - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); + + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; - LLManip::rebuild(childp); - } + LLManip::rebuild(childp); + } index++; - } + } } return ; } //counter-translation -void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) +void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified, BOOL skip_avatar_child) { if(mChildList.empty()) { @@ -5921,20 +6137,22 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif } else //avatar { - LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; + if(!skip_avatar_child) + { + LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); - - LLManip::rebuild(childp); - } - } + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); + LLManip::rebuild(childp); + } + } + } } return ; } -// virtual +// virtual BOOL LLViewerObject::isTempAttachment() const { return (mID.notNull() && (mID == mAttachmentItemID)); @@ -5943,7 +6161,7 @@ BOOL LLViewerObject::isTempAttachment() const // std::string LLViewerObject::getAttachmentPointName() { - S32 point = ATTACHMENT_ID_FROM_STATE(mState); + S32 point = ATTACHMENT_ID_FROM_STATE(mAttachmentState); LLVOAvatar::attachment_map_t::iterator it = gAgentAvatarp->mAttachmentPoints.find(point); if(it != gAgentAvatarp->mAttachmentPoints.end()) { diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 19e7aab91..d031f3de4 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -112,7 +112,10 @@ struct PotentialReturnableObject //============================================================================ -class LLViewerObject: public LLPrimitive, public LLRefCount, public LLGLUpdate +class LLViewerObject +: public LLPrimitive, + public LLRefCount, + public LLGLUpdate { protected: ~LLViewerObject(); // use unref() @@ -219,6 +222,7 @@ public: LLViewerRegion* getRegion() const { return mRegionp; } BOOL isSelected() const { return mUserSelected; } + BOOL isAnySelected() const; void setSelected(BOOL sel); const LLUUID &getID() const { return mID; } @@ -230,6 +234,7 @@ public: virtual BOOL isFlexible() const { return FALSE; } virtual BOOL isSculpted() const { return FALSE; } virtual BOOL isMesh() const { return FALSE; } + virtual BOOL isRiggedMesh() const { return FALSE; } virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by @@ -254,6 +259,8 @@ public: */ virtual BOOL setParent(LLViewerObject* parent); + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); + virtual void afterReparent(); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); const_child_list_t& getChildren() const { return mChildList; } @@ -378,7 +385,7 @@ public: // U8 getState() { return mState; } // [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a - U8 getState() const { return mState; } + U8 getAttachmentState() const { return mAttachmentState; } // [/RLVa:KB] F32 getAppAngle() const { return mAppAngle; } @@ -411,13 +418,16 @@ public: void setCanSelect(BOOL canSelect); void setDebugText(const std::string &utf8text); + void initHudText(); + // std::string getDebugText(); // void setIcon(LLViewerTexture* icon_image); void clearIcon(); - void markForUpdate(BOOL priority); + void recursiveMarkForUpdate(BOOL priority); + virtual void markForUpdate(BOOL priority); void updateVolume(const LLVolumeParams& volume_params); virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); virtual F32 getBinRadius(); @@ -430,6 +440,7 @@ public: void setDrawableState(U32 state, BOOL recursive = TRUE); void clearDrawableState(U32 state, BOOL recursive = TRUE); + BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const; // Called when the drawable shifts virtual void onShift(const LLVector4a &shift_vector) { } @@ -444,7 +455,7 @@ public: // viewer object has the inventory stored locally. void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); void removeInventoryListener(LLVOInventoryListener* listener); - BOOL isInventoryPending() { return mInventoryPending; } + BOOL isInventoryPending(); void clearInventoryListeners(); bool hasInventoryListeners(); void requestInventory(); @@ -543,6 +554,7 @@ public: virtual void updateRegion(LLViewerRegion *regionp) {} void updateFlags(BOOL physics_changed = FALSE); + void loadFlags(U32 flags); //load flags from cache or from message BOOL setFlags(U32 flag, BOOL state); BOOL setFlagsWithoutUpdate(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); @@ -574,7 +586,7 @@ public: public: //counter-translation - void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; + void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE, BOOL skip_avatar_child = FALSE) ; //counter-rotation void resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) ; @@ -681,6 +693,9 @@ public: static BOOL sUseSharedDrawables; +public: + + virtual bool isAnimatedObject() const; protected: // delete an item in the inventory, but don't tell the // server. This is used internally by remove, update, and @@ -757,9 +772,17 @@ protected: callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + enum EInventoryRequestState + { + INVENTORY_REQUEST_STOPPED, + INVENTORY_REQUEST_PENDING, + INVENTORY_XFER + }; + EInventoryRequestState mInvRequestState; + U64 mInvRequestXFerId; + BOOL mInventoryDirty; + LLViewerRegion *mRegionp; // Region that this object belongs to. - BOOL mInventoryPending; - BOOL mInventoryDirty; BOOL mDead; BOOL mOrphaned; // This is an orphaned child BOOL mUserSelected; // Cached user select information @@ -772,7 +795,7 @@ protected: LLQuaternion mAngularVelocityRot; // accumulated rotation from the angular velocity computations LLQuaternion mPreviousRotation; - U8 mState; // legacy + U8 mAttachmentState; // this encodes the attachment id in a somewhat complex way. 0 if not an attachment. LLViewerObjectMedia* mMedia; // NULL if no media associated U8 mClickAction; F32 mObjectCost; //resource cost of this object or -1 if unknown diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index e0cb5c2d0..f84bb5ea6 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -291,7 +291,19 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, // RN: this must be called after we have a drawable // (from gPipeline.addObject) // so that the drawable parent is set properly - findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + if(msg != NULL) + { + findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + } + else + { + LLViewerRegion* regionp = objectp->getRegion(); + if(regionp != NULL) + { + findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort()); + } + } + if(just_created && objectp && (gImportTracker.getState() == ImportTracker::WAND /*|| @@ -434,19 +446,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { S32 uncompressed_length = 2048; compressed_dp.reset(); - - U32 flags = 0; - if (update_type != OUT_TERSE_IMPROVED) - { - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - } uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i, 2048); compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { + U32 flags = 0; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); compressed_dp.unpackU8(pcode, "PCode"); @@ -941,14 +949,14 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // update global timer F32 last_time = gFrameTimeSeconds; - U64 time = totalTime(); // this will become the new gFrameTime when the update is done + U64Microseconds time = totalTime(); // this will become the new gFrameTime when the update is done // Time _can_ go backwards, for example if the user changes the system clock. // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. // llassert(time > gFrameTime); - F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; - gFrameTime = time; - F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; - gFrameTimeSeconds = (F32)time_since_start; + F64Seconds time_diff = time - gFrameTime; + gFrameTime = time; + F64Seconds time_since_start = gFrameTime - gStartTime; + gFrameTimeSeconds = time_since_start; gFrameIntervalSeconds = gFrameTimeSeconds - last_time; if (gFrameIntervalSeconds < 0.f) @@ -1033,7 +1041,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) LLVolumeImplFlexible::updateClass(); //update animated textures - LLViewerTextureAnim::updateClass(); + if (gAnimateTextures) + { + LLViewerTextureAnim::updateClass(); + } } @@ -1051,7 +1062,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // don't factor frames that were paused into the stats if (! mWasPaused) { - LLViewerStats::getInstance()->updateFrameStats(time_diff); + LLViewerStats::getInstance()->updateFrameStats(time_diff.value()); } /* @@ -1252,9 +1263,11 @@ void LLViewerObjectList::clearDebugText() void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { + bool new_dead_object = true; if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { LL_INFOS() << "Object " << objectp->mID << " already on dead list!" << LL_ENDL; + new_dead_object = false; } else { @@ -1296,7 +1309,10 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // Also, not cleaned up removeDrawable(objectp->mDrawable); - mNumDeadObjects++; + if(new_dead_object) + { + mNumDeadObjects++; + } } static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); @@ -2031,6 +2047,10 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe // LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << LL_ENDL; return NULL; } + if(regionp) + { + regionp->addToCreatedList(local_id); + } mUUIDObjectMap[fullid] = objectp; if(objectp->isAvatar()) diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index ab3c9b3ac..bb6480f81 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -141,6 +141,7 @@ public: LLViewerObject *getSelectedObject(const U32 object_id); inline S32 getNumObjects() { return (S32) mObjects.size(); } + inline S32 getNumActiveObjects() { return (S32) mActiveObjects.size(); } void addToMap(LLViewerObject *objectp); void removeFromMap(LLViewerObject *objectp); diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 937fc7e3d..bfc533dbb 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -1101,7 +1101,7 @@ void LLOcclusionCullingGroup::checkOcclusion() LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT); while (!available && max_loop-- > 0) { - F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + F32 max_time = llmin(gFrameIntervalSeconds.value()*10.f, 1.f); //do some usefu work while we wait LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 44dd85350..47f9ad523 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -934,6 +934,10 @@ void LLViewerRegion::dirtyHeights() } } +void LLViewerRegion::clearCachedVisibleObjects() +{ +} + BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { // did_update returns TRUE if we did at least one significant update @@ -1446,6 +1450,81 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } +class BaseFeaturesReceived : public LLHTTPClient::ResponderWithResult +{ + LOG_CLASS(BaseFeaturesReceived); +public: + BaseFeaturesReceived(const std::string& retry_url, U64 region_handle, const char* classname, boost::function fn, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts), mClassName(classname), mFunction(fn) + { } + + + void httpFailure(void) + { + LL_WARNS("AppInit", mClassName) << dumpResponse() << LL_ENDL; + retry(); + } + + void httpSuccess(void) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) //region is removed or responder is not created. + { + LL_WARNS("AppInit", mClassName) + << "Received results for region that no longer exists!" << LL_ENDL; + return; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } + mFunction(regionp, content); + } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseFeaturesReceived_timeout; } + /*virtual*/ char const* getName(void) const { return mClassName; } + +private: + + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS("AppInit", mClassName) << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new BaseFeaturesReceived(*this)); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; + const char* mClassName; + boost::function mFunction; +}; + +void LLViewerRegion::requestSimulatorFeatures() +{ + LL_DEBUGS("SimulatorFeatures") << "region " << getName() << " ptr " << this + << " trying to request SimulatorFeatures" << LL_ENDL; + // kick off a request for simulator features + std::string url = getCapability("SimulatorFeatures"); + if (!url.empty()) + { + // kick off a request for simulator features + LLHTTPClient::get(url, new BaseFeaturesReceived(url, getHandle(), "SimulatorFeaturesReceived", &LLViewerRegion::setSimulatorFeatures)); + } + else + { + LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL; + } +} + boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb) { return mSimulatorFeaturesReceivedSignal.connect(cb); @@ -1476,10 +1555,11 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) std::stringstream str; LLSDSerialize::toPrettyXML(sim_features, str); - LL_DEBUGS("SimFeatures") << "\n" << str.str() << LL_ENDL; + LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL; mSimulatorFeatures = sim_features; setSimulatorFeaturesReceived(true); + } void LLViewerRegion::setGamingData(const LLSD& gaming_data) @@ -1554,6 +1634,14 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec return result; } +void LLViewerRegion::removeFromCreatedList(U32 local_id) +{ +} + +void LLViewerRegion::addToCreatedList(U32 local_id) +{ +} + // Get data packer for this object, if we have cached data // AND the CRC matches. JC LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) @@ -2041,64 +2129,6 @@ void LLViewerRegion::failedSeedCapability() } } -class BaseFeaturesReceived : public LLHTTPClient::ResponderWithResult -{ - LOG_CLASS(BaseFeaturesReceived); -public: - BaseFeaturesReceived(const std::string& retry_url, U64 region_handle, const char* classname, boost::function fn, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts), mClassName(classname), mFunction(fn) - { } - - - void httpFailure(void) - { - LL_WARNS("AppInit", mClassName) << dumpResponse() << LL_ENDL; - retry(); - } - - void httpSuccess(void) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS("AppInit", mClassName) - << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - const LLSD& content = getContent(); - if (!content.isMap()) - { - failureResult(400, "Malformed response contents", content); - return; - } - mFunction(regionp, content); - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseFeaturesReceived_timeout; } - /*virtual*/ char const* getName(void) const { return mClassName; } - -private: - - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS("AppInit", mClassName) << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new BaseFeaturesReceived(*this)); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; - const char* mClassName; - boost::function mFunction; -}; - void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") @@ -2114,10 +2144,8 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // although this is not needed later, add it so we can check if the sim supports it at all later - mImpl->mCapabilities[name] = url; - - // kick off a request for simulator features - LLHTTPClient::get(url, new BaseFeaturesReceived(url, getHandle(), "SimulatorFeaturesReceived", &LLViewerRegion::setSimulatorFeatures)); + mImpl->mCapabilities["SimulatorFeatures"] = url; + requestSimulatorFeatures(); } else if (name == "GamingData") { diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 1de1fe645..d32eb1746 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -328,6 +328,7 @@ public: bool meshUploadEnabled() const; // has region received its simulator features list? Requires an additional query after caps received. + void requestSimulatorFeatures(); void setSimulatorFeaturesReceived(bool); bool simulatorFeaturesReceived() const; boost::signals2::connection setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb); @@ -361,6 +362,7 @@ public: void requestCacheMisses(); void addCacheMissFull(const U32 local_id); + void clearCachedVisibleObjects(); void dumpCache(); void unpackRegionHandshake(); @@ -392,6 +394,9 @@ public: void resetMaterialsCapThrottle(); U32 getMaxMaterialsPerTransaction() const; + + void removeFromCreatedList(U32 local_id); + void addToCreatedList(U32 local_id); public: struct CompareDistance { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 885ba2d87..9e9907084 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1321,12 +1321,11 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl } S32Megabytes system_ram = gSysMemory.getPhysicalMemoryClamped(); // In MB - //LL_INFOS() << "*** DETECTED " << system_ram << " MB of system memory." << LL_ENDL; if (get_recommended) max_texmem = llmin(max_texmem, system_ram/2); else max_texmem = llmin(max_texmem, system_ram); - + // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise max_texmem = llmin(max_texmem, (S32Megabytes) (mem_multiplier * max_texmem)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 3ae1c9733..a5d8cf120 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3596,8 +3596,8 @@ void LLViewerWindow::updateMouseDelta() static F32 fdy = 0.f; F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds.value()*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds.value()*amount,1.f); mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy)); mouse_vel.setVec(fdx,fdy); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 0b1fb67ec..9c0c56efc 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1033,22 +1033,22 @@ const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; bool LLVOAvatar::sRenderGroupTitles = true; S32 LLVOAvatar::sNumVisibleChatBubbles = 0; -BOOL LLVOAvatar::sDebugInvisible = FALSE; -BOOL LLVOAvatar::sShowAttachmentPoints = FALSE; -BOOL LLVOAvatar::sShowAnimationDebug = FALSE; -BOOL LLVOAvatar::sShowFootPlane = FALSE; -BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; +BOOL LLVOAvatar::sDebugInvisible = false; +bool LLVOAvatar::sShowAttachmentPoints = false; +BOOL LLVOAvatar::sShowAnimationDebug = false; +bool LLVOAvatar::sShowFootPlane = false; +bool LLVOAvatar::sVisibleInFirstPerson = false; F32 LLVOAvatar::sLODFactor = 1.f; F32 LLVOAvatar::sPhysicsLODFactor = 1.f; -BOOL LLVOAvatar::sUseImpostors = FALSE; -BOOL LLVOAvatar::sJointDebug = FALSE; +bool LLVOAvatar::sUseImpostors = false; +BOOL LLVOAvatar::sJointDebug = false; F32 LLVOAvatar::sUnbakedTime = 0.f; F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; F32 LLVOAvatar::sGreyTime = 0.f; F32 LLVOAvatar::sGreyUpdateTime = 0.f; //Move to LLVOAvatarSelf -BOOL LLVOAvatar::sDebugAvatarRotation = FALSE; +BOOL LLVOAvatar::sDebugAvatarRotation = false; //----------------------------------------------------------------------------- // Helper functions @@ -1113,6 +1113,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mUseServerBakes(FALSE), mLastUpdateRequestCOFVersion(-1), mLastUpdateReceivedCOFVersion(-1), + mIsUIAvatar(false), // mHasPhysicsParameters( false ), mIdleMinute(0), @@ -1403,8 +1404,8 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) { if (rez_status==0) return "cloud"; if (rez_status==1) return "gray"; - if (rez_status==2) return "textured"; - if (rez_status==3) return "textured_and_downloaded"; + if (rez_status==2) return "downloading"; + if (rez_status==3) return "full"; return "unknown"; } @@ -1474,7 +1475,7 @@ void LLVOAvatar::dumpBakedStatus() const ETextureIndex index = baked_dict->mTextureIndex; if (!inst->isTextureDefined(index)) { - LL_CONT << " " << LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName; + LL_CONT << " " << (LLAvatarAppearanceDictionary::getInstance()->getTexture(index) ? LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName : ""); } } LL_CONT << " ) " << inst->getUnbakedPixelAreaRank(); @@ -1635,6 +1636,8 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + + mInitFlags |= 1<<1; } // virtual @@ -2423,13 +2426,11 @@ void LLVOAvatar::resetSkeleton(bool reset_animations) //----------------------------------------------------------------------------- void LLVOAvatar::releaseMeshData() { - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar()) { return; } - //LL_DEBUGS() << "Releasing mesh data" << LL_ENDL; - // cleanup mesh data for (avatar_joint_list_t::iterator iter = mMeshLOD.begin(); iter != mMeshLOD.end(); @@ -2477,6 +2478,10 @@ void LLVOAvatar::releaseMeshData() void LLVOAvatar::restoreMeshData() { llassert(!isSelf()); + if (mDrawable.isNull()) + { + return; + } //LL_INFOS() << "Restoring" << LL_ENDL; mMeshValid = TRUE; @@ -2655,9 +2660,6 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, } } - //LL_INFOS() << getRotation() << LL_ENDL; - //LL_INFOS() << getPosition() << LL_ENDL; - return retval; } @@ -2774,7 +2776,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE); - if (mIsSitting && getParent()) + if (isSitting() && getParent()) { LLViewerObject *root_object = (LLViewerObject*)getRoot(); LLDrawable* drawablep = root_object->mDrawable; @@ -2964,7 +2966,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) //-------------------------------------------------------------------------------------------- - if ( mIsSitting ) + if ( isSitting() ) { LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset ); @@ -3101,7 +3103,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } } - if(mDrawable) + if (mDrawable.notNull()) { mDrawable->movePartition(); @@ -3229,19 +3231,22 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { - if (isFullyLoaded() && mFirstFullyVisible && isSelf()) - { - LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } - if (isFullyLoaded() && mFirstFullyVisible && !isSelf()) - { - LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - } if (isFullyLoaded()) { + if (mFirstFullyVisible) + { + mFirstFullyVisible = FALSE; + if (isSelf()) + { + LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + else + { + LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + } + } + deleteParticleSource(); updateLOD(); } @@ -4753,22 +4758,22 @@ void LLVOAvatar::updateHeadOffset() { midEyePt = midEyePt * ~mDrawable->getWorldRotation(); } - if (mIsSitting) + if (isSitting()) { - mHeadOffset = midEyePt; + mHeadOffset = midEyePt; } else { F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped)); - mHeadOffset = lerp(midEyePt, mHeadOffset, u); + mHeadOffset = lerp(midEyePt, mHeadOffset, u); } } //------------------------------------------------------------------------ // postPelvisSetRecalc //------------------------------------------------------------------------ void LLVOAvatar::postPelvisSetRecalc() -{ - mRoot->updateWorldMatrixChildren(); +{ + mRoot->updateWorldMatrixChildren(); computeBodySize(); dirtyMesh(2); } @@ -4781,7 +4786,7 @@ void LLVOAvatar::updateVisibility() if (mIsDummy) { - visible = TRUE; + visible = FALSE; } else if (mDrawable.isNull()) { @@ -4798,14 +4803,14 @@ void LLVOAvatar::updateVisibility() visible = FALSE; } - if(isSelf()) + if (isSelf()) { if (!gAgentWearables.areWearablesLoaded()) { visible = FALSE; } } - else if( !mFirstAppearanceMessageReceived ) + else if (!mFirstAppearanceMessageReceived) { visible = FALSE; } @@ -4855,19 +4860,21 @@ void LLVOAvatar::updateVisibility() LL_INFOS() << "PA: " << getPositionAgent() << LL_ENDL; /*LL_INFOS() << "SPA: " << sel_pos_agent << LL_ENDL; LL_INFOS() << "WPA: " << wrist_right_pos_agent << LL_ENDL;*/ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + + + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { LLViewerJointAttachment* attachment = iter->second; for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { if (LLViewerObject *attached_object = (*attachment_iter)) { - if (attached_object->mDrawable->isVisible()) + if (attached_object && attached_object->mDrawable->isVisible()) { LL_INFOS() << attachment->getName() << " visible" << LL_ENDL; } @@ -4926,6 +4933,11 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) return num_indices; } + if (mDrawable.isNull()) + { + return num_indices; + } + LLFace* face = mDrawable->getFace(0); bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); @@ -5098,7 +5110,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) { if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { - if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) + if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar()) { LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD); if (head_mesh) @@ -5108,7 +5120,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } } - if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar()) { LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY); if (upper_mesh) @@ -5118,7 +5130,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } - if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar()) { LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY); if (lower_mesh) @@ -5150,7 +5162,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) U32 LLVOAvatar::renderTransparent(BOOL first_pass) { U32 num_indices = 0; - if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) + if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) ) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT); @@ -5229,7 +5241,7 @@ U32 LLVOAvatar::renderRigid() gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); } - if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy) + if (isTextureVisible(TEX_EYES_BAKED) || isUIAvatar()) { LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT); LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT); @@ -5450,7 +5462,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set& ids) const if (imagep) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - if (texture_dict->mIsLocalTexture) + if (texture_dict && texture_dict->mIsLocalTexture) { ids.insert(imagep->getID()); } @@ -5609,8 +5621,8 @@ void LLVOAvatar::updateTextures() if (imagep) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (texture_dict->mIsLocalTexture) + const EBakedTextureIndex baked_index = texture_dict ? texture_dict->mBakedTextureIndex : EBakedTextureIndex::BAKED_NUM_INDICES; + if (texture_dict && texture_dict->mIsLocalTexture) { addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, mBakedTextureDatas[baked_index].mIsUsed); } @@ -5862,7 +5874,7 @@ void LLVOAvatar::processAnimationStateChanges() startMotion(ANIM_AGENT_WALK_ADJUST); stopMotion(ANIM_AGENT_FLY_ADJUST); } - else if (mInAir && !mIsSitting) + else if (mInAir && !isSitting()) { stopMotion(ANIM_AGENT_WALK_ADJUST); startMotion(ANIM_AGENT_FLY_ADJUST); @@ -6293,7 +6305,7 @@ bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id) LLVOVolume* pVObj = pVO->mDrawable->getVOVolume(); if ( pVObj ) { - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj ); + const LLMeshSkinInfo* pSkinData = pVObj->getSkinInfo(); if (pSkinData && pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig && pSkinData->mAlternateBindMatrix.size() > 0 ) @@ -6721,7 +6733,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age LLVector3d z_vec(0.0f, 0.0f, 1.0f); LLVector3d p0_global, p1_global; - if (mIsDummy) + if (isUIAvatar()) { outNorm.setVec(z_vec); out_pos_agent = in_pos_agent; @@ -6750,7 +6762,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- F32 LLVOAvatar::getPixelArea() const { - if (mIsDummy) + if (isUIAvatar()) { return 100000.f; } @@ -6801,6 +6813,7 @@ BOOL LLVOAvatar::loadSkeletonNode () return TRUE; } + //----------------------------------------------------------------------------- // initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. //----------------------------------------------------------------------------- @@ -7181,7 +7194,7 @@ namespace LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState()); // This should never happen unless the server didn't process the attachment point // correctly, but putting this check in here to be safe. @@ -7438,7 +7451,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) //----------------------------------------------------------------------------- void LLVOAvatar::sitDown(BOOL bSitting) { - if (mIsSitting != bSitting) mIdleTimer.reset(); // Sitting changed, not idle + if (isSitting() != bSitting) mIdleTimer.reset(); // Sitting changed, not idle mIsSitting = bSitting; if (isSelf()) { @@ -9589,14 +9602,14 @@ void LLVOAvatar::cullAvatarsByPixelArea() if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame { sUnbakedUpdateTime = gFrameTimeSeconds; - sUnbakedTime += gFrameIntervalSeconds; + sUnbakedTime += gFrameIntervalSeconds.value(); } if (grey_avatars > 0) { if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame { sGreyUpdateTime = gFrameTimeSeconds; - sGreyTime += gFrameIntervalSeconds; + sGreyTime += gFrameIntervalSeconds.value(); } } } @@ -9777,7 +9790,7 @@ void LLVOAvatar::updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const bind_shape_matrix.affineTransform(v, t); final_mat.affineTransform(t, pos[j]); - pos[j].add(av_pos); + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. if (norm) { @@ -9798,10 +9811,10 @@ U32 LLVOAvatar::getPartitionType() const //static void LLVOAvatar::updateImpostors() { - LLCharacter::sAllowInstancesChange = FALSE ; - - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + std::vector instances_copy = LLCharacter::sInstances; + for (std::vector::iterator iter = instances_copy.begin(); + iter != instances_copy.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) @@ -9809,8 +9822,6 @@ void LLVOAvatar::updateImpostors() gPipeline.generateImpostor(avatar); } } - - LLCharacter::sAllowInstancesChange = TRUE ; } BOOL LLVOAvatar::isImpostor() const @@ -9995,12 +10006,11 @@ void LLVOAvatar::calculateUpdateRenderCost() for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) { LLUUID image_id = it->first; - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) + if( ! (image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + && (all_textures.find(image_id) == all_textures.end())) { // attachment texture not previously seen. - LL_INFOS() << "attachment_texture: " << image_id.asString() << LL_ENDL; + LL_DEBUGS("ARCdetail") << "attachment_texture: " << image_id.asString() << LL_ENDL; all_textures.insert(image_id); } } @@ -10020,7 +10030,7 @@ void LLVOAvatar::calculateUpdateRenderCost() continue; if (all_textures.find(image_id) == all_textures.end()) { - LL_INFOS() << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; + LL_DEBUGS("ARCdetail") << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; all_textures.insert(image_id); } } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f8451604b..5fdd4126f 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -248,7 +248,7 @@ public: void dumpAnimationState(); virtual LLJoint* getJoint(const std::string &name); - LLJoint* getJoint(S32 num); + LLJoint* getJoint(S32 num); void addAttachmentOverridesForObject(LLViewerObject *vo); void resetJointsOnDetach(const LLUUID& mesh_id); @@ -283,6 +283,7 @@ public: public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + virtual bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user) private: //aligned members LL_ALIGN_16(LLVector4a mImpostorExtents[2]); @@ -336,13 +337,13 @@ public: static U32 sMaxVisible; //(affected by control "RenderAvatarMaxVisible") static F32 sRenderDistance; //distance at which avatars will render. static BOOL sShowAnimationDebug; // show animation debug info - static BOOL sUseImpostors; //use impostors for far away avatars - static BOOL sShowFootPlane; // show foot collision plane reported by server - static BOOL sVisibleInFirstPerson; + static bool sUseImpostors; //use impostors for far away avatars + static bool sShowFootPlane; // show foot collision plane reported by server + static bool sVisibleInFirstPerson; static S32 sNumLODChangesThisFrame; static S32 sNumVisibleChatBubbles; static BOOL sDebugInvisible; - static BOOL sShowAttachmentPoints; + static bool sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar @@ -474,6 +475,8 @@ private: S32 mUpdatePeriod; S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. +public: + bool mIsUIAvatar; //-------------------------------------------------------------------- // Morph masks //-------------------------------------------------------------------- diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index f3ef19ee9..17acc11d9 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -260,6 +260,8 @@ void LLVOAvatarSelf::initInstance() doPeriodically(update_avatar_rez_metrics, 5.0); doPeriodically(check_for_unsupported_baked_appearance, 120.0); doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); + + mInitFlags |= 1<<2; } void LLVOAvatarSelf::setHoverIfRegionEnabled() @@ -609,6 +611,13 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) if (!jointp && mScreenp) { jointp = mScreenp->findJoint(name); + if (jointp) + { + joint_map_t::value_type entry; + strncpy(entry.first, name.c_str(), sizeof(entry.first)); + entry.second = jointp; + mJointMap.emplace_back(entry); + } } return jointp; @@ -3107,7 +3116,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam() // don't render selection beam on hud objects is_touching_or_grabbing = FALSE; } - return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); + return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); } void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index ad7efbf21..26e73c85b 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -103,7 +103,7 @@ LLVOGrass::~LLVOGrass() void LLVOGrass::updateSpecies() { - mSpecies = mState; + mSpecies = getAttachmentState(); if (!sSpeciesTable.count(mSpecies)) { diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 9d5f1c942..e96e2ec16 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -53,7 +53,7 @@ const F32 MAX_PART_LIFETIME = 120.f; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; LLPointer LLVOPartGroup::sVB = NULL; S32 LLVOPartGroup::sVBSlotFree[]; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 359d963c4..385a9e5bf 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -480,7 +480,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num, 1024); S32 result = unpackTEMessage(tdp); if (result & teDirtyBits) { @@ -969,13 +969,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo // if it's a mesh if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { //meshes might not have all LODs, get the force detail to best existing LOD - LLUUID mesh_id = volume_params.getSculptID(); - - lod = gMeshRepo.getActualMeshLOD(volume_params, lod); - if (lod == -1) + if (NO_LOD != lod) { - is404 = TRUE; - lod = 0; + lod = gMeshRepo.getActualMeshLOD(volume_params, lod); + if (lod == -1) + { + is404 = TRUE; + lod = 0; + } } } } @@ -1207,18 +1208,18 @@ void LLVOVolume::sculpt() } } -S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) +S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius, F32 lod_factor) { S32 cur_detail; if (LLPipeline::sDynamicLOD) { // We've got LOD in the profile, and in the twist. Use radius. - F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; + F32 tan_angle = (lod_factor*radius)/distance; cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); } else { - cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); + cur_detail = llclamp((S32) (sqrtf(radius)*lod_factor*4.f), 0, 3); } return cur_detail; } @@ -1234,10 +1235,16 @@ BOOL LLVOVolume::calcLOD() F32 radius; F32 distance; + F32 lod_factor = LLVOVolume::sLODFactor; if (mDrawable->isState(LLDrawable::RIGGED) && getAvatar() && getAvatar()->mDrawable) { LLVOAvatar* avatar = getAvatar(); + // Not sure how this can really happen, but alas it does. Better exit here than crashing. + if( !avatar || !avatar->mDrawable ) + { + return FALSE; + } distance = avatar->mDrawable->mDistanceWRTCamera; radius = avatar->getBinRadius(); } @@ -1261,8 +1268,16 @@ BOOL LLVOVolume::calcLOD() // DON'T Compensate for field of view changing on FOV zoom. distance *= F_PI/3.f; - cur_detail = computeLODDetail(ll_round(distance, 0.01f), - ll_round(radius, 0.01f)); + + if (isHUDAttachment()) + { + // HUDs always show at highest detail + cur_detail = 3; + } + else + { + cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor); + } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) && @@ -1279,10 +1294,7 @@ BOOL LLVOVolume::calcLOD() mLOD = cur_detail; return TRUE; } - else - { - return FALSE; - } + return FALSE; } BOOL LLVOVolume::updateLOD() @@ -1372,7 +1384,8 @@ void LLVOVolume::updateFaceFlags() BOOL LLVOVolume::setParent(LLViewerObject* parent) { BOOL ret = FALSE ; - if (parent != getParent()) + LLViewerObject *old_parent = (LLViewerObject*) getParent(); + if (parent != old_parent) { ret = LLViewerObject::setParent(parent); if (ret && mDrawable) @@ -1380,6 +1393,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent) gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } + onReparent(old_parent, parent); } return ret ; @@ -2458,7 +2472,9 @@ void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; impl->setMediaFailed(true); } - else { + // Make sure we are not bouncing to url we came from + else if (impl->getCurrentMediaURL() != url) + { // Okay, navigate now LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; impl->navigateTo(url, "", false, true); @@ -3202,6 +3218,23 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible) return res; } +const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const +{ + if (getVolume()) + { + return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); + } + else + { + return NULL; + } +} + +// virtual +BOOL LLVOVolume::isRiggedMesh() const +{ + return isMesh() && getSkinInfo(); +} //---------------------------------------------------------------------------- void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) @@ -3263,7 +3296,7 @@ void LLVOVolume::updateRadius() BOOL LLVOVolume::isAttachment() const { - return mState != 0 ; + return mAttachmentState != 0 ; } BOOL LLVOVolume::isHUDAttachment() const @@ -3271,7 +3304,7 @@ BOOL LLVOVolume::isHUDAttachment() const // *NOTE: we assume hud attachment points are in defined range // since this range is constant for backwards compatibility // reasons this is probably a reasonable assumption to make - S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); + S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState); return ( attachment_id >= 31 && attachment_id <= 38 ); } @@ -3644,10 +3677,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u void LLVOVolume::setSelected(BOOL sel) { LLViewerObject::setSelected(sel); - if (mDrawable.notNull()) - { - markForUpdate(TRUE); - } + if (isAnimatedObject()) + { + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + else + { + if (mDrawable.notNull()) + { + markForUpdate(TRUE); + } + } } void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -3756,6 +3796,12 @@ const LLMatrix4a& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const return xform->getWorldMatrix(); } +void LLVOVolume::markForUpdate(BOOL priority) +{ + LLViewerObject::markForUpdate(priority); + mVolumeChanged = TRUE; +} + LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { LLVector3 ret = pos - getRenderPosition(); @@ -4016,7 +4062,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& bool LLVOVolume::treatAsRigged() { return (gFloaterTools->getVisible() || LLFloaterInspect::findInstance()) && - isAttachment() && + (isAttachment() || isAnimatedObject()) && mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED); } @@ -4048,9 +4094,7 @@ void LLVOVolume::updateRiggedVolume(bool force_update) } LLVolume* volume = getVolume(); - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this); - + const LLMeshSkinInfo* skin = getSkinInfo(); if (!skin) { clearRiggedVolume(); @@ -4149,7 +4193,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons bind_shape_matrix.affineTransform(v, t); final_mat.affineTransform(t, pos[j]); - pos[j].add(av_pos); + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. } //update bounding box @@ -5500,9 +5544,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) + if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj->isNoLOD()) continue; + vobj->preRebuild(); if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 6dea71981..9bf1052ef 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -142,6 +142,8 @@ public: void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); /*virtual*/ BOOL setParent(LLViewerObject* parent); S32 getLOD() const { return mLOD; } + void setNoLOD() { mLOD = NO_LOD; mLODChanged = TRUE; } + bool isNoLOD() const { return NO_LOD == mLOD; } const LLVector3 getPivotPositionAgent() const; const LLMatrix4a& getRelativeXform() const { return mRelativeXform; } const LLMatrix4a& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } @@ -173,8 +175,8 @@ public: /*virtual*/ F32 getRadius() const { return mVObjRadius; }; const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const; - void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; } - void faceMappingChanged() { mFaceMappingChanged=TRUE; }; + void markForUpdate(BOOL priority); + void faceMappingChanged() { mFaceMappingChanged=TRUE; }; /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts @@ -273,13 +275,14 @@ public: virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; virtual BOOL isMesh() const; + virtual BOOL isRiggedMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); - + const LLMeshSkinInfo* getSkinInfo() const; // Functions that deal with media, or media navigation // Update this object's media data with the given media data array @@ -345,7 +348,7 @@ public: void clearRiggedVolume(); protected: - S32 computeLODDetail(F32 distance, F32 radius); + S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor); BOOL calcLOD(); LLFace* addFace(S32 face_index); void updateTEData(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index fdd105270..4e94ce3b2 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -769,6 +769,17 @@ void LLWorld::updateRegions(F32 max_update_time) } } + +void LLWorld::clearAllVisibleObjects() +{ + for (region_list_t::iterator iter = mRegionList.begin(); + iter != mRegionList.end(); ++iter) + { + //clear all cached visible objects. + (*iter)->clearCachedVisibleObjects(); + } +} + void LLWorld::updateParticles() { static const LLCachedControl freeze_time("FreezeTime",false); @@ -842,7 +853,6 @@ LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff) } #endif - void LLWorld::renderPropertyLines() { S32 region_count = 0; diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index fa65c364a..1620a9241 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -157,6 +157,7 @@ public: void getInfo(LLSD& info); + void clearAllVisibleObjects(); public: typedef std::list region_list_t; const region_list_t& getRegionList() const { return mActiveRegionList; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 8520ce150..3a34dd8f5 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -10576,11 +10576,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->setImpostorDim(tdim); - LLVOAvatar::sUseImpostors = TRUE; + LLVOAvatar::sUseImpostors = true; sUseOcclusion = occlusion; - sReflectionRender = FALSE; - sImpostorRender = FALSE; - sShadowRender = FALSE; + sReflectionRender = false; + sImpostorRender = false; + sShadowRender = false; popRenderTypeMask(); gGL.matrixMode(LLRender::MM_PROJECTION); diff --git a/indra/newview/rlvhelper.cpp b/indra/newview/rlvhelper.cpp index 92055cbde..fcffd476a 100644 --- a/indra/newview/rlvhelper.cpp +++ b/indra/newview/rlvhelper.cpp @@ -370,7 +370,7 @@ RlvObject::RlvObject(const LLUUID& idObj) : m_idObj(idObj), m_nLookupMisses(0) { LLViewerObject* pObj = gObjectList.findObject(idObj); m_fLookup = (NULL != pObj); - m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; + m_idxAttachPt = (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; m_idRoot = (pObj) ? pObj->getRootEdit()->getID() : LLUUID::null; } diff --git a/indra/newview/rlvlocks.h b/indra/newview/rlvlocks.h index 396496290..854144bee 100644 --- a/indra/newview/rlvlocks.h +++ b/indra/newview/rlvlocks.h @@ -422,7 +422,7 @@ inline S32 RlvAttachPtLookup::getAttachPointIndex(std::string strText) // Checked: 2010-03-03 (RLVa-1.2.0a) | Modified: RLVa-0.2.0d inline S32 RlvAttachPtLookup::getAttachPointIndex(const LLViewerObject* pObj) { - return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getState()) : 0; + return (pObj) ? ATTACHMENT_ID_FROM_STATE(pObj->getAttachmentState()) : 0; } // ============================================================================ diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml index fb7ba092d..5d208a06a 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml @@ -38,9 +38,11 @@ + +