summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rwxr-xr-xindra/llappearance/llavatarappearance.cpp2
-rwxr-xr-xindra/llappearance/llavatarappearance.h2
-rwxr-xr-x[-rw-r--r--]indra/llmessage/llurlrequest.cpp4
-rwxr-xr-xindra/newview/llappearancemgr.cpp90
-rwxr-xr-xindra/newview/llappearancemgr.h2
-rwxr-xr-x[-rw-r--r--]indra/newview/llcallbacklist.cpp49
-rw-r--r--indra/newview/llcallbacklist.h6
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp2
-rw-r--r--indra/newview/lltexturefetch.cpp2
-rwxr-xr-xindra/newview/llviewerregion.cpp5
-rwxr-xr-x[-rw-r--r--]indra/newview/llviewertexture.cpp6
-rwxr-xr-xindra/newview/llvoavatar.cpp76
-rwxr-xr-xindra/newview/llvoavatar.h1
13 files changed, 200 insertions, 47 deletions
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 3c01a00e61..c4ff667fa1 100755
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -175,7 +175,7 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
for (U32 i = 0; i < mBakedTextureDatas.size(); i++ )
{
- mBakedTextureDatas[i].mLastTextureIndex = IMG_DEFAULT_AVATAR;
+ mBakedTextureDatas[i].mLastTextureID = IMG_DEFAULT_AVATAR;
mBakedTextureDatas[i].mTexLayerSet = NULL;
mBakedTextureDatas[i].mIsLoaded = false;
mBakedTextureDatas[i].mIsUsed = false;
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index abe3599685..11ea5e5a46 100755
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -308,7 +308,7 @@ protected:
typedef std::deque<LLMaskedMorph *> morph_list_t;
struct BakedTextureData
{
- LLUUID mLastTextureIndex;
+ LLUUID mLastTextureID;
LLTexLayerSet* mTexLayerSet; // Only exists for self
bool mIsLoaded;
bool mIsUsed;
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index f3f0007205..8c0ad35204 100644..100755
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -181,6 +181,10 @@ void LLURLRequest::setURL(const std::string& url)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mDetail->mURL = url;
+ if (url.empty())
+ {
+ llwarns << "empty URL specified" << llendl;
+ }
}
std::string LLURLRequest::getURL() const
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 7a8586ebdc..4e103bb75e 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1750,6 +1750,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)
{
requestServerAppearanceUpdate();
}
+ // DRANO really should wait for the appearance message to set this.
+ // verify that deleting this line doesn't break anything.
gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion());
//dumpCat(getCOF(),"COF, start");
@@ -2650,12 +2652,70 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base
if (inventory_changed) gInventory.notifyObservers();
}
+// This is intended for use with HTTP Clients/Responders, but is not
+// specifically coupled with those classes.
+class LLHTTPRetryPolicy: public LLThreadSafeRefCount
+{
+public:
+ LLHTTPRetryPolicy() {}
+ virtual ~LLHTTPRetryPolicy() {}
+ virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0;
+};
+
+// Example of simplest possible policy, not necessarily recommended.
+class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy
+{
+public:
+ LLAlwaysRetryImmediatelyPolicy() {}
+ bool shouldRetry(U32 status, F32& seconds_to_wait)
+ {
+ seconds_to_wait = 0.0;
+ return true;
+ }
+};
+
+// Very general policy with geometric back-off after failures,
+// up to a maximum delay, and maximum number of retries.
+class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy
+{
+public:
+ LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries):
+ mMinDelay(min_delay),
+ mMaxDelay(max_delay),
+ mBackoffFactor(backoff_factor),
+ mMaxRetries(max_retries),
+ mDelay(min_delay),
+ mRetryCount(0)
+ {
+ }
+
+ bool shouldRetry(U32 status, F32& seconds_to_wait)
+ {
+ seconds_to_wait = mDelay;
+ mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay);
+ mRetryCount++;
+ return (mRetryCount<=mMaxRetries);
+ }
+
+private:
+ F32 mMinDelay; // delay never less than this value
+ F32 mMaxDelay; // delay never exceeds this value
+ F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay.
+ U32 mMaxRetries; // maximum number of times shouldRetry will return true.
+ F32 mDelay; // current delay.
+ U32 mRetryCount; // number of times shouldRetry has been called.
+};
+
class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder
{
public:
RequestAgentUpdateAppearanceResponder()
{
- llinfos << "request created" << llendl;
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5);
+ }
+
+ virtual ~RequestAgentUpdateAppearanceResponder()
+ {
}
// Successful completion.
@@ -2667,11 +2727,26 @@ public:
// Error
/*virtual*/ void error(U32 status, const std::string& reason)
{
- llwarns << "appearance update request failed, reason: " << reason << llendl;
+ llwarns << "appearance update request failed, status: " << status << " reason: " << reason << llendl;
+ F32 seconds_to_wait;
+ if (mRetryPolicy->shouldRetry(status,seconds_to_wait))
+ {
+ llinfos << "retrying" << llendl;
+ doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate,
+ LLAppearanceMgr::getInstance(),
+ LLCurl::ResponderPtr(this)),
+ seconds_to_wait);
+ }
+ else
+ {
+ llwarns << "giving up after too many retries" << llendl;
+ }
}
+
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
};
-void LLAppearanceMgr::requestServerAppearanceUpdate()
+void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr)
{
if (!gAgent.getRegion())
{
@@ -2684,14 +2759,19 @@ void LLAppearanceMgr::requestServerAppearanceUpdate()
std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");
if (url.empty())
{
- llwarns << "NO CAP for UpdateAvatarAppearance. This is a bug." << llendl;
+ llwarns << "No cap for UpdateAvatarAppearance." << llendl;
return;
}
LLSD body;
S32 cof_version = getCOFVersion();
body["cof_version"] = cof_version;
- LLHTTPClient::post(url, body, new RequestAgentUpdateAppearanceResponder);
+ //LLCurl::ResponderPtr responder_ptr;
+ if (!responder_ptr.get())
+ {
+ responder_ptr = new RequestAgentUpdateAppearanceResponder;
+ }
+ LLHTTPClient::post(url, body, responder_ptr);
llassert(cof_version >= mLastUpdateRequestCOFVersion);
mLastUpdateRequestCOFVersion = cof_version;
}
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index 4baee10218..01ed66711c 100755
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -187,7 +187,7 @@ public:
bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; }
- void requestServerAppearanceUpdate();
+ void requestServerAppearanceUpdate(LLCurl::ResponderPtr responder_ptr = NULL);
protected:
LLAppearanceMgr();
diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp
index 357a6582d1..79ec43dfe9 100644..100755
--- a/indra/newview/llcallbacklist.cpp
+++ b/indra/newview/llcallbacklist.cpp
@@ -27,6 +27,7 @@
#include "llviewerprecompiledheaders.h"
#include "llcallbacklist.h"
+#include "lleventtimer.h"
// Library includes
#include "llerror.h"
@@ -180,6 +181,54 @@ void doOnIdleRepeating(bool_func_t callable)
gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor);
}
+class NullaryFuncEventTimer: public LLEventTimer
+{
+public:
+ NullaryFuncEventTimer(nullary_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+
+private:
+ BOOL tick()
+ {
+ mCallable();
+ return TRUE;
+ }
+
+ nullary_func_t mCallable;
+};
+
+// Call a given callable once after specified interval.
+void doAfterInterval(nullary_func_t callable, F32 seconds)
+{
+ new NullaryFuncEventTimer(callable, seconds);
+}
+
+class BoolFuncEventTimer: public LLEventTimer
+{
+public:
+ BoolFuncEventTimer(bool_func_t callable, F32 seconds):
+ LLEventTimer(seconds),
+ mCallable(callable)
+ {
+ }
+private:
+ BOOL tick()
+ {
+ return mCallable();
+ }
+
+ bool_func_t mCallable;
+};
+
+// Call a given callable every specified number of seconds, until it returns true.
+void doPeriodically(bool_func_t callable, F32 seconds)
+{
+ new BoolFuncEventTimer(callable, seconds);
+}
+
#ifdef _DEBUG
void test1(void *data)
diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h
index 97f3bfd9ee..0516c9cdb4 100644
--- a/indra/newview/llcallbacklist.h
+++ b/indra/newview/llcallbacklist.h
@@ -61,6 +61,12 @@ void doOnIdleOneTime(nullary_func_t callable);
// Repeatedly call a callable in idle loop until it returns true.
void doOnIdleRepeating(bool_func_t callable);
+// Call a given callable once after specified interval.
+void doAfterInterval(nullary_func_t callable, F32 seconds);
+
+// Call a given callable every specified number of seconds, until it returns true.
+void doPeriodically(bool_func_t callable, F32 seconds);
+
extern LLCallbackList gIdleCallbacks;
#endif
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index f4d0110b0f..eb92902de9 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -183,7 +183,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *)
void LLInventoryModelBackgroundFetch::backgroundFetch()
{
- if (mBackgroundFetchActive && gAgent.getRegion())
+ if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
{
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
if (gSavedSettings.getBOOL("UseHTTPInventory"))
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index db08c16f15..43bfb4442b 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -351,7 +351,7 @@ public:
if (!success)
{
worker->setGetStatus(status, reason);
-// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
+ llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << " id: " << mID <<llendl;
}
data_size = worker->callbackHttpGet(channels, buffer, partial, success);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 0855bc9243..c8ab055e3f 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1745,6 +1745,11 @@ bool LLViewerRegion::isSpecialCapabilityName(const std::string &name)
std::string LLViewerRegion::getCapability(const std::string& name) const
{
+ if (!capabilitiesReceived() && (name!=std::string("Seed")))
+ {
+ llwarns << "getCapability called before caps received" << llendl;
+ }
+
CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name);
if(iter == mImpl->mCapabilities.end())
{
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a73ce1d115..37f2fd3520 100644..100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1946,8 +1946,10 @@ void LLViewerFetchedTexture::setIsMissingAsset()
}
else
{
- //it is normal no map tile on an empty region.
- //llwarns << mUrl << ": Marking image as missing" << llendl;
+ // This may or may not be an error - it is normal to have no
+ // map tile on an empty region, but bad if we're failing on a
+ // server bake texture.
+ llwarns << mUrl << ": Marking image as missing" << llendl;
}
if (mHasFetcher)
{
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 168a116b95..75e71a7613 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -5767,6 +5767,25 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const
return mMotionController.findMotion(id);
}
+void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color)
+{
+ if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
+ {
+ avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
+ avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
+ for (; iter != end; ++iter)
+ {
+ LLAvatarJointMesh* mesh = (*iter);
+ if (mesh)
+ {
+ {
+ mesh->setColor(color);
+ }
+ }
+ }
+ }
+}
+
//-----------------------------------------------------------------------------
// updateMeshTextures()
// Uses the current TE values to set the meshes' and layersets' textures.
@@ -5814,7 +5833,7 @@ void LLVOAvatar::updateMeshTextures()
&& ( !layerset->getViewerComposite()->isInitialized()
|| !layerset->isLocalTextureDataAvailable() );
use_lkg_baked_layer[i] = (!is_layer_baked[i]
- && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR)
+ && (mBakedTextureDatas[i].mLastTextureID != IMG_DEFAULT_AVATAR)
&& layerset_invalid);
if (use_lkg_baked_layer[i])
{
@@ -5824,21 +5843,23 @@ void LLVOAvatar::updateMeshTextures()
else
{
use_lkg_baked_layer[i] = (!is_layer_baked[i]
- && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR);
+ && mBakedTextureDatas[i].mLastTextureID != IMG_DEFAULT_AVATAR);
}
}
for (U32 i=0; i < mBakedTextureDatas.size(); i++)
{
+ debugColorizeSubMeshes(i, LLColor4::white);
+
LLViewerTexLayerSet* layerset = getTexLayerSet(i);
if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() )
{
LLViewerFetchedTexture* baked_img;
- const std::string url = getImageURL(i, mBakedTextureDatas[i].mLastTextureIndex);
+ const std::string url = getImageURL(i, mBakedTextureDatas[i].mLastTextureID);
if (!url.empty())
{
- baked_img = LLViewerTextureManager::getFetchedTextureFromUrl(url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, mBakedTextureDatas[i].mLastTextureIndex);
+ baked_img = LLViewerTextureManager::getFetchedTextureFromUrl(url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, mBakedTextureDatas[i].mLastTextureID);
}
else
{
@@ -5849,10 +5870,13 @@ void LLVOAvatar::updateMeshTextures()
llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl;
}
- baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host );
+ baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureID, target_host );
}
mBakedTextureDatas[i].mIsUsed = TRUE;
+
+ debugColorizeSubMeshes(i,LLColor4::red);
+
avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
for (; iter != end; ++iter)
@@ -5861,17 +5885,13 @@ void LLVOAvatar::updateMeshTextures()
if (mesh)
{
mesh->setTexture( baked_img );
- if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
- {
- mesh->setColor(LLColor4::red);
- }
}
}
}
else if (!isUsingLocalAppearance() && is_layer_baked[i])
{
LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
- if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex )
+ if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureID )
{
// Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing).
useBakedTexture( baked_img->getID() );
@@ -5890,9 +5910,12 @@ void LLVOAvatar::updateMeshTextures()
}
else if (layerset && isUsingLocalAppearance())
{
+ debugColorizeSubMeshes(i,LLColor4::yellow );
+
layerset->createComposite();
layerset->setUpdatesEnabled( TRUE );
mBakedTextureDatas[i].mIsUsed = FALSE;
+
avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
for (; iter != end; ++iter)
@@ -5901,28 +5924,12 @@ void LLVOAvatar::updateMeshTextures()
if (mesh)
{
mesh->setLayerSet( layerset );
- if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
- {
- mesh->setColor( LLColor4::yellow );
- }
}
}
}
else
{
- if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
- {
- avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
- avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
- for (; iter != end; ++iter)
- {
- LLAvatarJointMesh* mesh = (*iter);
- if (mesh)
- {
- mesh->setColor( LLColor4::blue );
- }
- }
- }
+ debugColorizeSubMeshes(i,LLColor4::blue);
}
}
@@ -6241,7 +6248,7 @@ void LLVOAvatar::onFirstTEMessageReceived()
if (layer_baked)
{
LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex, 0 ), TRUE) ;
- mBakedTextureDatas[i].mLastTextureIndex = image->getID();
+ mBakedTextureDatas[i].mLastTextureID = image->getID();
// If we have more than one texture for the other baked layers, we'll want to call this for them too.
if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
{
@@ -6432,11 +6439,11 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++)
{
if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex)
- && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT
+ && mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT
&& baked_index != BAKED_SKIRT)
{
setTEImage(mBakedTextureDatas[baked_index].mTextureIndex,
- LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+ LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
}
}
@@ -6766,8 +6773,11 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
{
LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL;
mBakedTextureDatas[i].mIsLoaded = true;
- mBakedTextureDatas[i].mLastTextureIndex = id;
+ mBakedTextureDatas[i].mLastTextureID = id;
mBakedTextureDatas[i].mIsUsed = true;
+
+ debugColorizeSubMeshes(i,LLColor4::green);
+
avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end();
for (; iter != end; ++iter)
@@ -6776,10 +6786,6 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
if (mesh)
{
mesh->setTexture( image_baked );
- if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked"))
- {
- mesh->setColor( LLColor4::green );
- }
}
}
if (mBakedTextureDatas[i].mTexLayerSet)
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 5f858a2bea..8f3811f184 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -595,6 +595,7 @@ private:
**/
public:
+ void debugColorizeSubMeshes(U32 i, const LLColor4& color);
virtual void updateMeshTextures();
void updateSexDependentLayerSets(BOOL upload_bake);
virtual void dirtyMesh(); // Dirty the avatar mesh