@@ -402,16 +402,16 @@ void LLPanelLocalAssetBase::onRemoveBtn()
402402
403403 for (const auto & entry : selected)
404404 {
405- if (!entry. first . empty ())
406- {
407- LLLocalAssetPaths::getInstance ()-> removePath ( assetType (), entry. first ); // forget the path
408- }
409- // Unload every decoded unit backing this row. For a multi-material glTF file
410- // that's all of the file's material units, not just the selected row .
405+ // Unload every decoded unit backing this row FIRST and forget the path
406+ // only once they are all gone. delUnit() fires the manager signals
407+ // synchronously, and the add-only LLLocalAssetPaths::onUnitsChanged()
408+ // re-records any path a still-loaded unit reports -- removePath() up
409+ // front would be undone by the very first delUnit (mesh teardown, or a
410+ // multi-material glTF file's surviving sibling units) .
411411 std::vector<LLUUID > ids;
412412 if (!entry.first .empty ())
413413 {
414- unitsForPath (entry.first , ids);
414+ unitsForPath (entry.first , ids); // all of the file's units, not just the row
415415 }
416416 if (ids.empty () && entry.second .notNull ())
417417 {
@@ -421,6 +421,10 @@ void LLPanelLocalAssetBase::onRemoveBtn()
421421 {
422422 delUnit (id); // unload the decoded unit (fires the manager signal)
423423 }
424+ if (!entry.first .empty ())
425+ {
426+ LLLocalAssetPaths::getInstance ()->removePath (assetType (), entry.first ); // forget the path
427+ }
424428 }
425429 refresh (); // removePath() alone (undecoded rows) doesn't fire a manager signal
426430}
@@ -723,11 +727,15 @@ void LLPanelLocalMesh::onRez()
723727 doSpawn (id); // always rez a new copy
724728 return ;
725729 }
726- // Undecoded: load it and rez once it finishes (addAndSpawn handles the async load).
730+ // Undecoded: load it and rez once it finishes (addAndSpawn handles the async
731+ // load). Decode with the joint-position flag the artist saved for this file,
732+ // like loadPath -- defaulting it would also make onUnitsChanged erase the
733+ // saved flag.
727734 const std::string path = getSelectedPath ();
728735 if (!path.empty ())
729736 {
730- LLLocalMeshMgr::getInstance ()->addAndSpawn (std::vector<std::string>(1 , path));
737+ LLLocalMeshMgr::getInstance ()->addAndSpawn (std::vector<std::string>(1 , path),
738+ LLLocalAssetPaths::getInstance ()->getMeshJoints (path));
731739 }
732740}
733741
@@ -740,11 +748,12 @@ void LLPanelLocalMesh::onAttach()
740748 return ;
741749 }
742750 // Undecoded row: load it and attach once it finishes loading (mirrors how Rez
743- // handles an undecoded row via addAndSpawn).
751+ // handles an undecoded row via addAndSpawn), honoring the saved joint flag .
744752 const std::string path = getSelectedPath ();
745753 if (!path.empty ())
746754 {
747- LLLocalMeshMgr::getInstance ()->addAndAttach (path, getComboAttachPoint ());
755+ LLLocalMeshMgr::getInstance ()->addAndAttach (path, getComboAttachPoint (),
756+ LLLocalAssetPaths::getInstance ()->getMeshJoints (path));
748757 }
749758}
750759
@@ -837,9 +846,13 @@ void LLPanelLocalMesh::doRemove(const LLUUID& tracking_id)
837846{
838847 if (tracking_id.notNull ())
839848 {
840- LLLocalAssetPaths::getInstance ()->removePath (LLLocalAssetPaths::TYPE_MESH ,
841- pathForUnit (tracking_id));
849+ // Resolve the path before the unit dies, but forget it only AFTER
850+ // delUnit: the units-changed listeners fire during teardown and the
851+ // add-only LLLocalAssetPaths::onUnitsChanged would re-record a path
852+ // removed up front (see onRemoveBtn).
853+ const std::string path = pathForUnit (tracking_id);
842854 delUnit (tracking_id); // units-changed signal -> refresh()
855+ LLLocalAssetPaths::getInstance ()->removePath (LLLocalAssetPaths::TYPE_MESH , path);
843856 }
844857}
845858
@@ -1217,7 +1230,9 @@ class LLPanelLocalTexture final : public LLPanelLocalApplyAsset
12171230 }
12181231 LLUUID unitForPath (const std::string& path) const override
12191232 {
1220- return LLLocalBitmapMgr::getInstance ()->getUnitID (path);
1233+ // User units only: a mesh-owned import of the same file is a distinct,
1234+ // read-only unit this tab must neither claim as loaded nor delete.
1235+ return LLLocalBitmapMgr::getInstance ()->getUnitID (path, /* mesh_owned=*/ false );
12211236 }
12221237 std::string pathForUnit (const LLUUID & tracking_id) const override
12231238 {
@@ -1271,8 +1286,9 @@ class LLPanelLocalMaterial final : public LLPanelLocalApplyAsset
12711286 }
12721287 LLUUID unitForPath (const std::string& path) const override
12731288 {
1274- // A file holds >= 1 material; treat it as loaded if its first material is.
1275- return LLLocalGLTFMaterialMgr::getInstance ()->getUnitID (path, 0 );
1289+ // A file holds >= 1 material; treat it as loaded if its first USER material
1290+ // is (a mesh-owned import of the same file is a distinct, read-only set).
1291+ return LLLocalGLTFMaterialMgr::getInstance ()->getUnitID (path, 0 , /* mesh_owned=*/ false );
12761292 }
12771293 std::string pathForUnit (const LLUUID & tracking_id) const override
12781294 {
@@ -1283,8 +1299,10 @@ class LLPanelLocalMaterial final : public LLPanelLocalApplyAsset
12831299 }
12841300 void unitsForPath (const std::string& path, std::vector<LLUUID >& out) const override
12851301 {
1286- // One .gltf/.glb can decode to several material units; remove them all.
1287- LLLocalGLTFMaterialMgr::getInstance ()->getTrackingIDs (path, out);
1302+ // One .gltf/.glb can decode to several material units; act on all of the
1303+ // USER's. Mesh-owned imports of the same file belong to a loaded mesh and
1304+ // must not be deleted from this tab.
1305+ LLLocalGLTFMaterialMgr::getInstance ()->getTrackingIDs (path, out, /* mesh_owned=*/ false );
12881306 }
12891307 std::string iconName () const override
12901308 {
0 commit comments