summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerobject.cpp')
-rw-r--r--indra/newview/llviewerobject.cpp340
1 files changed, 294 insertions, 46 deletions
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 86440fca48..59bcad9a26 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -1290,7 +1290,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
#endif
//clear cost and linkset cost
setObjectCostStale();
- if (isSelected())
+ if (isSelected() && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -1729,7 +1729,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
#endif
setObjectCostStale();
- if (isSelected())
+ if (isSelected() && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -2325,6 +2325,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
// Set the rotation of the object followed by adjusting for the accumulated angular velocity (llSetTargetOmega)
setRotation(new_rot * mAngularVelocityRot);
+ if ((mFlags & FLAGS_SERVER_AUTOPILOT) && asAvatar() && asAvatar()->isSelf())
+ {
+ gAgent.resetAxes();
+ gAgent.rotate(new_rot);
+ gAgentCamera.resetView();
+ }
setChanged(ROTATED | SILHOUETTE);
}
@@ -2917,6 +2923,17 @@ void LLViewerObject::fetchInventoryFromServer()
delete mInventory;
mInventory = NULL;
+ // This will get reset by doInventoryCallback or processTaskInv
+ mInvRequestState = INVENTORY_REQUEST_PENDING;
+
+ if (mRegionp && !mRegionp->getCapability("RequestTaskInventory").empty())
+ {
+ LLCoros::instance().launch("LLViewerObject::fetchInventoryFromCapCoro()",
+ boost::bind(&LLViewerObject::fetchInventoryFromCapCoro, mID));
+ }
+ else
+ {
+ LL_WARNS() << "Using old task inventory path!" << LL_ENDL;
// Results in processTaskInv
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_RequestTaskInventory);
@@ -2926,15 +2943,13 @@ void LLViewerObject::fetchInventoryFromServer()
msg->nextBlockFast(_PREHASH_InventoryData);
msg->addU32Fast(_PREHASH_LocalID, mLocalID);
msg->sendReliable(mRegionp->getHost());
-
- // 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
+ // unless already waiting, drop previous request and schedule an update
if (mInvRequestState != INVENTORY_REQUEST_WAIT)
{
if (mInvRequestXFerId != 0)
@@ -2965,6 +2980,80 @@ void LLViewerObject::fetchInventoryDelayedCoro(const LLUUID task_inv, const F64
}
}
+//static
+void LLViewerObject::fetchInventoryFromCapCoro(const LLUUID task_inv)
+{
+ LLViewerObject *obj = gObjectList.findObject(task_inv);
+ if (obj)
+ {
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TaskInventoryRequest", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ std::string url = obj->mRegionp->getCapability("RequestTaskInventory") + "?task_id=" + obj->mID.asString();
+ // If we already have a copy of the inventory then add it so the server won't re-send something we already have.
+ // We expect this case to crop up in the case of failed inventory mutations, but it might happen otherwise as well.
+ if (obj->mInventorySerialNum && obj->mInventory)
+ url += "&inventory_serial=" + std::to_string(obj->mInventorySerialNum);
+
+ obj->mInvRequestState = INVENTORY_XFER;
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, url);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ // Object may have gone away while we were suspended, double-check that it still exists
+ obj = gObjectList.findObject(task_inv);
+ if (!obj)
+ {
+ LL_WARNS() << "Object " << task_inv << " went away while fetching inventory, dropping result" << LL_ENDL;
+ return;
+ }
+
+ bool potentially_stale = false;
+ if (status)
+ {
+ // Dealing with inventory serials is kind of funky. They're monotonically increasing and 16 bits,
+ // so we expect them to overflow, but we can use inv serial < expected serial as a signal that we may
+ // have mutated the task inventory since we kicked off the request, and those mutations may have not
+ // been taken into account yet. Of course, those mutations may have actually failed which would result
+ // in the inv serial never increasing.
+ //
+ // When we detect this case, set the expected inv serial to the inventory serial we actually received
+ // and kick off a re-request after a slight delay.
+ S16 serial = (S16)result["inventory_serial"].asInteger();
+ potentially_stale = serial < obj->mExpectedInventorySerialNum;
+ LL_INFOS() << "Inventory loaded for " << task_inv << LL_ENDL;
+ obj->mInventorySerialNum = serial;
+ obj->mExpectedInventorySerialNum = serial;
+ obj->loadTaskInvLLSD(result);
+ }
+ else if (status.getType() == 304)
+ {
+ LL_INFOS() << "Inventory wasn't changed on server!" << LL_ENDL;
+ obj->mInvRequestState = INVENTORY_REQUEST_STOPPED;
+ // Even though it wasn't necessary to send a response, we still may have mutated
+ // the inventory since we kicked off the request, check for that case.
+ potentially_stale = obj->mInventorySerialNum < obj->mExpectedInventorySerialNum;
+ // Set this to what we already have so that we don't re-request a second time.
+ obj->mExpectedInventorySerialNum = obj->mInventorySerialNum;
+ }
+ else
+ {
+ // Not sure that there's anything sensible we can do to recover here, retrying in a loop would be bad.
+ LL_WARNS() << "Error status while requesting task inventory: " << status.toString() << LL_ENDL;
+ obj->mInvRequestState = INVENTORY_REQUEST_STOPPED;
+ }
+
+ if (potentially_stale)
+ {
+ // Stale? I guess we can use what we got for now, but we'll have to re-request
+ LL_WARNS() << "Stale inv_serial? Re-requesting." << LL_ENDL;
+ obj->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED);
+ }
+ }
+}
+
LLControlAvatar *LLViewerObject::getControlAvatar()
{
return getRootEdit()->mControlAvatar.get();
@@ -3140,6 +3229,20 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
S16 serial = 0;
msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial);
+ if (object->mRegionp && !object->mRegionp->getCapability("RequestTaskInventory").empty())
+ {
+ // It seems that simulator may ask us to re-download the task inventory if an update to the inventory
+ // happened out-of-band while we had the object selected (like if a script is saved.)
+ //
+ // If we're meant to use the HTTP capability, ignore the contents of the UDP message and fetch the
+ // inventory via the CAP so that we don't flow down the UDP inventory request path unconditionally here.
+ // We shouldn't need to wait, as any updates should already be ready to fetch by this point.
+ LL_INFOS() << "Handling unsolicited ReplyTaskInventory for " << task_id << LL_ENDL;
+ object->mExpectedInventorySerialNum = serial;
+ object->fetchInventoryFromServer();
+ return;
+ }
+
if (serial == object->mInventorySerialNum
&& serial < object->mExpectedInventorySerialNum)
{
@@ -3347,6 +3450,47 @@ bool LLViewerObject::loadTaskInvFile(const std::string& filename)
return true;
}
+void LLViewerObject::loadTaskInvLLSD(const LLSD& inv_result)
+{
+ if (inv_result.has("contents"))
+ {
+ if(mInventory)
+ {
+ mInventory->clear(); // will deref and delete it
+ }
+ else
+ {
+ mInventory = new LLInventoryObject::object_list_t;
+ }
+
+ // Synthesize the "Contents" category, the viewer expects it, but it isn't sent.
+ LLPointer<LLInventoryObject> inv = new LLInventoryObject(mID, LLUUID::null, LLAssetType::AT_CATEGORY, "Contents");
+ mInventory->push_front(inv);
+
+ const LLSD& inventory = inv_result["contents"];
+ for (const auto& inv_entry : llsd::inArray(inventory))
+ {
+ if (inv_entry.has("item_id"))
+ {
+ LLPointer<LLViewerInventoryItem> inv = new LLViewerInventoryItem;
+ inv->unpackMessage(inv_entry);
+ mInventory->push_front(inv);
+ }
+ else
+ {
+ LL_WARNS_ONCE() << "Unknown inventory entry while reading from inventory file. Entry: '"
+ << inv_entry << "'" << LL_ENDL;
+ }
+ }
+ }
+ else
+ {
+ LL_WARNS() << "unable to load task inventory: " << inv_result << LL_ENDL;
+ return;
+ }
+ doInventoryCallback();
+}
+
void LLViewerObject::doInventoryCallback()
{
for (callback_list_t::iterator iter = mInventoryCallbacks.begin();
@@ -3747,7 +3891,7 @@ void LLViewerObject::setObjectCost(F32 cost)
mObjectCost = cost;
mCostStale = false;
- if (isSelected())
+ if (isSelected() && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -3767,7 +3911,7 @@ void LLViewerObject::setLinksetCost(F32 cost)
iter++;
}
- if (needs_refresh)
+ if (needs_refresh && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -3778,7 +3922,7 @@ void LLViewerObject::setPhysicsCost(F32 cost)
mPhysicsCost = cost;
mCostStale = false;
- if (isSelected())
+ if (isSelected() && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -3789,7 +3933,7 @@ void LLViewerObject::setLinksetPhysicsCost(F32 cost)
mLinksetPhysicsCost = cost;
mCostStale = false;
- if (isSelected())
+ if (isSelected() && gFloaterTools)
{
gFloaterTools->dirty();
}
@@ -4040,8 +4184,11 @@ void LLViewerObject::boostTexturePriority(bool boost_children /* = true */)
if (isSculpted() && !isMesh())
{
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
- LLUUID sculpt_id = sculpt_params->getSculptTexture();
- LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED);
+ if (sculpt_params)
+ {
+ LLUUID sculpt_id = sculpt_params->getSculptTexture();
+ LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED);
+ }
}
if (boost_children)
@@ -4682,6 +4829,18 @@ void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, bool damped)
else
{
setPositionRegion(pos_parent, damped);
+
+ // #1964 mark reflection probe in the linkset to update position after moving via script
+ for (LLViewerObject* child : mChildList)
+ {
+ if (child && child->isReflectionProbe())
+ {
+ if (LLDrawable* drawablep = child->mDrawable)
+ {
+ gPipeline.markMoved(drawablep);
+ }
+ }
+ }
}
}
@@ -4931,11 +5090,10 @@ void LLViewerObject::setNumTEs(const U8 num_tes)
if (base_material && override_material)
{
tep->setGLTFMaterialOverride(new LLGLTFMaterial(*override_material));
-
- LLGLTFMaterial* render_material = new LLFetchedGLTFMaterial();
- *render_material = *base_material;
- render_material->applyOverride(*override_material);
- tep->setGLTFRenderMaterial(render_material);
+ }
+ if (base_material)
+ {
+ initRenderMaterial(i);
}
}
}
@@ -5111,6 +5269,9 @@ void LLViewerObject::updateTEMaterialTextures(U8 te)
});
}
getTE(te)->setGLTFMaterial(mat);
+ initRenderMaterial(te);
+ mat = (LLFetchedGLTFMaterial*) getTE(te)->getGLTFRenderMaterial();
+ llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(getTE(te)->getGLTFRenderMaterial()) != nullptr);
}
else if (mat_id.isNull() && mat != nullptr)
{
@@ -5500,6 +5661,42 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
return retval;
}
+// Set render material if there are overrides or if the base material is has a
+// baked texture. Otherwise, set it to null.
+// If you are setting the material override and not sending an update message,
+// you should probably call this function.
+S32 LLViewerObject::initRenderMaterial(U8 te)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ LLTextureEntry* tep = getTE(te);
+ if (!tep) { return 0; }
+ const LLFetchedGLTFMaterial* base_material = static_cast<LLFetchedGLTFMaterial*>(tep->getGLTFMaterial());
+ llassert(base_material);
+ if (!base_material) { return 0; }
+ const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
+ LLFetchedGLTFMaterial* render_material = nullptr;
+ bool need_render_material = override_material;
+ if (!need_render_material)
+ {
+ for (const LLUUID& texture_id : base_material->mTextureId)
+ {
+ if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(texture_id))
+ {
+ need_render_material = true;
+ break;
+ }
+ }
+ }
+ if (need_render_material)
+ {
+ render_material = new LLFetchedGLTFMaterial(*base_material);
+ if (override_material) { render_material->applyOverride(*override_material); }
+ render_material->clearFetchedTextures();
+ }
+ return tep->setGLTFRenderMaterial(render_material);
+}
+
S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* override_mat)
{
LL_PROFILE_ZONE_SCOPED;
@@ -5533,22 +5730,13 @@ S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* override_ma
if (retval)
{
+ retval = initRenderMaterial(te) | retval;
if (override_mat)
{
- LLFetchedGLTFMaterial* render_mat = new LLFetchedGLTFMaterial(*src_mat);
- render_mat->applyOverride(*override_mat);
- tep->setGLTFRenderMaterial(render_mat);
- retval = TEM_CHANGE_TEXTURE;
-
for (LLGLTFMaterial::local_tex_map_t::value_type &val : override_mat->mTrackingIdToLocalTexture)
{
LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(val.first, override_mat);
}
-
- }
- else if (tep->setGLTFRenderMaterial(nullptr))
- {
- retval = TEM_CHANGE_TEXTURE;
}
}
@@ -7047,7 +7235,7 @@ void LLAlphaObject::getBlendFunc(S32 face, LLRender::eBlendFactor& src, LLRender
void LLStaticViewerObject::updateDrawable(bool force_damped)
{
// Force an immediate rebuild on any update
- if (mDrawable.notNull())
+ if (mDrawable.notNull() && mDrawable->getVObj())
{
mDrawable->updateXform(true);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL);
@@ -7418,25 +7606,15 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat
// the overrides have not changed due to being only texture
// transforms. Re-apply the overrides to the render material here,
// if present.
- const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
- if (override_material)
+ // Also, sometimes, the material has baked textures, which requires
+ // a copy unique to this object.
+ // Currently, we do not deduplicate render materials.
+ new_material->onMaterialComplete([obj_id = getID(), te]()
{
- new_material->onMaterialComplete([obj_id = getID(), te]()
- {
- LLViewerObject* obj = gObjectList.findObject(obj_id);
- if (!obj) { return; }
- LLTextureEntry* tep = obj->getTE(te);
- if (!tep) { return; }
- const LLGLTFMaterial* new_material = tep->getGLTFMaterial();
- if (!new_material) { return; }
- const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
- if (!override_material) { return; }
- LLGLTFMaterial* render_material = new LLFetchedGLTFMaterial();
- *render_material = *new_material;
- render_material->applyOverride(*override_material);
- tep->setGLTFRenderMaterial(render_material);
- });
- }
+ LLViewerObject* obj = gObjectList.findObject(obj_id);
+ if (!obj) { return; }
+ obj->initRenderMaterial(te);
+ });
}
}
@@ -7532,6 +7710,76 @@ void LLViewerObject::setGLTFAsset(const LLUUID& id)
updateVolume(volume_params);
}
+void LLViewerObject::clearTEWaterExclusion(const U8 te)
+{
+ if (permModify())
+ {
+ LLViewerTexture* image = getTEImage(te);
+ if (image && (IMG_ALPHA_GRAD == image->getID()))
+ {
+ // reset texture to default plywood
+ setTEImage(te, LLViewerTextureManager::getFetchedTexture(DEFAULT_OBJECT_TEXTURE, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+
+ // reset texture repeats, that might be altered by invisiprim script from wiki
+ U32 s_axis, t_axis;
+ if (!LLPrimitive::getTESTAxes(te, &s_axis, &t_axis))
+ {
+ return;
+ }
+ F32 DEFAULT_REPEATS = 2.f;
+ F32 new_s = getScale().mV[s_axis] * DEFAULT_REPEATS;
+ F32 new_t = getScale().mV[t_axis] * DEFAULT_REPEATS;
+
+ setTEScale(te, new_s, new_t);
+ sendTEUpdate();
+ }
+ }
+}
+
+bool LLViewerObject::isReachable()
+{
+ LLViewerRegion* agent_region = gAgent.getRegion();
+ LLViewerRegion* object_region = getRegion();
+
+ if (!agent_region || !object_region)
+ {
+ return false;
+ }
+ if (agent_region == object_region)
+ {
+ return true;
+ }
+
+ std::unordered_set<LLViewerRegion*> visited;
+ std::queue<LLViewerRegion*> pending;
+ visited.insert(agent_region);
+ pending.push(agent_region);
+
+ while (!pending.empty())
+ {
+ LLViewerRegion* current = pending.front();
+ pending.pop();
+
+ std::vector<LLViewerRegion*> neighbors;
+ current->getNeighboringRegions(neighbors);
+
+ for (LLViewerRegion* neighbor : neighbors)
+ {
+ if (!neighbor) continue;
+
+ if (neighbor == object_region)
+ {
+ return true;
+ }
+ // region's neighbors were not checked
+ if (visited.insert(neighbor).second)
+ {
+ pending.push(neighbor);
+ }
+ }
+ }
+ return false;
+}
class ObjectPhysicsProperties : public LLHTTPNode
{