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
This commit is contained in:
parent
30144d1dfd
commit
8014db4013
3 changed files with 147 additions and 67 deletions
|
@ -9,10 +9,12 @@
|
|||
*/
|
||||
|
||||
#include "asset.h"
|
||||
#include <drivers.h>
|
||||
#include <tgf.h>
|
||||
#include <cjson/cJSON.h>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -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<GfDriver *> 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<GfDriver *> 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue