llviewerobject.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:132k
- /**
- * @file llviewerobject.cpp
- * @brief Base class for viewer objects
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llviewerobject.h"
- #include "llaudioengine.h"
- #include "imageids.h"
- #include "indra_constants.h"
- #include "llmath.h"
- #include "llflexibleobject.h"
- #include "llviewercontrol.h"
- #include "lldatapacker.h"
- #include "llfasttimer.h"
- #include "llfloaterreg.h"
- #include "llfontgl.h"
- #include "llframetimer.h"
- #include "llinventory.h"
- #include "llmaterialtable.h"
- #include "llmutelist.h"
- #include "llnamevalue.h"
- #include "llprimitive.h"
- #include "llquantize.h"
- #include "llregionhandle.h"
- #include "lltree_common.h"
- #include "llxfermanager.h"
- #include "message.h"
- #include "object_flags.h"
- #include "timing.h"
- #include "llaudiosourcevo.h"
- #include "llagent.h"
- #include "llbbox.h"
- #include "llbox.h"
- #include "llcylinder.h"
- #include "lldrawable.h"
- #include "llface.h"
- #include "llfloaterproperties.h"
- #include "llfollowcam.h"
- #include "llselectmgr.h"
- #include "llrendersphere.h"
- #include "lltooldraganddrop.h"
- #include "llviewercamera.h"
- #include "llviewertexturelist.h"
- #include "llviewerinventory.h"
- #include "llviewerobjectlist.h"
- #include "llviewerparceloverlay.h"
- #include "llviewerpartsource.h"
- #include "llviewerregion.h"
- #include "llviewertextureanim.h"
- #include "llviewerwindow.h" // For getSpinAxis
- #include "llvoavatar.h"
- #include "llvoavatarself.h"
- #include "llvoclouds.h"
- #include "llvograss.h"
- #include "llvoground.h"
- #include "llvolume.h"
- #include "llvolumemessage.h"
- #include "llvopartgroup.h"
- #include "llvosky.h"
- #include "llvosurfacepatch.h"
- #include "llvotextbubble.h"
- #include "llvotree.h"
- #include "llvovolume.h"
- #include "llvowater.h"
- #include "llworld.h"
- #include "llui.h"
- #include "pipeline.h"
- #include "llviewernetwork.h"
- #include "llvowlsky.h"
- #include "llmanip.h"
- #include "lltrans.h"
- #include "llsdutil.h"
- #include "llmediaentry.h"
- //#define DEBUG_UPDATE_TYPE
- BOOL gVelocityInterpolate = TRUE;
- BOOL gPingInterpolate = TRUE;
- U32 LLViewerObject::sNumZombieObjects = 0;
- S32 LLViewerObject::sNumObjects = 0;
- BOOL LLViewerObject::sMapDebug = TRUE;
- LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK
- LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit
- S32 LLViewerObject::sAxisArrowLength(50);
- BOOL LLViewerObject::sPulseEnabled(FALSE);
- BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
- static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object");
- // static
- LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
- {
- LLViewerObject *res = NULL;
- LLFastTimer t1(FTM_CREATE_OBJECT);
-
- switch (pcode)
- {
- case LL_PCODE_VOLUME:
- res = new LLVOVolume(id, pcode, regionp); break;
- case LL_PCODE_LEGACY_AVATAR:
- {
- if (id == gAgentID)
- {
- res = new LLVOAvatarSelf(id, pcode, regionp);
- }
- else
- {
- res = new LLVOAvatar(id, pcode, regionp);
- }
- static_cast<LLVOAvatar*>(res)->initInstance();
- break;
- }
- case LL_PCODE_LEGACY_GRASS:
- res = new LLVOGrass(id, pcode, regionp); break;
- case LL_PCODE_LEGACY_PART_SYS:
- // llwarns << "Creating old part sys!" << llendl;
- // res = new LLVOPart(id, pcode, regionp); break;
- res = NULL; break;
- case LL_PCODE_LEGACY_TREE:
- res = new LLVOTree(id, pcode, regionp); break;
- case LL_PCODE_TREE_NEW:
- // llwarns << "Creating new tree!" << llendl;
- // res = new LLVOTree(id, pcode, regionp); break;
- res = NULL; break;
- case LL_PCODE_LEGACY_TEXT_BUBBLE:
- res = new LLVOTextBubble(id, pcode, regionp); break;
- case LL_VO_CLOUDS:
- res = new LLVOClouds(id, pcode, regionp); break;
- case LL_VO_SURFACE_PATCH:
- res = new LLVOSurfacePatch(id, pcode, regionp); break;
- case LL_VO_SKY:
- res = new LLVOSky(id, pcode, regionp); break;
- case LL_VO_WATER:
- res = new LLVOWater(id, pcode, regionp); break;
- case LL_VO_GROUND:
- res = new LLVOGround(id, pcode, regionp); break;
- case LL_VO_PART_GROUP:
- res = new LLVOPartGroup(id, pcode, regionp); break;
- case LL_VO_HUD_PART_GROUP:
- res = new LLVOHUDPartGroup(id, pcode, regionp); break;
- case LL_VO_WL_SKY:
- res = new LLVOWLSky(id, pcode, regionp); break;
- default:
- llwarns << "Unknown object pcode " << (S32)pcode << llendl;
- res = NULL; break;
- }
- return res;
- }
- LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global)
- : LLPrimitive(),
- mChildList(),
- mID(id),
- mLocalID(0),
- mTotalCRC(0),
- mTEImages(NULL),
- mGLName(0),
- mbCanSelect(TRUE),
- mFlags(0),
- mDrawable(),
- mCreateSelected(FALSE),
- mRenderMedia(FALSE),
- mBestUpdatePrecision(0),
- mText(),
- mLastInterpUpdateSecs(0.f),
- mLastMessageUpdateSecs(0.f),
- mLatestRecvPacketID(0),
- mData(NULL),
- mAudioSourcep(NULL),
- mAudioGain(1.f),
- mAppAngle(0.f),
- mPixelArea(1024.f),
- mInventory(NULL),
- mInventorySerialNum(0),
- mRegionp( regionp ),
- mInventoryPending(FALSE),
- mInventoryDirty(FALSE),
- mDead(FALSE),
- mOrphaned(FALSE),
- mUserSelected(FALSE),
- mOnActiveList(FALSE),
- mOnMap(FALSE),
- mStatic(FALSE),
- mNumFaces(0),
- mTimeDilation(1.f),
- mRotTime(0.f),
- mJointInfo(NULL),
- mState(0),
- mMedia(NULL),
- mClickAction(0),
- mAttachmentItemID(LLUUID::null)
- {
- if(!is_global)
- {
- llassert(mRegionp);
- }
- LLPrimitive::init_primitive(pcode);
- // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time
- mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
- mPositionRegion = LLVector3(0.f, 0.f, 0.f);
- if(!is_global)
- {
- mPositionAgent = mRegionp->getOriginAgent();
- }
- LLViewerObject::sNumObjects++;
- }
- LLViewerObject::~LLViewerObject()
- {
- deleteTEImages();
- if(mInventory)
- {
- mInventory->clear(); // will deref and delete entries
- delete mInventory;
- mInventory = NULL;
- }
- if (mJointInfo)
- {
- delete mJointInfo;
- mJointInfo = NULL;
- }
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- // Delete memory associated with extra parameters.
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if(iter->second != NULL)
- {
- delete iter->second->data;
- delete iter->second;
- }
- }
- mExtraParameterList.clear();
- for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
- mNameValuePairs.clear();
-
- delete[] mData;
- mData = NULL;
- delete mMedia;
- mMedia = NULL;
- sNumObjects--;
- sNumZombieObjects--;
- llassert(mChildList.size() == 0);
- clearInventoryListeners();
- }
- void LLViewerObject::deleteTEImages()
- {
- delete[] mTEImages;
- mTEImages = NULL;
- }
- void LLViewerObject::markDead()
- {
- if (!mDead)
- {
- //llinfos << "Marking self " << mLocalID << " as dead." << llendl;
-
- // Root object of this hierarchy unlinks itself.
- if (getParent())
- {
- ((LLViewerObject *)getParent())->removeChild(this);
- // go ahead and delete any jointinfo's that we find
- delete mJointInfo;
- mJointInfo = NULL;
- }
- // Mark itself as dead
- mDead = TRUE;
- gObjectList.cleanupReferences(this);
- LLViewerObject *childp;
- while (mChildList.size() > 0)
- {
- childp = mChildList.back();
- if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
- {
- //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;
- childp->setParent(NULL); // LLViewerObject::markDead 1
- childp->markDead();
- }
- else
- {
- // make sure avatar is no longer parented,
- // so we can properly set it's position
- childp->setDrawableParent(NULL);
- ((LLVOAvatar*)childp)->getOffObject();
- childp->setParent(NULL); // LLViewerObject::markDead 2
- }
- mChildList.pop_back();
- }
- if (mDrawable.notNull())
- {
- // Drawables are reference counted, mark as dead, then nuke the pointer.
- mDrawable->markDead();
- mDrawable = NULL;
- }
- if (mText)
- {
- mText->markDead();
- mText = NULL;
- }
- if (mIcon)
- {
- mIcon->markDead();
- mIcon = NULL;
- }
- if (mPartSourcep)
- {
- mPartSourcep->setDead();
- mPartSourcep = NULL;
- }
- if (mAudioSourcep)
- {
- // Do some cleanup
- if (gAudiop)
- {
- gAudiop->cleanupAudioSource(mAudioSourcep);
- }
- mAudioSourcep = NULL;
- }
- if (flagAnimSource())
- {
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (avatarp && !avatarp->isDead())
- {
- // stop motions associated with this object
- avatarp->stopMotionFromSource(mID);
- }
- }
- if (flagCameraSource())
- {
- LLFollowCamMgr::removeFollowCamParams(mID);
- }
- sNumZombieObjects++;
- }
- }
- void LLViewerObject::dump() const
- {
- llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl;
- llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl;
- llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl;
- llinfos << "Parent: " << getParent() << llendl;
- llinfos << "ID: " << mID << llendl;
- llinfos << "LocalID: " << mLocalID << llendl;
- llinfos << "PositionRegion: " << getPositionRegion() << llendl;
- llinfos << "PositionAgent: " << getPositionAgent() << llendl;
- llinfos << "PositionGlobal: " << getPositionGlobal() << llendl;
- llinfos << "Velocity: " << getVelocity() << llendl;
- if (mDrawable.notNull() && mDrawable->getNumFaces())
- {
- LLFacePool *poolp = mDrawable->getFace(0)->getPool();
- if (poolp)
- {
- llinfos << "Pool: " << poolp << llendl;
- llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl;
- }
- }
- //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl;
- //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl;
- /*
- llinfos << "Velocity: " << getVelocity() << llendl;
- llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl;
- llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl;
- llinfos << "AppAngle: " << mAppAngle << llendl;
- llinfos << "PixelArea: " << mPixelArea << llendl;
- char buffer[1000];
- char *key;
- for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() )
- {
- mNameValuePairs[key]->printNameValue(buffer);
- llinfos << buffer << llendl;
- }
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- llinfos << " child " << child->getID() << llendl;
- }
- */
- }
- void LLViewerObject::printNameValuePairs() const
- {
- for (name_value_map_t::const_iterator iter = mNameValuePairs.begin();
- iter != mNameValuePairs.end(); iter++)
- {
- LLNameValue* nv = iter->second;
- llinfos << nv->printNameValue() << llendl;
- }
- }
- void LLViewerObject::initVOClasses()
- {
- // Initialized shared class stuff first.
- LLVOAvatar::initClass();
- LLVOTree::initClass();
- if (gNoRender)
- {
- // Don't init anything else in drone mode
- return;
- }
- llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl;
- LLVOGrass::initClass();
- LLVOWater::initClass();
- LLVOSky::initClass();
- LLVOVolume::initClass();
- }
- void LLViewerObject::cleanupVOClasses()
- {
- LLVOGrass::cleanupClass();
- LLVOWater::cleanupClass();
- LLVOTree::cleanupClass();
- LLVOAvatar::cleanupClass();
- LLVOVolume::cleanupClass();
- }
- // Replaces all name value pairs with data from n delimited list
- // Does not update server
- void LLViewerObject::setNameValueList(const std::string& name_value_list)
- {
- // Clear out the old
- for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
- mNameValuePairs.clear();
- // Bring in the new
- std::string::size_type length = name_value_list.length();
- std::string::size_type start = 0;
- while (start < length)
- {
- std::string::size_type end = name_value_list.find_first_of("n", start);
- if (end == std::string::npos) end = length;
- if (end > start)
- {
- std::string tok = name_value_list.substr(start, end - start);
- addNVPair(tok);
- }
- start = end+1;
- }
- }
- // This method returns true if the object is over land owned by the
- // agent.
- BOOL LLViewerObject::isOverAgentOwnedLand() const
- {
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedSelf(getPositionRegion());
- }
- // This method returns true if the object is over land owned by the
- // agent.
- BOOL LLViewerObject::isOverGroupOwnedLand() const
- {
- return mRegionp
- && mRegionp->getParcelOverlay()
- && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion());
- }
- BOOL LLViewerObject::setParent(LLViewerObject* parent)
- {
- if(mParent != parent)
- {
- LLViewerObject* old_parent = (LLViewerObject*)mParent ;
- BOOL ret = LLPrimitive::setParent(parent);
- if(ret && old_parent && parent)
- {
- old_parent->removeChild(this) ;
- }
- return ret ;
- }
- return FALSE ;
- }
- void LLViewerObject::addChild(LLViewerObject *childp)
- {
- for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
- {
- if (*i == childp)
- { //already has child
- return;
- }
- }
-
- if (!isAvatar())
- {
- // propagate selection properties
- childp->mbCanSelect = mbCanSelect;
- }
- if(childp->setParent(this))
- {
- mChildList.push_back(childp);
- }
- }
- void LLViewerObject::removeChild(LLViewerObject *childp)
- {
- for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
- {
- if (*i == childp)
- {
- if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar())
- {
- gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME);
- }
- mChildList.erase(i);
- if(childp->getParent() == this)
- {
- childp->setParent(NULL);
- }
- break;
- }
- }
-
- if (childp->isSelected())
- {
- LLSelectMgr::getInstance()->deselectObjectAndFamily(childp);
- BOOL add_to_end = TRUE;
- LLSelectMgr::getInstance()->selectObjectAndFamily(childp, add_to_end);
- }
- }
- void LLViewerObject::addThisAndAllChildren(std::vector<LLViewerObject*>& objects)
- {
- objects.push_back(this);
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if (!child->isAvatar())
- {
- child->addThisAndAllChildren(objects);
- }
- }
- }
- void LLViewerObject::addThisAndNonJointChildren(std::vector<LLViewerObject*>& objects)
- {
- objects.push_back(this);
- // don't add any attachments when temporarily selecting avatar
- if (isAvatar())
- {
- return;
- }
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if ( (!child->isAvatar()) && (!child->isJointChild()))
- {
- child->addThisAndNonJointChildren(objects);
- }
- }
- }
- BOOL LLViewerObject::isChild(LLViewerObject *childp) const
- {
- for (child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* testchild = *iter;
- if (testchild == childp)
- return TRUE;
- }
- return FALSE;
- }
- // returns TRUE if at least one avatar is sitting on this object
- BOOL LLViewerObject::isSeat() const
- {
- for (child_list_t::const_iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if (child->isAvatar())
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp)
- {
- if (mDrawable.isNull())
- {
- return FALSE;
- }
- BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
- if(!ret)
- {
- return FALSE ;
- }
- LLDrawable* old_parent = mDrawable->mParent;
- mDrawable->mParent = parentp;
-
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
- if( (old_parent != parentp && old_parent)
- || (parentp && parentp->isActive()))
- {
- // *TODO we should not be relying on setDrawable parent to call markMoved
- gPipeline.markMoved(mDrawable, FALSE);
- }
- else if (!mDrawable->isAvatar())
- {
- mDrawable->updateXform(TRUE);
- /*if (!mDrawable->getSpatialGroup())
- {
- mDrawable->movePartition();
- }*/
- }
-
- return ret;
- }
- // Show or hide particles, icon and HUD
- void LLViewerObject::hideExtraDisplayItems( BOOL hidden )
- {
- if( mPartSourcep.notNull() )
- {
- LLViewerPartSourceScript *partSourceScript = mPartSourcep.get();
- partSourceScript->setSuspended( hidden );
- }
- if( mText.notNull() )
- {
- LLHUDText *hudText = mText.get();
- hudText->setHidden( hidden );
- }
- if( mIcon.notNull() )
- {
- LLHUDIcon *hudIcon = mIcon.get();
- hudIcon->setHidden( hidden );
- }
- }
- U32 LLViewerObject::checkMediaURL(const std::string &media_url)
- {
- U32 retval = (U32)0x0;
- if (!mMedia && !media_url.empty())
- {
- retval |= MEDIA_URL_ADDED;
- mMedia = new LLViewerObjectMedia;
- mMedia->mMediaURL = media_url;
- mMedia->mMediaType = LLViewerObject::MEDIA_SET;
- mMedia->mPassedWhitelist = FALSE;
- }
- else if (mMedia)
- {
- if (media_url.empty())
- {
- 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))
- */
- {
- // 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,
- void **user_data,
- U32 block_num,
- const EObjectUpdateType update_type,
- LLDataPacker *dp)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
- U32 retval = 0x0;
-
- // Coordinates of objects on simulators are region-local.
- U64 region_handle;
- mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
- mRegionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
- if (!mRegionp)
- {
- U32 x, y;
- from_region_handle(region_handle, &x, &y);
- llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl;
- return retval;
- }
- U16 time_dilation16;
- mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16);
- F32 time_dilation = ((F32) time_dilation16) / 65535.f;
- mTimeDilation = time_dilation;
- mRegionp->setTimeDilation(time_dilation);
- // this will be used to determine if we've really changed position
- // Use getPosition, not getPositionRegion, since this is what we're comparing directly against.
- LLVector3 test_pos_parent = getPosition();
- U8 data[60+16]; // This needs to match the largest size below.
- #ifdef LL_BIG_ENDIAN
- U16 valswizzle[4];
- #endif
- U16 *val;
- const F32 size = LLWorld::getInstance()->getRegionWidthInMeters();
- const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight();
- const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight();
- S32 length;
- S32 count;
- S32 this_update_precision = 32; // in bits
- // Temporaries, because we need to compare w/ previous to set dirty flags...
- LLVector3 new_pos_parent;
- LLVector3 new_vel;
- LLVector3 new_acc;
- LLVector3 new_angv;
- LLVector3 old_angv = getAngularVelocity();
- LLQuaternion new_rot;
- LLVector3 new_scale = getScale();
- U32 parent_id = 0;
- U8 material = 0;
- U8 click_action = 0;
- U32 crc = 0;
- bool old_special_hover_cursor = specialHoverCursor();
- LLViewerObject *cur_parentp = (LLViewerObject *)getParent();
- if (cur_parentp)
- {
- parent_id = cur_parentp->mLocalID;
- }
- if (!dp)
- {
- switch(update_type)
- {
- case OUT_FULL:
- {
- #ifdef DEBUG_UPDATE_TYPE
- llinfos << "Full:" << getID() << llendl;
- #endif
- LLUUID audio_uuid;
- LLUUID owner_id; // only valid if audio_uuid or particle system is not null
- F32 gain;
- U8 sound_flags;
- mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num);
- mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num);
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num );
- // HACK: Owner id only valid if non-null sound id or particle system
- mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num );
- 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->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num );
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
- mTotalCRC = crc;
- // Owner ID used for sound muting or particle system muting
- setAttachedSound(audio_uuid, owner_id, gain, sound_flags);
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- setClickAction(click_action);
- count = 0;
- LLVector4 collision_plane;
-
- switch(length)
- {
- case (60 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 60:
- this_update_precision = 32;
- // this is a terse update
- // pos
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // vel
- htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // acc
- htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // theta
- {
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- }
- count += sizeof(LLVector3);
- // omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- #if LL_DARWIN
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
- #endif
- break;
- case(32 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 32:
- this_update_precision = 16;
- test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
- // This is a terse 16 update, so treat data as an array of U16's.
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
- 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);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- setVelocity(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size)));
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size)));
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- new_angv.setVec(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- break;
- case 16:
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
- // this is a terse 8 update
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size) );
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size) );
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
- new_angv.setVec(U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size) );
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- break;
- }
- ////////////////////////////////////////////////////
- //
- // Here we handle data specific to the full message.
- //
- U32 flags;
- mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
- // clear all but local flags
- mFlags &= FLAGS_LOCAL;
- mFlags |= flags;
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
- // ...new objects that should come in selected need to be added to the selected list
- mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
- // Set all name value pairs
- S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue);
- if (nv_size > 0)
- {
- std::string name_value_list;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, name_value_list, block_num);
- setNameValueList(name_value_list);
- }
- // Clear out any existing generic data
- if (mData)
- {
- delete [] mData;
- }
- // Check for appended generic data
- S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data);
- if (data_size <= 0)
- {
- mData = NULL;
- }
- else
- {
- // ...has generic data
- mData = new U8[data_size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num);
- }
- S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text);
- if (text_size > 1)
- {
- // 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());
- }
- std::string temp_string;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num );
-
- LLColor4U coloru;
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num);
- // alpha was flipped so that it zero encoded better
- coloru.mV[3] = 255 - coloru.mV[3];
- mText->setColor(LLColor4(coloru));
- mText->setStringUTF8(temp_string);
-
- if (mDrawable.notNull())
- {
- setChanged(MOVED | SILHOUETTE);
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- else if (mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
- std::string media_url;
- mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num);
- retval |= checkMediaURL(media_url);
-
- //
- // Unpack particle system data
- //
- unpackParticleSource(block_num, owner_id);
- // Mark all extra parameters not used
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- iter->second->in_use = FALSE;
- }
- // Unpack extra parameters
- S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams);
- if (size > 0)
- {
- U8 *buffer = new U8[size];
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num);
- LLDataPackerBinaryBuffer dp(buffer, size);
- U8 num_parameters;
- dp.unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param=0; param<num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp.unpackU16(param_type, "param_type");
- dp.unpackBinaryData(param_block, param_size, "param_data");
- //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
- delete[] buffer;
- }
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if (!iter->second->in_use)
- {
- // Send an update message in case it was formerly in use
- parameterChanged(iter->first, iter->second->data, FALSE, false);
- }
- }
- U8 joint_type = 0;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num);
- if (joint_type)
- {
- // create new joint info
- if (!mJointInfo)
- {
- mJointInfo = new LLVOJointInfo;
- }
- mJointInfo->mJointType = (EHavokJointType) joint_type;
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num);
- mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num);
- }
- else if (mJointInfo)
- {
- // this joint info is no longer needed
- delete mJointInfo;
- mJointInfo = NULL;
- }
- break;
- }
- case OUT_TERSE_IMPROVED:
- {
- #ifdef DEBUG_UPDATE_TYPE
- llinfos << "TI:" << getID() << llendl;
- #endif
- length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
- mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
- count = 0;
- LLVector4 collision_plane;
-
- switch(length)
- {
- case(60 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 60:
- // this is a terse 32 update
- // pos
- this_update_precision = 32;
- htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // vel
- htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // acc
- htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- count += sizeof(LLVector3);
- // theta
- {
- LLVector3 vec;
- htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- new_rot.unpackFromVector3(vec);
- }
- count += sizeof(LLVector3);
- // omega
- htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
- if (new_angv.isExactlyZero())
- {
- // reset rotation time
- resetRot();
- }
- setAngularVelocity(new_angv);
- #if LL_DARWIN
- if (length == 76)
- {
- setAngularVelocity(LLVector3::zero);
- }
- #endif
- break;
- case(32 + 16):
- // pull out collision normal for avatar
- htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- count += sizeof(LLVector4);
- // fall through
- case 32:
- // this is a terse 16 update
- this_update_precision = 16;
- 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);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
- 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);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- setVelocity(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*3;
- setAcceleration(U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- count += sizeof(U16)*4;
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
- #ifdef LL_BIG_ENDIAN
- htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
- val = valswizzle;
- #else
- val = (U16 *) &data[count];
- #endif
- setAngularVelocity( U16_to_F32(val[VX], -size, size),
- U16_to_F32(val[VY], -size, size),
- U16_to_F32(val[VZ], -size, size));
- break;
- case 16:
- // this is a terse 8 update
- this_update_precision = 8;
- test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
- new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
- new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
- setVelocity(U8_to_F32(data[3], -size, size),
- U8_to_F32(data[4], -size, size),
- U8_to_F32(data[5], -size, size) );
- setAcceleration(U8_to_F32(data[6], -size, size),
- U8_to_F32(data[7], -size, size),
- U8_to_F32(data[8], -size, size) );
- new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
- new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
- new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
- new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
- setAngularVelocity( U8_to_F32(data[13], -size, size),
- U8_to_F32(data[14], -size, size),
- U8_to_F32(data[15], -size, size) );
- break;
- }
- U8 state;
- mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
- break;
- }
- default:
- break;
- }
- }
- else
- {
- // handle the compressed case
- LLUUID sound_uuid;
- LLUUID owner_id;
- F32 gain = 0;
- U8 sound_flags = 0;
- F32 cutoff = 0;
- U16 val[4];
- U8 state;
- dp->unpackU8(state, "State");
- mState = state;
- switch(update_type)
- {
- case OUT_TERSE_IMPROVED:
- {
- #ifdef DEBUG_UPDATE_TYPE
- llinfos << "CompTI:" << getID() << llendl;
- #endif
- U8 value;
- dp->unpackU8(value, "agent");
- if (value)
- {
- LLVector4 collision_plane;
- dp->unpackVector4(collision_plane, "Plane");
- ((LLVOAvatar*)this)->setFootPlane(collision_plane);
- }
- test_pos_parent = getPosition();
- dp->unpackVector3(new_pos_parent, "Pos");
- dp->unpackU16(val[VX], "VelX");
- dp->unpackU16(val[VY], "VelY");
- dp->unpackU16(val[VZ], "VelZ");
- setVelocity(U16_to_F32(val[VX], -128.f, 128.f),
- U16_to_F32(val[VY], -128.f, 128.f),
- U16_to_F32(val[VZ], -128.f, 128.f));
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- setAcceleration(U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
- dp->unpackU16(val[VX], "ThetaX");
- dp->unpackU16(val[VY], "ThetaY");
- dp->unpackU16(val[VZ], "ThetaZ");
- dp->unpackU16(val[VS], "ThetaS");
- new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
- new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
- new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
- new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f);
- dp->unpackU16(val[VX], "AccX");
- dp->unpackU16(val[VY], "AccY");
- dp->unpackU16(val[VZ], "AccZ");
- setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f),
- U16_to_F32(val[VY], -64.f, 64.f),
- U16_to_F32(val[VZ], -64.f, 64.f));
- }
- break;
- case OUT_FULL_COMPRESSED:
- case OUT_FULL_CACHED:
- {
- #ifdef DEBUG_UPDATE_TYPE
- llinfos << "CompFull:" << getID() << llendl;
- #endif
- dp->unpackU32(crc, "CRC");
- mTotalCRC = crc;
- dp->unpackU8(material, "Material");
- U8 old_material = getMaterial();
- if (old_material != material)
- {
- setMaterial(material);
- if (mDrawable.notNull())
- {
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- dp->unpackU8(click_action, "ClickAction");
- setClickAction(click_action);
- dp->unpackVector3(new_scale, "Scale");
- dp->unpackVector3(new_pos_parent, "Pos");
- LLVector3 vec;
- dp->unpackVector3(vec, "Rot");
- new_rot.unpackFromVector3(vec);
- setAcceleration(LLVector3::zero);
- U32 value;
- dp->unpackU32(value, "SpecialCode");
- dp->setPassFlags(value);
- dp->unpackUUID(owner_id, "Owner");
- if (value & 0x80)
- {
- dp->unpackVector3(vec, "Omega");
- setAngularVelocity(vec);
- }
- if (value & 0x20)
- {
- dp->unpackU32(parent_id, "ParentID");
- }
- else
- {
- parent_id = 0;
- }
- S32 sp_size;
- U32 size;
- if (value & 0x2)
- {
- sp_size = 1;
- delete [] mData;
- mData = new U8[1];
- dp->unpackU8(((U8*)mData)[0], "TreeData");
- }
- else if (value & 0x1)
- {
- dp->unpackU32(size, "ScratchPadSize");
- delete [] mData;
- mData = new U8[size];
- dp->unpackBinaryData((U8 *)mData, sp_size, "PartData");
- }
- else
- {
- mData = NULL;
- }
- // Setup object text
- if (!mText && (value & 0x4))
- {
- mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
- mText->setFont(LLFontGL::getFontSansSerif());
- mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
- mText->setMaxLines(-1); // Set to match current agni behavior.
- mText->setSourceObject(this);
- mText->setOnHUDAttachment(isHUDAttachment());
- }
- if (value & 0x4)
- {
- std::string temp_string;
- dp->unpackString(temp_string, "Text");
- LLColor4U coloru;
- dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
- coloru.mV[3] = 255 - coloru.mV[3];
- mText->setColor(LLColor4(coloru));
- mText->setStringUTF8(temp_string);
- setChanged(TEXTURE);
- }
- else if(mText.notNull())
- {
- mText->markDead();
- mText = NULL;
- }
- std::string media_url;
- if (value & 0x200)
- {
- dp->unpackString(media_url, "MediaURL");
- }
- retval |= checkMediaURL(media_url);
- //
- // Unpack particle system data
- //
- if (value & 0x8)
- {
- unpackParticleSource(*dp, owner_id);
- }
- else
- {
- deleteParticleSource();
- }
-
- // Mark all extra parameters not used
- std::map<U16, ExtraParameter*>::iterator iter;
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- iter->second->in_use = FALSE;
- }
- // Unpack extra params
- U8 num_parameters;
- dp->unpackU8(num_parameters, "num_params");
- U8 param_block[MAX_OBJECT_PARAMS_SIZE];
- for (U8 param=0; param<num_parameters; ++param)
- {
- U16 param_type;
- S32 param_size;
- dp->unpackU16(param_type, "param_type");
- dp->unpackBinaryData(param_block, param_size, "param_data");
- //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
- LLDataPackerBinaryBuffer dp2(param_block, param_size);
- unpackParameterEntry(param_type, &dp2);
- }
- for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
- {
- if (!iter->second->in_use)
- {
- // Send an update message in case it was formerly in use
- parameterChanged(iter->first, iter->second->data, FALSE, false);
- }
- }
- if (value & 0x10)
- {
- dp->unpackUUID(sound_uuid, "SoundUUID");
- dp->unpackF32(gain, "SoundGain");
- dp->unpackU8(sound_flags, "SoundFlags");
- dp->unpackF32(cutoff, "SoundRadius");
- }
- if (value & 0x100)
- {
- std::string name_value_list;
- dp->unpackString(name_value_list, "NV");
- setNameValueList(name_value_list);
- }
- mTotalCRC = crc;
- setAttachedSound(sound_uuid, owner_id, gain, sound_flags);
- // only get these flags on updates from sim, not cached ones
- // 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);
- }
- break;
- default:
- break;
- }
- }
- //
- // Fix object parenting.
- //
- BOOL b_changed_status = FALSE;
- if (OUT_TERSE_IMPROVED != update_type)
- {
- // We only need to update parenting on full updates, terse updates
- // don't send parenting information.
- if (!cur_parentp)
- {
- if (parent_id == 0)
- {
- // No parent now, no parent in message -> do nothing
- }
- else
- {
- // No parent now, new parent in message -> attach to that parent if possible
- LLUUID parent_uuid;
- LLViewerObjectList::getUUIDFromLocal(parent_uuid,
- parent_id,
- mesgsys->getSenderIP(),
- mesgsys->getSenderPort());
- LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid);
- //
- // Check to see if we have the corresponding viewer object for the parent.
- //
- if (sent_parentp && sent_parentp->getParent() == this)
- {
- // Try to recover if we attempt to attach a parent to its child
- llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl;
- this->removeChild(sent_parentp);
- sent_parentp->setDrawableParent(NULL);
- }
-
- if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead())
- {
- //
- // We have a viewer object for the parent, and it's not dead.
- // Do the actual reparenting here.
- //
- // new parent is valid
- b_changed_status = TRUE;
- // ...no current parent, so don't try to remove child
- if (mDrawable.notNull())
- {
- if (mDrawable->isDead() || !mDrawable->getVObj())
- {
- llwarns << "Drawable is dead or no VObj!" << llendl;
- sent_parentp->addChild(this);
- }
- else
- {
- if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1
- {
- // Bad, we got a cycle somehow.
- // Kill both the parent and the child, and
- // set cache misses for both of them.
- llwarns << "Attempting to recover from parenting cycle!" << llendl;
- llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
- llwarns << "Adding to cache miss list" << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- sent_parentp->addChild(this);
- // make sure this object gets a non-damped update
- if (sent_parentp->mDrawable.notNull())
- {
- gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
- }
- }
- }
- else
- {
- sent_parentp->addChild(this);
- }
-
- // Show particles, icon and HUD
- hideExtraDisplayItems( FALSE );
- setChanged(MOVED | SILHOUETTE);
- }
- else
- {
- //
- // 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();
-
- gObjectList.orphanize(this, parent_id, ip, port);
- // Hide particles, icon and HUD
- hideExtraDisplayItems( TRUE );
- }
- }
- }
- else
- {
- // BUG: this is a bad assumption once border crossing is alowed
- if ( (parent_id == cur_parentp->mLocalID)
- &&(update_type == OUT_TERSE_IMPROVED))
- {
- // Parent now, same parent in message -> do nothing
- // Debugging for suspected problems with local ids.
- //LLUUID parent_uuid;
- //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() );
- //if (parent_uuid != cur_parentp->getID() )
- //{
- // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl;
- //}
- }
- else
- {
- // Parented now, different parent in message
- LLViewerObject *sent_parentp;
- if (parent_id == 0)
- {
- //
- // This object is no longer parented, we sent in a zero parent ID.
- //
- sent_parentp = NULL;
- }
- else
- {
- LLUUID parent_uuid;
- LLViewerObjectList::getUUIDFromLocal(parent_uuid,
- parent_id,
- gMessageSystem->getSenderIP(),
- gMessageSystem->getSenderPort());
- 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
- // ahead of the object she was sitting on (which is common as objects are transfered through
- // a slower route than agents)...
- // In this case, the local id for the object will not be valid, since the viewer has not received
- // a full update for the object from that sim yet, so we assume that the agent is still sitting
- // where she was originally. --RN
- if (!sent_parentp)
- {
- sent_parentp = cur_parentp;
- }
- }
- else if (!sent_parentp)
- {
- //
- // Switching parents, but we don't know the new parent.
- //
- U32 ip = mesgsys->getSenderIP();
- U32 port = mesgsys->getSenderPort();
- // We're an orphan, flag things appropriately.
- gObjectList.orphanize(this, parent_id, ip, port);
- }
- }
- // Reattach if possible.
- if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this)
- {
- // New parent is valid, detach and reattach
- b_changed_status = TRUE;
- if (mDrawable.notNull())
- {
- if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2
- {
- // Bad, we got a cycle somehow.
- // Kill both the parent and the child, and
- // set cache misses for both of them.
- llwarns << "Attempting to recover from parenting cycle!" << llendl;
- llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
- llwarns << "Adding to cache miss list" << llendl;
- setParent(NULL);
- sent_parentp->setParent(NULL);
- getRegion()->addCacheMissFull(getLocalID());
- getRegion()->addCacheMissFull(sent_parentp->getLocalID());
- gObjectList.killObject(sent_parentp);
- gObjectList.killObject(this);
- return retval;
- }
- // make sure this object gets a non-damped update
- }
- cur_parentp->removeChild(this);
- sent_parentp->addChild(this);
- setChanged(MOVED | SILHOUETTE);
- sent_parentp->setChanged(MOVED | SILHOUETTE);
- if (sent_parentp->mDrawable.notNull())
- {
- gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
- }
- }
- else if (!sent_parentp)
- {
- bool remove_parent = true;
- // No new parent, or the parent that we sent doesn't exist on the viewer.
- LLViewerObject *parentp = (LLViewerObject *)getParent();
- if (parentp)
- {
- if (parentp->getRegion() != getRegion())
- {
- // This is probably an object flying across a region boundary, the
- // object probably ISN'T being reparented, but just got an object
- // update out of order (child update before parent).
- //llinfos << "Don't reparent object handoffs!" << llendl;
- remove_parent = false;
- }
- }
- if (remove_parent)
- {
- b_changed_status = TRUE;
- if (mDrawable.notNull())
- {
- // clear parent to removeChild can put the drawable on the damped list
- setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3
- }
- cur_parentp->removeChild(this);
- if (mJointInfo && !parent_id)
- {
- // since this object is no longer parent-relative
- // we make sure we delete any joint info
- delete mJointInfo;
- mJointInfo = NULL;
- }
- setChanged(MOVED | SILHOUETTE);
- if (mDrawable.notNull())
- {
- // make sure this object gets a non-damped update
- gPipeline.markMoved(mDrawable, FALSE); // undamped
- }
- }
- }
- }
- }
- }
- new_rot.normQuat();
- if (gPingInterpolate)
- {
- LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
- if (cdp)
- {
- F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped);
- LLVector3 diff = getVelocity() * (0.5f*mTimeDilation*(gFrameDTClamped + ((F32)ping_delay)*0.001f));
- new_pos_parent += diff;
- }
- else
- {
- llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl;
- }
- }
- //////////////////////////
- //
- // Set the generic change flags...
- //
- //
- 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;
- // Set the change flags for scale
- if (new_scale != getScale())
- {
- setChanged(SCALED | SILHOUETTE);
- setScale(new_scale); // Must follow setting permYouOwner()
- }
- // first, let's see if the new position is actually a change
- //static S32 counter = 0;
- F32 vel_mag_sq = getVelocity().magVecSquared();
- F32 accel_mag_sq = getAcceleration().magVecSquared();
- if ( ((b_changed_status)||(test_pos_parent != new_pos_parent))
- ||( (!isSelected())
- &&( (vel_mag_sq != 0.f)
- ||(accel_mag_sq != 0.f)
- ||(this_update_precision > mBestUpdatePrecision))))
- {
- mBestUpdatePrecision = this_update_precision;
-
- LLVector3 diff = new_pos_parent - test_pos_parent ;
- F32 mag_sqr = diff.magVecSquared() ;
- if(llfinite(mag_sqr))
- {
- setPositionParent(new_pos_parent);
- }
- else
- {
- llwarns << "Can not move the object/avatar to an infinite location!" << llendl ;
- retval |= INVALID_UPDATE ;
- }
- if (mParent && ((LLViewerObject*)mParent)->isAvatar())
- {
- // we have changed the position of an attachment, so we need to clamp it
- LLVOAvatar *avatar = (LLVOAvatar*)mParent;
- avatar->clampAttachmentPositions();
- }
- }
- if (new_rot != mLastRot
- || new_angv != old_angv)
- {
- if (new_rot != mLastRot)
- {
- mLastRot = new_rot;
- setRotation(new_rot);
- }
-
- setChanged(ROTATED | SILHOUETTE);
-
- resetRot();
- }
- if ( gShowObjectUpdates )
- {
- if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->isSelf()))
- && mRegionp)
- {
- LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp);
- LLVOTextBubble* bubble = (LLVOTextBubble*) object;
- if (update_type == OUT_TERSE_IMPROVED)
- {
- bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f);
- }
- else
- {
- bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f);
- }
- object->setPositionGlobal(getPositionGlobal());
- gPipeline.addObject(object);
- }
- }
- if ((0.0f == vel_mag_sq) &&
- (0.0f == accel_mag_sq) &&
- (0.0f == getAngularVelocity().magVecSquared()))
- {
- mStatic = TRUE; // This object doesn't move!
- }
- else
- {
- 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
- //
- // Additionally, if any child is selected, need to update the dialogs and selection
- // center.
- BOOL needs_refresh = mUserSelected;
- for (child_list_t::iterator iter = mChildList.begin();
- iter != mChildList.end(); iter++)
- {
- LLViewerObject* child = *iter;
- needs_refresh = needs_refresh || child->mUserSelected;
- }
- if (needs_refresh)
- {
- LLSelectMgr::getInstance()->updateSelectionCenter();
- dialog_refresh_all();
- }
- // Mark update time as approx. now, with the ping delay.
- // Ping delay is off because it's not set for velocity interpolation, causing
- // much jumping and hopping around...
- // U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay();
- mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
- mLastMessageUpdateSecs = LLFrameTimer::getElapsedSeconds();
- if (mDrawable.notNull())
- {
- // Don't clear invisibility flag on update if still orphaned!
- if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned)
- {
- // lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl;
- mDrawable->setState(LLDrawable::CLEAR_INVISIBLE);
- }
- }
- // Update special hover cursor status
- bool special_hover_cursor = specialHoverCursor();
- if (old_special_hover_cursor != special_hover_cursor
- && mDrawable.notNull())
- {
- mDrawable->updateSpecialHoverCursor(special_hover_cursor);
- }
- return retval;
- }
- BOOL LLViewerObject::isActive() const
- {
- return TRUE;
- }
- BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
- {
- if (mDead)
- {
- // It's dead. Don't update it.
- return TRUE;
- }
- // CRO - don't velocity interp linked objects!
- // Leviathan - but DO velocity interp joints
- if (!mStatic && gVelocityInterpolate && !isSelected())
- {
- // calculate dt from last update
- F32 dt_raw = (F32)(time - mLastInterpUpdateSecs);
- F32 dt = mTimeDilation * dt_raw;
- if (!mJointInfo)
- {
- applyAngularVelocity(dt);
- }
- LLViewerObject *parentp = (LLViewerObject *) getParent();
- if (mJointInfo)
- {
- if (parentp)
- {
- // do parent-relative stuff
- LLVector3 ang_vel = getAngularVelocity();
- F32 omega = ang_vel.magVecSquared();
- F32 angle = 0.0f;
- LLQuaternion dQ;
- if (omega > 0.00001f)
- {
- omega = sqrt(omega);
- angle = omega * dt;
- dQ.setQuat(angle, ang_vel);
- }
- LLVector3 pos = getPosition();
-
- if (HJT_HINGE == mJointInfo->mJointType)
- {
- // hinge = uniform circular motion
- LLVector3 parent_pivot = getVelocity();
- LLVector3 parent_axis = getAcceleration();
-
- angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
- dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
- LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame
- pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos
- pos = mJointInfo->mPivot + pivot_offset; // parent-frame
- LLViewerObject::setPosition(pos);
- LLQuaternion Q_PC = getRotation();
- setRotation(Q_PC * dQ);
- mLastInterpUpdateSecs = time;
- }
- else if (HJT_POINT == mJointInfo->mJointType)
- // || HJT_LPOINT == mJointInfo->mJointType)
- {
- // point-to-point = spin about axis and uniform circular motion
- // of axis about the pivot point
- //
- // NOTE: this interpolation scheme is not quite good enough to
- // reduce the bandwidth -- needs a gravitational correction.
- // Similarly for hinges with axes that deviate from vertical.
-
- LLQuaternion Q_PC = getRotation();
- Q_PC = Q_PC * dQ;
- setRotation(Q_PC);
- LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor
- pos = mJointInfo->mPivot + pivot_to_child * Q_PC;
- LLViewerObject::setPosition(pos);
- mLastInterpUpdateSecs = time;
- }
- /* else if (HJT_WHEEL == mJointInfo->mJointInfo)
- {
- // wheel = uniform rotation about axis, with linear
- // velocity interpolation (if any)
- LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame)
-
- LLQuaternion Q_PC = getRotation();
-
- angle = dt * (parent_axis * ang_vel);
- dQ.setQuat(angle, parent_axis);
-
- Q_PC = Q_PC * dQ;
- setRotation(Q_PC);
- pos = getPosition() + dt * getVelocity();
- LLViewerObject::setPosition(pos);
- mLastInterpUpdateSecs = time;
- }*/
- }
- }
- else if (isAttachment())
- {
- mLastInterpUpdateSecs = time;
- return TRUE;
- }
- else
- {
- // linear motion
- // 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
- //
- // There is a problem here if dt is negative. . .
- // *TODO: should also wrap linear accel/velocity in check
- // to see if object is selected, instead of explicitly
- // zeroing it out
- LLVector3 accel = getAcceleration();
- LLVector3 vel = getVelocity();
-
- if (!(accel.isExactlyZero() && vel.isExactlyZero()))
- {
- LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;
-
- // region local
- setPositionRegion(pos + getPositionRegion());
- setVelocity(vel + accel*dt);
-
- // for objects that are spinning but not translating, make sure to flag them as having moved
- setChanged(MOVED | SILHOUETTE);
- }
-
- mLastInterpUpdateSecs = time;
- }
- }
- if (gNoRender)
- {
- // Skip drawable stuff if not rendering.
- return TRUE;
- }
- updateDrawable(FALSE);
- return TRUE;
- }
- BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- delete [] mData;
- if (datap)
- {
- mData = new U8[data_size];
- if (!mData)
- {
- return FALSE;
- }
- memcpy(mData, datap, data_size); /* Flawfinder: ignore */
- }
- return TRUE;
- }
- // delete an item in the inventory, but don't tell the server. This is
- // used internally by remove, update, and savescript.
- // This will only delete the first item with an item_id in the list
- void LLViewerObject::deleteInventoryItem(const LLUUID& item_id)
- {
- if(mInventory)
- {
- InventoryObjectList::iterator it = mInventory->begin();
- InventoryObjectList::iterator end = mInventory->end();
- for( ; it != end; ++it )
- {
- if((*it)->getUUID() == item_id)
- {
- // This is safe only because we return immediatly.
- mInventory->erase(it); // will deref and delete it
- return;
- }
- }
- doInventoryCallback();
- }
- }
- void LLViewerObject::doUpdateInventory(
- LLPointer<LLViewerInventoryItem>& item,
- U8 key,
- bool is_new)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
- LLViewerInventoryItem* old_item = NULL;
- if(TASK_INVENTORY_ITEM_KEY == key)
- {
- old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID());
- }
- else if(TASK_INVENTORY_ASSET_KEY == key)
- {
- old_item = getInventoryItemByAsset(item->getAssetUUID());
- }
- LLUUID item_id;
- LLUUID new_owner;
- LLUUID new_group;
- BOOL group_owned = FALSE;
- if(old_item)
- {
- item_id = old_item->getUUID();
- new_owner = old_item->getPermissions().getOwner();
- new_group = old_item->getPermissions().getGroup();
- group_owned = old_item->getPermissions().isGroupOwned();
- old_item = NULL;
- }
- else
- {
- item_id = item->getUUID();
- }
- if(!is_new && mInventory)
- {
- // Attempt to update the local inventory. If we can get the
- // object perm, we have perfect visibility, so we want the
- // serial number to match. Otherwise, take our best guess and
- // make sure that the serial number does not match.
- deleteInventoryItem(item_id);
- LLPermissions perm(item->getPermissions());
- LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this);
- bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true;
- if(obj_perm)
- {
- perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic);
- }
- else
- {
- if(group_owned)
- {
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- else if(!new_owner.isNull())
- {
- // The object used to be in inventory, so we can
- // assume the owner and group will match what they are
- // there.
- perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
- }
- // *FIX: can make an even better guess by using the mPermGroup flags
- else if(permYouOwner())
- {
- // best guess.
- perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic);
- --mInventorySerialNum;
- }
- else
- {
- // dummy it up.
- perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic);
- --mInventorySerialNum;
- }
- }
- LLViewerInventoryItem* oldItem = item;
- LLViewerInventoryItem* new_item = new LLViewerInventoryItem(oldItem);
- new_item->setPermissions(perm);
- mInventory->push_front(new_item);
- doInventoryCallback();
- ++mInventorySerialNum;
- }
- }
- // save a script, which involves removing the old one, and rezzing
- // in the new one. This method should be called with the asset id
- // of the new and old script AFTER the bytecode has been saved.
- void LLViewerObject::saveScript(
- const LLViewerInventoryItem* item,
- BOOL active,
- bool is_new)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
- /*
- * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the
- * interaction with doUpdateInventory() called below.
- */
- lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl;
- LLPointer<LLViewerInventoryItem> task_item =
- new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
- item->getAssetUUID(), item->getType(),
- item->getInventoryType(),
- item->getName(), item->getDescription(),
- item->getSaleInfo(), item->getFlags(),
- item->getCreationDate());
- task_item->setTransactionID(item->getTransactionID());
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RezScript);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- msg->nextBlockFast(_PREHASH_UpdateBlock);
- msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID));
- U8 enabled = active;
- msg->addBOOLFast(_PREHASH_Enabled, enabled);
- msg->nextBlockFast(_PREHASH_InventoryBlock);
- task_item->packMessage(msg);
- msg->sendReliable(mRegionp->getHost());
- // do the internal logic
- doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new);
- }
- void LLViewerObject::moveInventory(const LLUUID& folder_id,
- const LLUUID& item_id)
- {
- lldebugs << "LLViewerObject::moveInventory " << item_id << llendl;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_MoveTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_FolderID, folder_id);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->sendReliable(mRegionp->getHost());
- LLInventoryObject* inv_obj = getInventoryObject(item_id);
- if(inv_obj)
- {
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj;
- if(!item->getPermissions().allowCopyBy(gAgent.getID()))
- {
- deleteInventoryItem(item_id);
- ++mInventorySerialNum;
- }
- }
- }
- void LLViewerObject::dirtyInventory()
- {
- // If there aren't any LLVOInventoryListeners, we won't be
- // able to update our mInventory when it comes back from the
- // simulator, so we should not clear the inventory either.
- if(mInventory && !mInventoryCallbacks.empty())
- {
- mInventory->clear(); // will deref and delete entries
- delete mInventory;
- mInventory = NULL;
- mInventoryDirty = TRUE;
- }
- }
- void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo;
- info->mListener = listener;
- info->mInventoryData = user_data;
- mInventoryCallbacks.push_front(info);
- }
- void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
- {
- if (listener == NULL)
- return;
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info->mListener == listener)
- {
- delete info;
- mInventoryCallbacks.erase(curiter);
- break;
- }
- }
- }
- void LLViewerObject::clearInventoryListeners()
- {
- for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer());
- mInventoryCallbacks.clear();
- }
- void LLViewerObject::requestInventory()
- {
- mInventoryDirty = FALSE;
- if(mInventory)
- {
- //mInventory->clear() // will deref and delete it
- //delete mInventory;
- //mInventory = NULL;
- doInventoryCallback();
- }
- // throw away duplicate requests
- else
- {
- fetchInventoryFromServer();
- }
- }
- void LLViewerObject::fetchInventoryFromServer()
- {
- if (!mInventoryPending)
- {
- delete mInventory;
- mInventory = NULL;
- mInventoryDirty = FALSE;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RequestTaskInventory);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_LocalID, mLocalID);
- msg->sendReliable(mRegionp->getHost());
- // this will get reset by dirtyInventory or doInventoryCallback
- mInventoryPending = TRUE;
- }
- }
- struct LLFilenameAndTask
- {
- LLUUID mTaskID;
- std::string mFilename;
- #ifdef _DEBUG
- static S32 sCount;
- LLFilenameAndTask()
- {
- ++sCount;
- lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl;
- }
- ~LLFilenameAndTask()
- {
- --sCount;
- lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl;
- }
- private:
- LLFilenameAndTask(const LLFilenameAndTask& rhs);
- const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const;
- #endif
- };
- #ifdef _DEBUG
- S32 LLFilenameAndTask::sCount = 0;
- #endif
- // static
- void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- LLUUID task_id;
- msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
- LLViewerObject* object = gObjectList.findObject(task_id);
- if(!object)
- {
- llwarns << "LLViewerObject::processTaskInv object "
- << task_id << " does not exist." << llendl;
- return;
- }
- msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
- LLFilenameAndTask* ft = new LLFilenameAndTask;
- ft->mTaskID = task_id;
- std::string unclean_filename;
- msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename);
- ft->mFilename = LLDir::getScrubbedFileName(unclean_filename);
-
- if(ft->mFilename.empty())
- {
- lldebugs << "Task has no inventory" << llendl;
- // mock up some inventory to make a drop target.
- if(object->mInventory)
- {
- object->mInventory->clear(); // will deref and delete it
- }
- else
- {
- object->mInventory = new InventoryObjectList();
- }
- LLPointer<LLInventoryObject> obj;
- obj = new LLInventoryObject(object->mID, LLUUID::null,
- LLAssetType::AT_CATEGORY,
- LLTrans::getString("ViewerObjectContents").c_str());
- object->mInventory->push_front(obj);
- object->doInventoryCallback();
- delete ft;
- return;
- }
- 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);
- }
- void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status)
- {
- LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
- LLViewerObject* object = NULL;
- if(ft && (0 == error_code) &&
- (object = gObjectList.findObject(ft->mTaskID)))
- {
- object->loadTaskInvFile(ft->mFilename);
- }
- else
- {
- // This Occurs When to requests were made, and the first one
- // has already handled it.
- lldebugs << "Problem loading task inventory. Return code: "
- << error_code << llendl;
- }
- delete ft;
- }
- void LLViewerObject::loadTaskInvFile(const std::string& filename)
- {
- LLMemType mt(LLMemType::MTYPE_OBJECT);
-
- std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename);
- llifstream ifs(filename_and_local_path);
- if(ifs.good())
- {
- char buffer[MAX_STRING]; /* Flawfinder: ignore */
- // *NOTE: This buffer size is hard coded into scanf() below.
- char keyword[MAX_STRING]; /* Flawfinder: ignore */
- if(mInventory)
- {
- mInventory->clear(); // will deref and delete it
- }
- else
- {
- mInventory = new InventoryObjectList;
- }
- while(ifs.good())
- {
- ifs.getline(buffer, MAX_STRING);
- sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */
- if(0 == strcmp("inv_item", keyword))
- {
- LLPointer<LLInventoryObject> inv = new LLViewerInventoryItem;
- inv->importLegacyStream(ifs);
- mInventory->push_front(inv);
- }
- else if(0 == strcmp("inv_object", keyword))
- {
- LLPointer<LLInventoryObject> inv = new LLInventoryObject;
- inv->importLegacyStream(ifs);
- inv->rename(LLTrans::getString("ViewerObjectContents").c_str());
- mInventory->push_front(inv);
- }
- else
- {
- llwarns << "Unknown token in inventory file '"
- << keyword << "'" << llendl;
- }
- }
- ifs.close();
- LLFile::remove(filename_and_local_path);
- }
- else
- {
- llwarns << "unable to load task inventory: " << filename_and_local_path
- << llendl;
- }
- doInventoryCallback();
- }
- void LLViewerObject::doInventoryCallback()
- {
- for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
- iter != mInventoryCallbacks.end(); )
- {
- callback_list_t::iterator curiter = iter++;
- LLInventoryCallbackInfo* info = *curiter;
- if (info->mListener != NULL)
- {
- info->mListener->inventoryChanged(this,
- mInventory,
- mInventorySerialNum,
- info->mInventoryData);
- }
- else
- {
- llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl;
- delete info;
- mInventoryCallbacks.erase(curiter);
- }
- }
- mInventoryPending = FALSE;
- }
- void LLViewerObject::removeInventory(const LLUUID& item_id)
- {
- // close any associated floater properties