From c8e9a162ea7aecb8aced5c64e884f9ced816f8ac Mon Sep 17 00:00:00 2001 From: Nemirtingas Date: Fri, 9 Oct 2020 13:48:09 +0200 Subject: [PATCH] Add steam screenshot api. --- dll/local_storage.cpp | 48 ++++++++++++++++++++ dll/local_storage.h | 23 ++++++++++ dll/steam_client.cpp | 2 +- dll/steam_screenshots.cpp | 95 ++++++++++++++++++++++++++++++++++++--- dll/steam_screenshots.h | 15 +++++++ 5 files changed, 177 insertions(+), 6 deletions(-) diff --git a/dll/local_storage.cpp b/dll/local_storage.cpp index 6bddb3aa..81e17b94 100644 --- a/dll/local_storage.cpp +++ b/dll/local_storage.cpp @@ -17,6 +17,16 @@ #include "local_storage.h" +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#define STBI_ONLY_PNG +#define STBI_ONLY_JPEG +#include "../stb/stb_image.h" + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#define STB_IMAGE_WRITE_STATIC +#include "../stb/stb_image_write.h" + struct File_Data { std::string name; }; @@ -143,6 +153,16 @@ std::vector Local_Storage::get_filenames_path(std::string path) return std::vector(); } +std::vector Local_Storage::load_image(std::string const& image_path) +{ + return std::vector(); +} + +bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels) +{ + return false; +} + #else #if defined(__WINDOWS__) @@ -737,4 +757,32 @@ bool Local_Storage::write_json_file(std::string folder, std::string const&file, return false; } +std::vector Local_Storage::load_image(std::string const& image_path) +{ + std::vector res; + FILE* hFile = fopen(image_path.c_str(), "r"); + if (hFile != nullptr) + { + int width, height; + image_pixel_t* img = (image_pixel_t*)stbi_load_from_file(hFile, &width, &height, nullptr, 4); + if (img != nullptr) + { + res.resize(width*height); + std::copy(img, img + width * height, res.begin()); + + stbi_image_free(img); + } + fclose(hFile); + } + return res; +} + +bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels) +{ + std::string screenshot_path = std::move(save_directory + appid + screenshots_folder + PATH_SEPARATOR); + create_directory(screenshot_path); + screenshot_path += image_path; + return stbi_write_png(screenshot_path.c_str(), width, height, channels, img_ptr, 0) == 1; +} + #endif diff --git a/dll/local_storage.h b/dll/local_storage.h index 49fe2d0f..11f520a0 100644 --- a/dll/local_storage.h +++ b/dll/local_storage.h @@ -22,6 +22,25 @@ #define MAX_FILENAME_LENGTH 300 +union image_pixel_t +{ + uint32_t pixel; + struct pixel_channels_t + { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + } channels; +}; + +struct image_t +{ + size_t width; + size_t height; + std::vector pix_map; +}; + class Local_Storage { public: static constexpr auto inventory_storage_folder = "inventory"; @@ -29,6 +48,7 @@ public: static constexpr auto remote_storage_folder = "remote"; static constexpr auto stats_storage_folder = "stats"; static constexpr auto user_data_storage = "local"; + static constexpr auto screenshots_folder = "screenshots"; static constexpr auto game_settings_folder = "steam_settings"; private: @@ -62,6 +82,9 @@ public: bool load_json(std::string full_path, nlohmann::json& json); bool load_json_file(std::string folder, std::string const& file, nlohmann::json& json); bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json); + + std::vector load_image(std::string const& image_path); + bool save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels); }; #endif diff --git a/dll/steam_client.cpp b/dll/steam_client.cpp index 8d0506a5..cb435a52 100644 --- a/dll/steam_client.cpp +++ b/dll/steam_client.cpp @@ -72,7 +72,7 @@ Steam_Client::Steam_Client() 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_screenshots = new Steam_Screenshots(); + 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); diff --git a/dll/steam_screenshots.cpp b/dll/steam_screenshots.cpp index 7e54911d..f4e0d450 100644 --- a/dll/steam_screenshots.cpp +++ b/dll/steam_screenshots.cpp @@ -17,12 +17,40 @@ #include "steam_screenshots.h" +Steam_Screenshots::Steam_Screenshots(class Local_Storage* local_storage, class SteamCallBacks* callbacks) : + local_storage(local_storage), + callbacks(callbacks) +{ +} + +ScreenshotHandle Steam_Screenshots::create_screenshot_handle() +{ + static ScreenshotHandle handle = 100; + return handle++; +} + // Writes a screenshot to the user's screenshot library given the raw image data, which must be in RGB format. // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. ScreenshotHandle Steam_Screenshots::WriteScreenshot( void *pubRGB, uint32 cubRGB, int nWidth, int nHeight ) { PRINT_DEBUG("WriteScreenshot\n"); - return INVALID_SCREENSHOT_HANDLE; + + char buff[128]; + auto now = std::chrono::system_clock::now(); + time_t now_time; + now_time = std::chrono::duration_cast(now.time_since_epoch()).count(); + strftime(buff, 128, "%a_%b_%d_%H_%M_%S_%Y", localtime(&now_time)); + std::string screenshot_name = buff; + screenshot_name += ".png"; + + if (!local_storage->save_screenshot( screenshot_name, (uint8_t*)pubRGB, nWidth, nHeight, 3)) + return INVALID_SCREENSHOT_HANDLE; + + auto handle = create_screenshot_handle(); + auto& infos = _screenshots[handle]; + infos.screenshot_name = buff; + + return handle; } @@ -33,7 +61,30 @@ ScreenshotHandle Steam_Screenshots::WriteScreenshot( void *pubRGB, uint32 cubRGB ScreenshotHandle Steam_Screenshots::AddScreenshotToLibrary( const char *pchFilename, const char *pchThumbnailFilename, int nWidth, int nHeight ) { PRINT_DEBUG("AddScreenshotToLibrary\n"); - return INVALID_SCREENSHOT_HANDLE; + + if (pchFilename == nullptr) + return INVALID_SCREENSHOT_HANDLE; + + std::vector pixels(std::move(local_storage->load_image(pchFilename))); + if (pixels.size() != size_t(nWidth) * size_t(nHeight)) + return INVALID_SCREENSHOT_HANDLE; + + char buff[128]; + auto now = std::chrono::system_clock::now(); + time_t now_time; + now_time = std::chrono::duration_cast(now.time_since_epoch()).count(); + strftime(buff, 128, "%a_%b_%d_%H_%M_%S_%Y", localtime(&now_time)); + std::string screenshot_name = buff; + screenshot_name += ".png"; + + if (!local_storage->save_screenshot(screenshot_name, (uint8_t*)pixels.data(), nWidth, nHeight, 4)) + return INVALID_SCREENSHOT_HANDLE; + + auto handle = create_screenshot_handle(); + auto& infos = _screenshots[handle]; + infos.screenshot_name = buff; + + return handle; } @@ -41,6 +92,16 @@ ScreenshotHandle Steam_Screenshots::AddScreenshotToLibrary( const char *pchFilen void Steam_Screenshots::TriggerScreenshot() { PRINT_DEBUG("TriggerScreenshot\n"); + + if (hooked) + { + ScreenshotRequested_t data; + callbacks->addCBResult(data.k_iCallback, &data, sizeof(data)); + } + else + { + PRINT_DEBUG("TODO: Make the overlay take a screenshot"); + } } @@ -58,7 +119,15 @@ void Steam_Screenshots::HookScreenshots( bool bHook ) bool Steam_Screenshots::SetLocation( ScreenshotHandle hScreenshot, const char *pchLocation ) { PRINT_DEBUG("SetLocation\n"); - return false; + + auto it = _screenshots.find(hScreenshot); + if (it == _screenshots.end()) + return false; + + it->second.metadatas["locations"].push_back(pchLocation); + local_storage->write_json_file(Local_Storage::screenshots_folder, it->second.screenshot_name + ".json", it->second.metadatas); + + return true; } @@ -66,7 +135,15 @@ bool Steam_Screenshots::SetLocation( ScreenshotHandle hScreenshot, const char *p bool Steam_Screenshots::TagUser( ScreenshotHandle hScreenshot, CSteamID steamID ) { PRINT_DEBUG("TagUser\n"); - return false; + + auto it = _screenshots.find(hScreenshot); + if (it == _screenshots.end()) + return false; + + it->second.metadatas["users"].push_back(uint64_t(steamID.ConvertToUint64())); + local_storage->write_json_file(Local_Storage::screenshots_folder, it->second.screenshot_name + ".json", it->second.metadatas); + + return true; } @@ -74,7 +151,15 @@ bool Steam_Screenshots::TagUser( ScreenshotHandle hScreenshot, CSteamID steamID bool Steam_Screenshots::TagPublishedFile( ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID ) { PRINT_DEBUG("TagPublishedFile\n"); - return false; + + auto it = _screenshots.find(hScreenshot); + if (it == _screenshots.end()) + return false; + + it->second.metadatas["published_files"].push_back(uint64_t(unPublishedFileID)); + local_storage->write_json_file(Local_Storage::screenshots_folder, it->second.screenshot_name + ".json", it->second.metadatas); + + return true; } diff --git a/dll/steam_screenshots.h b/dll/steam_screenshots.h index 7e536345..745be9f0 100644 --- a/dll/steam_screenshots.h +++ b/dll/steam_screenshots.h @@ -17,10 +17,25 @@ #include "base.h" +struct screenshot_infos_t +{ + std::string screenshot_name; + nlohmann::json metadatas; +}; + class Steam_Screenshots : public ISteamScreenshots { bool hooked = false; + std::map _screenshots; + + class Local_Storage* local_storage; + class SteamCallBacks* callbacks; + + ScreenshotHandle create_screenshot_handle(); + public: + Steam_Screenshots(class Local_Storage* local_storage, class SteamCallBacks* callbacks); + // Writes a screenshot to the user's screenshot library given the raw image data, which must be in RGB format. // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. ScreenshotHandle WriteScreenshot( void *pubRGB, uint32 cubRGB, int nWidth, int nHeight );