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 "asset.h"
|
||||||
|
#include <drivers.h>
|
||||||
#include <tgf.h>
|
#include <tgf.h>
|
||||||
#include <cjson/cJSON.h>
|
#include <cjson/cJSON.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -75,7 +77,8 @@ std::string Asset::path() const
|
||||||
return "cars/models/";
|
return "cars/models/";
|
||||||
|
|
||||||
case Asset::driver:
|
case Asset::driver:
|
||||||
return "drivers/";
|
// In the case of drivers, category means "driver type".
|
||||||
|
return "drivers/" + category + "/";
|
||||||
|
|
||||||
case Asset::track:
|
case Asset::track:
|
||||||
return "tracks/" + category + "/";
|
return "tracks/" + category + "/";
|
||||||
|
@ -84,6 +87,56 @@ std::string Asset::path() const
|
||||||
return "";
|
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)
|
int Asset::parse(const cJSON *c)
|
||||||
{
|
{
|
||||||
struct field
|
struct field
|
||||||
|
@ -173,3 +226,88 @@ bool Asset::operator==(const Asset &other) const
|
||||||
directory == other.directory &&
|
directory == other.directory &&
|
||||||
size == other.size;
|
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;
|
size_t size;
|
||||||
unsigned long long revision;
|
unsigned long long revision;
|
||||||
std::string path() const;
|
std::string path() const;
|
||||||
|
std::string basedir() const;
|
||||||
|
std::string dstdir() const;
|
||||||
|
int needs_update(bool &out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int parse(const std::string &s, unsigned long long &size);
|
int parse(const std::string &s, unsigned long long &size);
|
||||||
int check_dir(const std::string &d) const;
|
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
|
#endif
|
||||||
|
|
|
@ -571,14 +571,6 @@ int DownloadsMenu::extract(const entry *e, const std::string &src,
|
||||||
std::string &error) const
|
std::string &error) const
|
||||||
{
|
{
|
||||||
const Asset &a = e->a;
|
const Asset &a = e->a;
|
||||||
const char *data = GfDataDir();
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
GfLogError("GfDataDir failed\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
if (randname(name))
|
if (randname(name))
|
||||||
|
@ -588,9 +580,9 @@ int DownloadsMenu::extract(const entry *e, const std::string &src,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tmp = data + name + "/";
|
std::string base = a.basedir(), tmp = base + name + "/";
|
||||||
unzip u(src, tmp, a.directory);
|
unzip u(src, tmp, a.directory);
|
||||||
std::string dst = data + a.path() + a.directory,
|
std::string dst = base + a.dstdir(),
|
||||||
tmpd = tmp + a.directory;
|
tmpd = tmp + a.directory;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
|
@ -697,61 +689,6 @@ int DownloadsMenu::asset_fetched(CURLcode result, CURL *h, const sink *s,
|
||||||
return ret;
|
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,
|
int DownloadsMenu::thumbnail_fetched(CURLcode result, CURL *h, const sink *s,
|
||||||
std::string &error)
|
std::string &error)
|
||||||
{
|
{
|
||||||
|
@ -762,7 +699,7 @@ int DownloadsMenu::thumbnail_fetched(CURLcode result, CURL *h, const sink *s,
|
||||||
{
|
{
|
||||||
bool update;
|
bool update;
|
||||||
|
|
||||||
if (needs_update(e->a, update))
|
if (e->a.needs_update(update))
|
||||||
e->state = entry::download;
|
e->state = entry::download;
|
||||||
else if (update)
|
else if (update)
|
||||||
e->state = entry::update;
|
e->state = entry::update;
|
||||||
|
|
Loading…
Reference in a new issue