Skip to content

Commit a949c09

Browse files
authored
Merge pull request #73 from oblivioncth/dev
Merge to master for v0.8.3
2 parents ed288cc + f02411e commit a949c09

File tree

15 files changed

+151
-162
lines changed

15 files changed

+151
-162
lines changed

.github/workflows/build-project.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,12 @@ jobs:
2525
runs_exclude: >
2626
[
2727
{ "linkage": "shared" },
28-
{ "compiler": "g++-10" },
2928
{ "compiler": "g++-12" },
30-
{ "compiler": "clang++-12" },
31-
{ "compiler": "clang++-14" }
29+
{ "compiler": "clang++-15" }
3230
]
3331
runs_include: >
3432
[
35-
{ "os": "ubuntu-22.04", "compiler": "clang++-18", "linkage": "static" },
36-
{ "os": "ubuntu-24.04", "compiler": "clang++-18", "linkage": "static" },
37-
{ "os": "ubuntu-24.04", "compiler": "g++-14", "linkage": "static" }
33+
{ "os": "ubuntu-22.04", "compiler": "clang++-18", "linkage": "static" }
3834
]
3935
pre_build_steps: |
4036
- name: Install Clang 18 [Linux]

CMakeLists.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24.0...3.30.0)
66
# Project
77
# NOTE: DON'T USE TRAILING ZEROS IN VERSIONS
88
project(FIL
9-
VERSION 0.8.2
9+
VERSION 0.8.3
1010
LANGUAGES CXX
1111
DESCRIPTION "Flashpoint Importer for Launchers"
1212
)
@@ -62,6 +62,7 @@ set(FIL_QX_COMPONENTS
6262
Network
6363
Widgets
6464
Xml
65+
Sql
6566
)
6667

6768
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
@@ -74,20 +75,20 @@ endif()
7475

7576
include(OB/FetchQx)
7677
ob_fetch_qx(
77-
REF "v0.6.2"
78+
REF "v0.7"
7879
COMPONENTS
7980
${FIL_QX_COMPONENTS}
8081
)
8182

8283
# Fetch libfp (build and import from source)
8384
include(OB/Fetchlibfp)
84-
ob_fetch_libfp("v0.5.6")
85+
ob_fetch_libfp("v0.6")
8586

8687
# Fetch CLIFp (build and import from source)
8788
include(OB/Utility)
8889
ob_cache_project_version(CLIFp)
8990
include(OB/FetchCLIFp)
90-
ob_fetch_clifp("v0.9.14")
91+
ob_fetch_clifp("v0.9.15")
9192

9293
# TODO: The shared build of this is essentially useless as only the CLIFp executable
9394
# is deployed, which only works if it's statically linked. There isn't a simple way

app/src/import/settings.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,19 @@ struct UpdateOptions
3636
bool removeObsolete;
3737
};
3838

39+
struct InclusionOptions
40+
{
41+
QList<int> excludedTagIds;
42+
bool includeAnimations;
43+
};
44+
3945
struct OptionSet
4046
{
4147
UpdateOptions updateOptions;
4248
ImageMode imageMode;
4349
bool downloadImages;
4450
PlaylistGameMode playlistMode;
45-
Fp::Db::InclusionOptions inclusionOptions;
51+
InclusionOptions inclusionOptions;
4652
bool excludeAddApps;
4753
bool forceFullscreen;
4854
};

app/src/import/worker.cpp

Lines changed: 80 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@
99
#include "import/details.h"
1010
#include "import/backup.h"
1111

