SeedListFileTableModel.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <source/models/SeedListFileTableModel.h>
  9. #include <source/models/SeedListTableModel.h>
  10. #include <source/ui/SeedTabWidget.h>
  11. #include <source/utils/utils.h>
  12. #include <AzCore/Outcome/Outcome.h>
  13. #include <AzCore/std/smart_ptr/make_shared.h>
  14. #include <AzFramework/IO/LocalFileIO.h>
  15. #include <AzFramework/StringFunc/StringFunc.h>
  16. #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
  17. #include <QFileInfo>
  18. #include <QFont>
  19. namespace AssetBundler
  20. {
  21. //////////////////////////////////////////////////////////////////////////////////////////////////
  22. // SeedListFileInfo
  23. //////////////////////////////////////////////////////////////////////////////////////////////////
  24. SeedListFileInfo::SeedListFileInfo(
  25. const AZStd::string& absolutePath,
  26. const QString& fileName,
  27. const QString& project,
  28. bool loadFromFile,
  29. bool isDefaultSeedList,
  30. const AZStd::vector<AZStd::string>& defaultSeeds,
  31. const AzFramework::PlatformFlags& platforms)
  32. : m_absolutePath(absolutePath)
  33. , m_fileName(fileName)
  34. , m_project(project)
  35. , m_isDefaultSeedList(isDefaultSeedList)
  36. {
  37. AzFramework::StringFunc::Path::Normalize(m_absolutePath);
  38. // Load the contents of the seed file into memory
  39. if (loadFromFile)
  40. {
  41. m_seedListModel.reset(new SeedListTableModel(nullptr, absolutePath));
  42. QFileInfo fileInfo(m_absolutePath.c_str());
  43. m_fileModificationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
  44. }
  45. else
  46. {
  47. m_seedListModel.reset(new SeedListTableModel(nullptr, "", defaultSeeds, platforms));
  48. m_fileModificationTime = QDateTime::currentDateTime();
  49. }
  50. }
  51. bool SeedListFileInfo::SaveSeedFile()
  52. {
  53. if (m_seedListModel->Save(m_absolutePath))
  54. {
  55. m_fileModificationTime = QDateTime::currentDateTime();
  56. return true;
  57. }
  58. return false;
  59. }
  60. bool SeedListFileInfo::HasUnsavedChanges()
  61. {
  62. return m_seedListModel->HasUnsavedChanges();
  63. }
  64. //////////////////////////////////////////////////////////////////////////////////////////////////
  65. // SeedListFileTableModel
  66. //////////////////////////////////////////////////////////////////////////////////////////////////
  67. SeedListFileTableModel::SeedListFileTableModel(SeedTabWidget* parentSeedTabWidget)
  68. : AssetBundlerAbstractFileTableModel()
  69. , m_seedTabWidget(parentSeedTabWidget)
  70. {
  71. m_inMemoryDefaultSeedList.reset(new SeedListFileInfo("", "", "", false));
  72. }
  73. SeedListFileTableModel::~SeedListFileTableModel()
  74. {
  75. m_seedTabWidget = nullptr;
  76. }
  77. void SeedListFileTableModel::AddDefaultSeedsToInMemoryList(
  78. const AZStd::vector<AZStd::string>& defaultSeeds,
  79. const char* projectName,
  80. const AzFramework::PlatformFlags& platforms)
  81. {
  82. m_inMemoryDefaultSeedList.reset(
  83. new SeedListFileInfo(m_inMemoryDefaultSeedListKey, tr("DefaultSeeds"), QString(projectName), false, true, defaultSeeds, platforms));
  84. }
  85. AZStd::vector<AZStd::string> SeedListFileTableModel::CreateNewFiles(
  86. const AZStd::string& absoluteFilePath,
  87. const AzFramework::PlatformFlags& /*platforms*/,
  88. const QString& project)
  89. {
  90. if (absoluteFilePath.empty())
  91. {
  92. AZ_Error(AssetBundler::AppWindowName, false, "Input file path is empty.");
  93. return {};
  94. }
  95. // Get the file name without the extension for display purposes
  96. AZStd::string fileName;
  97. AzFramework::StringFunc::Path::GetFileName(absoluteFilePath.c_str(), fileName);
  98. // Create a Seed List File and save it to disk
  99. AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
  100. AZStd::shared_ptr<SeedListFileInfo> newSeedListFile =
  101. AZStd::make_shared<SeedListFileInfo>(absoluteFilePath, QString(fileName.c_str()), project, false);
  102. newSeedListFile->m_seedListModel->SetHasUnsavedChanges(true);
  103. bool saveResult = newSeedListFile->SaveSeedFile();
  104. if (!saveResult)
  105. {
  106. AZ_Error(AssetBundler::AppWindowName, false, "Unable to create Seed List File: %s", absoluteFilePath.c_str());
  107. return {};
  108. }
  109. // Add new file to the model
  110. m_seedListFileInfoMap[key] = newSeedListFile;
  111. AddFileKey(key);
  112. AZStd::vector<AZStd::string> createdFiles = { absoluteFilePath };
  113. return createdFiles;
  114. }
  115. bool SeedListFileTableModel::DeleteFile(const QModelIndex& index)
  116. {
  117. AZStd::string key = GetFileKey(index);
  118. if (key.empty())
  119. {
  120. // Error has already been thrown
  121. return false;
  122. }
  123. if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
  124. {
  125. AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
  126. return false;
  127. }
  128. SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
  129. // Remove file from disk
  130. const char* absolutePath = seedFileInfo->m_absolutePath.c_str();
  131. if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath))
  132. {
  133. if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(absolutePath))
  134. {
  135. AZ_Error(AssetBundler::AppWindowName, false, ReadOnlyFileErrorMessage, absolutePath);
  136. return false;
  137. }
  138. auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(absolutePath);
  139. if (!deleteResult)
  140. {
  141. AZ_Error(AssetBundler::AppWindowName, false,
  142. "Unable to delete (%s). Result code: %u", absolutePath, deleteResult.GetResultCode());
  143. return false;
  144. }
  145. }
  146. // Remove file from model
  147. m_seedListFileInfoMap.erase(key);
  148. RemoveFileKey(index);
  149. return true;
  150. }
  151. void SeedListFileTableModel::Reload(
  152. const char* fileExtension,
  153. const QSet<QString>& watchedFolders,
  154. const QSet<QString>& watchedFiles,
  155. const AZStd::unordered_map<AZStd::string, AZStd::string>& pathToProjectNameMap)
  156. {
  157. // Load in the Seed List files from disk
  158. AssetBundlerAbstractFileTableModel::Reload(fileExtension, watchedFolders, watchedFiles, pathToProjectNameMap);
  159. // Add the in-memory Default Seed List to the model
  160. m_seedListFileInfoMap[m_inMemoryDefaultSeedListKey] = m_inMemoryDefaultSeedList;
  161. AddFileKey(m_inMemoryDefaultSeedListKey);
  162. }
  163. void SeedListFileTableModel::LoadFile(const AZStd::string& absoluteFilePath, const AZStd::string& projectName, bool isDefaultFile)
  164. {
  165. // Get the file name without the extension for display purposes
  166. AZStd::string fileName;
  167. AzFramework::StringFunc::Path::GetFileName(absoluteFilePath.c_str(), fileName);
  168. // Read the SeedListFile into memory and store it
  169. AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
  170. auto fileInfoIt = m_seedListFileInfoMap.find(key);
  171. if (fileInfoIt != m_seedListFileInfoMap.end() && fileInfoIt->second->HasUnsavedChanges())
  172. {
  173. AZ_Warning(AssetBundler::AppWindowName, false,
  174. "Seed List File %s has unsaved changes and couldn't be reloaded", absoluteFilePath.c_str());
  175. return;
  176. }
  177. AZStd::string projectNameOnDisplay = projectName;
  178. if (projectName.empty())
  179. {
  180. auto outcome = AssetBundler::GetCurrentProjectName();
  181. if (!outcome.IsSuccess())
  182. {
  183. AZ_Error(AssetBundler::AppWindowName, false, outcome.TakeError().c_str());
  184. return;
  185. }
  186. projectNameOnDisplay = outcome.TakeValue();
  187. }
  188. m_seedListFileInfoMap[key].reset(
  189. new SeedListFileInfo(absoluteFilePath, QString(fileName.c_str()), QString(projectNameOnDisplay.c_str()), true, isDefaultFile));
  190. AddFileKey(key);
  191. }
  192. void SeedListFileTableModel::SelectDefaultSeedLists(bool setSelected)
  193. {
  194. for (const AZStd::string& key : GetAllFileKeys())
  195. {
  196. auto seedFileInfo = m_seedListFileInfoMap[key];
  197. if (!seedFileInfo->m_isDefaultSeedList)
  198. {
  199. continue;
  200. }
  201. seedFileInfo->m_isChecked = setSelected;
  202. if(setSelected)
  203. {
  204. m_checkedSeedListFiles.insert(key);
  205. }
  206. else
  207. {
  208. m_checkedSeedListFiles.erase(key);
  209. }
  210. }
  211. m_seedTabWidget->SetGenerateAssetListsButtonEnabled(!m_checkedSeedListFiles.empty());
  212. // Update the Check State display of all elements
  213. QModelIndex firstIndex = index(0, 0);
  214. QModelIndex lastIndex = index(rowCount() - 1, columnCount() - 1);
  215. emit dataChanged(firstIndex, lastIndex, { Qt::CheckStateRole });
  216. }
  217. AZStd::vector<AZStd::string> SeedListFileTableModel::GenerateAssetLists(
  218. const AZStd::string& absoluteFilePath,
  219. const AzFramework::PlatformFlags& platforms)
  220. {
  221. if (!m_checkedSeedListFiles.size())
  222. {
  223. AZ_Error(AssetBundler::AppWindowName, false, "Cannot Generate Asset List File(s): No Seed List Files are selected");
  224. return {};
  225. }
  226. if (absoluteFilePath.empty())
  227. {
  228. AZ_Error(AssetBundler::AppWindowName, false, "File path cannot be empty");
  229. return {};
  230. }
  231. if(platforms == AzFramework::PlatformFlags::Platform_NONE)
  232. {
  233. AZ_Error(AssetBundler::AppWindowName, false, "Input platform cannot be empty");
  234. return {};
  235. }
  236. // Get all of the Seeds into one AssetSeedManager
  237. AzToolsFramework::AssetSeedManager assetSeedManager;
  238. if (m_checkedSeedListFiles.find(m_inMemoryDefaultSeedListKey) != m_checkedSeedListFiles.end())
  239. {
  240. // The In-Memory Default Seed List can't be loaded from a file on disk, it is a special case
  241. assetSeedManager = *m_inMemoryDefaultSeedList->m_seedListModel->GetSeedListManager().get();
  242. m_checkedSeedListFiles.erase(m_inMemoryDefaultSeedListKey);
  243. }
  244. for (const auto& checkedSeedFileKey : m_checkedSeedListFiles)
  245. {
  246. assetSeedManager.Load(m_seedListFileInfoMap[checkedSeedFileKey]->m_absolutePath);
  247. }
  248. // Generate an AssetList for every input platform
  249. AZStd::vector<AZStd::string> createdFiles;
  250. for (const auto& platformIndex : AzFramework::PlatformHelper::GetPlatformIndicesInterpreted(platforms))
  251. {
  252. AZStd::string platformSpecificCachePath =
  253. AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(platformIndex);
  254. AzFramework::StringFunc::Path::StripFullName(platformSpecificCachePath);
  255. FilePath platformSpecificPath(absoluteFilePath, AZStd::string(AzFramework::PlatformHelper::GetPlatformName(platformIndex)));
  256. if (assetSeedManager.SaveAssetFileInfo(platformSpecificPath.AbsolutePath(), AzFramework::PlatformHelper::GetPlatformFlagFromPlatformIndex(platformIndex)))
  257. {
  258. createdFiles.emplace_back(platformSpecificPath.AbsolutePath());
  259. }
  260. }
  261. return createdFiles;
  262. }
  263. QSharedPointer<SeedListTableModel> SeedListFileTableModel::GetSeedListFileContents(const QModelIndex& index)
  264. {
  265. auto seedFileInfoOutcome = GetSeedFileInfo(index);
  266. if (!seedFileInfoOutcome.IsSuccess())
  267. {
  268. return QSharedPointer<SeedListTableModel>();
  269. }
  270. return seedFileInfoOutcome.GetValue()->m_seedListModel;
  271. }
  272. bool SeedListFileTableModel::SetSeedPlatforms(
  273. const QModelIndex& seedFileIndex,
  274. const QModelIndex& seedIndex,
  275. const AzFramework::PlatformFlags& platforms)
  276. {
  277. AZStd::string key = GetFileKey(seedFileIndex);
  278. if (key.empty())
  279. {
  280. // Error has already been thrown
  281. return false;
  282. }
  283. if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
  284. {
  285. AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
  286. return false;
  287. }
  288. SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
  289. if (!seedFileInfo->m_seedListModel->SetSeedPlatforms(seedIndex, platforms))
  290. {
  291. // Error has already been thrown
  292. return false;
  293. }
  294. // Update display so the user knows there are unsaved changes
  295. m_keysWithUnsavedChanges.insert(key);
  296. QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
  297. emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
  298. return true;
  299. }
  300. bool SeedListFileTableModel::AddSeed(
  301. const QModelIndex& seedFileIndex,
  302. const AZStd::string& seedRelativePath,
  303. const AzFramework::PlatformFlags& platforms)
  304. {
  305. AZStd::string key = GetFileKey(seedFileIndex);
  306. if (key.empty())
  307. {
  308. // Error has already been thrown
  309. return false;
  310. }
  311. if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
  312. {
  313. AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
  314. return false;
  315. }
  316. SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
  317. if (!seedFileInfo->m_seedListModel->AddSeed(seedRelativePath, platforms))
  318. {
  319. // Error has already been thrown
  320. return false;
  321. }
  322. // Update display so the user knows there are unsaved changes
  323. m_keysWithUnsavedChanges.insert(key);
  324. QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
  325. emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
  326. return true;
  327. }
  328. bool SeedListFileTableModel::RemoveSeed(const QModelIndex& seedFileIndex, const QModelIndex& seedIndex)
  329. {
  330. AZStd::string key = GetFileKey(seedFileIndex);
  331. if (key.empty())
  332. {
  333. // Error has already been thrown
  334. return false;
  335. }
  336. if (m_seedListFileInfoMap.find(key) == m_seedListFileInfoMap.end())
  337. {
  338. AZ_Error(AssetBundler::AppWindowName, false, "Unable to find Seed File Info with key ( %s )", key.c_str());
  339. return false;
  340. }
  341. SeedListFileInfoPtr seedFileInfo = m_seedListFileInfoMap[key];
  342. if (!seedFileInfo->m_seedListModel->RemoveSeed(seedIndex))
  343. {
  344. // Error has already been thrown
  345. return false;
  346. }
  347. // Update display so the user knows there are unsaved changes
  348. m_keysWithUnsavedChanges.insert(key);
  349. QModelIndex changedIndex = QAbstractTableModel::index(seedFileIndex.row(), Column::ColumnFileName);
  350. emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
  351. return true;
  352. }
  353. bool SeedListFileTableModel::WriteToDisk(const AZStd::string& key)
  354. {
  355. if (key == m_inMemoryDefaultSeedListKey)
  356. {
  357. return true;
  358. }
  359. auto seedListFileIt = m_seedListFileInfoMap.find(key);
  360. return seedListFileIt != m_seedListFileInfoMap.end() && seedListFileIt->second->SaveSeedFile();
  361. }
  362. AZStd::string SeedListFileTableModel::GetFileAbsolutePath(const QModelIndex& index) const
  363. {
  364. auto seedFileInfoOutcome = GetSeedFileInfo(index);
  365. if (!seedFileInfoOutcome.IsSuccess() || seedFileInfoOutcome.GetValue()->m_absolutePath == m_inMemoryDefaultSeedListKey)
  366. {
  367. // Error has already been thrown
  368. return AZStd::string();
  369. }
  370. return seedFileInfoOutcome.GetValue()->m_absolutePath;
  371. }
  372. int SeedListFileTableModel::GetFileNameColumnIndex() const
  373. {
  374. return Column::ColumnFileName;
  375. }
  376. int SeedListFileTableModel::GetTimeStampColumnIndex() const
  377. {
  378. return Column::ColumnFileModificationTime;
  379. }
  380. int SeedListFileTableModel::columnCount(const QModelIndex& parent) const
  381. {
  382. return parent.isValid() ? 0 : Column::Max;
  383. }
  384. QVariant SeedListFileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
  385. {
  386. if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
  387. {
  388. switch (section)
  389. {
  390. case Column::ColumnFileName:
  391. return QString(tr("Seed List File"));
  392. case Column::ColumnProject:
  393. return QString(tr("Project Source"));
  394. case Column::ColumnFileModificationTime:
  395. return QString(tr("Modification Time"));
  396. default:
  397. break;
  398. }
  399. }
  400. return QVariant();
  401. }
  402. QVariant SeedListFileTableModel::data(const QModelIndex& index, int role) const
  403. {
  404. auto seedFileInfoOutcome = GetSeedFileInfo(index);
  405. if (!seedFileInfoOutcome.IsSuccess())
  406. {
  407. return QVariant();
  408. }
  409. int col = index.column();
  410. bool hasUnsavedChanges = seedFileInfoOutcome.GetValue()->m_seedListModel->HasUnsavedChanges();
  411. switch (role)
  412. {
  413. case Qt::DisplayRole:
  414. [[fallthrough]];
  415. case SortRole:
  416. {
  417. if (col == Column::ColumnFileName)
  418. {
  419. QString displayName = seedFileInfoOutcome.GetValue()->m_fileName;
  420. if (hasUnsavedChanges)
  421. {
  422. displayName.append("*");
  423. }
  424. return displayName;
  425. }
  426. else if (col == Column::ColumnProject)
  427. {
  428. return seedFileInfoOutcome.GetValue()->m_project;
  429. }
  430. else if (col == Column::ColumnFileModificationTime)
  431. {
  432. if (role == SortRole)
  433. {
  434. return seedFileInfoOutcome.GetValue()->m_fileModificationTime;
  435. }
  436. else
  437. {
  438. return seedFileInfoOutcome.GetValue()->m_fileModificationTime.toString(DateTimeFormat);
  439. }
  440. }
  441. else
  442. {
  443. // Returning an empty QString will ensure the checkboxes do not have any text displayed next to them
  444. return QString();
  445. }
  446. }
  447. case Qt::FontRole:
  448. {
  449. if (col == Column::ColumnFileName && hasUnsavedChanges)
  450. {
  451. QFont boldFont;
  452. boldFont.setBold(true);
  453. return boldFont;
  454. }
  455. }
  456. case Qt::CheckStateRole:
  457. {
  458. if (col == Column::ColumnCheckBox)
  459. {
  460. if (seedFileInfoOutcome.GetValue()->m_isChecked)
  461. {
  462. return Qt::Checked;
  463. }
  464. else
  465. {
  466. return Qt::Unchecked;
  467. }
  468. }
  469. }
  470. default:
  471. break;
  472. }
  473. return QVariant();
  474. }
  475. bool SeedListFileTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
  476. {
  477. if (role != Qt::CheckStateRole || index.column() != Column::ColumnCheckBox)
  478. {
  479. return false;
  480. }
  481. AZStd::string key = GetFileKey(index);
  482. if (key.empty())
  483. {
  484. return false;
  485. }
  486. auto seedFileInfo = m_seedListFileInfoMap.find(key);
  487. if (seedFileInfo == m_seedListFileInfoMap.end())
  488. {
  489. return false;
  490. }
  491. if (value == Qt::CheckState::Unchecked)
  492. {
  493. seedFileInfo->second->m_isChecked = false;
  494. m_checkedSeedListFiles.erase(key);
  495. if (seedFileInfo->second->m_isDefaultSeedList)
  496. {
  497. m_seedTabWidget->UncheckSelectDefaultSeedListsCheckBox();
  498. }
  499. }
  500. else
  501. {
  502. seedFileInfo->second->m_isChecked = true;
  503. m_checkedSeedListFiles.insert(key);
  504. }
  505. m_seedTabWidget->SetGenerateAssetListsButtonEnabled(!m_checkedSeedListFiles.empty());
  506. return true;
  507. }
  508. Qt::ItemFlags SeedListFileTableModel::flags(const QModelIndex& index) const
  509. {
  510. if (index.column() == Column::ColumnCheckBox)
  511. {
  512. return Qt::ItemIsUserCheckable | QAbstractTableModel::flags(index);
  513. }
  514. return QAbstractTableModel::flags(index);
  515. }
  516. AZ::Outcome<SeedListFileInfoPtr, void> SeedListFileTableModel::GetSeedFileInfo(const QModelIndex& index) const
  517. {
  518. AZStd::string key = GetFileKey(index);
  519. if (key.empty())
  520. {
  521. // Error has already been thrown
  522. return AZ::Failure();
  523. }
  524. if (m_seedListFileInfoMap.find(key) != m_seedListFileInfoMap.end())
  525. {
  526. return AZ::Success(m_seedListFileInfoMap.at(key));
  527. }
  528. else
  529. {
  530. AZ_Error(AssetBundler::AppWindowName, false, "Cannot find Seed File Info");
  531. return AZ::Failure();
  532. }
  533. }
  534. } // namespace AssetBundler