rcjoblistmodel.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  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 "rcjoblistmodel.h"
  9. // uncomment this in order to add additional verbose log output for this class.
  10. // can drastically slow down function since this class is a hotspot
  11. // #define DEBUG_RCJOB_MODEL
  12. namespace AssetProcessor
  13. {
  14. RCJobListModel::RCJobListModel(QObject* parent)
  15. : QAbstractItemModel(parent)
  16. {
  17. }
  18. int RCJobListModel::rowCount(const QModelIndex& parent) const
  19. {
  20. if (parent.isValid())
  21. {
  22. return 0;
  23. }
  24. return itemCount();
  25. }
  26. QModelIndex RCJobListModel::parent(const QModelIndex& /*index*/) const
  27. {
  28. return QModelIndex();
  29. }
  30. QModelIndex RCJobListModel::index(int row, int column, const QModelIndex& parent) const
  31. {
  32. if (row >= rowCount(parent) || column >= columnCount(parent))
  33. {
  34. return QModelIndex();
  35. }
  36. return createIndex(row, column);
  37. }
  38. int RCJobListModel::columnCount(const QModelIndex& parent) const
  39. {
  40. return parent.isValid() ? 0 : Column::Max;
  41. }
  42. QVariant RCJobListModel::headerData(int section, Qt::Orientation orientation, int role) const
  43. {
  44. if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
  45. {
  46. switch (section)
  47. {
  48. case ColumnState:
  49. return tr("State");
  50. case ColumnJobId:
  51. return tr("Job Id");
  52. case ColumnCommand:
  53. return tr("Asset");
  54. case ColumnCompleted:
  55. return tr("Completed");
  56. case ColumnPlatform:
  57. return tr("Platform");
  58. default:
  59. break;
  60. }
  61. }
  62. return QAbstractItemModel::headerData(section, orientation, role);
  63. }
  64. unsigned int RCJobListModel::jobsInFlight() const
  65. {
  66. return m_jobsInFlight.size();
  67. }
  68. unsigned int RCJobListModel::jobsInQueueWithoutMissingDependencies() const
  69. {
  70. unsigned int jobsWithNoMissingDependencies = 0;
  71. for (const auto& job : m_jobsInQueueLookup)
  72. {
  73. if (!job->HasMissingSourceDependency())
  74. {
  75. ++jobsWithNoMissingDependencies;
  76. }
  77. }
  78. return jobsWithNoMissingDependencies;
  79. }
  80. unsigned int RCJobListModel::jobsPendingCatalog() const
  81. {
  82. return m_finishedJobsNotInCatalog.count();
  83. }
  84. void RCJobListModel::UpdateJobEscalation(const QueueElementID& toEscalate, int valueToEscalateTo)
  85. {
  86. for (auto foundInQueue = m_jobsInQueueLookup.find(toEscalate); foundInQueue != m_jobsInQueueLookup.end(); ++foundInQueue)
  87. {
  88. RCJob* job = foundInQueue.value();
  89. // this is a multi-map, so we have to keep going until it no longer matches.
  90. if (!job)
  91. {
  92. continue;
  93. }
  94. if (job->GetElementID() != toEscalate)
  95. {
  96. break;
  97. }
  98. if (job->JobEscalation() != valueToEscalateTo)
  99. {
  100. UpdateJobEscalation(job, valueToEscalateTo);
  101. }
  102. }
  103. }
  104. void RCJobListModel::UpdateJobPriority(const QueueElementID& priorityUpdate, int newPriority)
  105. {
  106. for (auto foundInQueue = m_jobsInQueueLookup.find(priorityUpdate); foundInQueue != m_jobsInQueueLookup.end(); ++foundInQueue)
  107. {
  108. RCJob* job = foundInQueue.value();
  109. // this is a multi-map, so we have to keep going until it no longer matches.
  110. if (!job)
  111. {
  112. continue;
  113. }
  114. if (job->GetElementID() != priorityUpdate)
  115. {
  116. break;
  117. }
  118. if (job->GetPriority() != newPriority)
  119. {
  120. UpdateJobPriority(job, newPriority);
  121. }
  122. }
  123. }
  124. void RCJobListModel::UpdateJobPriority(AssetProcessor::RCJob* rcJob, int newPriority)
  125. {
  126. for (int idx = 0; idx < rowCount(); ++idx)
  127. {
  128. RCJob* job = getItem(idx);
  129. if (job == rcJob)
  130. {
  131. if (job->GetPriority() != newPriority)
  132. {
  133. job->SetPriority(newPriority);
  134. Q_EMIT dataChanged(index(idx, 0), index(idx, columnCount() - 1)); // need to do this to update the sort model.
  135. }
  136. break;
  137. }
  138. }
  139. }
  140. void RCJobListModel::UpdateJobEscalation(AssetProcessor::RCJob* rcJob, int valueToEscalateTo)
  141. {
  142. for (int idx = 0; idx < rowCount(); ++idx)
  143. {
  144. RCJob* job = getItem(idx);
  145. if (job == rcJob)
  146. {
  147. if (job->JobEscalation() != valueToEscalateTo)
  148. {
  149. job->SetJobEscalation(valueToEscalateTo);
  150. Q_EMIT dataChanged(index(idx, 0), index(idx, columnCount() - 1));
  151. }
  152. break;
  153. }
  154. }
  155. }
  156. void RCJobListModel::UpdateRow(int jobIndex)
  157. {
  158. Q_EMIT dataChanged(index(jobIndex, 0), index(jobIndex, columnCount() - 1));
  159. }
  160. QVariant RCJobListModel::data(const QModelIndex& index, int role) const
  161. {
  162. if (!index.isValid())
  163. {
  164. return QVariant();
  165. }
  166. if (index.row() >= itemCount())
  167. {
  168. return QVariant();
  169. }
  170. switch (role)
  171. {
  172. case jobIndexRole:
  173. return getItem(index.row())->GetJobEntry().m_jobRunKey;
  174. case stateRole:
  175. return RCJob::GetStateDescription(getItem(index.row())->GetState());
  176. case displayNameRole:
  177. return getItem(index.row())->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  178. case timeCreatedRole:
  179. return getItem(index.row())->GetTimeCreated().toString("hh:mm:ss.zzz");
  180. case timeLaunchedRole:
  181. return getItem(index.row())->GetTimeLaunched().toString("hh:mm:ss.zzz");
  182. case timeCompletedRole:
  183. return getItem(index.row())->GetTimeCompleted().toString("hh:mm:ss.zzz");
  184. case Qt::DisplayRole:
  185. switch (index.column())
  186. {
  187. case ColumnJobId:
  188. return getItem(index.row())->GetJobEntry().m_jobRunKey;
  189. case ColumnState:
  190. return RCJob::GetStateDescription(getItem(index.row())->GetState());
  191. case ColumnCommand:
  192. return getItem(index.row())->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  193. case ColumnCompleted:
  194. return getItem(index.row())->GetTimeCompleted().toString("hh:mm:ss.zzz");
  195. case ColumnPlatform:
  196. return QString::fromUtf8(getItem(index.row())->GetPlatformInfo().m_identifier.c_str());
  197. default:
  198. break;
  199. }
  200. default:
  201. break;
  202. }
  203. return QVariant();
  204. }
  205. int RCJobListModel::itemCount() const
  206. {
  207. return aznumeric_caster(m_jobs.size());
  208. }
  209. RCJob* RCJobListModel::getItem(int index) const
  210. {
  211. if (index >= 0 && index < m_jobs.size())
  212. {
  213. return m_jobs[index];
  214. }
  215. return nullptr; //invalid index
  216. }
  217. bool RCJobListModel::isEmpty()
  218. {
  219. return m_jobs.empty();
  220. }
  221. void RCJobListModel::addNewJob(RCJob* rcJob)
  222. {
  223. int posForInsert = aznumeric_caster(m_jobs.size());
  224. beginInsertRows(QModelIndex(), posForInsert, posForInsert);
  225. m_jobs.push_back(rcJob);
  226. #if defined(DEBUG_RCJOB_MODEL)
  227. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace AddNewJob(%i %s,%s,%s)\n", rcJob, rcJob->GetInputFileAbsolutePath().toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData());
  228. #endif
  229. if (rcJob->GetState() == RCJob::pending)
  230. {
  231. m_jobsInQueueLookup.insert(rcJob->GetElementID(), rcJob);
  232. }
  233. endInsertRows();
  234. }
  235. void RCJobListModel::markAsProcessing(RCJob* rcJob)
  236. {
  237. #if defined(DEBUG_RCJOB_MODEL)
  238. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace markAsProcessing(%i %s,%s,%s)\n", rcJob, rcJob->GetJobEntry().m_databaseSourceName.toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData());
  239. #endif
  240. rcJob->SetState(RCJob::processing);
  241. rcJob->SetTimeLaunched(QDateTime::currentDateTime());
  242. m_jobsInFlight.insert(rcJob);
  243. for(int jobIndex = static_cast<int>(m_jobs.size()) - 1; jobIndex >= 0; --jobIndex)
  244. {
  245. if(m_jobs[jobIndex] == rcJob)
  246. {
  247. Q_EMIT dataChanged(index(jobIndex, 0, QModelIndex()), index(jobIndex, 0, QModelIndex()));
  248. return;
  249. }
  250. }
  251. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace jobIndex == -1!!! (%i %s,%s,%s)\n",
  252. rcJob, rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  253. rcJob->GetPlatformInfo().m_identifier.c_str(),
  254. rcJob->GetJobKey().toUtf8().constData());
  255. AZ_Assert(false, "Job not found!!!");
  256. }
  257. void RCJobListModel::markAsStarted(RCJob* rcJob)
  258. {
  259. #if defined(DEBUG_RCJOB_MODEL)
  260. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace markAsStarted(%i %s,%s,%s)\n", rcJob, rcJob->GetInputFileAbsolutePath().toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData());
  261. #endif
  262. auto foundInQueue = m_jobsInQueueLookup.find(rcJob->GetElementID());
  263. while ((foundInQueue != m_jobsInQueueLookup.end()) && (foundInQueue.value() == rcJob))
  264. {
  265. foundInQueue = m_jobsInQueueLookup.erase(foundInQueue);
  266. }
  267. }
  268. void RCJobListModel::markAsCompleted(RCJob* rcJob)
  269. {
  270. #if defined(DEBUG_RCJOB_MODEL)
  271. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace markAsCompleted(%i %s,%s,%s)\n", rcJob, rcJob->GetInputFileAbsolutePath().toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData());
  272. #endif
  273. rcJob->SetTimeCompleted(QDateTime::currentDateTime());
  274. auto foundInQueue = m_jobsInQueueLookup.find(rcJob->GetElementID());
  275. while ((foundInQueue != m_jobsInQueueLookup.end()) && (foundInQueue.value() == rcJob))
  276. {
  277. foundInQueue = m_jobsInQueueLookup.erase(foundInQueue);
  278. }
  279. for (int jobIndex = static_cast<int>(m_jobs.size()) - 1; jobIndex >= 0; --jobIndex)
  280. {
  281. if(m_jobs[jobIndex] == rcJob)
  282. {
  283. m_jobsInFlight.remove(rcJob);
  284. // remove it from the list and delete it - there is a separate model that keeps track for the GUI so no need to keep jobs around.
  285. {
  286. #if defined(DEBUG_RCJOB_MODEL)
  287. AZ_TracePrintf(AssetProcessor::DebugChannel, "JobTrace =>JobCompleted(%i %s,%s,%s)\n", rcJob, rcJob->GetJobEntry().m_databaseSourceName.toUtf8().constData(), rcJob->GetPlatformInfo().m_identifier.c_str(), rcJob->GetJobKey().toUtf8().constData());
  288. #endif
  289. beginRemoveRows(QModelIndex(), jobIndex, jobIndex);
  290. m_jobs.erase(m_jobs.begin() + jobIndex);
  291. endRemoveRows();
  292. // Only completed jobs need to wait on a catalog write
  293. if (rcJob->GetState() == RCJob::completed)
  294. {
  295. const auto& id = rcJob->GetElementID();
  296. auto itr = m_finishedJobsNotInCatalog.find(id);
  297. if (itr != m_finishedJobsNotInCatalog.end())
  298. {
  299. itr.value()++;
  300. }
  301. else
  302. {
  303. m_finishedJobsNotInCatalog.insert(id, 1);
  304. }
  305. }
  306. rcJob->deleteLater();
  307. }
  308. return;
  309. }
  310. }
  311. AZ_Error(
  312. AssetProcessor::ConsoleChannel,
  313. false,
  314. "Programmer Error: Could not mark job for file %s as completed, job was not tracked in the m_jobs container. It was either already finished, or never queued. (platform:%s, job key:%s)\n",
  315. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  316. rcJob->GetPlatformInfo().m_identifier.c_str(),
  317. rcJob->GetJobKey().toUtf8().constData());
  318. }
  319. void RCJobListModel::markAsCataloged(const AssetProcessor::QueueElementID& check)
  320. {
  321. auto itr = m_finishedJobsNotInCatalog.find(check);
  322. if(itr == m_finishedJobsNotInCatalog.end())
  323. {
  324. AZ_Assert(false, "Attempting to mark a job as written to the catalog before the job has been put in the waiting queue! %s", check.GetSourceAssetReference().AbsolutePath().c_str());
  325. return;
  326. }
  327. itr.value()--;
  328. if (itr.value() == 0)
  329. {
  330. m_finishedJobsNotInCatalog.erase(itr);
  331. }
  332. }
  333. bool RCJobListModel::isInFlight(const AssetProcessor::QueueElementID& check) const
  334. {
  335. for (auto rcJob : m_jobsInFlight)
  336. {
  337. if (check == rcJob->GetElementID())
  338. {
  339. return true;
  340. }
  341. }
  342. return false;
  343. }
  344. int RCJobListModel::GetIndexOfJobByState(const QueueElementID& elementId, RCJob::JobState jobState)
  345. {
  346. for (int idx = 0; idx < rowCount(); ++idx)
  347. {
  348. RCJob* job = getItem(idx);
  349. if (job->GetState() == jobState && job->GetElementID() == elementId)
  350. {
  351. return idx;
  352. break;
  353. }
  354. }
  355. return -1; // invalid index
  356. }
  357. void RCJobListModel::EraseJobs(const SourceAssetReference& sourceAsset, AZStd::vector<RCJob*>& pendingJobs)
  358. {
  359. for (int jobIdx = 0; jobIdx < rowCount(); ++jobIdx)
  360. {
  361. RCJob* job = getItem(jobIdx);
  362. if (job->GetJobEntry().m_sourceAssetReference == sourceAsset)
  363. {
  364. const QueueElementID& target = job->GetElementID();
  365. if ((isInQueue(target)) || (isInFlight(target)))
  366. {
  367. // Its important that this still follows the 'cancelled' flow, so that other parts of the code can update their "in progress" and other maps.
  368. AZ_TracePrintf(
  369. AssetProcessor::DebugChannel,
  370. "Cancelling Job [%s, %s, %s] because the source file no longer exists.\n",
  371. target.GetSourceAssetReference().AbsolutePath().c_str(),
  372. target.GetPlatform().toUtf8().data(),
  373. target.GetJobDescriptor().toUtf8().data());
  374. // if a job is pending, it was never started and thus will never enter Finished state,
  375. // so simply changing its state to cancelled is not enough, collect them and return to rccontroller to process manually
  376. if (job->GetState() == RCJob::JobState::pending)
  377. {
  378. pendingJobs.push_back(job);
  379. }
  380. job->SetState(RCJob::JobState::cancelled);
  381. AssetBuilderSDK::JobCommandBus::Event(job->GetJobEntry().m_jobRunKey, &AssetBuilderSDK::JobCommandBus::Events::Cancel);
  382. UpdateRow(jobIdx);
  383. }
  384. }
  385. }
  386. }
  387. bool RCJobListModel::isInQueue(const AssetProcessor::QueueElementID& check) const
  388. {
  389. return m_jobsInQueueLookup.contains(check);
  390. }
  391. bool RCJobListModel::isWaitingOnCatalog(const QueueElementID& check) const
  392. {
  393. return m_finishedJobsNotInCatalog.contains(check);
  394. }
  395. void RCJobListModel::PerformHeuristicSearch(QString searchTerm, QString platform, QSet<QueueElementID>& found, AssetProcessor::JobIdEscalationList& escalationList, bool isStatusRequest, int searchRules)
  396. {
  397. int escalationValue = 0;
  398. if (isStatusRequest)
  399. {
  400. escalationValue = AssetProcessor::JobEscalation::ProcessAssetRequestStatusEscalation;
  401. }
  402. else
  403. {
  404. escalationValue = AssetProcessor::JobEscalation::ProcessAssetRequestSyncEscalation;
  405. }
  406. // try to narrowly exact-match the search term in case the search term refers to a specific actual source file:
  407. for (const RCJob* rcJob : m_jobs)
  408. {
  409. if ((platform != rcJob->GetPlatformInfo().m_identifier.c_str()) || (rcJob->GetState() != RCJob::pending))
  410. {
  411. continue;
  412. }
  413. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  414. if (input.endsWith(searchTerm, Qt::CaseInsensitive))
  415. {
  416. AZ_TracePrintf(
  417. AssetProcessor::DebugChannel,
  418. "Job Queue: Heuristic search found exact match (%s,%s,%s).\n",
  419. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  420. rcJob->GetPlatformInfo().m_identifier.c_str(),
  421. rcJob->GetJobKey().toUtf8().constData());
  422. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  423. escalationList.append(qMakePair(rcJob->GetJobEntry().m_jobRunKey, escalationValue));
  424. }
  425. }
  426. for (const RCJob* rcJob : m_jobsInFlight)
  427. {
  428. if (platform != rcJob->GetPlatformInfo().m_identifier.c_str())
  429. {
  430. continue;
  431. }
  432. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  433. if (input.endsWith(searchTerm, Qt::CaseInsensitive))
  434. {
  435. AZ_TracePrintf(
  436. AssetProcessor::DebugChannel,
  437. "Job Queue: Heuristic search found exact match (%s,%s,%s).\n",
  438. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  439. rcJob->GetPlatformInfo().m_identifier.c_str(),
  440. rcJob->GetJobKey().toUtf8().constData());
  441. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  442. }
  443. }
  444. if (!found.isEmpty() || searchRules == AzFramework::AssetSystem::RequestAssetStatus::SearchType::Exact)
  445. {
  446. return;
  447. }
  448. // broaden the heuristic. Try without extensions - that is, ignore everything after the dot.
  449. // if there are dashes, ignore them also. This is how you match "blah.dds" to actually mean "blah.tif"
  450. // since we have no idea what products will be generated by a source still in the queue until it runs
  451. QString searchTermWithNoExtension = searchTerm;
  452. int dotIndex = searchTerm.lastIndexOf('.');
  453. while (dotIndex != -1)
  454. {
  455. searchTermWithNoExtension = searchTerm.mid(0, dotIndex);
  456. for (const auto& rcJob : m_jobs)
  457. {
  458. if ((platform != rcJob->GetPlatformInfo().m_identifier.c_str()) || (rcJob->GetState() != RCJob::pending))
  459. {
  460. continue;
  461. }
  462. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  463. dotIndex = input.lastIndexOf('.');
  464. if (dotIndex != -1)
  465. {
  466. QStringRef testref = input.midRef(0, dotIndex);
  467. if (testref.endsWith(searchTermWithNoExtension, Qt::CaseInsensitive))
  468. {
  469. AZ_TracePrintf(
  470. AssetProcessor::DebugChannel,
  471. "Job Queue: Heuristic search found broad match (%s,%s,%s).\n",
  472. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  473. rcJob->GetPlatformInfo().m_identifier.c_str(),
  474. rcJob->GetJobKey().toUtf8().constData());
  475. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  476. escalationList.append(qMakePair(rcJob->GetJobEntry().m_jobRunKey, escalationValue));
  477. }
  478. }
  479. }
  480. for (const RCJob* rcJob : m_jobsInFlight)
  481. {
  482. if (platform != rcJob->GetPlatformInfo().m_identifier.c_str())
  483. {
  484. continue;
  485. }
  486. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  487. dotIndex = input.lastIndexOf('.');
  488. if (dotIndex != -1)
  489. {
  490. QStringRef testref = input.midRef(0, dotIndex);
  491. if (testref.endsWith(searchTermWithNoExtension, Qt::CaseInsensitive))
  492. {
  493. AZ_TracePrintf(
  494. AssetProcessor::DebugChannel,
  495. "Job Queue: Heuristic search found broad match (%s,%s,%s).\n",
  496. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  497. rcJob->GetPlatformInfo().m_identifier.c_str(),
  498. rcJob->GetJobKey().toUtf8().constData());
  499. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  500. }
  501. }
  502. }
  503. dotIndex = searchTermWithNoExtension.lastIndexOf('.');
  504. }
  505. if (!found.isEmpty())
  506. {
  507. return;
  508. }
  509. // broaden the heuristic further. Eliminate anything after the last underscore in the file name
  510. // (so blahblah_diff.dds just becomes blahblah) and then allow anything which has that file somewhere in it.
  511. int slashIndex = searchTerm.lastIndexOf('/');
  512. int dashIndex = searchTerm.lastIndexOf('_');
  513. QString searchTermWithNoSuffix = searchTermWithNoExtension;
  514. if ((dashIndex != -1) && (slashIndex == -1) || (dashIndex > slashIndex))
  515. {
  516. searchTermWithNoSuffix = searchTermWithNoSuffix.mid(0, dashIndex);
  517. }
  518. for (const auto& rcJob : m_jobs)
  519. {
  520. if ((platform != rcJob->GetPlatformInfo().m_identifier.c_str()) || (rcJob->GetState() != RCJob::pending))
  521. {
  522. continue;
  523. }
  524. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  525. if (input.contains(searchTermWithNoSuffix, Qt::CaseInsensitive)) //notice here that we use simply CONTAINS instead of endswith - this can potentially be very broad!
  526. {
  527. AZ_TracePrintf(
  528. AssetProcessor::DebugChannel,
  529. "Job Queue: Heuristic search found ultra-broad match (%s,%s,%s).\n",
  530. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  531. rcJob->GetPlatformInfo().m_identifier.c_str(),
  532. rcJob->GetJobKey().toUtf8().constData());
  533. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  534. escalationList.append(qMakePair(rcJob->GetJobEntry().m_jobRunKey, escalationValue));
  535. }
  536. }
  537. for (const RCJob* rcJob : m_jobsInFlight)
  538. {
  539. if (platform != rcJob->GetPlatformInfo().m_identifier.c_str())
  540. {
  541. continue;
  542. }
  543. QString input = rcJob->GetJobEntry().m_sourceAssetReference.RelativePath().c_str();
  544. if (input.contains(searchTermWithNoSuffix, Qt::CaseInsensitive)) //notice here that we use simply CONTAINS instead of endswith - this can potentially be very broad!
  545. {
  546. AZ_TracePrintf(
  547. AssetProcessor::DebugChannel,
  548. "Job Queue: Heuristic search found ultra-broad match (%s,%s,%s).\n",
  549. rcJob->GetJobEntry().GetAbsoluteSourcePath().toUtf8().constData(),
  550. rcJob->GetPlatformInfo().m_identifier.c_str(),
  551. rcJob->GetJobKey().toUtf8().constData());
  552. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  553. }
  554. }
  555. }
  556. void RCJobListModel::PerformUUIDSearch(AZ::Uuid searchUuid, QString platform, QSet<QueueElementID>& found, AssetProcessor::JobIdEscalationList& escalationList, bool isStatusRequest)
  557. {
  558. int escalationValue = 0;
  559. if (isStatusRequest)
  560. {
  561. escalationValue = AssetProcessor::JobEscalation::ProcessAssetRequestStatusEscalation;
  562. }
  563. else
  564. {
  565. escalationValue = AssetProcessor::JobEscalation::ProcessAssetRequestSyncEscalation;
  566. }
  567. for (const RCJob* rcJob : m_jobs)
  568. {
  569. if ((platform != rcJob->GetPlatformInfo().m_identifier.c_str()) || (rcJob->GetState() != RCJob::pending))
  570. {
  571. continue;
  572. }
  573. if (rcJob->GetJobEntry().m_sourceFileUUID == searchUuid)
  574. {
  575. found.insert(QueueElementID(rcJob->GetJobEntry().m_sourceAssetReference, platform, rcJob->GetJobKey()));
  576. escalationList.append(qMakePair(rcJob->GetJobEntry().m_jobRunKey, escalationValue));
  577. }
  578. }
  579. }
  580. bool RCJobListModel::UpdateMissingSourceDependencies(const QString& sourceFileName)
  581. {
  582. bool jobsUnblocked = false;
  583. SourceAssetReference sourceAssetReference(sourceFileName.toUtf8().constData());
  584. for (RCJob* rcJob : m_jobs)
  585. {
  586. jobsUnblocked = jobsUnblocked || rcJob->UpdateMissingDependencies(sourceAssetReference);
  587. }
  588. return jobsUnblocked;
  589. }
  590. }// namespace AssetProcessor