12+
/* TODO: There was an efficiency drop with this since the change to libfp that uses Qx::Sql, as the results are
13+
* all returned as a list and not something iterable that pulls from the DB as needed. Benchmark this, and
14+
* if the memory usage is particularly high, then we might need to introduce an iterable wrapper to libfp
15+
* that holds Qx::SqlResult internally, so that we can go back to not loading the whole list at once.
16+
*
17+
* Alternatively, since most of this comes from the fact that we query a lot up-front to get sizes for
18+
* progress tracking, we could add methods to libfp that just return the size of the result only (i.e.
19+
* without actually making the full query), use those for the progress setup, and then run the actual
20+
* query that returns the whole list immediately before they're needed. This won't reduce things quite as much,
21+
* but is still better than nothing.
22+
*/
23+
1224
namespace Import
1325
{
1426

@@ -49,6 +61,29 @@ Qx::ProgressGroup* Worker::initializeProgressGroup(const QString& groupName, qui
4961
return pg;
5062
}
5163

64+
Fp::DbError Worker::loadGamesByPlatform(QList<PlatformQueryResult>& games, const QStringList& platforms, const InclusionOptions& inclusions, const QList<QUuid>& idWhitelist)
65+
{
66+
games.clear();
67+
games.reserve(platforms.size());
68+
Fp::Db* db = mFlashpointInstall->database();
69+
70+
// Build common filter
71+
Fp::Db::GameFilter gf{.excludedTagIds = inclusions.excludedTagIds, .includedIds = idWhitelist, .includeAnimations = inclusions.includeAnimations};
72+
73+
// Load one platform at a time
74+
for(const auto& pf : platforms)
75+
{
76+
PlatformQueryResult& res = games.emplaceBack();
77+
res.platform = pf;
78+
gf.platforms = {pf};
79+
80+
if(auto err = db->searchGames(res.result, gf); err.isValid())
81+
return err;
82+
}
83+
84+
return {};
85+
}
86+
5287
Qx::Error Worker::preloadPlaylists(QList<Fp::Playlist>& targetPlaylists)
5388
{
5489
// Reset playlists
@@ -64,7 +99,7 @@ Qx::Error Worker::preloadPlaylists(QList<Fp::Playlist>& targetPlaylists)
6499

65100
targetPlaylists.removeIf([&plNames, inclAnim](const Fp::Playlist& pl){
66101
return !plNames.contains(pl.title()) ||
67-
(pl.library() == Fp::Db::Table_Game::ENTRY_ANIM_LIBRARY && !inclAnim);
102+
(pl.library() == Fp::Library::Animation && !inclAnim);
68103
});
69104

70105
return Qx::Error();
@@ -81,61 +116,32 @@ QList<QUuid> Worker::getPlaylistSpecificGameIds(const QList<Fp::Playlist>& playl
81116
return playlistSpecGameIds;
82117
}
83118

84-
Worker::Result Worker::processPlatformGames(Qx::Error& errorReport, std::unique_ptr<Lr::IPlatformDoc>& platformDoc, Fp::Db::QueryBuffer& gameQueryResult)
119+
Worker::Result Worker::processPlatformGames(Qx::Error& errorReport, std::unique_ptr<Lr::IPlatformDoc>& platformDoc, const PlatformQueryResult& gameQueryResult)
85120
{
86121
Fp::Db* db = mFlashpointInstall->database();
87122

88123
// Add/Update games
89-
for(int j = 0; j < gameQueryResult.size; j++)
124+
for(const auto& game : gameQueryResult.result)
90125
{
91-
// Advance to next record
92-
gameQueryResult.result.next();
93-
94-
// Form game from record
95-
Fp::Game::Builder fpGb;
96-
fpGb.wId(gameQueryResult.result.value(Fp::Db::Table_Game::COL_ID).toString());
97-
fpGb.wTitle(gameQueryResult.result.value(Fp::Db::Table_Game::COL_TITLE).toString().remove(Qx::RegularExpression::LINE_BREAKS));
98-
fpGb.wSeries(gameQueryResult.result.value(Fp::Db::Table_Game::COL_SERIES).toString().remove(Qx::RegularExpression::LINE_BREAKS));
99-
fpGb.wDeveloper(gameQueryResult.result.value(Fp::Db::Table_Game::COL_DEVELOPER).toString().remove(Qx::RegularExpression::LINE_BREAKS));
100-
fpGb.wPublisher(gameQueryResult.result.value(Fp::Db::Table_Game::COL_PUBLISHER).toString().remove(Qx::RegularExpression::LINE_BREAKS));
101-
fpGb.wDateAdded(gameQueryResult.result.value(Fp::Db::Table_Game::COL_DATE_ADDED).toString());
102-
fpGb.wDateModified(gameQueryResult.result.value(Fp::Db::Table_Game::COL_DATE_MODIFIED).toString());
103-
fpGb.wBroken(gameQueryResult.result.value(Fp::Db::Table_Game::COL_BROKEN).toString());
104-
fpGb.wPlayMode(gameQueryResult.result.value(Fp::Db::Table_Game::COL_PLAY_MODE).toString());
105-
fpGb.wStatus(gameQueryResult.result.value(Fp::Db::Table_Game::COL_STATUS).toString());
106-
fpGb.wNotes(gameQueryResult.result.value(Fp::Db::Table_Game::COL_NOTES).toString());
107-
fpGb.wSource(gameQueryResult.result.value(Fp::Db::Table_Game::COL_SOURCE).toString().remove(Qx::RegularExpression::LINE_BREAKS));
108-
fpGb.wAppPath(gameQueryResult.result.value(Fp::Db::Table_Game::COL_APP_PATH).toString());
109-
fpGb.wLaunchCommand(gameQueryResult.result.value(Fp::Db::Table_Game::COL_LAUNCH_COMMAND).toString());
110-
fpGb.wReleaseDate(gameQueryResult.result.value(Fp::Db::Table_Game::COL_RELEASE_DATE).toString());
111-
fpGb.wVersion(gameQueryResult.result.value(Fp::Db::Table_Game::COL_VERSION).toString().remove(Qx::RegularExpression::LINE_BREAKS));
112-
fpGb.wOriginalDescription(gameQueryResult.result.value(Fp::Db::Table_Game::COL_ORIGINAL_DESC).toString());
113-
fpGb.wLanguage(gameQueryResult.result.value(Fp::Db::Table_Game::COL_LANGUAGE).toString().remove(Qx::RegularExpression::LINE_BREAKS));
114-
fpGb.wOrderTitle(gameQueryResult.result.value(Fp::Db::Table_Game::COL_ORDER_TITLE).toString().remove(Qx::RegularExpression::LINE_BREAKS));
115-
fpGb.wLibrary(gameQueryResult.result.value(Fp::Db::Table_Game::COL_LIBRARY).toString());
116-
fpGb.wPlatformName(gameQueryResult.result.value(Fp::Db::Table_Game::COL_PLATFORM_NAME).toString());
117-
118-
Fp::Game builtGame = fpGb.build();
119-
120126
// Get tags
121127
Fp::GameTags gameTags;
122-
if(auto dbErr = db->getGameTags(gameTags, builtGame.id()); dbErr.isValid())
128+
if(auto dbErr = db->getGameTags(gameTags, game.id()); dbErr.isValid())
123129
{
124130
errorReport = Qx::Error();
125131
return Failed;
126132
}
127133

128134
// Construct full game set
129135
Fp::Set::Builder sb;
130-
sb.wGame(builtGame); // From above
136+
sb.wGame(game); // From above
131137
sb.wTags(gameTags); // From above
132138
if(!mOptionSet.excludeAddApps)
133139
{
134140
// Add playable add apps
135-
auto addApps = mAddAppsCache.values(builtGame.id());
141+
auto addApps = mAddAppsCache.values(game.id());
136142
addApps.removeIf([](const Fp::AddApp& aa){ return !aa.isPlayable(); });
137143
sb.wAddApps(addApps);
138-
mAddAppsCache.remove(builtGame.id());
144+
mAddAppsCache.remove(game.id());
139145
}
140146

141147
// Add set to doc
@@ -174,29 +180,13 @@ void Worker::cullUnimportedPlaylistGames(QList<Fp::Playlist>& playlists)
174180
}
175181
}
176182

177-
Worker::Result Worker::preloadAddApps(Qx::Error& errorReport, Fp::Db::QueryBuffer& addAppQuery)
183+
Worker::Result Worker::preloadAddApps(Qx::Error& errorReport, const QList<Fp::AddApp>& addAppQuery)
178184
{
179-
mAddAppsCache.reserve(addAppQuery.size);
180-
for(int i = 0; i < addAppQuery.size; i++)
185+
mAddAppsCache.reserve(addAppQuery.size());
186+
for(const auto& aa : addAppQuery)
181187
{
182-
// Advance to next record
183-
addAppQuery.result.next();
184-
185-
// Form additional app from record
186-
Fp::AddApp::Builder fpAab;
187-
fpAab.wId(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_ID).toString());
188-
fpAab.wAppPath(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_APP_PATH).toString());
189-
fpAab.wAutorunBefore(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_AUTORUN).toString());
190-
fpAab.wLaunchCommand(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_LAUNCH_COMMAND).toString());
191-
fpAab.wName(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_NAME).toString().remove(Qx::RegularExpression::LINE_BREAKS));
192-
fpAab.wWaitExit(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_WAIT_EXIT).toString());
193-
fpAab.wParentId(addAppQuery.result.value(Fp::Db::Table_Add_App::COL_PARENT_ID).toString());
194-
195-
// Build additional app
196-
Fp::AddApp additionalApp = fpAab.build();
197-
198188
// Add to cache
199-
mAddAppsCache.insert(additionalApp.parentId(), additionalApp);
189+
mAddAppsCache.insert(aa.parentGameId(), aa);
200190

