From 586cb84aa580ab1210a2530dbe50c6bb79298a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Tue, 5 Jul 2016 11:24:32 +0300 Subject: [PATCH] Resources|libdoomsday: Handling of .box contents Contained data bundles are now divided to three categories: required, recommended, and extra. These are taken into account (and checked for configured preferences) when a .box is loaded. --- .../include/doomsday/resource/bundles.h | 4 +- .../include/doomsday/resource/databundle.h | 2 + doomsday/apps/libdoomsday/src/games.cpp | 2 +- .../apps/libdoomsday/src/resource/bundles.cpp | 62 +++++++++++++++++-- .../libdoomsday/src/resource/databundle.cpp | 55 +++++++++++++--- 5 files changed, 107 insertions(+), 18 deletions(-) diff --git a/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h b/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h index bbcf70f9c9..1aad1fce83 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h +++ b/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h @@ -40,8 +40,8 @@ class LIBDOOMSDAY_PUBLIC Bundles public: typedef QList BlockElements; - /// Notified when a data bundle refresh/identification has been made. - DENG2_DEFINE_AUDIENCE2(Identify, void dataBundlesIdentified(bool wereIdentified)) + /// Notified when a data bundle refresh/identification has been completed. + DENG2_DEFINE_AUDIENCE2(Identify, void dataBundlesIdentified()) DENG2_ERROR(InvalidError); diff --git a/doomsday/apps/libdoomsday/include/doomsday/resource/databundle.h b/doomsday/apps/libdoomsday/include/doomsday/resource/databundle.h index 6cc8e794a7..6d3f20bb48 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/resource/databundle.h +++ b/doomsday/apps/libdoomsday/include/doomsday/resource/databundle.h @@ -136,6 +136,8 @@ class LIBDOOMSDAY_PUBLIC DataBundle : public de::IByteArray */ static Format packageBundleFormat(de::String const &packageId); + static DataBundle const *bundleForPackage(de::String const &packageId); + protected: void setFormat(Format format); diff --git a/doomsday/apps/libdoomsday/src/games.cpp b/doomsday/apps/libdoomsday/src/games.cpp index e73a7a36d4..6ce2c2bf9d 100644 --- a/doomsday/apps/libdoomsday/src/games.cpp +++ b/doomsday/apps/libdoomsday/src/games.cpp @@ -122,7 +122,7 @@ DENG2_PIMPL(Games) return nullptr; } - void dataBundlesIdentified(bool) + void dataBundlesIdentified() { if (!mainCall) { diff --git a/doomsday/apps/libdoomsday/src/resource/bundles.cpp b/doomsday/apps/libdoomsday/src/resource/bundles.cpp index 4fd01096f6..48a030d61e 100644 --- a/doomsday/apps/libdoomsday/src/resource/bundles.cpp +++ b/doomsday/apps/libdoomsday/src/resource/bundles.cpp @@ -21,6 +21,8 @@ #include "doomsday/filesys/datafolder.h" #include +#include +#include #include #include #include @@ -191,10 +193,14 @@ void Bundles::identify() { d->tasks.start([this] () { - bool const identified = d->identifyAddedDataBundles(); - DENG2_FOR_AUDIENCE2(Identify, i) + d->identifyAddedDataBundles(); + + if (isEverythingIdentified()) { - i->dataBundlesIdentified(identified); + DENG2_FOR_AUDIENCE2(Identify, i) + { + i->dataBundlesIdentified(); + } } }); } @@ -346,14 +352,60 @@ Bundles::MatchResult Bundles::match(DataBundle const &bundle) const QList Bundles::loaded() const { + auto &loader = PackageLoader::get(); QList loadedBundles; + // Collection contents enabled/disabled for use. + DictionaryValue const &selPkgs = Config::get()["resource.selectedPackages"].value(); + // Check all the loaded packages to see which ones are data bundles. - for (auto *f : App::packageLoader().loadedPackagesAsFilesInPackageOrder()) + for (auto *f : loader.loadedPackagesAsFilesInPackageOrder()) { if (DataBundle const *bundle = f->maybeAs()) { - loadedBundles << bundle; + if (bundle->format() == DataBundle::Collection) + { + // Instead of adding the collection, check which contained packages are + // selected for loading. + + auto isSelected = [bundle, &selPkgs] (TextValue const &id, bool byDefault) -> bool + { + TextValue const key(bundle->packageId()); + if (selPkgs.contains(key)) { + auto const &sels = selPkgs.element(key).as(); + if (sels.contains(id)) { + return sels.element(id).isTrue(); + } + } + return byDefault; + }; + + auto addToLoaded = [&loadedBundles] (String const &id) + { + if (DataBundle const *b = DataBundle::bundleForPackage(id)) { + loadedBundles << b; + } + }; + + Record const &meta = bundle->packageMetadata(); + for (auto const *id : meta.geta("requires").elements()) + { + addToLoaded(id->asText()); + } + for (auto const *id : meta.geta("recommends").elements()) + { + if (isSelected(id->asText(), true)) addToLoaded(id->asText()); + } + for (auto const *id : meta.geta("extras").elements()) + { + if (isSelected(id->asText(), false)) addToLoaded(id->asText()); + } + } + else + { + // Non-collection data files are loaded as-is. + loadedBundles << bundle; + } } } diff --git a/doomsday/apps/libdoomsday/src/resource/databundle.cpp b/doomsday/apps/libdoomsday/src/resource/databundle.cpp index 43bcba4d30..87617c1f89 100644 --- a/doomsday/apps/libdoomsday/src/resource/databundle.cpp +++ b/doomsday/apps/libdoomsday/src/resource/databundle.cpp @@ -44,6 +44,10 @@ static String const VAR_AUTHOR ("author"); static String const VAR_TAGS ("tags"); static String const VAR_DATA_FILES ("dataFiles"); static String const VAR_BUNDLE_SCORE("bundleScore"); +static String const VAR_REQUIRES ("requires"); +static String const VAR_RECOMMENDS ("recommends"); +static String const VAR_EXTRAS ("extras"); +static String const VAR_CATEGORY ("category"); namespace internal { @@ -61,7 +65,7 @@ namespace internal }; } -DENG2_PIMPL(DataBundle) +DENG2_PIMPL(DataBundle), public Lockable { bool ignored = false; SafePtr source; @@ -76,6 +80,7 @@ DENG2_PIMPL(DataBundle) ~Impl() { + DENG2_GUARD(this); delete pkgLink.get(); } @@ -134,6 +139,8 @@ DENG2_PIMPL(DataBundle) */ bool identify() { + DENG2_GUARD(this); + // It is sufficient to identify each bundle only once. if (ignored || !packageId.isEmpty()) return false; @@ -187,6 +194,11 @@ DENG2_PIMPL(DataBundle) else { meta.addArray(VAR_DATA_FILES); + + // Collections have a number of subsets. + meta.addArray(VAR_REQUIRES); + meta.addArray(VAR_RECOMMENDS); + meta.addArray(VAR_EXTRAS); } if (isAutoLoaded()) @@ -383,12 +395,19 @@ DENG2_PIMPL(DataBundle) container->isLinkedAsPackage() && container->format() == Collection) { - if (isAutoLoaded()) /*|| - Package::matchTags(container->d->pkgLink, "\\b(hidden|core|gamedata)\\b"))*/ + //File &containerFile = *container->d->pkgLink; + + String subset = VAR_RECOMMENDS; + String parentFolder = dataFilePath.fileNamePath().fileName(); + if (!parentFolder.compareWithoutCase(QStringLiteral("Extra"))) + { + subset = VAR_EXTRAS; + } + else if (!parentFolder.compareWithoutCase(QStringLiteral("Required"))) { - // Autoloaded data files are hidden. - metadata.appendUniqueWord(VAR_TAGS, "hidden"); + subset = VAR_REQUIRES; } + container->packageMetadata().appendToArray(subset, new TextValue(versionedPackageId)); /* qDebug() << container->d->versionedPackageId @@ -399,7 +418,7 @@ DENG2_PIMPL(DataBundle) << "from" << dataFilePath; */ - Package::addRequiredPackage(*container->d->pkgLink, versionedPackageId); + //Package::addRequiredPackage(containerFile, versionedPackageId); } return true; } @@ -491,7 +510,6 @@ DENG2_PIMPL(DataBundle) if (!component.compareWithoutCase("game-jdoom")) { meta.appendUniqueWord(VAR_TAGS, "doom"); - meta.appendUniqueWord(VAR_TAGS, "doom2"); } else if (!component.compareWithoutCase("game-jheretic")) { @@ -503,6 +521,13 @@ DENG2_PIMPL(DataBundle) } } + String category = rootBlock.keyValue("category"); + if (!category.isEmpty()) + { + meta.appendUniqueWord(VAR_TAGS, category); + meta.set(VAR_CATEGORY, category); + } + if (Info::BlockElement const *english = rootBlock.findAs("english")) { if(english->blockType() == "language") @@ -762,16 +787,26 @@ Record const &DataBundle::objectNamespace() const return asFile().objectNamespace().subrecord(QStringLiteral("package")); } -DataBundle::Format DataBundle::packageBundleFormat(String const &packageId) +DataBundle::Format DataBundle::packageBundleFormat(String const &packageId) // static +{ + if (auto const *bundle = bundleForPackage(packageId)) + { + Guard g(bundle->d); + return bundle->format(); + } + return Unknown; +} + +DataBundle const *DataBundle::bundleForPackage(String const &packageId) // static { if (File const *file = PackageLoader::get().select(packageId)) { if (auto const *bundle = file->target().maybeAs()) { - return bundle->format(); + return bundle; } } - return Unknown; + return nullptr; } void DataBundle::setFormat(Format format)