llinventoryobserver.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:15k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llinventoryobserver.cpp
  3.  * @brief Implementation of the inventory observers used to track agent inventory.
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llinventoryobserver.h"
  34. #include "llassetstorage.h"
  35. #include "llcrc.h"
  36. #include "lldir.h"
  37. #include "llsys.h"
  38. #include "llxfermanager.h"
  39. #include "message.h"
  40. #include "llagent.h"
  41. #include "llagentwearables.h"
  42. #include "llfloater.h"
  43. #include "llfocusmgr.h"
  44. #include "llinventorybridge.h"
  45. #include "llinventoryfunctions.h"
  46. #include "llinventorymodel.h"
  47. #include "llviewermessage.h"
  48. #include "llviewerwindow.h"
  49. #include "llviewerregion.h"
  50. #include "llappviewer.h"
  51. #include "lldbstrings.h"
  52. #include "llviewerstats.h"
  53. #include "llmutelist.h"
  54. #include "llnotificationsutil.h"
  55. #include "llcallbacklist.h"
  56. #include "llpreview.h"
  57. #include "llviewercontrol.h"
  58. #include "llvoavatarself.h"
  59. #include "llsdutil.h"
  60. #include <deque>
  61. LLInventoryObserver::LLInventoryObserver()
  62. {
  63. }
  64. // virtual
  65. LLInventoryObserver::~LLInventoryObserver()
  66. {
  67. }
  68. void LLInventoryCompletionObserver::changed(U32 mask)
  69. {
  70. // scan through the incomplete items and move or erase them as
  71. // appropriate.
  72. if(!mIncomplete.empty())
  73. {
  74. for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); )
  75. {
  76. LLViewerInventoryItem* item = gInventory.getItem(*it);
  77. if(!item)
  78. {
  79. it = mIncomplete.erase(it);
  80. continue;
  81. }
  82. if(item->isComplete())
  83. {
  84. mComplete.push_back(*it);
  85. it = mIncomplete.erase(it);
  86. continue;
  87. }
  88. ++it;
  89. }
  90. if(mIncomplete.empty())
  91. {
  92. done();
  93. }
  94. }
  95. }
  96. void LLInventoryCompletionObserver::watchItem(const LLUUID& id)
  97. {
  98. if(id.notNull())
  99. {
  100. mIncomplete.push_back(id);
  101. }
  102. }
  103. void LLInventoryFetchObserver::changed(U32 mask)
  104. {
  105. // scan through the incomplete items and move or erase them as
  106. // appropriate.
  107. if(!mIncomplete.empty())
  108. {
  109. for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); )
  110. {
  111. LLViewerInventoryItem* item = gInventory.getItem(*it);
  112. if(!item)
  113. {
  114. if (mRetryIfMissing)
  115. {
  116. // BAP changed to skip these items, so we should keep retrying until they arrive.
  117. // Did not make this the default behavior because of uncertainty about impact -
  118. // could cause some observers that currently complete to wait forever.
  119. ++it;
  120. }
  121. else
  122. {
  123. // BUG: This can cause done() to get called prematurely below.
  124. // This happens with the LLGestureInventoryFetchObserver that
  125. // loads gestures at startup. JC
  126. it = mIncomplete.erase(it);
  127. }
  128. continue;
  129. }
  130. if(item->isComplete())
  131. {
  132. mComplete.push_back(*it);
  133. it = mIncomplete.erase(it);
  134. continue;
  135. }
  136. ++it;
  137. }
  138. if(mIncomplete.empty())
  139. {
  140. done();
  141. }
  142. }
  143. //llinfos << "LLInventoryFetchObserver::changed() mComplete size " << mComplete.size() << llendl;
  144. //llinfos << "LLInventoryFetchObserver::changed() mIncomplete size " << mIncomplete.size() << llendl;
  145. }
  146. bool LLInventoryFetchObserver::isEverythingComplete() const
  147. {
  148. return mIncomplete.empty();
  149. }
  150. void fetch_items_from_llsd(const LLSD& items_llsd)
  151. {
  152. if (!items_llsd.size()) return;
  153. LLSD body;
  154. body[0]["cap_name"] = "FetchInventory";
  155. body[1]["cap_name"] = "FetchLib";
  156. for (S32 i=0; i<items_llsd.size();i++)
  157. {
  158. if (items_llsd[i]["owner_id"].asString() == gAgent.getID().asString())
  159. {
  160. body[0]["items"].append(items_llsd[i]);
  161. continue;
  162. }
  163. if (items_llsd[i]["owner_id"].asString() == ALEXANDRIA_LINDEN_ID.asString())
  164. {
  165. body[1]["items"].append(items_llsd[i]);
  166. continue;
  167. }
  168. }
  169. for (S32 i=0; i<body.size(); i++)
  170. {
  171. if (0 >= body[i].size()) continue;
  172. std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString());
  173. if (!url.empty())
  174. {
  175. body[i]["agent_id"] = gAgent.getID();
  176. LLHTTPClient::post(url, body[i], new LLInventoryModel::fetchInventoryResponder(body[i]));
  177. break;
  178. }
  179. LLMessageSystem* msg = gMessageSystem;
  180. BOOL start_new_message = TRUE;
  181. for (S32 j=0; j<body[i]["items"].size(); j++)
  182. {
  183. LLSD item_entry = body[i]["items"][j];
  184. if(start_new_message)
  185. {
  186. start_new_message = FALSE;
  187. msg->newMessageFast(_PREHASH_FetchInventory);
  188. msg->nextBlockFast(_PREHASH_AgentData);
  189. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  190. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  191. }
  192. msg->nextBlockFast(_PREHASH_InventoryData);
  193. msg->addUUIDFast(_PREHASH_OwnerID, item_entry["owner_id"].asUUID());
  194. msg->addUUIDFast(_PREHASH_ItemID, item_entry["item_id"].asUUID());
  195. if(msg->isSendFull(NULL))
  196. {
  197. start_new_message = TRUE;
  198. gAgent.sendReliableMessage();
  199. }
  200. }
  201. if(!start_new_message)
  202. {
  203. gAgent.sendReliableMessage();
  204. }
  205. }
  206. }
  207. void LLInventoryFetchObserver::fetchItems(
  208. const LLInventoryFetchObserver::item_ref_t& ids)
  209. {
  210. LLUUID owner_id;
  211. LLSD items_llsd;
  212. for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it)
  213. {
  214. LLViewerInventoryItem* item = gInventory.getItem(*it);
  215. if(item)
  216. {
  217. if(item->isComplete())
  218. {
  219. // It's complete, so put it on the complete container.
  220. mComplete.push_back(*it);
  221. continue;
  222. }
  223. else
  224. {
  225. owner_id = item->getPermissions().getOwner();
  226. }
  227. }
  228. else
  229. {
  230. // assume it's agent inventory.
  231. owner_id = gAgent.getID();
  232. }
  233. // It's incomplete, so put it on the incomplete container, and
  234. // pack this on the message.
  235. mIncomplete.push_back(*it);
  236. // Prepare the data to fetch
  237. LLSD item_entry;
  238. item_entry["owner_id"] = owner_id;
  239. item_entry["item_id"] = (*it);
  240. items_llsd.append(item_entry);
  241. }
  242. fetch_items_from_llsd(items_llsd);
  243. }
  244. // virtual
  245. void LLInventoryFetchDescendentsObserver::changed(U32 mask)
  246. {
  247. for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();)
  248. {
  249. LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
  250. if(!cat)
  251. {
  252. it = mIncompleteFolders.erase(it);
  253. continue;
  254. }
  255. if(isComplete(cat))
  256. {
  257. mCompleteFolders.push_back(*it);
  258. it = mIncompleteFolders.erase(it);
  259. continue;
  260. }
  261. ++it;
  262. }
  263. if(mIncompleteFolders.empty())
  264. {
  265. done();
  266. }
  267. }
  268. void LLInventoryFetchDescendentsObserver::fetchDescendents(
  269. const folder_ref_t& ids)
  270. {
  271. for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
  272. {
  273. LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
  274. if(!cat) continue;
  275. if(!isComplete(cat))
  276. {
  277. cat->fetchDescendents(); //blindly fetch it without seeing if anything else is fetching it.
  278. mIncompleteFolders.push_back(*it); //Add to list of things being downloaded for this observer.
  279. }
  280. else
  281. {
  282. mCompleteFolders.push_back(*it);
  283. }
  284. }
  285. }
  286. bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const
  287. {
  288. return mIncompleteFolders.empty();
  289. }
  290. bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat)
  291. {
  292. const S32 version = cat->getVersion();
  293. const S32 expected_num_descendents = cat->getDescendentCount();
  294. if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) ||
  295. (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN))
  296. {
  297. return false;
  298. }
  299. // it might be complete - check known descendents against
  300. // currently available.
  301. LLInventoryModel::cat_array_t* cats;
  302. LLInventoryModel::item_array_t* items;
  303. gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
  304. if(!cats || !items)
  305. {
  306. llwarns << "Category '" << cat->getName() << "' descendents corrupted, fetch failed." << llendl;
  307. // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean
  308. // that the cat just doesn't have any items or subfolders).
  309. // Unrecoverable, so just return done so that this observer can be cleared
  310. // from memory.
  311. return true;
  312. }
  313. const S32 current_num_known_descendents = cats->count() + items->count();
  314. // Got the number of descendents that we were expecting, so we're done.
  315. if (current_num_known_descendents == expected_num_descendents)
  316. {
  317. return true;
  318. }
  319. // Error condition, but recoverable.  This happens if something was added to the
  320. // category before it was initialized, so accountForUpdate didn't update descendent
  321. // count and thus the category thinks it has fewer descendents than it actually has.
  322. if (current_num_known_descendents >= expected_num_descendents)
  323. {
  324. llwarns << "Category '" << cat->getName() << "' expected descendentcount:" << expected_num_descendents << " descendents but got descendentcount:" << current_num_known_descendents << llendl;
  325. cat->setDescendentCount(current_num_known_descendents);
  326. return true;
  327. }
  328. return false;
  329. }
  330. void LLInventoryFetchComboObserver::changed(U32 mask)
  331. {
  332. if(!mIncompleteItems.empty())
  333. {
  334. for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); )
  335. {
  336. LLViewerInventoryItem* item = gInventory.getItem(*it);
  337. if(!item)
  338. {
  339. it = mIncompleteItems.erase(it);
  340. continue;
  341. }
  342. if(item->isComplete())
  343. {
  344. mCompleteItems.push_back(*it);
  345. it = mIncompleteItems.erase(it);
  346. continue;
  347. }
  348. ++it;
  349. }
  350. }
  351. if(!mIncompleteFolders.empty())
  352. {
  353. for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();)
  354. {
  355. LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
  356. if(!cat)
  357. {
  358. it = mIncompleteFolders.erase(it);
  359. continue;
  360. }
  361. if(gInventory.isCategoryComplete(*it))
  362. {
  363. mCompleteFolders.push_back(*it);
  364. it = mIncompleteFolders.erase(it);
  365. continue;
  366. }
  367. ++it;
  368. }
  369. }
  370. if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty())
  371. {
  372. mDone = true;
  373. done();
  374. }
  375. }
  376. void LLInventoryFetchComboObserver::fetch(
  377. const folder_ref_t& folder_ids,
  378. const item_ref_t& item_ids)
  379. {
  380. lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl;
  381. for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit)
  382. {
  383. LLViewerInventoryCategory* cat = gInventory.getCategory(*fit);
  384. if(!cat) continue;
  385. if(!gInventory.isCategoryComplete(*fit))
  386. {
  387. cat->fetchDescendents();
  388. lldebugs << "fetching folder " << *fit <<llendl;
  389. mIncompleteFolders.push_back(*fit);
  390. }
  391. else
  392. {
  393. mCompleteFolders.push_back(*fit);
  394. lldebugs << "completing folder " << *fit <<llendl;
  395. }
  396. }
  397. // Now for the items - we fetch everything which is not a direct
  398. // descendent of an incomplete folder because the item will show
  399. // up in an inventory descendents message soon enough so we do not
  400. // have to fetch it individually.
  401. LLSD items_llsd;
  402. LLUUID owner_id;
  403. for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit)
  404. {
  405. LLViewerInventoryItem* item = gInventory.getItem(*iit);
  406. if(!item)
  407. {
  408. lldebugs << "uanble to find item " << *iit << llendl;
  409. continue;
  410. }
  411. if(item->isComplete())
  412. {
  413. // It's complete, so put it on the complete container.
  414. mCompleteItems.push_back(*iit);
  415. lldebugs << "completing item " << *iit << llendl;
  416. continue;
  417. }
  418. else
  419. {
  420. mIncompleteItems.push_back(*iit);
  421. owner_id = item->getPermissions().getOwner();
  422. }
  423. if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end())
  424. {
  425. LLSD item_entry;
  426. item_entry["owner_id"] = owner_id;
  427. item_entry["item_id"] = (*iit);
  428. items_llsd.append(item_entry);
  429. }
  430. else
  431. {
  432. lldebugs << "not worrying about " << *iit << llendl;
  433. }
  434. }
  435. fetch_items_from_llsd(items_llsd);
  436. }
  437. void LLInventoryExistenceObserver::watchItem(const LLUUID& id)
  438. {
  439. if(id.notNull())
  440. {
  441. mMIA.push_back(id);
  442. }
  443. }
  444. void LLInventoryExistenceObserver::changed(U32 mask)
  445. {
  446. // scan through the incomplete items and move or erase them as
  447. // appropriate.
  448. if(!mMIA.empty())
  449. {
  450. for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); )
  451. {
  452. LLViewerInventoryItem* item = gInventory.getItem(*it);
  453. if(!item)
  454. {
  455. ++it;
  456. continue;
  457. }
  458. mExist.push_back(*it);
  459. it = mMIA.erase(it);
  460. }
  461. if(mMIA.empty())
  462. {
  463. done();
  464. }
  465. }
  466. }
  467. void LLInventoryAddedObserver::changed(U32 mask)
  468. {
  469. if(!(mask & LLInventoryObserver::ADD))
  470. {
  471. return;
  472. }
  473. // *HACK: If this was in response to a packet off
  474. // the network, figure out which item was updated.
  475. LLMessageSystem* msg = gMessageSystem;
  476. std::string msg_name;
  477. if (mMessageName.empty())
  478. {
  479. msg_name = msg->getMessageName();
  480. }
  481. else
  482. {
  483. msg_name = mMessageName;
  484. }
  485. if (msg_name.empty())
  486. {
  487. return;
  488. }
  489. // We only want newly created inventory items. JC
  490. if ( msg_name != "UpdateCreateInventoryItem")
  491. {
  492. return;
  493. }
  494. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  495. S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  496. for(S32 i = 0; i < num_blocks; ++i)
  497. {
  498. titem->unpackMessage(msg, _PREHASH_InventoryData, i);
  499. if (!(titem->getUUID().isNull()))
  500. {
  501. //we don't do anything with null keys
  502. mAdded.push_back(titem->getUUID());
  503. }
  504. }
  505. if (!mAdded.empty())
  506. {
  507. done();
  508. }
  509. }
  510. LLInventoryTransactionObserver::LLInventoryTransactionObserver(
  511. const LLTransactionID& transaction_id) :
  512. mTransactionID(transaction_id)
  513. {
  514. }
  515. void LLInventoryTransactionObserver::changed(U32 mask)
  516. {
  517. if(mask & LLInventoryObserver::ADD)
  518. {
  519. // This could be it - see if we are processing a bulk update
  520. LLMessageSystem* msg = gMessageSystem;
  521. if(msg->getMessageName()
  522.    && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory")))
  523. {
  524. // we have a match for the message - now check the
  525. // transaction id.
  526. LLUUID id;
  527. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id);
  528. if(id == mTransactionID)
  529. {
  530. // woo hoo, we found it
  531. folder_ref_t folders;
  532. item_ref_t items;
  533. S32 count;
  534. count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  535. S32 i;
  536. for(i = 0; i < count; ++i)
  537. {
  538. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i);
  539. if(id.notNull())
  540. {
  541. folders.push_back(id);
  542. }
  543. }
  544. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  545. for(i = 0; i < count; ++i)
  546. {
  547. msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i);
  548. if(id.notNull())
  549. {
  550. items.push_back(id);
  551. }
  552. }
  553. // call the derived class the implements this method.
  554. done(folders, items);
  555. }
  556. }
  557. }
  558. }