From 0d1e54e9a22f31110a02d2edd4e532b017ec9695 Mon Sep 17 00:00:00 2001 From: otavepto <153766569+otavepto@users.noreply.github.com> Date: Sun, 14 Jan 2024 19:39:19 +0200 Subject: [PATCH] =?UTF-8?q?=EF=BB=BF*=20a=20working=20impl=20to=20bridge?= =?UTF-8?q?=20ugc/remote=5Fstorage=20as=20suggested=20by=20Detanup01?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- dll/dll/common_includes.h | 5 + dll/dll/local_storage.h | 14 +- dll/dll/settings.h | 16 +- dll/dll/steam_client.h | 3 + dll/dll/steam_remote_storage.h | 662 ++++++++++++++---- dll/dll/steam_ugc.h | 451 +++++++++--- dll/dll/ugc_remote_storage_bridge.h | 33 + dll/settings.cpp | 10 +- dll/settings_parser.cpp | 102 ++- dll/steam_client.cpp | 8 +- dll/ugc_remote_storage_bridge.cpp | 33 + helpers/common_helpers.cpp | 25 +- helpers/common_helpers/common_helpers.hpp | 10 +- .../mod_images/12345/Readme.txt | 1 + .../mod_images/12345/my_preview_image.jpg | Bin 0 -> 3409 bytes .../steam_settings.EXAMPLE/mods.EXAMPLE.json | 4 +- 16 files changed, 1084 insertions(+), 293 deletions(-) create mode 100644 dll/dll/ugc_remote_storage_bridge.h create mode 100644 dll/ugc_remote_storage_bridge.cpp create mode 100644 post_build/steam_settings.EXAMPLE/mod_images/12345/Readme.txt create mode 100644 post_build/steam_settings.EXAMPLE/mod_images/12345/my_preview_image.jpg diff --git a/dll/dll/common_includes.h b/dll/dll/common_includes.h index 8f86518a..5aa0d72d 100644 --- a/dll/dll/common_includes.h +++ b/dll/dll/common_includes.h @@ -73,6 +73,8 @@ #include #include +#include +#include // 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" diff --git a/dll/dll/local_storage.h b/dll/dll/local_storage.h index 7578ec9c..c5094ca0 100644 --- a/dll/dll/local_storage.h +++ b/dll/dll/local_storage.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; diff --git a/dll/dll/settings.h b/dll/dll/settings.h index 30e95c6a..f1905723 100644 --- a/dll/dll/settings.h +++ b/dll/dll/settings.h @@ -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 { diff --git a/dll/dll/steam_client.h b/dll/dll/steam_client.h index 73a74e5d..000486a3 100644 --- a/dll/dll/steam_client.h +++ b/dll/dll/steam_client.h @@ -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; diff --git a/dll/dll/steam_remote_storage.h b/dll/dll/steam_remote_storage.h index 25c90720..97b45918 100644 --- a/dll/dll/steam_remote_storage.h +++ b/dll/dll/steam_remote_storage.h @@ -16,13 +16,14 @@ . */ #include "base.h" +#include "dll/ugc_remote_storage_bridge.h" struct Async_Read { - SteamAPICall_t api_call; - uint32 offset; - uint32 to_read; - uint32 size; - std::string file_name; + SteamAPICall_t api_call; + uint32 offset; + uint32 to_read; + uint32 size; + std::string file_name; }; struct Stream_Write { @@ -32,10 +33,39 @@ struct Stream_Write { }; struct Downloaded_File { + enum DownloadSource { + AfterFileShare, // attempted download after a call to Steam_Remote_Storage::FileShare() + AfterSendQueryUGCRequest, // attempted download after a call to Steam_UGC::SendQueryUGCRequest() + AfterUGCDownloadToLocation, // attempted download after a call to Steam_Remote_Storage::UGCDownloadToLocation() + } source; + + // *** used in any case std::string file; uint64 total_size; + + // put any additional data needed by other sources here + + // *** used when source = SendQueryUGCRequest only + Ugc_Remote_Storage_Bridge::QueryInfo mod_query_info; + + // *** used when source = AfterUGCDownloadToLocation only + std::string download_to_location_fullpath; }; +static void copy_file(const std::string &src_filepath, const std::string &dst_filepath) +{ + try + { + PRINT_DEBUG("Steam_Remote_Storage::copy_file copying file '%s' to '%s'", src_filepath.c_str(), dst_filepath.c_str()); + const auto src_p = std::filesystem::path(src_filepath); + if (!std::filesystem::exists(src_p) || std::filesystem::is_directory(src_p)) return; + + const auto dst_p = std::filesystem::path(dst_filepath); + std::filesystem::create_directories(dst_p.parent_path()); // make the folder tree if needed + std::filesystem::copy_file(src_p, dst_p, std::filesystem::copy_options::overwrite_existing); + } catch(...) {} +} + class Steam_Remote_Storage : public ISteamRemoteStorage001, public ISteamRemoteStorage002, @@ -55,6 +85,7 @@ public ISteamRemoteStorage { private: class Settings *settings; + class Ugc_Remote_Storage_Bridge *ugc_bridge; Local_Storage *local_storage; class SteamCallResults *callback_results; bool steam_cloud_enabled; @@ -62,15 +93,20 @@ private: std::vector stream_writes; std::map shared_files; std::map downloaded_files; + std::set subscribed; // just to keep the running state of subscription public: -Steam_Remote_Storage(class Settings *settings, Local_Storage *local_storage, class SteamCallResults *callback_results) +Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, Local_Storage *local_storage, class SteamCallResults *callback_results) { this->settings = settings; + this->ugc_bridge = ugc_bridge; this->local_storage = local_storage; this->callback_results = callback_results; steam_cloud_enabled = true; local_storage->update_save_filenames(Local_Storage::remote_storage_folder); + + // subscribe to all mods initially + subscribed = settings->modSet(); } // NOTE @@ -81,39 +117,41 @@ Steam_Remote_Storage(class Settings *settings, Local_Storage *local_storage, cla // // file operations -bool FileWrite( const char *pchFile, const void *pvData, int32 cubData ) +bool FileWrite( const char *pchFile, const void *pvData, int32 cubData ) { - PRINT_DEBUG("Steam_Remote_Storage::FileWrite %s %u\n", pchFile, cubData); + PRINT_DEBUG("Steam_Remote_Storage::FileWrite '%s' %p %u\n", pchFile, pvData, cubData); + std::lock_guard lock(global_mutex); + if (!pchFile || cubData <= 0 || cubData > k_unMaxCloudFileChunkSize || !pvData) { return false; } - std::lock_guard lock(global_mutex); int data_stored = local_storage->store_data(Local_Storage::remote_storage_folder, pchFile, (char* )pvData, cubData); PRINT_DEBUG("Steam_Remote_Storage::Stored %i, %u\n", data_stored, data_stored == cubData); return data_stored == cubData; } -int32 FileRead( const char *pchFile, void *pvData, int32 cubDataToRead ) +int32 FileRead( const char *pchFile, void *pvData, int32 cubDataToRead ) { - PRINT_DEBUG("Steam_Remote_Storage::FileRead %s %i\n", pchFile, cubDataToRead); - if (!pchFile || !pvData || !cubDataToRead) return 0; + PRINT_DEBUG("Steam_Remote_Storage::FileRead '%s' %p %i\n", pchFile, pvData, cubDataToRead); std::lock_guard lock(global_mutex); + + if (!pchFile || !pvData || !cubDataToRead) return 0; int read_data = local_storage->get_data(Local_Storage::remote_storage_folder, pchFile, (char* )pvData, cubDataToRead); if (read_data < 0) read_data = 0; - PRINT_DEBUG("Read %i\n", read_data); + PRINT_DEBUG(" Read %i\n", read_data); return read_data; } STEAM_CALL_RESULT( RemoteStorageFileWriteAsyncComplete_t ) SteamAPICall_t FileWriteAsync( const char *pchFile, const void *pvData, uint32 cubData ) { - PRINT_DEBUG("Steam_Remote_Storage::FileWriteAsync\n"); + PRINT_DEBUG("Steam_Remote_Storage::FileWriteAsync '%s' %p %u\n", pchFile, pvData, cubData); + std::lock_guard lock(global_mutex); if (!pchFile || cubData > k_unMaxCloudFileChunkSize || cubData == 0 || !pvData) { return k_uAPICallInvalid; } - std::lock_guard lock(global_mutex); bool success = local_storage->store_data(Local_Storage::remote_storage_folder, pchFile, (char* )pvData, cubData) == cubData; RemoteStorageFileWriteAsyncComplete_t data; data.m_eResult = success ? k_EResultOK : k_EResultFail; @@ -125,15 +163,15 @@ SteamAPICall_t FileWriteAsync( const char *pchFile, const void *pvData, uint32 c STEAM_CALL_RESULT( RemoteStorageFileReadAsyncComplete_t ) SteamAPICall_t FileReadAsync( const char *pchFile, uint32 nOffset, uint32 cubToRead ) { - PRINT_DEBUG("Steam_Remote_Storage::FileReadAsync\n"); - if (!pchFile) return k_uAPICallInvalid; + PRINT_DEBUG("Steam_Remote_Storage::FileReadAsync '%s' %u %u\n", pchFile, nOffset, cubToRead); std::lock_guard lock(global_mutex); + if (!pchFile) return k_uAPICallInvalid; unsigned int size = local_storage->file_size(Local_Storage::remote_storage_folder, pchFile); RemoteStorageFileReadAsyncComplete_t data; if (size <= nOffset) { - return k_uAPICallInvalid; + return k_uAPICallInvalid; } if ((size - nOffset) < cubToRead) cubToRead = size - nOffset; @@ -142,7 +180,7 @@ SteamAPICall_t FileReadAsync( const char *pchFile, uint32 nOffset, uint32 cubToR data.m_eResult = k_EResultOK; a_read.offset = data.m_nOffset = nOffset; a_read.api_call = data.m_hFileReadAsync = callback_results->reserveCallResult(); - a_read.to_read = data.m_cubRead = cubToRead; + a_read.to_read = data.m_cubRead = cubToRead; a_read.file_name = std::string(pchFile); a_read.size = size; @@ -151,11 +189,11 @@ SteamAPICall_t FileReadAsync( const char *pchFile, uint32 nOffset, uint32 cubToR return data.m_hFileReadAsync; } -bool FileReadAsyncComplete( SteamAPICall_t hReadCall, void *pvBuffer, uint32 cubToRead ) +bool FileReadAsyncComplete( SteamAPICall_t hReadCall, void *pvBuffer, uint32 cubToRead ) { PRINT_DEBUG("Steam_Remote_Storage::FileReadAsyncComplete\n"); - if (!pvBuffer) return false; std::lock_guard lock(global_mutex); + if (!pvBuffer) return false; auto a_read = std::find_if(async_reads.begin(), async_reads.end(), [&hReadCall](Async_Read const& item) { return item.api_call == hReadCall; }); if (async_reads.end() == a_read) @@ -178,15 +216,19 @@ bool FileReadAsyncComplete( SteamAPICall_t hReadCall, void *pvBuffer, uint32 cub } -bool FileForget( const char *pchFile ) +bool FileForget( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FileForget\n"); + std::lock_guard lock(global_mutex); + return true; } -bool FileDelete( const char *pchFile ) +bool FileDelete( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FileDelete\n"); + std::lock_guard lock(global_mutex); + return local_storage->file_delete(Local_Storage::remote_storage_folder, pchFile); } @@ -194,8 +236,8 @@ STEAM_CALL_RESULT( RemoteStorageFileShareResult_t ) SteamAPICall_t FileShare( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FileShare\n"); - if (!pchFile) return k_uAPICallInvalid; std::lock_guard lock(global_mutex); + if (!pchFile) return k_uAPICallInvalid; RemoteStorageFileShareResult_t data = {}; if (local_storage->file_exists(Local_Storage::remote_storage_folder, pchFile)) { data.m_eResult = k_EResultOK; @@ -209,9 +251,11 @@ SteamAPICall_t FileShare( const char *pchFile ) return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } -bool SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ) +bool SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ) { PRINT_DEBUG("Steam_Remote_Storage::SetSyncPlatforms\n"); + std::lock_guard lock(global_mutex); + return true; } @@ -268,33 +312,43 @@ bool FileWriteStreamCancel( UGCFileWriteStreamHandle_t writeHandle ) } // file information -bool FileExists( const char *pchFile ) +bool FileExists( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FileExists %s\n", pchFile); + std::lock_guard lock(global_mutex); + return local_storage->file_exists(Local_Storage::remote_storage_folder, pchFile); } -bool FilePersisted( const char *pchFile ) +bool FilePersisted( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FilePersisted\n"); + std::lock_guard lock(global_mutex); + return local_storage->file_exists(Local_Storage::remote_storage_folder, pchFile); } -int32 GetFileSize( const char *pchFile ) +int32 GetFileSize( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::GetFileSize %s\n", pchFile); + std::lock_guard lock(global_mutex); + return local_storage->file_size(Local_Storage::remote_storage_folder, pchFile); } -int64 GetFileTimestamp( const char *pchFile ) +int64 GetFileTimestamp( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::GetFileTimestamp\n"); + std::lock_guard lock(global_mutex); + return local_storage->file_timestamp(Local_Storage::remote_storage_folder, pchFile); } ERemoteStoragePlatform GetSyncPlatforms( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::GetSyncPlatforms\n"); + std::lock_guard lock(global_mutex); + return k_ERemoteStoragePlatformAll; } @@ -303,6 +357,8 @@ ERemoteStoragePlatform GetSyncPlatforms( const char *pchFile ) int32 GetFileCount() { PRINT_DEBUG("Steam_Remote_Storage::GetFileCount\n"); + std::lock_guard lock(global_mutex); + int32 num = local_storage->count_files(Local_Storage::remote_storage_folder); PRINT_DEBUG("Steam_Remote_Storage::File count: %i\n", num); return num; @@ -311,6 +367,8 @@ int32 GetFileCount() const char *GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) { PRINT_DEBUG("Steam_Remote_Storage::GetFileNameAndSize %i\n", iFile); + std::lock_guard lock(global_mutex); + static char output_filename[MAX_FILENAME_LENGTH]; if (local_storage->iterate_file(Local_Storage::remote_storage_folder, iFile, output_filename, pnFileSizeInBytes)) { PRINT_DEBUG("Steam_Remote_Storage::Name: |%s|, size: %i\n", output_filename, pnFileSizeInBytes ? *pnFileSizeInBytes : 0); @@ -325,6 +383,8 @@ const char *GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) bool GetQuota( uint64 *pnTotalBytes, uint64 *puAvailableBytes ) { PRINT_DEBUG("Steam_Remote_Storage::GetQuota\n"); + std::lock_guard lock(global_mutex); + uint64 quota = 2 << 26; *pnTotalBytes = quota; *puAvailableBytes = (quota); @@ -334,6 +394,8 @@ bool GetQuota( uint64 *pnTotalBytes, uint64 *puAvailableBytes ) bool GetQuota( int32 *pnTotalBytes, int32 *puAvailableBytes ) { PRINT_DEBUG("Steam_Remote_Storage::GetQuota\n"); + std::lock_guard lock(global_mutex); + uint64 quota = 2 << 26; *pnTotalBytes = quota; *puAvailableBytes = (quota); @@ -343,30 +405,40 @@ bool GetQuota( int32 *pnTotalBytes, int32 *puAvailableBytes ) bool IsCloudEnabledForAccount() { PRINT_DEBUG("Steam_Remote_Storage::IsCloudEnabledForAccount\n"); + std::lock_guard lock(global_mutex); + return true; } bool IsCloudEnabledForApp() { PRINT_DEBUG("Steam_Remote_Storage::IsCloudEnabledForApp\n"); + std::lock_guard lock(global_mutex); + return steam_cloud_enabled; } bool IsCloudEnabledThisApp() { PRINT_DEBUG("Steam_Remote_Storage::IsCloudEnabledThisApp\n"); + std::lock_guard lock(global_mutex); + return steam_cloud_enabled; } void SetCloudEnabledForApp( bool bEnabled ) { PRINT_DEBUG("Steam_Remote_Storage::SetCloudEnabledForApp\n"); + std::lock_guard lock(global_mutex); + steam_cloud_enabled = bEnabled; } bool SetCloudEnabledThisApp( bool bEnabled ) { PRINT_DEBUG("Steam_Remote_Storage::SetCloudEnabledThisApp\n"); + std::lock_guard lock(global_mutex); + steam_cloud_enabled = bEnabled; return true; } @@ -380,16 +452,46 @@ STEAM_CALL_RESULT( RemoteStorageDownloadUGCResult_t ) SteamAPICall_t UGCDownload( UGCHandle_t hContent, uint32 unPriority ) { PRINT_DEBUG("Steam_Remote_Storage::UGCDownload %llu\n", hContent); - RemoteStorageDownloadUGCResult_t data = {}; + std::lock_guard lock(global_mutex); + if (hContent == k_UGCHandleInvalid) return k_uAPICallInvalid; + + RemoteStorageDownloadUGCResult_t data{}; + data.m_hFile = hContent; + if (shared_files.count(hContent)) { data.m_eResult = k_EResultOK; - data.m_hFile = hContent; data.m_nAppID = settings->get_local_game_id().AppID(); - data.m_nSizeInBytes = local_storage->file_size(Local_Storage::remote_storage_folder, shared_files[hContent]); - shared_files[hContent].copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); data.m_ulSteamIDOwner = settings->get_local_steam_id().ConvertToUint64(); + data.m_nSizeInBytes = local_storage->file_size(Local_Storage::remote_storage_folder, shared_files[hContent]); + + shared_files[hContent].copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); + + downloaded_files[hContent].source = Downloaded_File::DownloadSource::AfterFileShare; downloaded_files[hContent].file = shared_files[hContent]; downloaded_files[hContent].total_size = data.m_nSizeInBytes; + } else if (auto query_res = ugc_bridge->get_ugc_query_result(hContent)) { + auto mod = settings->getMod(query_res.value().mod_id); + auto &mod_name = query_res.value().is_primary_file + ? mod.primaryFileName + : mod.previewFileName; + int32 mod_size = query_res.value().is_primary_file + ? mod.primaryFileSize + : mod.previewFileSize; + + data.m_eResult = k_EResultOK; + data.m_nAppID = settings->get_local_game_id().AppID(); + data.m_ulSteamIDOwner = mod.steamIDOwner; + data.m_nSizeInBytes = mod_size; + data.m_ulSteamIDOwner = mod.steamIDOwner; + + mod_name.copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); + + downloaded_files[hContent].source = Downloaded_File::DownloadSource::AfterSendQueryUGCRequest; + downloaded_files[hContent].file = mod_name; + downloaded_files[hContent].total_size = mod_size; + + downloaded_files[hContent].mod_query_info = query_res.value(); + } else { data.m_eResult = k_EResultFileNotFound; //TODO: not sure if this is the right result } @@ -407,23 +509,29 @@ SteamAPICall_t UGCDownload( UGCHandle_t hContent ) // Gets the amount of data downloaded so far for a piece of content. pnBytesExpected can be 0 if function returns false // or if the transfer hasn't started yet, so be careful to check for that before dividing to get a percentage -bool GetUGCDownloadProgress( UGCHandle_t hContent, int32 *pnBytesDownloaded, int32 *pnBytesExpected ) +bool GetUGCDownloadProgress( UGCHandle_t hContent, int32 *pnBytesDownloaded, int32 *pnBytesExpected ) { PRINT_DEBUG("Steam_Remote_Storage::GetUGCDownloadProgress\n"); + std::lock_guard lock(global_mutex); + return false; } -bool GetUGCDownloadProgress( UGCHandle_t hContent, uint32 *pnBytesDownloaded, uint32 *pnBytesExpected ) +bool GetUGCDownloadProgress( UGCHandle_t hContent, uint32 *pnBytesDownloaded, uint32 *pnBytesExpected ) { PRINT_DEBUG("Steam_Remote_Storage::GetUGCDownloadProgress old\n"); + std::lock_guard lock(global_mutex); + return false; } // Gets metadata for a file after it has been downloaded. This is the same metadata given in the RemoteStorageDownloadUGCResult_t call result -bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, STEAM_OUT_STRING() char **ppchName, int32 *pnFileSizeInBytes, STEAM_OUT_STRUCT() CSteamID *pSteamIDOwner ) +bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, STEAM_OUT_STRING() char **ppchName, int32 *pnFileSizeInBytes, STEAM_OUT_STRUCT() CSteamID *pSteamIDOwner ) { PRINT_DEBUG("Steam_Remote_Storage::GetUGCDetails\n"); + std::lock_guard lock(global_mutex); + return false; } @@ -434,46 +542,102 @@ bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, STEAM_OUT_STRING() c // enough memory for each chunk). Once the last byte is read, the file is implicitly closed and further calls to UGCRead will fail // unless UGCDownload is called again. // For especially large files (anything over 100MB) it is a requirement that the file is read in chunks. -int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction ) +int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset, EUGCReadAction eAction ) { - PRINT_DEBUG("Steam_Remote_Storage::UGCRead\n"); - if (!downloaded_files.count(hContent) || cubDataToRead < 0) { + PRINT_DEBUG("Steam_Remote_Storage::UGCRead %llu, %p, %i, %u, %i\n", hContent, pvData, cubDataToRead, cOffset, eAction); + std::lock_guard lock(global_mutex); + + if (hContent == k_UGCHandleInvalid || !downloaded_files.count(hContent) || cubDataToRead < 0) { return -1; //TODO: is this the right return value? } + int read_data = -1; + uint64 total_size = 0; Downloaded_File f = downloaded_files[hContent]; - int read_data = local_storage->get_data(Local_Storage::remote_storage_folder, f.file, (char* )pvData, cubDataToRead, cOffset); - if (eAction == k_EUGCRead_Close || (eAction == k_EUGCRead_ContinueReadingUntilFinished && (read_data < cubDataToRead || (cOffset + cubDataToRead) >= f.total_size))) { + switch (f.source) + { + case Downloaded_File::DownloadSource::AfterFileShare: + { + PRINT_DEBUG(" Steam_Remote_Storage::UGCRead source = AfterFileShare '%s'\n", f.file.c_str()); + read_data = local_storage->get_data(Local_Storage::remote_storage_folder, f.file, (char *)pvData, cubDataToRead, cOffset); + total_size = f.total_size; + } + break; + + case Downloaded_File::DownloadSource::AfterSendQueryUGCRequest: + case Downloaded_File::DownloadSource::AfterUGCDownloadToLocation: + { + PRINT_DEBUG(" Steam_Remote_Storage::UGCRead source = AfterSendQueryUGCRequest || AfterUGCDownloadToLocation [%i]\n", (int)f.source); + auto mod = settings->getMod(f.mod_query_info.mod_id); + auto &mod_name = f.mod_query_info.is_primary_file + ? mod.primaryFileName + : mod.previewFileName; + + std::string mod_fullpath{}; + if (f.source == Downloaded_File::DownloadSource::AfterSendQueryUGCRequest) { + std::string mod_base_path = f.mod_query_info.is_primary_file + ? mod.path + : Local_Storage::get_game_settings_path() + "mod_images" + PATH_SEPARATOR + std::to_string(mod.id); + + mod_fullpath = common_helpers::to_absolute(mod_name, mod_base_path); + } else { // Downloaded_File::DownloadSource::AfterUGCDownloadToLocation + mod_fullpath = f.download_to_location_fullpath; + } + + read_data = Local_Storage::get_file_data(mod_fullpath, (char *)pvData, cubDataToRead, cOffset); + PRINT_DEBUG(" Steam_Remote_Storage::UGCRead mod file '%s' [%i]\n", mod_fullpath.c_str(), read_data); + total_size = f.total_size; + } + break; + + default: + PRINT_DEBUG(" Steam_Remote_Storage::UGCRead unhandled download source %i\n", (int)f.source); + return -1; //TODO: is this the right return value? + break; + } + + PRINT_DEBUG(" Steam_Remote_Storage::UGCRead read bytes = %i\n", read_data); + if (read_data < 0) return -1; //TODO: is this the right return value? + + if (eAction == k_EUGCRead_Close || + (eAction == k_EUGCRead_ContinueReadingUntilFinished && (read_data < cubDataToRead || (cOffset + cubDataToRead) >= total_size))) { downloaded_files.erase(hContent); } - PRINT_DEBUG("Read %i\n", read_data); return read_data; } -int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead ) +int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead ) { PRINT_DEBUG("Steam_Remote_Storage::UGCRead old\n"); + std::lock_guard lock(global_mutex); + return UGCRead( hContent, pvData, cubDataToRead, 0); } -int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset) +int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset) { PRINT_DEBUG("Steam_Remote_Storage::UGCRead old2\n"); + std::lock_guard lock(global_mutex); + return UGCRead(hContent, pvData, cubDataToRead, cOffset, k_EUGCRead_ContinueReadingUntilFinished); } // Functions to iterate through UGC that has finished downloading but has not yet been read via UGCRead() -int32 GetCachedUGCCount() +int32 GetCachedUGCCount() { PRINT_DEBUG("Steam_Remote_Storage::GetCachedUGCCount\n"); + std::lock_guard lock(global_mutex); + return 0; } UGCHandle_t GetCachedUGCHandle( int32 iCachedContent ) { PRINT_DEBUG("Steam_Remote_Storage::GetCachedUGCHandle\n"); + std::lock_guard lock(global_mutex); + return k_UGCHandleInvalid; } @@ -486,12 +650,16 @@ UGCHandle_t GetCachedUGCHandle( int32 iCachedContent ) void GetFileListFromServer() { PRINT_DEBUG("Steam_Remote_Storage::GetFileListFromServer\n"); + std::lock_guard lock(global_mutex); + } // Indicate this file should be downloaded in the next sync bool FileFetch( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FileFetch\n"); + std::lock_guard lock(global_mutex); + return true; } @@ -499,6 +667,8 @@ bool FileFetch( const char *pchFile ) bool FilePersist( const char *pchFile ) { PRINT_DEBUG("Steam_Remote_Storage::FilePersist\n"); + std::lock_guard lock(global_mutex); + return true; } @@ -506,94 +676,124 @@ bool FilePersist( const char *pchFile ) bool SynchronizeToClient() { PRINT_DEBUG("Steam_Remote_Storage::SynchronizeToClient\n"); + std::lock_guard lock(global_mutex); + } // Upload any requested files to the Cloud - results in a RemoteStorageAppSyncedServer_t callback bool SynchronizeToServer() { PRINT_DEBUG("Steam_Remote_Storage::SynchronizeToServer\n"); + std::lock_guard lock(global_mutex); + } // Reset any fetch/persist/etc requests bool ResetFileRequestState() { PRINT_DEBUG("Steam_Remote_Storage::ResetFileRequestState\n"); + std::lock_guard lock(global_mutex); + } #endif // publishing UGC STEAM_CALL_RESULT( RemoteStoragePublishFileProgress_t ) -SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags, EWorkshopFileType eWorkshopFileType ) +SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags, EWorkshopFileType eWorkshopFileType ) { - PRINT_DEBUG("Steam_Remote_Storage::PublishWorkshopFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::PublishWorkshopFile\n"); + std::lock_guard lock(global_mutex); + return 0; } PublishedFileUpdateHandle_t CreatePublishedFileUpdateRequest( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::CreatePublishedFileUpdateRequest\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::CreatePublishedFileUpdateRequest\n"); + std::lock_guard lock(global_mutex); + return 0; } bool UpdatePublishedFileFile( PublishedFileUpdateHandle_t updateHandle, const char *pchFile ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFileFile\n"); + std::lock_guard lock(global_mutex); + return false; } -SteamAPICall_t PublishFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) +SteamAPICall_t PublishFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) { - PRINT_DEBUG("Steam_Remote_Storage::PublishFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::PublishFile\n"); + std::lock_guard lock(global_mutex); + return 0; } -SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, SteamParamStringArray_t *pTags ) +SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, SteamParamStringArray_t *pTags ) { - PRINT_DEBUG("Steam_Remote_Storage::PublishWorkshopFile old\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::PublishWorkshopFile old\n"); + std::lock_guard lock(global_mutex); + return 0; } -SteamAPICall_t UpdatePublishedFile( RemoteStorageUpdatePublishedFileRequest_t updatePublishedFileRequest ) +SteamAPICall_t UpdatePublishedFile( RemoteStorageUpdatePublishedFileRequest_t updatePublishedFileRequest ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFile\n"); + std::lock_guard lock(global_mutex); + return 0; } bool UpdatePublishedFilePreviewFile( PublishedFileUpdateHandle_t updateHandle, const char *pchPreviewFile ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFilePreviewFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFilePreviewFile\n"); + std::lock_guard lock(global_mutex); + return false; } bool UpdatePublishedFileTitle( PublishedFileUpdateHandle_t updateHandle, const char *pchTitle ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileTitle\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFileTitle\n"); + std::lock_guard lock(global_mutex); + return false; } bool UpdatePublishedFileDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchDescription ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileDescription\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFileDescription\n"); + std::lock_guard lock(global_mutex); + return false; } bool UpdatePublishedFileVisibility( PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileVisibility\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFileVisibility\n"); + std::lock_guard lock(global_mutex); + return false; } bool UpdatePublishedFileTags( PublishedFileUpdateHandle_t updateHandle, SteamParamStringArray_t *pTags ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileTags\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdatePublishedFileTags\n"); + std::lock_guard lock(global_mutex); + return false; } STEAM_CALL_RESULT( RemoteStorageUpdatePublishedFileResult_t ) -SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHandle ) +SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHandle ) { - PRINT_DEBUG("Steam_Remote_Storage::CommitPublishedFileUpdate\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::CommitPublishedFileUpdate %llu\n", updateHandle); + std::lock_guard lock(global_mutex); + return 0; } @@ -601,11 +801,47 @@ SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHand // cached data may be returned, depending on how long ago it was cached. A value of 0 will force a refresh. // A value of k_WorkshopForceLoadPublishedFileDetailsFromCache will use cached data if it exists, no matter how old it is. STEAM_CALL_RESULT( RemoteStorageGetPublishedFileDetailsResult_t ) -SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ) +SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ) { - PRINT_DEBUG("Steam_Remote_Storage::GetPublishedFileDetails %llu\n", unPublishedFileId); + PRINT_DEBUG("TODO Steam_Remote_Storage::GetPublishedFileDetails %llu %u\n", unPublishedFileId, unMaxSecondsOld); //TODO: check what this function really returns - return 0; + // TODO is this implementation correct? + std::lock_guard lock(global_mutex); + + RemoteStorageGetPublishedFileDetailsResult_t data{}; + data.m_nPublishedFileId = unPublishedFileId; + + if (settings->isModInstalled(unPublishedFileId)) { + auto mod = settings->getMod(unPublishedFileId); + data.m_eResult = EResult::k_EResultOK; + data.m_bAcceptedForUse = mod.acceptedForUse; + data.m_bBanned = mod.banned; + data.m_bTagsTruncated = mod.tagsTruncated; + data.m_eFileType = mod.fileType; + data.m_eVisibility = mod.visibility; + data.m_hFile = mod.handleFile; + data.m_hPreviewFile = mod.handlePreviewFile; + data.m_nConsumerAppID = settings->get_local_game_id().AppID(); // TODO is this correct? + data.m_nCreatorAppID = settings->get_local_game_id().AppID(); // TODO is this correct? + data.m_nFileSize = mod.primaryFileSize; + data.m_nPreviewFileSize = mod.previewFileSize; + data.m_rtimeCreated = mod.timeCreated; + data.m_rtimeUpdated = mod.timeUpdated; + data.m_ulSteamIDOwner = mod.steamIDOwner; + + mod.primaryFileName.copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); + mod.description.copy(data.m_rgchDescription, sizeof(data.m_rgchDescription) - 1); + mod.tags.copy(data.m_rgchTags, sizeof(data.m_rgchTags) - 1); + mod.title.copy(data.m_rgchTitle, sizeof(data.m_rgchTitle) - 1); + mod.workshopItemURL.copy(data.m_rgchURL, sizeof(data.m_rgchURL) - 1); + + } else { + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); + + // return 0; /* std::lock_guard lock(global_mutex); RemoteStorageGetPublishedFileDetailsResult_t data = {}; @@ -616,106 +852,221 @@ SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uin } STEAM_CALL_RESULT( RemoteStorageGetPublishedFileDetailsResult_t ) -SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::GetPublishedFileDetails old\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::GetPublishedFileDetails old\n"); return GetPublishedFileDetails(unPublishedFileId, 0); } STEAM_CALL_RESULT( RemoteStorageDeletePublishedFileResult_t ) -SteamAPICall_t DeletePublishedFile( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t DeletePublishedFile( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::DeletePublishedFile\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::DeletePublishedFile %llu\n", unPublishedFileId); + std::lock_guard lock(global_mutex); + return 0; } // enumerate the files that the current user published with this app STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) -SteamAPICall_t EnumerateUserPublishedFiles( uint32 unStartIndex ) +SteamAPICall_t EnumerateUserPublishedFiles( uint32 unStartIndex ) { - PRINT_DEBUG("Steam_Remote_Storage::EnumerateUserPublishedFiles\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::EnumerateUserPublishedFiles %u\n", unStartIndex); + // TODO is this implementation correct? std::lock_guard lock(global_mutex); - RemoteStorageEnumerateUserPublishedFilesResult_t data; - data.m_eResult = k_EResultOK; - data.m_nResultsReturned = 0; - data.m_nTotalResultCount = 0; - //data.m_rgPublishedFileId; + RemoteStorageEnumerateUserPublishedFilesResult_t data{}; + + // collect all published mods by this user + auto mods = settings->modSet(); + std::vector user_pubed{}; + for (auto& id : mods) { + auto mod = settings->getMod(id); + if (mod.steamIDOwner == settings->get_local_steam_id().ConvertToUint64()) { + user_pubed.push_back(id); + } + } + uint32_t modCount = (uint32_t)user_pubed.size(); + + if (unStartIndex >= modCount) { + data.m_eResult = EResult::k_EResultInvalidParam; // TODO is this correct? + } else { + data.m_eResult = EResult::k_EResultOK; + data.m_nTotalResultCount = modCount - unStartIndex; // total count starting from this index + std::vector::iterator i = user_pubed.begin(); + std::advance(i, unStartIndex); + uint32_t iterated = 0; + for (; i != user_pubed.end() && iterated < k_unEnumeratePublishedFilesMaxResults; i++) { + PublishedFileId_t modId = *i; + auto mod = settings->getMod(modId); + data.m_rgPublishedFileId[iterated] = modId; + iterated++; + PRINT_DEBUG(" EnumerateUserPublishedFiles file %llu\n", modId); + } + data.m_nResultsReturned = iterated; + } + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t ) -SteamAPICall_t SubscribePublishedFile( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t SubscribePublishedFile( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::SubscribePublishedFile\n"); - return 0; + PRINT_DEBUG("TODO Steam_Remote_Storage::SubscribePublishedFile %llu\n", unPublishedFileId); + std::lock_guard lock(global_mutex); + // TODO is this implementation correct? + RemoteStorageSubscribePublishedFileResult_t data{}; + data.m_nPublishedFileId = unPublishedFileId; + + if (settings->isModInstalled(unPublishedFileId)) { + data.m_eResult = EResult::k_EResultOK; + subscribed.insert(unPublishedFileId); + } else { + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageEnumerateUserSubscribedFilesResult_t ) -SteamAPICall_t EnumerateUserSubscribedFiles( uint32 unStartIndex ) +SteamAPICall_t EnumerateUserSubscribedFiles( uint32 unStartIndex ) { - PRINT_DEBUG("Steam_Remote_Storage::EnumerateUserSubscribedFiles\n"); + // https://partner.steamgames.com/doc/api/ISteamRemoteStorage + PRINT_DEBUG("Steam_Remote_Storage::EnumerateUserSubscribedFiles %u\n", unStartIndex); std::lock_guard lock(global_mutex); // Get ready for a working but bad implementation - Detanup01 - RemoteStorageEnumerateUserSubscribedFilesResult_t data; - data.m_eResult = k_EResultOK; - auto mods = settings->modSet(); - uint32_t modCount = mods.size(); - data.m_nResultsReturned = modCount; - data.m_nTotalResultCount = modCount; - data.m_rgPublishedFileId; - data.m_rgRTimeSubscribed; - uint32_t iterated = 0; - for (std::set::iterator i = mods.begin(); i != mods.end(); i++) { - PublishedFileId_t modId = *i; - auto mod = settings->getMod(modId); - uint32 time = mod.timeAddedToUserList; //this can be changed, default is 1554997000 - data.m_rgPublishedFileId[iterated] = modId; - data.m_rgRTimeSubscribed[iterated] = time; - iterated++; + RemoteStorageEnumerateUserSubscribedFilesResult_t data{}; + uint32_t modCount = (uint32_t)subscribed.size(); + if (unStartIndex >= modCount) { + data.m_eResult = EResult::k_EResultInvalidParam; // is this correct? + } else { + data.m_eResult = k_EResultOK; + data.m_nTotalResultCount = modCount - unStartIndex; // total amount starting from given index + std::set::iterator i = subscribed.begin(); + std::advance(i, unStartIndex); + uint32_t iterated = 0; + for (; i != subscribed.end() && iterated < k_unEnumeratePublishedFilesMaxResults; i++) { + PublishedFileId_t modId = *i; + auto mod = settings->getMod(modId); + uint32 time = mod.timeAddedToUserList; //this can be changed, default is 1554997000 + data.m_rgPublishedFileId[iterated] = modId; + data.m_rgRTimeSubscribed[iterated] = time; + iterated++; + PRINT_DEBUG(" EnumerateUserSubscribedFiles file %llu\n", modId); + } + data.m_nResultsReturned = iterated; } + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t ) -SteamAPICall_t UnsubscribePublishedFile( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t UnsubscribePublishedFile( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::UnsubscribePublishedFile\n"); - return 0; + PRINT_DEBUG("TODO Steam_Remote_Storage::UnsubscribePublishedFile %llu\n", unPublishedFileId); + std::lock_guard lock(global_mutex); + // TODO is this implementation correct? + RemoteStorageUnsubscribePublishedFileResult_t data{}; + data.m_nPublishedFileId = unPublishedFileId; + // TODO is this correct? + if (subscribed.count(unPublishedFileId)) { + data.m_eResult = k_EResultOK; + subscribed.erase(unPublishedFileId); + } else { + data.m_eResult = k_EResultFail; + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } bool UpdatePublishedFileSetChangeDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchChangeDescription ) { PRINT_DEBUG("Steam_Remote_Storage::UpdatePublishedFileSetChangeDescription\n"); + std::lock_guard lock(global_mutex); + return false; } STEAM_CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) -SteamAPICall_t GetPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t GetPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) { - PRINT_DEBUG("Steam_Remote_Storage::GetPublishedItemVoteDetails\n"); - return 0; + PRINT_DEBUG("TODO Steam_Remote_Storage::GetPublishedItemVoteDetails\n"); + // TODO s this implementation correct? + std::lock_guard lock(global_mutex); + RemoteStorageGetPublishedItemVoteDetailsResult_t data{}; + data.m_unPublishedFileId = unPublishedFileId; + if (settings->isModInstalled(unPublishedFileId)) { + data.m_eResult = EResult::k_EResultOK; + auto mod = settings->getMod(unPublishedFileId); + data.m_fScore = mod.score; + data.m_nReports = 0; // TODO is this ok? + data.m_nVotesAgainst = mod.votesDown; + data.m_nVotesFor = mod.votesUp; + } else { + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageUpdateUserPublishedItemVoteResult_t ) -SteamAPICall_t UpdateUserPublishedItemVote( PublishedFileId_t unPublishedFileId, bool bVoteUp ) +SteamAPICall_t UpdateUserPublishedItemVote( PublishedFileId_t unPublishedFileId, bool bVoteUp ) { - PRINT_DEBUG("Steam_Remote_Storage::UpdateUserPublishedItemVote\n"); - return 0; + // I assume this function is supposed to increase the upvotes of the mod, + // given that the mod owner is the current user + PRINT_DEBUG("TODO Steam_Remote_Storage::UpdateUserPublishedItemVote\n"); + // TODO is this implementation correct? + std::lock_guard lock(global_mutex); + RemoteStorageUpdateUserPublishedItemVoteResult_t data{}; + data.m_nPublishedFileId = unPublishedFileId; + if (settings->isModInstalled(unPublishedFileId)) { + auto mod = settings->getMod(unPublishedFileId); + if (mod.steamIDOwner == settings->get_local_steam_id().ConvertToUint64()) { + data.m_eResult = EResult::k_EResultOK; + } else { // not published by this user + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + } else { // mod not installed + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t ) -SteamAPICall_t GetUserPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) +SteamAPICall_t GetUserPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) { PRINT_DEBUG("Steam_Remote_Storage::GetUserPublishedItemVoteDetails\n"); + + // TODO is this implementation correct? + std::lock_guard lock(global_mutex); + RemoteStorageGetPublishedItemVoteDetailsResult_t data{}; + data.m_unPublishedFileId = unPublishedFileId; + if (settings->isModInstalled(unPublishedFileId)) { + auto mod = settings->getMod(unPublishedFileId); + if (mod.steamIDOwner == settings->get_local_steam_id().ConvertToUint64()) { + data.m_eResult = EResult::k_EResultOK; + data.m_fScore = mod.score; + data.m_nReports = 0; // TODO is this ok? + data.m_nVotesAgainst = mod.votesDown; + data.m_nVotesFor = mod.votesUp; + } else { // not published by this user + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + } else { // mod not installed + data.m_eResult = EResult::k_EResultFail; // TODO is this correct? + } + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); + return 0; } STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) -SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) +SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) { PRINT_DEBUG("Steam_Remote_Storage::EnumerateUserSharedWorkshopFiles\n"); std::lock_guard lock(global_mutex); - RemoteStorageEnumerateUserPublishedFilesResult_t data; + RemoteStorageEnumerateUserPublishedFilesResult_t data{}; data.m_eResult = k_EResultOK; data.m_nResultsReturned = 0; data.m_nTotalResultCount = 0; @@ -724,70 +1075,107 @@ SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStar } STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t ) -SteamAPICall_t EnumerateUserSharedWorkshopFiles(AppId_t nAppId, CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) +SteamAPICall_t EnumerateUserSharedWorkshopFiles(AppId_t nAppId, CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) { PRINT_DEBUG("Steam_Remote_Storage::EnumerateUserSharedWorkshopFiles old\n"); return EnumerateUserSharedWorkshopFiles(steamId, unStartIndex, pRequiredTags, pExcludedTags); } STEAM_CALL_RESULT( RemoteStoragePublishFileProgress_t ) -SteamAPICall_t PublishVideo( EWorkshopVideoProvider eVideoProvider, const char *pchVideoAccount, const char *pchVideoIdentifier, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) +SteamAPICall_t PublishVideo( EWorkshopVideoProvider eVideoProvider, const char *pchVideoAccount, const char *pchVideoIdentifier, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) { - PRINT_DEBUG("Steam_Remote_Storage::PublishVideo\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::PublishVideo\n"); + std::lock_guard lock(global_mutex); return 0; } STEAM_CALL_RESULT( RemoteStoragePublishFileProgress_t ) -SteamAPICall_t PublishVideo(const char *pchFileName, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) +SteamAPICall_t PublishVideo(const char *pchFileName, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) { - PRINT_DEBUG("Steam_Remote_Storage::PublishVideo old\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::PublishVideo old\n"); + std::lock_guard lock(global_mutex); return 0; } STEAM_CALL_RESULT( RemoteStorageSetUserPublishedFileActionResult_t ) -SteamAPICall_t SetUserPublishedFileAction( PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ) +SteamAPICall_t SetUserPublishedFileAction( PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ) { - PRINT_DEBUG("Steam_Remote_Storage::SetUserPublishedFileAction\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::SetUserPublishedFileAction\n"); + std::lock_guard lock(global_mutex); return 0; } STEAM_CALL_RESULT( RemoteStorageEnumeratePublishedFilesByUserActionResult_t ) -SteamAPICall_t EnumeratePublishedFilesByUserAction( EWorkshopFileAction eAction, uint32 unStartIndex ) +SteamAPICall_t EnumeratePublishedFilesByUserAction( EWorkshopFileAction eAction, uint32 unStartIndex ) { - PRINT_DEBUG("Steam_Remote_Storage::EnumeratePublishedFilesByUserAction\n"); + PRINT_DEBUG("TODO Steam_Remote_Storage::EnumeratePublishedFilesByUserAction\n"); + std::lock_guard lock(global_mutex); return 0; } // this method enumerates the public view of workshop files STEAM_CALL_RESULT( RemoteStorageEnumerateWorkshopFilesResult_t ) -SteamAPICall_t EnumeratePublishedWorkshopFiles( EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t *pTags, SteamParamStringArray_t *pUserTags ) +SteamAPICall_t EnumeratePublishedWorkshopFiles( EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t *pTags, SteamParamStringArray_t *pUserTags ) { - PRINT_DEBUG("Steam_Remote_Storage::EnumeratePublishedWorkshopFiles\n"); - return 0; + PRINT_DEBUG("TODO Steam_Remote_Storage::EnumeratePublishedWorkshopFiles\n"); + // TODO is this implementation correct? + std::lock_guard lock(global_mutex); + RemoteStorageEnumerateWorkshopFilesResult_t data{}; + data.m_eResult = EResult::k_EResultOK; + data.m_nResultsReturned = 0; + data.m_nTotalResultCount = 0; + + return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } STEAM_CALL_RESULT( RemoteStorageDownloadUGCResult_t ) SteamAPICall_t UGCDownloadToLocation( UGCHandle_t hContent, const char *pchLocation, uint32 unPriority ) { - PRINT_DEBUG("Steam_Remote_Storage::UGCDownloadToLocation %llu %s\n", hContent, pchLocation); + PRINT_DEBUG("TODO Steam_Remote_Storage::UGCDownloadToLocation %llu %s\n", hContent, pchLocation); // TODO is this implementation correct? std::lock_guard lock(global_mutex); + if (hContent == k_UGCHandleInvalid) return k_uAPICallInvalid; + RemoteStorageDownloadUGCResult_t data{}; data.m_hFile = hContent; data.m_nAppID = settings->get_local_game_id().AppID(); - data.m_ulSteamIDOwner = settings->get_local_steam_id().ConvertToUint64(); if (!pchLocation || !pchLocation[0]) { data.m_eResult = EResult::k_EResultInvalidParam; //TODO: not sure if this is the right result data.m_nSizeInBytes = 0; - data.m_pchFileName[0] = '\0'; - } else if (shared_files.count(hContent)) { + } else if (auto query_res = ugc_bridge->get_ugc_query_result(hContent)) { + auto mod = settings->getMod(query_res.value().mod_id); + auto &mod_name = query_res.value().is_primary_file + ? mod.primaryFileName + : mod.previewFileName; + std::string mod_base_path = query_res.value().is_primary_file + ? mod.path + : Local_Storage::get_game_settings_path() + "mod_images" + PATH_SEPARATOR + std::to_string(mod.id); + int32 mod_size = query_res.value().is_primary_file + ? mod.primaryFileSize + : mod.previewFileSize; + data.m_eResult = k_EResultOK; - data.m_nSizeInBytes = local_storage->file_size(Local_Storage::remote_storage_folder, shared_files[hContent]); - shared_files[hContent].copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); - downloaded_files[hContent].file = shared_files[hContent]; - downloaded_files[hContent].total_size = data.m_nSizeInBytes; + data.m_nAppID = settings->get_local_game_id().AppID(); + data.m_ulSteamIDOwner = mod.steamIDOwner; + data.m_nSizeInBytes = mod_size; + data.m_ulSteamIDOwner = mod.steamIDOwner; + + mod_name.copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1); + + // copy the file + const auto mod_fullpath = common_helpers::to_absolute(mod_name, mod_base_path); + copy_file(mod_fullpath, pchLocation); + + // TODO not sure about this though + downloaded_files[hContent].source = Downloaded_File::DownloadSource::AfterUGCDownloadToLocation; + downloaded_files[hContent].file = mod_name; + downloaded_files[hContent].total_size = mod_size; + + downloaded_files[hContent].mod_query_info = query_res.value(); + downloaded_files[hContent].download_to_location_fullpath = pchLocation; + } else { data.m_eResult = k_EResultFileNotFound; //TODO: not sure if this is the right result } @@ -798,13 +1186,17 @@ SteamAPICall_t UGCDownloadToLocation( UGCHandle_t hContent, const char *pchLocat // Cloud dynamic state change notification int32 GetLocalFileChangeCount() { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("GetLocalFileChangeCount\n"); + std::lock_guard lock(global_mutex); + return 0; } const char *GetLocalFileChange( int iFile, ERemoteStorageLocalFileChange *pEChangeType, ERemoteStorageFilePathType *pEFilePathType ) { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("GetLocalFileChange\n"); + std::lock_guard lock(global_mutex); + return ""; } @@ -812,13 +1204,17 @@ const char *GetLocalFileChange( int iFile, ERemoteStorageLocalFileChange *pEChan // operations - for example, writing a game save that requires updating two files. bool BeginFileWriteBatch() { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("BeginFileWriteBatch\n"); + std::lock_guard lock(global_mutex); + return true; } bool EndFileWriteBatch() { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("EndFileWriteBatch\n"); + std::lock_guard lock(global_mutex); + return true; } diff --git a/dll/dll/steam_ugc.h b/dll/dll/steam_ugc.h index 07bb18a1..312bbd82 100644 --- a/dll/dll/steam_ugc.h +++ b/dll/dll/steam_ugc.h @@ -45,72 +45,81 @@ public ISteamUGC017, public ISteamUGC { class Settings *settings; + Ugc_Remote_Storage_Bridge *ugc_bridge; class SteamCallResults *callback_results; class SteamCallBacks *callbacks; std::set subscribed; - UGCQueryHandle_t handle = 0; - //temporary (or forever) thing - UGCHandle_t ugc_file_handle = 0; //file - UGCHandle_t ugc_prev_handle = 0; //Preview + UGCQueryHandle_t handle = 50; // just makes debugging easier, any initial val is fine, even 1 std::vector ugc_queries; -UGCQueryHandle_t new_ugc_query(bool return_all_subscribed = false, std::set return_only = std::set()) +UGCQueryHandle_t new_ugc_query( + bool return_all_subscribed = false, + std::set return_only = std::set()) { std::lock_guard lock(global_mutex); - struct UGC_query query; + ++handle; + if ((handle == 0) || (handle == k_UGCQueryHandleInvalid)) handle = 50; + + struct UGC_query query{}; query.handle = handle; query.return_all_subscribed = return_all_subscribed; query.return_only = return_only; ugc_queries.push_back(query); + PRINT_DEBUG("Steam_UGC::new_ugc_query handle = %llu\n", query.handle); return query.handle; } void set_details(PublishedFileId_t id, SteamUGCDetails_t *pDetails) { if (pDetails) { + pDetails->m_nPublishedFileId = id; + if (settings->isModInstalled(id)) { - ++ugc_file_handle; - ugc_prev_handle += ugc_file_handle + 1; + PRINT_DEBUG(" mod is installed, setting details\n"); + auto mod = settings->getMod(id); pDetails->m_eResult = k_EResultOK; - pDetails->m_nPublishedFileId = id; - pDetails->m_nCreatorAppID = settings->get_local_game_id().AppID(); + pDetails->m_bAcceptedForUse = mod.acceptedForUse; + pDetails->m_bBanned = mod.banned; + pDetails->m_bTagsTruncated = mod.tagsTruncated; + pDetails->m_eFileType = mod.fileType; + pDetails->m_eVisibility = mod.visibility; + pDetails->m_hFile = mod.handleFile; + pDetails->m_hPreviewFile = mod.handlePreviewFile; pDetails->m_nConsumerAppID = settings->get_local_game_id().AppID(); - snprintf(pDetails->m_rgchTitle, k_cchPublishedDocumentTitleMax, "%s", settings->getMod(id).title.c_str()); - pDetails->m_eFileType = settings->getMod(id).fileType; - snprintf(pDetails->m_rgchDescription, k_cchPublishedDocumentDescriptionMax, "%s", settings->getMod(id).description.c_str()); + pDetails->m_nCreatorAppID = settings->get_local_game_id().AppID(); + pDetails->m_nFileSize = mod.primaryFileSize; + pDetails->m_nPreviewFileSize = mod.previewFileSize; + pDetails->m_rtimeCreated = mod.timeCreated; + pDetails->m_rtimeUpdated = mod.timeUpdated; pDetails->m_ulSteamIDOwner = settings->get_local_steam_id().ConvertToUint64(); - pDetails->m_rtimeCreated = settings->getMod(id).timeCreated; - pDetails->m_rtimeUpdated = settings->getMod(id).timeUpdated; - pDetails->m_rtimeAddedToUserList = settings->getMod(id).timeAddedToUserList; - pDetails->m_eVisibility = settings->getMod(id).visibility; - pDetails->m_bBanned = settings->getMod(id).banned; - pDetails->m_bAcceptedForUse = settings->getMod(id).acceptedForUse; - pDetails->m_bTagsTruncated = settings->getMod(id).tagsTruncated; - snprintf(pDetails->m_rgchTags, k_cchTagListMax, "%s", settings->getMod(id).tags.c_str()); - snprintf(pDetails->m_pchFileName, k_cchFilenameMax, "%s", settings->getMod(id).primaryFileName.c_str()); - pDetails->m_nFileSize = settings->getMod(id).primaryFileSize; - pDetails->m_nPreviewFileSize = settings->getMod(id).previewFileSize; - snprintf(pDetails->m_rgchURL, k_cchPublishedFileURLMax, "%s", settings->getMod(id).workshopItemURL.c_str()); - pDetails->m_unVotesUp = settings->getMod(id).votesUp; - pDetails->m_unVotesDown = settings->getMod(id).votesDown; - pDetails->m_flScore = settings->getMod(id).score; - // implement something like: - pDetails->m_hFile = ugc_file_handle; - pDetails->m_hPreviewFile = ugc_prev_handle; - //pDetails->m_unNumChildren = settings->getMod(id).numChildren; + + pDetails->m_rtimeAddedToUserList = mod.timeAddedToUserList; + pDetails->m_unVotesUp = mod.votesUp; + pDetails->m_unVotesDown = mod.votesDown; + pDetails->m_flScore = mod.score; + + mod.primaryFileName.copy(pDetails->m_pchFileName, sizeof(pDetails->m_pchFileName) - 1); + mod.description.copy(pDetails->m_rgchDescription, sizeof(pDetails->m_rgchDescription) - 1); + mod.tags.copy(pDetails->m_rgchTags, sizeof(pDetails->m_rgchTags) - 1); + mod.title.copy(pDetails->m_rgchTitle, sizeof(pDetails->m_rgchTitle) - 1); + mod.workshopItemURL.copy(pDetails->m_rgchURL, sizeof(pDetails->m_rgchURL) - 1); + + // TODO should we enable this? + // pDetails->m_unNumChildren = mod.numChildren; } else { - pDetails->m_nPublishedFileId = id; + PRINT_DEBUG(" mod isn't installed, returning failure\n"); pDetails->m_eResult = k_EResultFail; } } } public: -Steam_UGC(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks) +Steam_UGC(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class SteamCallResults *callback_results, class SteamCallBacks *callbacks) { this->settings = settings; + this->ugc_bridge = ugc_bridge; this->callbacks = callbacks; this->callback_results = callback_results; @@ -156,11 +165,13 @@ UGCQueryHandle_t CreateQueryUGCDetailsRequest( PublishedFileId_t *pvecPublishedF STEAM_CALL_RESULT( SteamUGCQueryCompleted_t ) SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) { - PRINT_DEBUG("Steam_UGC::SendQueryUGCRequest\n"); + PRINT_DEBUG("Steam_UGC::SendQueryUGCRequest %llu\n", handle); std::lock_guard lock(global_mutex); + if (handle == k_UGCQueryHandleInvalid) return k_uAPICallInvalid; + auto request = std::find_if(ugc_queries.begin(), ugc_queries.end(), [&handle](struct UGC_query const& item) { return item.handle == handle; }); if (ugc_queries.end() == request) - return 0; + return k_uAPICallInvalid; if (request->return_all_subscribed) { request->results = subscribed; @@ -174,6 +185,14 @@ SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) } } + // send these handles to stea_remote_storage since the game will later + // call Steam_Remote_Storage::UGCDownload() with these files handles (primary + preview) + for (auto fileid : request->results) { + auto mod = settings->getMod(fileid); + ugc_bridge->add_ugc_query_result(mod.handleFile, fileid, true); + ugc_bridge->add_ugc_query_result(mod.handlePreviewFile, fileid, false); + } + SteamUGCQueryCompleted_t data = {}; data.m_handle = handle; data.m_eResult = k_EResultOK; @@ -187,7 +206,7 @@ SteamAPICall_t SendQueryUGCRequest( UGCQueryHandle_t handle ) // Retrieve an individual result after receiving the callback for querying UGC bool GetQueryUGCResult( UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t *pDetails ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCResult %llu %u\n", handle, index); + PRINT_DEBUG("Steam_UGC::GetQueryUGCResult %llu %u %p\n", handle, index, pDetails); std::lock_guard lock(global_mutex); if (pDetails) { memset(pDetails, 0, sizeof(SteamUGCDetails_t)); @@ -205,27 +224,91 @@ bool GetQueryUGCResult( UGCQueryHandle_t handle, uint32 index, SteamUGCDetails_t auto it = request->results.begin(); std::advance(it, index); - set_details(*it, pDetails); - + PublishedFileId_t file_id = *it; + set_details(file_id, pDetails); return true; } +std::optional get_query_ugc(UGCQueryHandle_t handle, uint32 index) { + auto request = std::find_if(ugc_queries.begin(), ugc_queries.end(), [&handle](struct UGC_query const& item) { return item.handle == handle; }); + if (ugc_queries.end() == request) return std::nullopt; + if (index >= request->results.size()) return std::nullopt; + + auto it = request->results.begin(); + std::advance(it, index); + + PublishedFileId_t file_id = *it; + if (!settings->isModInstalled(file_id)) return std::nullopt; + + return settings->getMod(file_id); +} + +std::optional> get_query_ugc_tags(UGCQueryHandle_t handle, uint32 index) { + auto res = get_query_ugc(handle, index); + if (!res.has_value()) return std::nullopt; + + auto tags_tokens = std::vector{}; + std::stringstream ss(res.value().tags); + std::string tmp{}; + while(ss >> tmp) { + if (tmp.back() == ',') tmp = tmp.substr(0, tmp.size() - 1); + tags_tokens.push_back(tmp); + } + + return tags_tokens; + +} + +std::optional get_query_ugc_tag(UGCQueryHandle_t handle, uint32 index, uint32 indexTag) { + auto res = get_query_ugc_tags(handle, index); + if (!res.has_value()) return std::nullopt; + if (indexTag >= res.value().size()) return std::nullopt; + + std::string tmp = res.value()[indexTag]; + if (tmp.back() == ',') { + tmp = tmp.substr(0, tmp.size() - 1); + } + return tmp; +} + uint32 GetQueryUGCNumTags( UGCQueryHandle_t handle, uint32 index ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCNumTags\n"); - return 0; + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCNumTags\n"); + // TODO is this correct? + std::lock_guard lock(global_mutex); + + auto res = get_query_ugc_tags(handle, index); + return res.has_value() ? res.value().size() : 0; } bool GetQueryUGCTag( UGCQueryHandle_t handle, uint32 index, uint32 indexTag, STEAM_OUT_STRING_COUNT( cchValueSize ) char* pchValue, uint32 cchValueSize ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCTag\n"); - return false; + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCTag\n"); + // TODO is this correct? + std::lock_guard lock(global_mutex); + if (!pchValue || !cchValueSize) return false; + + auto res = get_query_ugc_tag(handle, index, indexTag); + if (!res.has_value()) return false; + + memset(pchValue, 0, cchValueSize); + res.value().copy(pchValue, cchValueSize - 1); + return true; } bool GetQueryUGCTagDisplayName( UGCQueryHandle_t handle, uint32 index, uint32 indexTag, STEAM_OUT_STRING_COUNT( cchValueSize ) char* pchValue, uint32 cchValueSize ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCTagDisplayName\n"); - return false; + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCTagDisplayName\n"); + // TODO is this correct? + std::lock_guard lock(global_mutex); + if (!pchValue || !cchValueSize) return false; + + auto res = get_query_ugc_tag(handle, index, indexTag); + if (!res.has_value()) return false; + + memset(pchValue, 0, cchValueSize); + res.value().copy(pchValue, cchValueSize - 1); + return true; } bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchURL, uint32 cchURLSize ) @@ -234,98 +317,114 @@ bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STR std::lock_guard lock(global_mutex); //TODO: escape simulator tries downloading this url and unsubscribes if it fails - auto request = std::find_if(ugc_queries.begin(), ugc_queries.end(), [&handle](struct UGC_query const& item) { return item.handle == handle; }); - if ((ugc_queries.end() != request) && (index < request->results.size())) { - // point at the beginning of the results - auto it = request->results.begin(); - // then get the target result - //this is required for Escape Simulator to show the correct Preview Image, else it will be always the first - std::advance(it, index); - - uint32 it2 = (uint32)*it; - PRINT_DEBUG("Steam_UGC:GetQueryUGCPreviewURL: %u %s\n", it2, settings->getMod(it2).previewURL.c_str()); - snprintf(pchURL, cchURLSize, "%s", settings->getMod(it2).previewURL.c_str()); - return true; - } + if (!pchURL || !cchURLSize) return false; - return false; + auto res = get_query_ugc(handle, index); + if (!res.has_value()) return false; + + auto mod = res.value(); + PRINT_DEBUG("Steam_UGC:GetQueryUGCPreviewURL: %s\n", mod.previewURL.c_str()); + mod.previewURL.copy(pchURL, cchURLSize - 1); + return true; } bool GetQueryUGCMetadata( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STRING_COUNT(cchMetadatasize) char *pchMetadata, uint32 cchMetadatasize ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCMetadata\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCMetadata\n"); + std::lock_guard lock(global_mutex); + return false; } bool GetQueryUGCChildren( UGCQueryHandle_t handle, uint32 index, PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCChildren\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCChildren\n"); + std::lock_guard lock(global_mutex); + return false; } bool GetQueryUGCStatistic( UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint64 *pStatValue ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCStatistic\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCStatistic\n"); + std::lock_guard lock(global_mutex); + return false; } bool GetQueryUGCStatistic( UGCQueryHandle_t handle, uint32 index, EItemStatistic eStatType, uint32 *pStatValue ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCStatistic old\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCStatistic old\n"); + std::lock_guard lock(global_mutex); + return false; } uint32 GetQueryUGCNumAdditionalPreviews( UGCQueryHandle_t handle, uint32 index ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCNumAdditionalPreviews\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCNumAdditionalPreviews\n"); + std::lock_guard lock(global_mutex); + return 0; } bool GetQueryUGCAdditionalPreview( UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchURLOrVideoID, uint32 cchURLSize, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchOriginalFileName, uint32 cchOriginalFileNameSize, EItemPreviewType *pPreviewType ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCAdditionalPreview\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCAdditionalPreview\n"); + std::lock_guard lock(global_mutex); + return false; } bool GetQueryUGCAdditionalPreview( UGCQueryHandle_t handle, uint32 index, uint32 previewIndex, char *pchURLOrVideoID, uint32 cchURLSize, bool *hz ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCAdditionalPreview old\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCAdditionalPreview old\n"); + std::lock_guard lock(global_mutex); + return false; } uint32 GetQueryUGCNumKeyValueTags( UGCQueryHandle_t handle, uint32 index ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCNumKeyValueTags\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCNumKeyValueTags\n"); + std::lock_guard lock(global_mutex); + return 0; } bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, uint32 keyValueTagIndex, STEAM_OUT_STRING_COUNT(cchKeySize) char *pchKey, uint32 cchKeySize, STEAM_OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCKeyValueTag\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCKeyValueTag\n"); + std::lock_guard lock(global_mutex); + return false; } bool GetQueryUGCKeyValueTag( UGCQueryHandle_t handle, uint32 index, const char *pchKey, STEAM_OUT_STRING_COUNT(cchValueSize) char *pchValue, uint32 cchValueSize ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCKeyValueTag2\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCKeyValueTag2\n"); + std::lock_guard lock(global_mutex); + return false; } uint32 GetQueryUGCContentDescriptors( UGCQueryHandle_t handle, uint32 index, EUGCContentDescriptorID *pvecDescriptors, uint32 cMaxEntries ) { - PRINT_DEBUG("Steam_UGC::GetQueryUGCContentDescriptors\n"); + PRINT_DEBUG("TODO Steam_UGC::GetQueryUGCContentDescriptors\n"); + std::lock_guard lock(global_mutex); + return 0; } // Release the request to free up memory, after retrieving results bool ReleaseQueryUGCRequest( UGCQueryHandle_t handle ) { - PRINT_DEBUG("Steam_UGC::ReleaseQueryUGCRequest\n"); + PRINT_DEBUG("Steam_UGC::ReleaseQueryUGCRequest %llu\n", handle); std::lock_guard lock(global_mutex); auto request = std::find_if(ugc_queries.begin(), ugc_queries.end(), [&handle](struct UGC_query const& item) { return item.handle == handle; }); if (ugc_queries.end() == request) @@ -339,89 +438,115 @@ bool ReleaseQueryUGCRequest( UGCQueryHandle_t handle ) // Options to set for querying UGC bool AddRequiredTag( UGCQueryHandle_t handle, const char *pTagName ) { - PRINT_DEBUG("Steam_UGC::AddRequiredTag\n"); + PRINT_DEBUG("TODO Steam_UGC::AddRequiredTag\n"); + std::lock_guard lock(global_mutex); + return true; } bool AddRequiredTagGroup( UGCQueryHandle_t handle, const SteamParamStringArray_t *pTagGroups ) { - PRINT_DEBUG("Steam_UGC::AddRequiredTagGroup\n"); + PRINT_DEBUG("TODO Steam_UGC::AddRequiredTagGroup\n"); + std::lock_guard lock(global_mutex); + return true; } bool AddExcludedTag( UGCQueryHandle_t handle, const char *pTagName ) { - PRINT_DEBUG("Steam_UGC::AddExcludedTag\n"); + PRINT_DEBUG("TODO Steam_UGC::AddExcludedTag\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnOnlyIDs( UGCQueryHandle_t handle, bool bReturnOnlyIDs ) { - PRINT_DEBUG("Steam_UGC::SetReturnOnlyIDs\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnOnlyIDs\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnKeyValueTags( UGCQueryHandle_t handle, bool bReturnKeyValueTags ) { - PRINT_DEBUG("Steam_UGC::SetReturnKeyValueTags\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnKeyValueTags\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnLongDescription( UGCQueryHandle_t handle, bool bReturnLongDescription ) { - PRINT_DEBUG("Steam_UGC::SetReturnLongDescription\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnLongDescription\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnMetadata( UGCQueryHandle_t handle, bool bReturnMetadata ) { - PRINT_DEBUG("Steam_UGC::SetReturnMetadata\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnMetadata\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnChildren( UGCQueryHandle_t handle, bool bReturnChildren ) { - PRINT_DEBUG("Steam_UGC::SetReturnChildren\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnChildren\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnAdditionalPreviews( UGCQueryHandle_t handle, bool bReturnAdditionalPreviews ) { - PRINT_DEBUG("Steam_UGC::SetReturnAdditionalPreviews\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnAdditionalPreviews\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnTotalOnly( UGCQueryHandle_t handle, bool bReturnTotalOnly ) { - PRINT_DEBUG("Steam_UGC::SetReturnTotalOnly\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnTotalOnly\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetReturnPlaytimeStats( UGCQueryHandle_t handle, uint32 unDays ) { - PRINT_DEBUG("Steam_UGC::SetReturnPlaytimeStats\n"); + PRINT_DEBUG("TODO Steam_UGC::SetReturnPlaytimeStats\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetLanguage( UGCQueryHandle_t handle, const char *pchLanguage ) { - PRINT_DEBUG("Steam_UGC::SetLanguage\n"); + PRINT_DEBUG("TODO Steam_UGC::SetLanguage\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetAllowCachedResponse( UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ) { - PRINT_DEBUG("Steam_UGC::SetAllowCachedResponse\n"); + PRINT_DEBUG("TODO Steam_UGC::SetAllowCachedResponse\n"); + std::lock_guard lock(global_mutex); + return true; } @@ -429,7 +554,9 @@ bool SetAllowCachedResponse( UGCQueryHandle_t handle, uint32 unMaxAgeSeconds ) // Options only for querying user UGC bool SetCloudFileNameFilter( UGCQueryHandle_t handle, const char *pMatchCloudFileName ) { - PRINT_DEBUG("Steam_UGC::SetCloudFileNameFilter\n"); + PRINT_DEBUG("TODO Steam_UGC::SetCloudFileNameFilter\n"); + std::lock_guard lock(global_mutex); + return true; } @@ -437,47 +564,61 @@ bool SetCloudFileNameFilter( UGCQueryHandle_t handle, const char *pMatchCloudFil // Options only for querying all UGC bool SetMatchAnyTag( UGCQueryHandle_t handle, bool bMatchAnyTag ) { - PRINT_DEBUG("Steam_UGC::SetMatchAnyTag\n"); + PRINT_DEBUG("TODO Steam_UGC::SetMatchAnyTag\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetSearchText( UGCQueryHandle_t handle, const char *pSearchText ) { - PRINT_DEBUG("Steam_UGC::SetSearchText\n"); + PRINT_DEBUG("TODO Steam_UGC::SetSearchText\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetRankedByTrendDays( UGCQueryHandle_t handle, uint32 unDays ) { - PRINT_DEBUG("Steam_UGC::SetRankedByTrendDays\n"); + PRINT_DEBUG("TODO Steam_UGC::SetRankedByTrendDays\n"); + std::lock_guard lock(global_mutex); + return true; } bool AddRequiredKeyValueTag( UGCQueryHandle_t handle, const char *pKey, const char *pValue ) { - PRINT_DEBUG("Steam_UGC::AddRequiredKeyValueTag\n"); + PRINT_DEBUG("TODO Steam_UGC::AddRequiredKeyValueTag\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetTimeCreatedDateRange( UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ) { - PRINT_DEBUG("Steam_UGC::SetTimeCreatedDateRange\n"); + PRINT_DEBUG("TODO Steam_UGC::SetTimeCreatedDateRange\n"); + std::lock_guard lock(global_mutex); + return true; } bool SetTimeUpdatedDateRange( UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd ) { - PRINT_DEBUG("Steam_UGC::SetTimeUpdatedDateRange\n"); + PRINT_DEBUG("TODO Steam_UGC::SetTimeUpdatedDateRange\n"); + std::lock_guard lock(global_mutex); + return true; } // DEPRECATED - Use CreateQueryUGCDetailsRequest call above instead! SteamAPICall_t RequestUGCDetails( PublishedFileId_t nPublishedFileID, uint32 unMaxAgeSeconds ) { - PRINT_DEBUG("Steam_UGC::RequestUGCDetails\n"); + PRINT_DEBUG("Steam_UGC::RequestUGCDetails %llu\n", nPublishedFileID); + std::lock_guard lock(global_mutex); + SteamUGCRequestUGCDetailsResult_t data = {}; data.m_bCachedData = false; set_details(nPublishedFileID, &(data.m_details)); @@ -496,6 +637,8 @@ STEAM_CALL_RESULT( CreateItemResult_t ) SteamAPICall_t CreateItem( AppId_t nConsumerAppId, EWorkshopFileType eFileType ) { PRINT_DEBUG("Steam_UGC::CreateItem\n"); + std::lock_guard lock(global_mutex); + return 0; } // create new item for this app with no content attached yet @@ -504,6 +647,8 @@ SteamAPICall_t CreateItem( AppId_t nConsumerAppId, EWorkshopFileType eFileType ) UGCUpdateHandle_t StartItemUpdate( AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::StartItemUpdate\n"); + std::lock_guard lock(global_mutex); + return 0; } // start an UGC item update. Set changed properties before commiting update with CommitItemUpdate() @@ -512,6 +657,8 @@ UGCUpdateHandle_t StartItemUpdate( AppId_t nConsumerAppId, PublishedFileId_t nPu bool SetItemTitle( UGCUpdateHandle_t handle, const char *pchTitle ) { PRINT_DEBUG("Steam_UGC::SetItemTitle\n"); + std::lock_guard lock(global_mutex); + return false; } // change the title of an UGC item @@ -520,6 +667,8 @@ bool SetItemTitle( UGCUpdateHandle_t handle, const char *pchTitle ) bool SetItemDescription( UGCUpdateHandle_t handle, const char *pchDescription ) { PRINT_DEBUG("Steam_UGC::SetItemDescription\n"); + std::lock_guard lock(global_mutex); + return false; } // change the description of an UGC item @@ -528,6 +677,8 @@ bool SetItemDescription( UGCUpdateHandle_t handle, const char *pchDescription ) bool SetItemUpdateLanguage( UGCUpdateHandle_t handle, const char *pchLanguage ) { PRINT_DEBUG("Steam_UGC::SetItemUpdateLanguage\n"); + std::lock_guard lock(global_mutex); + return false; } // specify the language of the title or description that will be set @@ -536,6 +687,8 @@ bool SetItemUpdateLanguage( UGCUpdateHandle_t handle, const char *pchLanguage ) bool SetItemMetadata( UGCUpdateHandle_t handle, const char *pchMetaData ) { PRINT_DEBUG("Steam_UGC::SetItemMetadata\n"); + std::lock_guard lock(global_mutex); + return false; } // change the metadata of an UGC item (max = k_cchDeveloperMetadataMax) @@ -544,6 +697,8 @@ bool SetItemMetadata( UGCUpdateHandle_t handle, const char *pchMetaData ) bool SetItemVisibility( UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility eVisibility ) { PRINT_DEBUG("Steam_UGC::SetItemVisibility\n"); + std::lock_guard lock(global_mutex); + return false; } // change the visibility of an UGC item @@ -552,12 +707,16 @@ bool SetItemVisibility( UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVis bool SetItemTags( UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t *pTags ) { PRINT_DEBUG("Steam_UGC::SetItemTags old\n"); + std::lock_guard lock(global_mutex); + return false; } bool SetItemTags( UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t *pTags, bool bAllowAdminTags ) { PRINT_DEBUG("Steam_UGC::SetItemTags\n"); + std::lock_guard lock(global_mutex); + return false; } // change the tags of an UGC item @@ -565,6 +724,8 @@ bool SetItemTags( UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t bool SetItemContent( UGCUpdateHandle_t handle, const char *pszContentFolder ) { PRINT_DEBUG("Steam_UGC::SetItemContent\n"); + std::lock_guard lock(global_mutex); + return false; } // update item content from this local folder @@ -573,6 +734,8 @@ bool SetItemContent( UGCUpdateHandle_t handle, const char *pszContentFolder ) bool SetItemPreview( UGCUpdateHandle_t handle, const char *pszPreviewFile ) { PRINT_DEBUG("Steam_UGC::SetItemPreview\n"); + std::lock_guard lock(global_mutex); + return false; } // change preview image file for this item. pszPreviewFile points to local image file, which must be under 1MB in size @@ -580,12 +743,16 @@ bool SetItemPreview( UGCUpdateHandle_t handle, const char *pszPreviewFile ) bool SetAllowLegacyUpload( UGCUpdateHandle_t handle, bool bAllowLegacyUpload ) { PRINT_DEBUG("Steam_UGC::SetAllowLegacyUpload\n"); + std::lock_guard lock(global_mutex); + return false; } bool RemoveAllItemKeyValueTags( UGCUpdateHandle_t handle ) { PRINT_DEBUG("Steam_UGC::RemoveAllItemKeyValueTags\n"); + std::lock_guard lock(global_mutex); + return false; } // remove all existing key-value tags (you can add new ones via the AddItemKeyValueTag function) @@ -593,6 +760,8 @@ bool RemoveAllItemKeyValueTags( UGCUpdateHandle_t handle ) bool RemoveItemKeyValueTags( UGCUpdateHandle_t handle, const char *pchKey ) { PRINT_DEBUG("Steam_UGC::RemoveItemKeyValueTags\n"); + std::lock_guard lock(global_mutex); + return false; } // remove any existing key-value tags with the specified key @@ -601,6 +770,8 @@ bool RemoveItemKeyValueTags( UGCUpdateHandle_t handle, const char *pchKey ) bool AddItemKeyValueTag( UGCUpdateHandle_t handle, const char *pchKey, const char *pchValue ) { PRINT_DEBUG("Steam_UGC::AddItemKeyValueTag\n"); + std::lock_guard lock(global_mutex); + return false; } // add new key-value tags for the item. Note that there can be multiple values for a tag. @@ -609,6 +780,8 @@ bool AddItemKeyValueTag( UGCUpdateHandle_t handle, const char *pchKey, const cha bool AddItemPreviewFile( UGCUpdateHandle_t handle, const char *pszPreviewFile, EItemPreviewType type ) { PRINT_DEBUG("Steam_UGC::AddItemPreviewFile\n"); + std::lock_guard lock(global_mutex); + return false; } // add preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size @@ -617,6 +790,8 @@ bool AddItemPreviewFile( UGCUpdateHandle_t handle, const char *pszPreviewFile, E bool AddItemPreviewVideo( UGCUpdateHandle_t handle, const char *pszVideoID ) { PRINT_DEBUG("Steam_UGC::AddItemPreviewVideo\n"); + std::lock_guard lock(global_mutex); + return false; } // add preview video for this item @@ -625,6 +800,8 @@ bool AddItemPreviewVideo( UGCUpdateHandle_t handle, const char *pszVideoID ) bool UpdateItemPreviewFile( UGCUpdateHandle_t handle, uint32 index, const char *pszPreviewFile ) { PRINT_DEBUG("Steam_UGC::UpdateItemPreviewFile\n"); + std::lock_guard lock(global_mutex); + return false; } // updates an existing preview file for this item. pszPreviewFile points to local file, which must be under 1MB in size @@ -633,6 +810,8 @@ bool UpdateItemPreviewFile( UGCUpdateHandle_t handle, uint32 index, const char * bool UpdateItemPreviewVideo( UGCUpdateHandle_t handle, uint32 index, const char *pszVideoID ) { PRINT_DEBUG("Steam_UGC::UpdateItemPreviewVideo\n"); + std::lock_guard lock(global_mutex); + return false; } // updates an existing preview video for this item @@ -641,6 +820,8 @@ bool UpdateItemPreviewVideo( UGCUpdateHandle_t handle, uint32 index, const char bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index ) { PRINT_DEBUG("Steam_UGC::RemoveItemPreview %llu %u\n", handle, index); + std::lock_guard lock(global_mutex); + return false; } // remove a preview by index starting at 0 (previews are sorted) @@ -648,12 +829,16 @@ bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index ) bool AddContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ) { PRINT_DEBUG("Steam_UGC::AddContentDescriptor %llu %u\n", handle, descid); + std::lock_guard lock(global_mutex); + return false; } bool RemoveContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid ) { PRINT_DEBUG("Steam_UGC::RemoveContentDescriptor %llu %u\n", handle, descid); + std::lock_guard lock(global_mutex); + return false; } @@ -661,6 +846,8 @@ STEAM_CALL_RESULT( SubmitItemUpdateResult_t ) SteamAPICall_t SubmitItemUpdate( UGCUpdateHandle_t handle, const char *pchChangeNote ) { PRINT_DEBUG("Steam_UGC::SubmitItemUpdate\n"); + std::lock_guard lock(global_mutex); + return 0; } // commit update process started with StartItemUpdate() @@ -669,6 +856,8 @@ SteamAPICall_t SubmitItemUpdate( UGCUpdateHandle_t handle, const char *pchChange EItemUpdateStatus GetItemUpdateProgress( UGCUpdateHandle_t handle, uint64 *punBytesProcessed, uint64* punBytesTotal ) { PRINT_DEBUG("Steam_UGC::GetItemUpdateProgress\n"); + std::lock_guard lock(global_mutex); + return k_EItemUpdateStatusInvalid; } @@ -679,6 +868,8 @@ STEAM_CALL_RESULT( SetUserItemVoteResult_t ) SteamAPICall_t SetUserItemVote( PublishedFileId_t nPublishedFileID, bool bVoteUp ) { PRINT_DEBUG("Steam_UGC::SetUserItemVote\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -687,6 +878,8 @@ STEAM_CALL_RESULT( GetUserItemVoteResult_t ) SteamAPICall_t GetUserItemVote( PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::GetUserItemVote\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -695,6 +888,8 @@ STEAM_CALL_RESULT( UserFavoriteItemsListChanged_t ) SteamAPICall_t AddItemToFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::AddItemToFavorites\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -703,6 +898,8 @@ STEAM_CALL_RESULT( UserFavoriteItemsListChanged_t ) SteamAPICall_t RemoveItemFromFavorites( AppId_t nAppId, PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::RemoveItemFromFavorites\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -712,15 +909,15 @@ SteamAPICall_t SubscribeItem( PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::SubscribeItem %llu\n", nPublishedFileID); std::lock_guard lock(global_mutex); - subscribed.insert(nPublishedFileID); RemoteStorageSubscribePublishedFileResult_t data; + data.m_nPublishedFileId = nPublishedFileID; if (settings->isModInstalled(nPublishedFileID)) { data.m_eResult = k_EResultOK; + subscribed.insert(nPublishedFileID); } else { data.m_eResult = k_EResultFail; } - data.m_nPublishedFileId = nPublishedFileID; return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } // subscribe to this item, will be installed ASAP @@ -731,13 +928,14 @@ SteamAPICall_t UnsubscribeItem( PublishedFileId_t nPublishedFileID ) PRINT_DEBUG("Steam_UGC::UnsubscribeItem %llu\n", nPublishedFileID); std::lock_guard lock(global_mutex); RemoteStorageUnsubscribePublishedFileResult_t data; - data.m_eResult = k_EResultOK; + data.m_nPublishedFileId = nPublishedFileID; if (subscribed.count(nPublishedFileID) == 0) { data.m_eResult = k_EResultFail; //TODO: check if this is accurate + } else { + data.m_eResult = k_EResultOK; + subscribed.erase(nPublishedFileID); } - subscribed.erase(nPublishedFileID); - data.m_nPublishedFileId = nPublishedFileID; return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data)); } // unsubscribe from this item, will be uninstalled after game quits @@ -746,13 +944,15 @@ uint32 GetNumSubscribedItems() { PRINT_DEBUG("Steam_UGC::GetNumSubscribedItems\n"); std::lock_guard lock(global_mutex); + + PRINT_DEBUG(" Steam_UGC::GetNumSubscribedItems = %zu\n", subscribed.size()); return subscribed.size(); } // number of subscribed items uint32 GetSubscribedItems( PublishedFileId_t* pvecPublishedFileID, uint32 cMaxEntries ) { - PRINT_DEBUG("Steam_UGC::GetSubscribedItems\n"); + PRINT_DEBUG("Steam_UGC::GetSubscribedItems %p %u\n", pvecPublishedFileID, cMaxEntries); std::lock_guard lock(global_mutex); if (cMaxEntries > subscribed.size()) { cMaxEntries = subscribed.size(); @@ -784,16 +984,17 @@ uint32 GetItemState( PublishedFileId_t nPublishedFileID ) // if k_EItemStateLegacyItem is set, pchFolder contains the path to the legacy file itself (not a folder) bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDisk, STEAM_OUT_STRING_COUNT( cchFolderSize ) char *pchFolder, uint32 cchFolderSize, uint32 *punTimeStamp ) { - PRINT_DEBUG("Steam_UGC::GetItemInstallInfo\n"); + PRINT_DEBUG("Steam_UGC::GetItemInstallInfo %llu\n", nPublishedFileID); std::lock_guard lock(global_mutex); if (!settings->isModInstalled(nPublishedFileID)) { return false; } - if (punSizeOnDisk) *punSizeOnDisk = settings->getMod(nPublishedFileID).primaryFileSize; - if (punTimeStamp) *punTimeStamp = settings->getMod(nPublishedFileID).timeCreated; + auto mod = settings->getMod(nPublishedFileID); + if (punSizeOnDisk) *punSizeOnDisk = mod.primaryFileSize; + if (punTimeStamp) *punTimeStamp = mod.timeCreated; if (pchFolder && cchFolderSize) { - snprintf(pchFolder, cchFolderSize, "%s", settings->getMod(nPublishedFileID).path.c_str()); + mod.path.copy(pchFolder, cchFolderSize - 1); } return true; @@ -804,8 +1005,12 @@ bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDi bool GetItemDownloadInfo( PublishedFileId_t nPublishedFileID, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) { PRINT_DEBUG("Steam_UGC::GetItemDownloadInfo %llu\n", nPublishedFileID); - if (punBytesDownloaded) *punBytesDownloaded = settings->getMod(nPublishedFileID).primaryFileSize; - if (punBytesTotal) *punBytesTotal = settings->getMod(nPublishedFileID).primaryFileSize; + std::lock_guard lock(global_mutex); + if (!settings->isModInstalled(nPublishedFileID)) return false; + + auto mod = settings->getMod(nPublishedFileID); + if (punBytesDownloaded) *punBytesDownloaded = mod.primaryFileSize; + if (punBytesTotal) *punBytesTotal = mod.primaryFileSize; return true; } @@ -818,7 +1023,13 @@ bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDi bool GetItemUpdateInfo( PublishedFileId_t nPublishedFileID, bool *pbNeedsUpdate, bool *pbIsDownloading, uint64 *punBytesDownloaded, uint64 *punBytesTotal ) { PRINT_DEBUG("Steam_UGC::GetItemDownloadInfo old\n"); - return false; + std::lock_guard lock(global_mutex); + bool res = GetItemDownloadInfo(nPublishedFileID, punBytesDownloaded, punBytesTotal); + if (res) { + if (pbNeedsUpdate) *pbNeedsUpdate = false; + if (pbIsDownloading) *pbIsDownloading = false; + } + return res; } bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDisk, char *pchFolder, uint32 cchFolderSize ) // returns true if item is installed @@ -834,6 +1045,8 @@ bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDi bool DownloadItem( PublishedFileId_t nPublishedFileID, bool bHighPriority ) { PRINT_DEBUG("Steam_UGC::DownloadItem\n"); + std::lock_guard lock(global_mutex); + return false; } @@ -843,6 +1056,8 @@ bool DownloadItem( PublishedFileId_t nPublishedFileID, bool bHighPriority ) bool BInitWorkshopForGameServer( DepotId_t unWorkshopDepotID, const char *pszFolder ) { PRINT_DEBUG("Steam_UGC::BInitWorkshopForGameServer\n"); + std::lock_guard lock(global_mutex); + return false; } @@ -851,6 +1066,8 @@ bool BInitWorkshopForGameServer( DepotId_t unWorkshopDepotID, const char *pszFol void SuspendDownloads( bool bSuspend ) { PRINT_DEBUG("Steam_UGC::SuspendDownloads\n"); + std::lock_guard lock(global_mutex); + } @@ -891,6 +1108,8 @@ STEAM_CALL_RESULT( AddUGCDependencyResult_t ) SteamAPICall_t AddDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) { PRINT_DEBUG("Steam_UGC::AddDependency\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -898,6 +1117,8 @@ STEAM_CALL_RESULT( RemoveUGCDependencyResult_t ) SteamAPICall_t RemoveDependency( PublishedFileId_t nParentPublishedFileID, PublishedFileId_t nChildPublishedFileID ) { PRINT_DEBUG("Steam_UGC::RemoveDependency\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -907,6 +1128,8 @@ STEAM_CALL_RESULT( AddAppDependencyResult_t ) SteamAPICall_t AddAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) { PRINT_DEBUG("Steam_UGC::AddAppDependency\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -914,6 +1137,8 @@ STEAM_CALL_RESULT( RemoveAppDependencyResult_t ) SteamAPICall_t RemoveAppDependency( PublishedFileId_t nPublishedFileID, AppId_t nAppID ) { PRINT_DEBUG("Steam_UGC::RemoveAppDependency\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -923,6 +1148,8 @@ STEAM_CALL_RESULT( GetAppDependenciesResult_t ) SteamAPICall_t GetAppDependencies( PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::GetAppDependencies\n"); + std::lock_guard lock(global_mutex); + return 0; } @@ -932,13 +1159,17 @@ STEAM_CALL_RESULT( DeleteItemResult_t ) SteamAPICall_t DeleteItem( PublishedFileId_t nPublishedFileID ) { PRINT_DEBUG("Steam_UGC::DeleteItem\n"); + std::lock_guard lock(global_mutex); + return 0; } // Show the app's latest Workshop EULA to the user in an overlay window, where they can accept it or not bool ShowWorkshopEULA() { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("ShowWorkshopEULA\n"); + std::lock_guard lock(global_mutex); + return false; } @@ -946,14 +1177,18 @@ bool ShowWorkshopEULA() STEAM_CALL_RESULT( WorkshopEULAStatus_t ) SteamAPICall_t GetWorkshopEULAStatus() { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("GetWorkshopEULAStatus\n"); + std::lock_guard lock(global_mutex); + return 0; } // Return the user's community content descriptor preferences uint32 GetUserContentDescriptorPreferences( EUGCContentDescriptorID *pvecDescriptors, uint32 cMaxEntries ) { - PRINT_DEBUG("%s\n", __FUNCTION__); + PRINT_DEBUG("GetWorkshopEULAStatus\n"); + std::lock_guard lock(global_mutex); + return 0; } diff --git a/dll/dll/ugc_remote_storage_bridge.h b/dll/dll/ugc_remote_storage_bridge.h new file mode 100644 index 00000000..d19bb85f --- /dev/null +++ b/dll/dll/ugc_remote_storage_bridge.h @@ -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 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 get_ugc_query_result(UGCHandle_t file_handle); + + ~Ugc_Remote_Storage_Bridge(); +}; + + +#endif // __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__ + diff --git a/dll/settings.cpp b/dll/settings.cpp index ad8bcd9c..ec1b8142 100644 --- a/dll/settings.cpp +++ b/dll/settings.cpp @@ -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; } } diff --git a/dll/settings_parser.cpp b/dll/settings_parser.cpp index f8e3a8a2..842ebed0 100644 --- a/dll/settings_parser.cpp +++ b/dll/settings_parser.cpp @@ -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(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; diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 6520feb1..c1313c23 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -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); diff --git a/dll/ugc_remote_storage_bridge.cpp b/dll/ugc_remote_storage_bridge.cpp new file mode 100644 index 00000000..20108a8a --- /dev/null +++ b/dll/ugc_remote_storage_bridge.cpp @@ -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::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(); +} diff --git a/helpers/common_helpers.cpp b/helpers/common_helpers.cpp index 1fed2148..b802c03b 100644 --- a/helpers/common_helpers.cpp +++ b/helpers/common_helpers.cpp @@ -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; diff --git a/helpers/common_helpers/common_helpers.hpp b/helpers/common_helpers/common_helpers.hpp index 27789189..b4c2ec04 100644 --- a/helpers/common_helpers/common_helpers.hpp +++ b/helpers/common_helpers/common_helpers.hpp @@ -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); diff --git a/post_build/steam_settings.EXAMPLE/mod_images/12345/Readme.txt b/post_build/steam_settings.EXAMPLE/mod_images/12345/Readme.txt new file mode 100644 index 00000000..b59053ae --- /dev/null +++ b/post_build/steam_settings.EXAMPLE/mod_images/12345/Readme.txt @@ -0,0 +1 @@ +Put here the files whose names are specified by the JSON key "preview_filename" inside mods.json \ No newline at end of file diff --git a/post_build/steam_settings.EXAMPLE/mod_images/12345/my_preview_image.jpg b/post_build/steam_settings.EXAMPLE/mod_images/12345/my_preview_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa490cb4ea49d648b7d333c98c8f2acd01695589 GIT binary patch literal 3409 zcmd^>do+~m9>I(WdrhTpE(&xMjvATkawxg`!@CF1AausY4+u z(#DbN5R(vUmo`btA@@rS#&rxc?|$ulc87ib*=MiTI_s?SyzBR_^{(H$zR&Y{e&65w zKJZ)k1CTgqY-$WpC;(8%1z-XA+Q^z_aLB@XAIZyI!{@k%7b$q>_8lbhsi33&UL@0l zCZvOwG!s(rSG&}U=bg)NG*aw_sNGNf%Jm9463>S`MmHFju_cWfc6k(WhKI2?|EC#)k7 z){$jpWXb>WfFA=%Jg5K_Xp}M#l0=~;QE)v_L?DGxzYOrtff7O^>&4+k2y2iRN+p00 z3XK-RpoN7o8077GdoL&Ve%{04lG3vB3TEY#y84EvjZMwZTH9W?zv+0} z`L4IGe_(KEcw}^pGc`RkJ2%f=;4O2Z0Qy%fJ{fXIAa&pYj&>BS%zK#oh^?W_Sx7z~^; zU|_h19-#qw_dqS|7Ct|Klf7uXD1iK-iH}g6ZPx!|N^9ohduHhx?|aPj1KqZC`qirj zD%~;pcVN&&e=ev}6-1FU(R3JG&7a^0LwtO@L+Jyki9Ro=q6(sX@&VC`_J_iu6&j#; zAXP|0sz9{*llqR|5+`d4`||hOd#5CP9lKF}GEtoFUpK2;tiPdz(Yk3P7j@4-%Ct|{ z*taUyy}|c#Kdz$7z>~*u@>!CfRL{lj-)3U%Kimw1#u4;@I%RBa&ci9N0N3^V0(BglcG>7gih5XdBp7<5zsrgtgB2n427yv? z)Z~52;7Me~sR|6soM$_!GfFfdTfP(>0DUZm!H98Qd%mNNCG%Dn5h>u*BsUm-q5z{ziNp$N{3g35ceF&;@!85U7<;bD{i*v73Dsv9}YXr+{+t^&>PJiKN2(6Z5DPTJ5}V+gGS{G zKj3RIA=1;Db>gvS(vzXJ2{GH@J{xWr~_3;^hjrQxWYU?XkUNP?c8gHi*9Fa*mTU+O_WeXzH}jqFG>b~P5JJOlg*Op z=&l2iC;HoTR7QOJ-T`t}%;zXw>6&cQWm8_~2V3y*R{Gfdvt=EEb1pEbY2(J-@c&dy#rMGew!x!0z<;_rcbUa-!e!ILhZm=S`KJaPe zmbd9Z;iWmv*+}rR8#SfuEIsy0Fh^5d!E!}_T zbs_GeRG%P=GY^Z2}pr{>tb3^h`-tBiR-tEBoNH#BXv6;&tq`;imoODyB(# z=Jj-Zm3sVR zG0Hz6pR{sw&AK-(mrXrWU8}FqEJYB{y$EOj+Zw+lZbz-TLnDnF?G~2T)#&G)_@k`7 z4!F^zc)##2)a$|37F?85TpWQxbhrx*gi+aYeSUKF&XWm{tIv+^1x4@a@P~hW(M|8- z2$~BwtZ2#K+VhJ!a)ugl+$e~nZ4om>9*k|=siu4pH}4)#8Do8Nq6p5XP`P5PUT4)M zQC4x=xy^Qm$FzgzQl87#-c2`<6>=j9)ko|t%%%43nJnjvR;mg_m0{4Ai+)P=p-{}I zT;p@iexhA-)=FQ3)z+hz1}qS|5#M+ru8p%@CGvaGmCygh z2~b{E53ABFnJIEd2jT`j>2}Q+sk3?IbEoE)77oLp2k8O=aw=Hdw