From 8014db4013d8146d9b4fb7116d8b825c9aab520c Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Tue, 19 Nov 2024 08:04:09 +0100 Subject: [PATCH] legacymenu: Update driver handling in downloader Dynamically generated drivers have introduced a few breaking changes: - Now, all drivers, whether generated or not, are stored into GfLocalDir. - Driver indexes, and therefore directory names, are recalculated every time GfDrivers::reload is called, so the in-game must find the next available index number on a given subdirectory. - As a consequence of this, the file-based timestamp mechanism used in cars and tracks cannot be used for drivers, since the directory name can (and will) change at any time. Instead, GfDrivers::self() is looked up. Former-commit-id: 05dcbec981a449be50e8656f105481b77881508b Former-commit-id: c965c211b9e427f37317c84c16a6746f1b817eff --- .../legacymenu/mainscreens/asset.cpp | 140 +++++++++++++++++- .../legacymenu/mainscreens/asset.h | 5 + .../legacymenu/mainscreens/downloadsmenu.cpp | 69 +-------- 3 files changed, 147 insertions(+), 67 deletions(-) diff --git a/src/modules/userinterface/legacymenu/mainscreens/asset.cpp b/src/modules/userinterface/legacymenu/mainscreens/asset.cpp index 38202709..351fa45a 100644 --- a/src/modules/userinterface/legacymenu/mainscreens/asset.cpp +++ b/src/modules/userinterface/legacymenu/mainscreens/asset.cpp @@ -9,10 +9,12 @@ */ #include "asset.h" +#include #include #include #include #include +#include #include #include #include @@ -75,7 +77,8 @@ std::string Asset::path() const return "cars/models/"; case Asset::driver: - return "drivers/"; + // In the case of drivers, category means "driver type". + return "drivers/" + category + "/"; case Asset::track: return "tracks/" + category + "/"; @@ -84,6 +87,56 @@ std::string Asset::path() const return ""; } +std::string Asset::basedir() const +{ + switch (type) + { + case Asset::car: + case Asset::track: + return GfDataDir(); + + case Asset::driver: + return GfLocalDir(); + } + + return ""; +} + +std::string Asset::dstdir() const +{ + switch (type) + { + case Asset::car: + case Asset::track: + return path() + directory; + + case Asset::driver: + { + int idx = 0; + // In the case of drivers, category means "driver type". + std::vector drivers = + GfDrivers::self()->getDriversWithTypeAndCategory(category); + + for (const GfDriver *d : drivers) + { + int drvidx = d->getInterfaceIndex(); + + if (d->getName() == name) + { + idx = drvidx; + break; + } + else if (drvidx >= idx) + idx = drvidx + 1; + } + + return path() + std::to_string(idx) + "/"; + } + } + + return ""; +} + int Asset::parse(const cJSON *c) { struct field @@ -173,3 +226,88 @@ bool Asset::operator==(const Asset &other) const directory == other.directory && size == other.size; } + +int Asset::needs_update(bool &out) const +{ + switch (type) + { + case Asset::type::car: + case Asset::type::track: + { + std::string path = basedir() + this->path() + directory + + "/.revision"; + + return needs_update(path, out); + } + + case Asset::type::driver: + return needs_update_drv(out); + } + + return -1; +} + +int Asset::needs_update(const std::string &path, bool &out) const +{ + std::ifstream f(path, std::ios::binary); + + if (!f.is_open()) + return -1; + + char v[sizeof "18446744073709551615"]; + + f.getline(v, sizeof v); + + if (f.fail()) + { + GfLogError("Error while reading revision\n"); + return -1; + } + + unsigned long long rev; + + try + { + size_t pos; + + rev = std::stoull(v, &pos); + + if (pos != strlen(v)) + { + GfLogError("Invalid number: %s\n", v); + return -1; + } + } + catch (const std::invalid_argument &e) + { + GfLogError("caught std::invalid_argument with %s\n", v); + return -1; + } + catch (const std::out_of_range &e) + { + GfLogError("caught std::out_of_range with %s\n", v); + return -1; + } + + out = revision > rev; + return 0; +} + +int Asset::needs_update_drv(bool &out) const +{ + // In the case of drivers, category means "driver type". + std::vector drivers = + GfDrivers::self()->getDriversWithTypeAndCategory(category); + + for (const GfDriver *d : drivers) + if (d->getName() == name) + { + int idx = d->getInterfaceIndex(); + std::string path = basedir() + this->path() + std::to_string(idx) + + "/.revision"; + + return needs_update(path, out); + } + + return -1; +} diff --git a/src/modules/userinterface/legacymenu/mainscreens/asset.h b/src/modules/userinterface/legacymenu/mainscreens/asset.h index ecbe835e..2cb25cd7 100644 --- a/src/modules/userinterface/legacymenu/mainscreens/asset.h +++ b/src/modules/userinterface/legacymenu/mainscreens/asset.h @@ -26,10 +26,15 @@ public: size_t size; unsigned long long revision; std::string path() const; + std::string basedir() const; + std::string dstdir() const; + int needs_update(bool &out) const; private: int parse(const std::string &s, unsigned long long &size); int check_dir(const std::string &d) const; + int needs_update(const std::string &path, bool &out) const; + int needs_update_drv(bool &out) const; }; #endif diff --git a/src/modules/userinterface/legacymenu/mainscreens/downloadsmenu.cpp b/src/modules/userinterface/legacymenu/mainscreens/downloadsmenu.cpp index cfd24e5c..5392c3ed 100644 --- a/src/modules/userinterface/legacymenu/mainscreens/downloadsmenu.cpp +++ b/src/modules/userinterface/legacymenu/mainscreens/downloadsmenu.cpp @@ -571,14 +571,6 @@ int DownloadsMenu::extract(const entry *e, const std::string &src, std::string &error) const { const Asset &a = e->a; - const char *data = GfDataDir(); - - if (!data) - { - GfLogError("GfDataDir failed\n"); - return -1; - } - std::string name; if (randname(name)) @@ -588,9 +580,9 @@ int DownloadsMenu::extract(const entry *e, const std::string &src, return -1; } - std::string tmp = data + name + "/"; + std::string base = a.basedir(), tmp = base + name + "/"; unzip u(src, tmp, a.directory); - std::string dst = data + a.path() + a.directory, + std::string dst = base + a.dstdir(), tmpd = tmp + a.directory; int ret = -1; @@ -697,61 +689,6 @@ int DownloadsMenu::asset_fetched(CURLcode result, CURL *h, const sink *s, return ret; } -static int needs_update(const Asset &a, bool &out) -{ - const char *data = GfDataDir(); - - if (!data) - { - GfLogError("GfDataDir failed\n"); - return -1; - } - - std::string path = data + a.path() + a.directory + "/.revision"; - std::ifstream f(path, std::ios::binary); - - if (!f.is_open()) - return -1; - - char v[sizeof "18446744073709551615"]; - - f.getline(v, sizeof v); - - if (f.fail()) - { - GfLogError("Error while reading revision\n"); - return -1; - } - - unsigned long long rev; - - try - { - size_t pos; - - rev = std::stoull(v, &pos); - - if (pos != strlen(v)) - { - GfLogError("Invalid number: %s\n", v); - return -1; - } - } - catch (const std::invalid_argument &e) - { - GfLogError("caught std::invalid_argument with %s\n", v); - return -1; - } - catch (const std::out_of_range &e) - { - GfLogError("caught std::out_of_range with %s\n", v); - return -1; - } - - out = a.revision > rev; - return 0; -} - int DownloadsMenu::thumbnail_fetched(CURLcode result, CURL *h, const sink *s, std::string &error) { @@ -762,7 +699,7 @@ int DownloadsMenu::thumbnail_fetched(CURLcode result, CURL *h, const sink *s, { bool update; - if (needs_update(e->a, update)) + if (e->a.needs_update(update)) e->state = entry::download; else if (update) e->state = entry::update;