summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llviewerobject.cpp60
-rw-r--r--indra/newview/llviewerobject.h11
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;