From 25d34a65c42d93f461612a860c5869ebd4cc8b3c Mon Sep 17 00:00:00 2001 From: redpolline <11156324-redpolline@users.noreply.gitlab.com> Date: Sat, 14 Dec 2024 20:04:28 -0500 Subject: [PATCH] Redo image handling in settings. Lock the buffers when modifying them. Notify when callers change a set avatar image. Create a get function for images. Allow deletion of previously loaded images, and reuse of their ids. --- dll/settings.cpp | 224 +++++++++++++++++++++++++++++++++++++++++++++-- dll/settings.h | 28 ++++++ 2 files changed, 243 insertions(+), 9 deletions(-) diff --git a/dll/settings.cpp b/dll/settings.cpp index 7d59938..cc9a8b7 100644 --- a/dll/settings.cpp +++ b/dll/settings.cpp @@ -16,7 +16,7 @@ . */ #include "settings.h" - +#include "dll.h" std::string Settings::sanitize(std::string name) { @@ -54,6 +54,28 @@ Settings::Settings(CSteamID steam_id, CGameID game_id, std::string name, std::st this->offline = offline; this->create_unknown_leaderboards = true; + + this->next_free = 1; + this->preferred_network_image_type = Image::JPG; + + this->background_thread_exit = false; + PRINT_DEBUG("%s.\n", "Settings::Settings Creating new background_monitor thread"); + background_monitor_thread = std::thread(Settings::background_monitor_entry, this); +} + +Settings::~Settings() +{ + bool wait = false; + { + std::lock_guard lock(background_thread_mutex); + if (background_monitor_thread.joinable()) { + background_thread_exit = true; + wait = true; + } + } + if (wait) { + background_monitor_thread.join(); + } } CSteamID Settings::get_local_steam_id() @@ -214,19 +236,126 @@ void Settings::setLeaderboard(std::string leaderboard, enum ELeaderboardSortMeth leaderboards[leaderboard] = leader; } +int Settings::find_next_free_image_ref() { + int ret = 0; + + std::lock_guard lock(images_mutex); + + if (images.size() == 0) { + ret = 1; + } else { + for (auto x : images) { + auto y = images.upper_bound(x.first); + if (y == images.end()) { + if ((x.first + 1) == 0) { + ret = 1; + break; + } else { + ret = x.first + 1; + break; + } + } else { + if ((x.first + 1) < y->first) { + if ((x.first + 1) != 0) { + ret = x.first + 1; + break; + } + } + } + } + } + + next_free = ret; + + return ret; +} + +int Settings::remove_image(int ref) { + int ret = 0; + + std::lock_guard lock(images_mutex); + + auto x = images.find(ref); + if (x != images.end()) { + images.erase(x); + ret = find_next_free_image_ref(); + } else { + ret = next_free; + } + + return ret; +} + +int Settings::replace_image(int ref, std::string data, uint32 width, uint32 height) +{ + std::lock_guard lock(images_mutex); + int ret = 0; + if (ref == 0) { + ret = add_image(data, width, height); + } else { + auto t = images.find(ref); + if (t != images.end()) { + ret = t->first; + t->second.data = data; + t->second.width = width; + t->second.height = height; + } else { + ret = add_image(data, width, height); + } + } + return ret; +} + int Settings::add_image(std::string data, uint32 width, uint32 height) { - int last = images.size() + 1; - struct Image_Data dt; - dt.width = width; - dt.height = height; - dt.data = data; - images[last] = dt; + int last = 0; + std::lock_guard lock(images_mutex); + if (next_free != 0) { + last = next_free; + struct Image_Data dt; + dt.width = width; + dt.height = height; + dt.data = data; + images[last] = dt; + find_next_free_image_ref(); + } else { + PRINT_DEBUG("%s.\n", + "Settings::add_image failed. Buffer is full"); + } return last; } +int Settings::get_image(int ref, std::string * data, uint32 * width, uint32 * height) +{ + std::lock_guard lock(images_mutex); + int ret = 0; + auto t = images.find(ref); + if (t != images.end()) { + ret = t->first; + if (data != NULL) { + *data = t->second.data; + } + if (width != NULL) { + *width = t->second.width; + } + if (height != NULL) { + *height = t->second.height; + } + } else { + ret = 0; + if (width != NULL) { + *width = 0; + } + if (height != NULL) { + *height = 0; + } + } + return ret; +} + int Settings::get_profile_image(int eAvatarSize) { + std::lock_guard lock(images_mutex); int ret = 0; for (auto i : profile_images) { if (i.first == eAvatarSize) { @@ -237,6 +366,64 @@ int Settings::get_profile_image(int eAvatarSize) return ret; } +void Settings::background_monitor_entry(Settings * settings) { + PRINT_DEBUG("%s.\n", "Settings::background_monitor_entry thread starting"); + if (settings != NULL) { + settings->background_monitor(); + } + PRINT_DEBUG("%s.\n", "Settings::background_monitor_entry thread exiting"); + return; +} + +void Settings::background_monitor() { + bool exit = false; + do { + { + std::lock_guard lock(background_thread_mutex); + exit = background_thread_exit; + if (!exit) { + if (background_tasks.size() > 0) { + for (auto x = background_tasks.begin(); x != background_tasks.end(); x++) { + bool task_done = false; + Steam_Client * client = try_get_steam_client(); + if (client != NULL) { + switch (x->id) { + case Settings_Background_Task_IDs::NOTIFY_AVATAR_IMAGE: + { + PRINT_DEBUG("%s.\n", "Settings::background_monitor Got NOTIFY_AVATAR_IMAGE task"); + + if (client != NULL && client->steam_friends != NULL) { + client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize32x32); + client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize64x64); + client->steam_friends->GetFriendAvatar(this->steam_id, k_EAvatarSize184x184); + task_done = true; + } + } + break; + default: + PRINT_DEBUG("%s %d.\n", "Settings::background_monitor Unknown task", x->id); + task_done = true; + break; + }; + if (task_done) { + background_tasks.erase(x); + break; + } + } + } + } + } + } + } while(!exit); + return; +} + +void Settings::create_background_notify_task(Settings_Background_Task_IDs id, void *arg = NULL) { + std::lock_guard lock(background_thread_mutex); + background_tasks.push_back(Settings_Background_Task{id, arg}); + return; +} + int Settings::set_profile_image(int eAvatarSize, Image_Data * image) { bool size_ok = false; @@ -252,11 +439,13 @@ int Settings::set_profile_image(int eAvatarSize, Image_Data * image) if (size_ok == true && image->data.length() > 0) { ref = this->add_image(image->data, image->width, image->height); - PRINT_DEBUG("set_profile_image %d -> %d.\n", eAvatarSize, ref); + PRINT_DEBUG("Settings::set_profile_image %d -> %d.\n", eAvatarSize, ref); + std::lock_guard lock(images_mutex); profile_images[eAvatarSize] = ref; + create_background_notify_task(Settings_Background_Task_IDs::NOTIFY_AVATAR_IMAGE, NULL); } else { PRINT_DEBUG("%s %d %dx%d %"PRI_ZU".\n", - "set_profile_image failed", + "Settings::set_profile_image failed", eAvatarSize, image->width, image->height, @@ -266,3 +455,20 @@ int Settings::set_profile_image(int eAvatarSize, Image_Data * image) return ref; } + +void Settings::set_preferred_network_image_type(int new_type) +{ + switch (new_type) { + case Image::RAW: + case Image::PNG: + case Image::JPG: + this->preferred_network_image_type = new_type; + break; + default: + PRINT_DEBUG("%s %d.\n", + "Settings::set_preferred_network_image_type failed. Requested type", + new_type); + break; + }; + return; +} diff --git a/dll/settings.h b/dll/settings.h index 202c68c..8b7e7c2 100644 --- a/dll/settings.h +++ b/dll/settings.h @@ -65,11 +65,25 @@ struct Controller_Settings { std::map, std::string>>> action_set_layers; }; +enum Settings_Background_Task_IDs { + NOTIFY_AVATAR_IMAGE = 0 +}; + +struct Settings_Background_Task { + enum Settings_Background_Task_IDs id; + void * arg; +}; + class Settings { CSteamID steam_id; CGameID game_id; std::string name, language; CSteamID lobby_id; + uint32 preferred_network_image_type; + bool background_thread_exit; + std::vector background_tasks; + std::thread background_monitor_thread; + std::recursive_mutex background_thread_mutex; bool unlockAllDLCs; bool offline; @@ -83,6 +97,12 @@ class Settings { std::map profile_images; bool create_unknown_leaderboards; uint16 port; + int next_free; + + int find_next_free_image_ref(); + void create_background_notify_task(Settings_Background_Task_IDs id, void *arg); + static void background_monitor_entry(Settings * settings); + void background_monitor(); public: #ifdef LOBBY_CONNECT @@ -90,8 +110,10 @@ public: #else static const bool is_lobby_connect = false; #endif + static std::string sanitize(std::string name); Settings(CSteamID steam_id, CGameID game_id, std::string name, std::string language, bool offline); + ~Settings(); CSteamID get_local_steam_id(); CGameID get_local_game_id(); const char *get_local_name(); @@ -146,10 +168,16 @@ public: std::set subscribed_groups; //images + std::recursive_mutex images_mutex; std::map images; + int remove_image(int ref); + int replace_image(int ref, std::string data, uint32 width, uint32 height); int add_image(std::string data, uint32 width, uint32 height); + int get_image(int ref, std::string * data, uint32 * width, uint32 * height); int get_profile_image(int eAvatarSize); int set_profile_image(int eAvatarSize, Image_Data * image); + int get_preferred_network_image_type() { return this->preferred_network_image_type; } + void set_preferred_network_image_type(int new_type); //controller struct Controller_Settings controller_settings;