diff options
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 60 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 11 | 
2 files changed, 58 insertions, 13 deletions
| diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6c0f101cd7..bbd454c4f5 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -142,6 +142,9 @@ 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; +const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds +const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1; +  static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");  // static @@ -2979,6 +2982,8 @@ void LLViewerObject::fetchInventoryFromServer()  	if (!isInventoryPending())  	{  		delete mInventory; + +		// Results in processTaskInv  		LLMessageSystem* msg = gMessageSystem;  		msg->newMessageFast(_PREHASH_RequestTaskInventory);  		msg->nextBlockFast(_PREHASH_AgentData); @@ -2988,11 +2993,44 @@ void LLViewerObject::fetchInventoryFromServer()  		msg->addU32Fast(_PREHASH_LocalID, mLocalID);  		msg->sendReliable(mRegionp->getHost()); -		// this will get reset by dirtyInventory or doInventoryCallback +		// This will get reset by doInventoryCallback or processTaskInv  		mInvRequestState = INVENTORY_REQUEST_PENDING;  	}  } +void LLViewerObject::fetchInventoryDelayed(const F64 &time_seconds) +{ +    // unless already waiting, drop previous request and shedule an update +    if (mInvRequestState != INVENTORY_REQUEST_WAIT) +    { +        if (mInvRequestXFerId != 0) +        { +            // abort download. +            gXferManager->abortRequestById(mInvRequestXFerId, -1); +            mInvRequestXFerId = 0; +        } +        mInvRequestState = INVENTORY_REQUEST_WAIT; // affects isInventoryPending() +        LLCoros::instance().launch("LLViewerObject::fetchInventoryDelayedCoro()", +            boost::bind(&LLViewerObject::fetchInventoryDelayedCoro, mID, time_seconds)); +    } +} + +//static +void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds) +{ +    llcoro::suspendUntilTimeout(time_seconds); +    LLViewerObject *obj = gObjectList.findObject(task_inv); +    if (obj) +    { +        // Might be good idea to prolong delay here in case expected serial changed. +        // As it is, it will get a response with obsolete serial and will delay again. + +        // drop waiting state to unlock isInventoryPending() +        obj->mInvRequestState = INVENTORY_REQUEST_STOPPED; +        obj->fetchInventoryFromServer(); +    } +} +  LLControlAvatar *LLViewerObject::getControlAvatar()  {      return getRootEdit()->mControlAvatar.get(); @@ -3166,30 +3204,32 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)      // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update      msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); -    if (ft->mSerial == object->mInventorySerialNum) +    if (ft->mSerial == object->mInventorySerialNum +        && ft->mSerial < object->mExpectedInventorySerialNum)      {          // Loop Protection.          // We received same serial twice.          // Viewer did some changes to inventory that couldn't be saved server side -        // or something went wrong to cause serial to be out of sync +        // or something went wrong to cause serial to be out of sync. +        // Drop xfer and restart after some time, assign server's value as expected          LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL;          object->mExpectedInventorySerialNum = ft->mSerial; +        object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_DESYNC);      } - -    if (ft->mSerial < object->mExpectedInventorySerialNum) +    else if (ft->mSerial < object->mExpectedInventorySerialNum)      { -        // out of date message, record to current serial for loop protection, but do not load it -        // just drop xfer to restart on idle +        // Out of date message, record to current serial for loop protection, but do not load it +        // Drop xfer and restart after some time          if (ft->mSerial < object->mInventorySerialNum)          { -            LL_WARNS() << "Somehow task serial decreased, out of order packet?" << LL_ENDL; +            LL_WARNS() << "Task serial decreased. Potentially out of order packet or desync." << LL_ENDL;          }          object->mInventorySerialNum = ft->mSerial; -        object->mInvRequestXFerId = 0; -        object->mInvRequestState = INVENTORY_REQUEST_STOPPED; +        object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED);      }      else if (ft->mSerial >= object->mExpectedInventorySerialNum)      { +        // We received version we expected or newer. Load it.          object->mInventorySerialNum = ft->mSerial;          object->mExpectedInventorySerialNum = ft->mSerial; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 077b02e097..89cea5756f 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -621,9 +621,13 @@ private:  	static void initObjectDataMap(); -	// forms task inventory request if none are pending +	// forms task inventory request if none are pending, marks request as pending  	void fetchInventoryFromServer(); +	// forms task inventory request after some time passed, marks request as pending +	void fetchInventoryDelayed(const F64 &time_seconds); +	static void fetchInventoryDelayedCoro(const LLUUID task_inv, const F64 time_seconds); +  public:  	//  	// Viewer-side only types - use the LL_PCODE_APP mask. @@ -807,8 +811,9 @@ protected:  	enum EInventoryRequestState  	{  		INVENTORY_REQUEST_STOPPED, -		INVENTORY_REQUEST_PENDING, -		INVENTORY_XFER +		INVENTORY_REQUEST_WAIT,    // delay before requesting +		INVENTORY_REQUEST_PENDING, // just did fetchInventoryFromServer() +		INVENTORY_XFER             // processed response from 'fetch', now doing an xfer  	};  	EInventoryRequestState	mInvRequestState;  	U64						mInvRequestXFerId; | 