201191
// Update progress dialog value
202192
if(mCanceled)
@@ -213,7 +203,7 @@ Worker::Result Worker::preloadAddApps(Qx::Error& errorReport, Fp::Db::QueryBuffe
213203
return Successful;
214204
}
215205

216-
Worker::Result Worker::processGames(Qx::Error& errorReport, QList<Fp::Db::QueryBuffer>& primary, QList<Fp::Db::QueryBuffer>& playlistSpecific)
206+
Worker::Result Worker::processGames(Qx::Error& errorReport, QList<PlatformQueryResult>& primary, QList<PlatformQueryResult>& playlistSpecific)
217207
{
218208
// Status tracking
219209
Result platformImportStatus;
@@ -222,16 +212,14 @@ Worker::Result Worker::processGames(Qx::Error& errorReport, QList<Fp::Db::QueryB
222212
qsizetype remainingPlatforms = primary.size() + playlistSpecific.size();
223213

224214
// Use lambda to handle both lists due to major overlap
225-
auto platformsHandler = [&remainingPlatforms, &errorReport, this](QList<Fp::Db::QueryBuffer>& platformQueryResults, QString label) -> Result {
215+
auto platformsHandler = [&remainingPlatforms, &errorReport, this](const QList<PlatformQueryResult>& platformQueryResults, QString label) -> Result {
226216
Result result;
227217

228-
for(int i = 0; i < platformQueryResults.size(); i++)
218+
for(const auto& pfQuery : platformQueryResults)
229219
{
230-
Fp::Db::QueryBuffer& currentQueryResult = platformQueryResults[i];
231-
232220
// Open launcher platform doc
233221
std::unique_ptr<Lr::IPlatformDoc> currentPlatformDoc;
234-
Lr::DocHandlingError platformReadError = mLauncherInstall->checkoutPlatformDoc(currentPlatformDoc, currentQueryResult.source);
222+
Lr::DocHandlingError platformReadError = mLauncherInstall->checkoutPlatformDoc(currentPlatformDoc, pfQuery.platform);
235223

236224
// Stop import if error occurred
237225
if(platformReadError.isValid())
@@ -242,8 +230,8 @@ Worker::Result Worker::processGames(Qx::Error& errorReport, QList<Fp::Db::QueryB
242230
}
243231

244232
//---Import games---------------------------------------
245-
emit progressStepChanged(label.arg(currentQueryResult.source));
246-
if((result = processPlatformGames(errorReport, currentPlatformDoc, currentQueryResult)) != Successful)
233+
emit progressStepChanged(label.arg(pfQuery.platform));
234+
if((result = processPlatformGames(errorReport, currentPlatformDoc, pfQuery)) != Successful)
247235
return result;
248236

249237
//---Close out document----------------------------------
@@ -381,9 +369,9 @@ Worker::Result Worker::doImport(Qx::Error& errorReport)
381369
Fp::DbError queryError;
382370

383371
// Initial query buffers
384-
QList<Fp::Db::QueryBuffer> gameQueries;
385-
QList<Fp::Db::QueryBuffer> playlistSpecGameQueries;
386-
Fp::Db::QueryBuffer addAppQuery;
372+
QList<PlatformQueryResult> gameQueries;
373+
QList<PlatformQueryResult> playlistSpecGameQueries;
374+
QList<Fp::AddApp> addAppQuery;
387375

388376
// Get flashpoint database
389377
Fp::Db* fpDatabase = mFlashpointInstall->database();
@@ -400,7 +388,7 @@ Worker::Result Worker::doImport(Qx::Error& errorReport)
400388
}
401389

402390
// Make initial game query
403-
queryError = fpDatabase->queryGamesByPlatform(gameQueries, mImportSelections.platforms, mOptionSet.inclusionOptions);
391+
queryError = loadGamesByPlatform(gameQueries, mImportSelections.platforms, mOptionSet.inclusionOptions);
404392
if(queryError.isValid())
405393
{
406394
errorReport = queryError;
@@ -413,18 +401,21 @@ Worker::Result Worker::doImport(Qx::Error& errorReport)
413401
// Get playlist game ID list
414402
const QList<QUuid> targetPlaylistGameIds = getPlaylistSpecificGameIds(targetPlaylists);
415403

416-
// Make unselected platforms list
417-
QStringList availablePlatforms = fpDatabase->platformNames();
418-
QStringList unselectedPlatforms = QStringList(availablePlatforms);
419-
for(const QString& selPlatform : std::as_const(mImportSelections.platforms))
420-
unselectedPlatforms.removeAll(selPlatform);
421-
422-
// Make game query
423-
queryError = fpDatabase->queryGamesByPlatform(playlistSpecGameQueries, unselectedPlatforms, mOptionSet.inclusionOptions, &targetPlaylistGameIds);
424-
if(queryError.isValid())
404+
if(!targetPlaylistGameIds.isEmpty())
425405
{
426-
errorReport = queryError;
427-
return Failed;
406+
// Make unselected platforms list
407+
QStringList availablePlatforms = fpDatabase->platformNames();
408+
QStringList unselectedPlatforms = QStringList(availablePlatforms);
409+
for(const QString& selPlatform : std::as_const(mImportSelections.platforms))
410+
unselectedPlatforms.removeAll(selPlatform);
411+
412+
// Make game query
413+
queryError = loadGamesByPlatform(playlistSpecGameQueries, unselectedPlatforms, mOptionSet.inclusionOptions, targetPlaylistGameIds);
414+
if(queryError.isValid())
415+
{
416+
errorReport = queryError;
417+
return Failed;
418+
}
428419
}
429420
}
430421

@@ -435,7 +426,7 @@ Worker::Result Worker::doImport(Qx::Error& errorReport)
435426
// Make initial add apps query
436427
if(!mOptionSet.excludeAddApps)
437428
{
438-
queryError = fpDatabase->queryAllAddApps(addAppQuery);
429+
queryError = fpDatabase->getAllAddApps(addAppQuery);
439430
if(queryError.isValid())
440431
{
441432
errorReport = queryError;
@@ -447,29 +438,29 @@ Worker::Result Worker::doImport(Qx::Error& errorReport)
447438
quint64 totalGameCount = 0;
448439

449440
QStringList playlistSpecPlatforms;
450-
for(const Fp::Db::QueryBuffer& query : std::as_const(playlistSpecGameQueries))
451-
playlistSpecPlatforms.append(query.source);
441+
for(const auto& query : std::as_const(playlistSpecGameQueries))
442+
playlistSpecPlatforms.append(query.platform);
452443
QStringList involvedPlatforms = mImportSelections.platforms + playlistSpecPlatforms;
453444

454445
// Additional App pre-load
455446
Qx::ProgressGroup* pgAddAppPreload = initializeProgressGroup(Pg::AddAppPreload, 2);
456-
pgAddAppPreload->setMaximum(addAppQuery.size);
447+
pgAddAppPreload->setMaximum(addAppQuery.size());
457448

458449
// Initialize game query progress group since there will always be at least one game to import
459450
Qx::ProgressGroup* pgGameImport = initializeProgressGroup(Pg::GameImport, 2);
460451

461452
// All games
462-
for(const Fp::Db::QueryBuffer& query : std::as_const(gameQueries))
453+
for(const auto& query : std::as_const(gameQueries))
463454
{
464-
pgGameImport->increaseMaximum(query.size);
465-
totalGameCount += query.size;
455+
pgGameImport->increaseMaximum(query.result.size());
456+
totalGameCount += query.result.size();
466457
}
467458

468459
// All playlist specific games
469-
for(const Fp::Db::QueryBuffer& query : std::as_const(playlistSpecGameQueries))
460+
for(const auto& query : std::as_const(playlistSpecGameQueries))
470461
{
471-
pgGameImport->increaseMaximum(query.size);
472-
totalGameCount += query.size;
462+
pgGameImport->increaseMaximum(query.result.size());
463+
totalGameCount += query.result.size();
473464
}
474465

475466
// TODO: Maybe move initial progress setup of image related tasks to ImageManager

0 commit comments

Comments
 (0)