mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 05:04:01 +08:00
* a working impl to bridge ugc/remote_storage as suggested by Detanup01
* edits by Kola124 + other changes in the settings parser * random ugc mod handle at object creation * file size using std::filesystem + fix warnings + some print + arg validation
This commit is contained in:
parent
4afd10219d
commit
0d1e54e9a2
@ -73,6 +73,8 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
|
||||
// OS specific includes + definitions
|
||||
#if defined(__WINDOWS__)
|
||||
@ -164,6 +166,9 @@ static inline void reset_LastError()
|
||||
#include "utfcpp/utf8.h"
|
||||
#include "controller/gamepad.h"
|
||||
|
||||
// common includes
|
||||
#include "common_helpers/common_helpers.hpp"
|
||||
|
||||
// Steamsdk includes
|
||||
#include "steam/steam_api.h"
|
||||
#include "steam/steam_gameserver.h"
|
||||
|
@ -43,14 +43,14 @@ struct image_t
|
||||
|
||||
class Local_Storage {
|
||||
public:
|
||||
static constexpr auto inventory_storage_folder = "inventory";
|
||||
static constexpr auto settings_storage_folder = "settings";
|
||||
static constexpr auto remote_storage_folder = "remote";
|
||||
static constexpr auto stats_storage_folder = "stats";
|
||||
static constexpr auto inventory_storage_folder = "inventory";
|
||||
static constexpr auto settings_storage_folder = "settings";
|
||||
static constexpr auto remote_storage_folder = "remote";
|
||||
static constexpr auto stats_storage_folder = "stats";
|
||||
static constexpr auto leaderboard_storage_folder = "leaderboard";
|
||||
static constexpr auto user_data_storage = "local";
|
||||
static constexpr auto screenshots_folder = "screenshots";
|
||||
static constexpr auto game_settings_folder = "steam_settings";
|
||||
static constexpr auto user_data_storage = "local";
|
||||
static constexpr auto screenshots_folder = "screenshots";
|
||||
static constexpr auto game_settings_folder = "steam_settings";
|
||||
|
||||
private:
|
||||
std::string save_directory;
|
||||
|
@ -46,8 +46,8 @@ struct Mod_entry {
|
||||
bool tagsTruncated;
|
||||
std::string tags;
|
||||
// file/url information
|
||||
UGCHandle_t handleFile = k_UGCHandleInvalid;
|
||||
UGCHandle_t handlePreviewFile = k_UGCHandleInvalid;
|
||||
UGCHandle_t handleFile = generate_file_handle();
|
||||
UGCHandle_t handlePreviewFile = generate_file_handle();
|
||||
std::string primaryFileName;
|
||||
int32 primaryFileSize;
|
||||
std::string previewFileName;
|
||||
@ -59,6 +59,18 @@ struct Mod_entry {
|
||||
float score;
|
||||
// collection details
|
||||
uint32 numChildren;
|
||||
|
||||
private:
|
||||
UGCHandle_t generate_file_handle()
|
||||
{
|
||||
static UGCHandle_t val = 0;
|
||||
|
||||
++val;
|
||||
if (val == 0 || val == k_UGCHandleInvalid) val = 1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Leaderboard_config {
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "steam_http.h"
|
||||
#include "steam_controller.h"
|
||||
#include "steam_ugc.h"
|
||||
#include "ugc_remote_storage_bridge.h"
|
||||
#include "steam_applist.h"
|
||||
#include "steam_music.h"
|
||||
#include "steam_musicremote.h"
|
||||
@ -84,6 +85,8 @@ public:
|
||||
Local_Storage *local_storage;
|
||||
RunEveryRunCB *run_every_runcb;
|
||||
|
||||
Ugc_Remote_Storage_Bridge *ugc_bridge;
|
||||
|
||||
Steam_User *steam_user;
|
||||
Steam_Friends *steam_friends;
|
||||
Steam_Utils *steam_utils;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
33
dll/dll/ugc_remote_storage_bridge.h
Normal file
33
dll/dll/ugc_remote_storage_bridge.h
Normal file
@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
||||
#define __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
||||
|
||||
#include "base.h"
|
||||
|
||||
class Ugc_Remote_Storage_Bridge
|
||||
{
|
||||
public:
|
||||
struct QueryInfo {
|
||||
PublishedFileId_t mod_id; // mod id
|
||||
bool is_primary_file; // was this query for the primary mod file or preview file
|
||||
};
|
||||
|
||||
private:
|
||||
// key: UGCHandle_t which is the file handle (primary or preview)
|
||||
// value: the mod id, true if UGCHandle_t of primary file | false if UGCHandle_t of preview file
|
||||
std::map<UGCHandle_t, QueryInfo> steam_ugc_queries{};
|
||||
|
||||
public:
|
||||
// called from Steam_UGC::SendQueryUGCRequest() after a successful query
|
||||
void add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file);
|
||||
|
||||
bool remove_ugc_query_result(UGCHandle_t file_handle);
|
||||
|
||||
std::optional<QueryInfo> get_ugc_query_result(UGCHandle_t file_handle);
|
||||
|
||||
~Ugc_Remote_Storage_Bridge();
|
||||
};
|
||||
|
||||
|
||||
#endif // __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
||||
|
@ -157,7 +157,7 @@ void Settings::addMod(PublishedFileId_t id, std::string title, std::string path)
|
||||
return;
|
||||
}
|
||||
|
||||
Mod_entry new_entry;
|
||||
Mod_entry new_entry{};
|
||||
new_entry.id = id;
|
||||
new_entry.title = title;
|
||||
new_entry.path = path;
|
||||
@ -168,7 +168,8 @@ void Settings::addModDetails(PublishedFileId_t id, Mod_entry details)
|
||||
{
|
||||
auto f = std::find_if(mods.begin(), mods.end(), [&id](Mod_entry const& item) { return item.id == id; });
|
||||
if (f != mods.end()) {
|
||||
f->previewURL = details.previewURL;
|
||||
// don't copy files handles, they're auto generated
|
||||
|
||||
f->fileType = details.fileType;
|
||||
f->description = details.description;
|
||||
f->steamIDOwner = details.steamIDOwner;
|
||||
@ -180,10 +181,6 @@ void Settings::addModDetails(PublishedFileId_t id, Mod_entry details)
|
||||
f->acceptedForUse = details.acceptedForUse;
|
||||
f->tagsTruncated = details.tagsTruncated;
|
||||
f->tags = details.tags;
|
||||
// - should we set the handles here instead of Invalid?
|
||||
f->handleFile = details.handleFile;
|
||||
f->handlePreviewFile = details.handlePreviewFile;
|
||||
// -
|
||||
f->primaryFileName = details.primaryFileName;
|
||||
f->primaryFileSize = details.primaryFileSize;
|
||||
f->previewFileName = details.previewFileName;
|
||||
@ -193,6 +190,7 @@ void Settings::addModDetails(PublishedFileId_t id, Mod_entry details)
|
||||
f->votesDown = details.votesDown;
|
||||
f->score = details.score;
|
||||
f->numChildren = details.numChildren;
|
||||
f->previewURL = details.previewURL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,6 +779,8 @@ static void parse_force_branch_name(class Settings *settings_client, Settings *s
|
||||
// steam_settings/mods
|
||||
static void parse_mods_folder(class Settings *settings_client, Settings *settings_server, class Local_Storage *local_storage)
|
||||
{
|
||||
std::chrono::system_clock::time_point one_week_ago = std::chrono::system_clock::now() - std::chrono::hours(24 * 7);
|
||||
auto one_week_ago_epoch = std::chrono::duration_cast<std::chrono::seconds>(one_week_ago.time_since_epoch()).count();
|
||||
std::string mod_path = Local_Storage::get_game_settings_path() + "mods";
|
||||
nlohmann::json mod_items = nlohmann::json::object();
|
||||
static constexpr auto mods_json_file = "mods.json";
|
||||
@ -786,6 +788,7 @@ static void parse_mods_folder(class Settings *settings_client, Settings *setting
|
||||
if (local_storage->load_json(mods_json_path, mod_items)) {
|
||||
for (auto mod = mod_items.begin(); mod != mod_items.end(); ++mod) {
|
||||
try {
|
||||
std::string mod_images_folder = Local_Storage::get_game_settings_path() + "mod_images" + PATH_SEPARATOR + std::string(mod.key());
|
||||
Mod_entry newMod;
|
||||
newMod.id = std::stoull(mod.key());
|
||||
newMod.title = mod.value().value("title", std::string(mod.key()));
|
||||
@ -795,47 +798,90 @@ static void parse_mods_folder(class Settings *settings_client, Settings *setting
|
||||
}
|
||||
newMod.fileType = k_EWorkshopFileTypeCommunity;
|
||||
newMod.description = mod.value().value("description", std::string(""));
|
||||
newMod.steamIDOwner = mod.value().value("steam_id_owner", (uint64)0);
|
||||
newMod.timeCreated = mod.value().value("time_created", (uint32)1554997000);
|
||||
newMod.timeUpdated = mod.value().value("time_updated", (uint32)1554997000);
|
||||
newMod.timeAddedToUserList = mod.value().value("time_added", (uint32)1554997000);
|
||||
newMod.steamIDOwner = mod.value().value("steam_id_owner", settings_client->get_local_steam_id().ConvertToUint64());
|
||||
newMod.timeCreated = mod.value().value("time_created", (uint32)std::chrono::system_clock::now().time_since_epoch().count());
|
||||
newMod.timeUpdated = mod.value().value("time_updated", (uint32)one_week_ago.time_since_epoch().count());
|
||||
newMod.timeAddedToUserList = mod.value().value("time_added", (uint32)one_week_ago_epoch);
|
||||
newMod.visibility = k_ERemoteStoragePublishedFileVisibilityPublic;
|
||||
newMod.banned = false;
|
||||
newMod.acceptedForUse = true;
|
||||
newMod.tagsTruncated = false;
|
||||
newMod.tags = mod.value().value("tags", std::string(""));
|
||||
|
||||
constexpr static auto get_file_size = [](
|
||||
const std::string &filepath,
|
||||
const std::string &basepath,
|
||||
int32 default_val = 0) -> size_t {
|
||||
try
|
||||
{
|
||||
const auto file_p = common_helpers::to_absolute(filepath, basepath);
|
||||
if (file_p.empty()) return default_val;
|
||||
|
||||
size_t size = 0;
|
||||
if (common_helpers::file_size(file_p, size)) {
|
||||
return size;
|
||||
}
|
||||
} catch(...) {}
|
||||
return default_val;
|
||||
};
|
||||
|
||||
newMod.primaryFileName = mod.value().value("primary_filename", std::string(""));
|
||||
if(newMod.primaryFileName!=""){
|
||||
long begin = 0, end = 0;
|
||||
const char* name = newMod.primaryFileName.c_str();
|
||||
std::fstream file(name);
|
||||
begin = file.tellg();
|
||||
file.seekg(0, std::ios::end);
|
||||
end = file.tellg();
|
||||
file.close();
|
||||
newMod.primaryFileSize = mod.value().value("primary_filesize", (end-begin));
|
||||
}
|
||||
else
|
||||
{
|
||||
newMod.primaryFileSize = mod.value().value("primary_filesize", (int32)1000000);
|
||||
int32 primary_filesize = 0;
|
||||
if (!newMod.primaryFileName.empty()) {
|
||||
primary_filesize = (int32)get_file_size(newMod.primaryFileName, newMod.path, primary_filesize);
|
||||
}
|
||||
newMod.primaryFileSize = mod.value().value("primary_filesize", primary_filesize);
|
||||
|
||||
newMod.previewFileName = mod.value().value("preview_filename", std::string(""));
|
||||
newMod.previewFileSize = mod.value().value("preview_filesize", (int32)1000000);
|
||||
newMod.workshopItemURL = mod.value().value("workshop_item_url", std::string(""));
|
||||
int32 preview_filesize = 0;
|
||||
if (!newMod.previewFileName.empty()) {
|
||||
preview_filesize = (int32)get_file_size(
|
||||
newMod.previewFileName,
|
||||
mod_images_folder,
|
||||
preview_filesize);
|
||||
}
|
||||
newMod.previewFileSize = mod.value().value("preview_filesize", preview_filesize);
|
||||
|
||||
newMod.workshopItemURL = mod.value().value("workshop_item_url", "https://steamcommunity.com/sharedfiles/filedetails/?id=" + std::string(mod.key()));
|
||||
newMod.votesUp = mod.value().value("upvotes", (uint32)1);
|
||||
newMod.votesDown = mod.value().value("downvotes", (uint32)0);
|
||||
newMod.score = mod.value().value("score", 1.0f);
|
||||
|
||||
float score = 1.0f;
|
||||
try
|
||||
{
|
||||
score = newMod.votesUp / (float)(newMod.votesUp + newMod.votesDown);
|
||||
} catch(...) {}
|
||||
newMod.score = mod.value().value("score", score);
|
||||
|
||||
newMod.numChildren = mod.value().value("num_children", (uint32)0);
|
||||
|
||||
newMod.previewURL = mod.value().value("preview_url", std::string(""));
|
||||
if (newMod.previewURL.empty()) {
|
||||
newMod.previewURL = newMod.previewFileName.empty()
|
||||
? ""
|
||||
: "file://" + Local_Storage::get_game_settings_path() + "mod_images/" + newMod.previewFileName;
|
||||
if (newMod.previewFileName.empty()) {
|
||||
newMod.previewURL = std::string();
|
||||
} else {
|
||||
auto settings_folder = std::string(Local_Storage::get_game_settings_path());
|
||||
std::replace(settings_folder.begin(), settings_folder.end(), '\\', '/');
|
||||
newMod.previewURL = "file://" + settings_folder + "mod_images/" + std::string(mod.key()) + "/" + newMod.previewFileName;
|
||||
}
|
||||
}
|
||||
|
||||
settings_client->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_server->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_client->addModDetails(newMod.id, newMod);
|
||||
settings_server->addModDetails(newMod.id, newMod);
|
||||
|
||||
PRINT_DEBUG(" parsed mod '%s':\n", std::string(mod.key()).c_str());
|
||||
PRINT_DEBUG(" path (will be used for primary file): '%s'\n", newMod.path.c_str());
|
||||
PRINT_DEBUG(" images path (will be used for preview file): '%s'\n", mod_images_folder.c_str());
|
||||
PRINT_DEBUG(" primary_filename: '%s'\n", newMod.primaryFileName.c_str());
|
||||
PRINT_DEBUG(" primary_filesize: %i bytes\n", newMod.primaryFileSize);
|
||||
PRINT_DEBUG(" primary file handle: %llu\n", settings_client->getMod(newMod.id).handleFile);
|
||||
PRINT_DEBUG(" preview_filename: '%s'\n", newMod.previewFileName.c_str());
|
||||
PRINT_DEBUG(" preview_filesize: %i bytes\n", newMod.previewFileSize);
|
||||
PRINT_DEBUG(" preview file handle: %llu\n", settings_client->getMod(newMod.id).handlePreviewFile);
|
||||
PRINT_DEBUG(" workshop_item_url: '%s'\n", newMod.workshopItemURL.c_str());
|
||||
PRINT_DEBUG(" preview_url: '%s'\n", newMod.previewURL.c_str());
|
||||
} catch (std::exception& e) {
|
||||
PRINT_DEBUG("MODLOADER ERROR: %s\n", e.what());
|
||||
}
|
||||
@ -852,18 +898,18 @@ static void parse_mods_folder(class Settings *settings_client, Settings *setting
|
||||
newMod.fileType = k_EWorkshopFileTypeCommunity;
|
||||
newMod.description = "";
|
||||
newMod.steamIDOwner = (uint64)0;
|
||||
newMod.timeCreated = (uint32)1554997000;
|
||||
newMod.timeUpdated = (uint32)1554997000;
|
||||
newMod.timeAddedToUserList = (uint32)1554997000;
|
||||
newMod.timeCreated = (uint32)one_week_ago_epoch;
|
||||
newMod.timeUpdated = (uint32)one_week_ago_epoch;
|
||||
newMod.timeAddedToUserList = (uint32)one_week_ago_epoch;
|
||||
newMod.visibility = k_ERemoteStoragePublishedFileVisibilityPublic;
|
||||
newMod.banned = false;
|
||||
newMod.acceptedForUse = true;
|
||||
newMod.tagsTruncated = false;
|
||||
newMod.tags = "";
|
||||
newMod.primaryFileName = "";
|
||||
newMod.primaryFileSize = (int32)1000000;
|
||||
newMod.primaryFileSize = (int32)0;
|
||||
newMod.previewFileName = "";
|
||||
newMod.previewFileSize = (int32)1000000;
|
||||
newMod.previewFileSize = (int32)0;
|
||||
newMod.workshopItemURL = "";
|
||||
newMod.votesUp = (uint32)1;
|
||||
newMod.votesDown = (uint32)0;
|
||||
|
@ -73,17 +73,19 @@ Steam_Client::Steam_Client()
|
||||
steam_user = new Steam_User(settings_client, local_storage, network, callback_results_client, callbacks_client);
|
||||
steam_friends = new Steam_Friends(settings_client, network, callback_results_client, callbacks_client, run_every_runcb, steam_overlay);
|
||||
steam_utils = new Steam_Utils(settings_client, callback_results_client, steam_overlay);
|
||||
|
||||
ugc_bridge = new Ugc_Remote_Storage_Bridge();
|
||||
|
||||
steam_matchmaking = new Steam_Matchmaking(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
|
||||
steam_matchmaking_servers = new Steam_Matchmaking_Servers(settings_client, network);
|
||||
steam_user_stats = new Steam_User_Stats(settings_client, local_storage, callback_results_client, callbacks_client, steam_overlay);
|
||||
steam_apps = new Steam_Apps(settings_client, callback_results_client);
|
||||
steam_networking = new Steam_Networking(settings_client, network, callbacks_client, run_every_runcb);
|
||||
steam_remote_storage = new Steam_Remote_Storage(settings_client, local_storage, callback_results_client);
|
||||
steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client);
|
||||
steam_screenshots = new Steam_Screenshots(local_storage, callbacks_client);
|
||||
steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client);
|
||||
steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb);
|
||||
steam_ugc = new Steam_UGC(settings_client, callback_results_client, callbacks_client);
|
||||
steam_ugc = new Steam_UGC(settings_client, ugc_bridge, callback_results_client, callbacks_client);
|
||||
steam_applist = new Steam_Applist();
|
||||
steam_music = new Steam_Music(callbacks_client);
|
||||
steam_musicremote = new Steam_MusicRemote();
|
||||
@ -109,7 +111,7 @@ Steam_Client::Steam_Client()
|
||||
steam_gameserver_networking = new Steam_Networking(settings_server, network, callbacks_server, run_every_runcb);
|
||||
steam_gameserver_http = new Steam_HTTP(settings_server, network, callback_results_server, callbacks_server);
|
||||
steam_gameserver_inventory = new Steam_Inventory(settings_server, callback_results_server, callbacks_server, run_every_runcb, local_storage);
|
||||
steam_gameserver_ugc = new Steam_UGC(settings_server, callback_results_server, callbacks_server);
|
||||
steam_gameserver_ugc = new Steam_UGC(settings_server, ugc_bridge, callback_results_server, callbacks_server);
|
||||
steam_gameserver_apps = new Steam_Apps(settings_server, callback_results_server);
|
||||
steam_gameserver_networking_sockets = new Steam_Networking_Sockets(settings_server, network, callback_results_server, callbacks_server, run_every_runcb, steam_networking_sockets->get_shared_between_client_server());
|
||||
steam_gameserver_networking_sockets_serialized = new Steam_Networking_Sockets_Serialized(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
|
33
dll/ugc_remote_storage_bridge.cpp
Normal file
33
dll/ugc_remote_storage_bridge.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "dll/ugc_remote_storage_bridge.h"
|
||||
|
||||
|
||||
void Ugc_Remote_Storage_Bridge::add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file)
|
||||
{
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
steam_ugc_queries[file_handle].mod_id = fileid;
|
||||
steam_ugc_queries[file_handle].is_primary_file = handle_of_primary_file;
|
||||
}
|
||||
|
||||
bool Ugc_Remote_Storage_Bridge::remove_ugc_query_result(UGCHandle_t file_handle)
|
||||
{
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
return !!steam_ugc_queries.erase(file_handle);
|
||||
}
|
||||
|
||||
std::optional<Ugc_Remote_Storage_Bridge::QueryInfo> Ugc_Remote_Storage_Bridge::get_ugc_query_result(UGCHandle_t file_handle)
|
||||
{
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
auto it = steam_ugc_queries.find(file_handle);
|
||||
if (steam_ugc_queries.end() == it) return std::nullopt;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Ugc_Remote_Storage_Bridge::~Ugc_Remote_Storage_Bridge()
|
||||
{
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
steam_ugc_queries.clear();
|
||||
}
|
@ -163,7 +163,7 @@ std::wstring common_helpers::to_absolute(const std::wstring &path, const std::ws
|
||||
return path_abs.wstring();
|
||||
}
|
||||
|
||||
bool common_helpers::file_exist(std::filesystem::path &filepath)
|
||||
bool common_helpers::file_exist(const std::filesystem::path &filepath)
|
||||
{
|
||||
if (std::filesystem::is_directory(filepath)) {
|
||||
return false;
|
||||
@ -188,7 +188,28 @@ bool common_helpers::file_exist(const std::wstring &filepath)
|
||||
return file_exist(path);
|
||||
}
|
||||
|
||||
bool common_helpers::dir_exist(std::filesystem::path &dirpath)
|
||||
bool common_helpers::file_size(const std::filesystem::path &filepath, size_t &size)
|
||||
{
|
||||
if (common_helpers::file_exist(filepath)) {
|
||||
size = std::filesystem::file_size(filepath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool common_helpers::file_size(const std::string &filepath, size_t &size)
|
||||
{
|
||||
const auto file_p = std::filesystem::path(filepath);
|
||||
return file_size(file_p, size);
|
||||
}
|
||||
|
||||
bool common_helpers::file_size(const std::wstring &filepath, size_t &size)
|
||||
{
|
||||
const auto file_p = std::filesystem::path(filepath);
|
||||
return file_size(file_p, size);
|
||||
}
|
||||
|
||||
bool common_helpers::dir_exist(const std::filesystem::path &dirpath)
|
||||
{
|
||||
if (std::filesystem::is_directory(dirpath)) {
|
||||
return true;
|
||||
|
@ -36,13 +36,19 @@ std::string to_absolute(const std::string &path, const std::string &base = std::
|
||||
|
||||
std::wstring to_absolute(const std::wstring &path, const std::wstring &base = std::wstring());
|
||||
|
||||
bool file_exist(std::filesystem::path &filepath);
|
||||
bool file_exist(const std::filesystem::path &filepath);
|
||||
|
||||
bool file_exist(const std::string &filepath);
|
||||
|
||||
bool file_exist(const std::wstring &filepath);
|
||||
|
||||
bool dir_exist(std::filesystem::path &dirpath);
|
||||
bool file_size(const std::filesystem::path &filepath, size_t &size);
|
||||
|
||||
bool file_size(const std::string &filepath, size_t &size);
|
||||
|
||||
bool file_size(const std::wstring &filepath, size_t &size);
|
||||
|
||||
bool dir_exist(const std::filesystem::path &dirpath);
|
||||
|
||||
bool dir_exist(const std::string &dirpath);
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
Put here the files whose names are specified by the JSON key "preview_filename" inside mods.json
|
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -12,8 +12,8 @@
|
||||
"preview_filename": "test.png",
|
||||
"preview_filesize": 1000000,
|
||||
"workshop_item_url": "https://steamcommunity.com/sharedfiles/filedetails/?id=111111111",
|
||||
"upvotes": 1,
|
||||
"downvotes": 0,
|
||||
"upvotes": 10,
|
||||
"downvotes": 1,
|
||||
"num_children": 0,
|
||||
"path": "C:\\games\\my_game\\steam_settings\\mods_data\\mod_111111111_data_folder",
|
||||
"preview_url": "file://C:/games/my_game/steam_settings/mod_images/my_preview.jpg",
|
||||
|
Loading…
Reference in New Issue
Block a user