mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 13:14:01 +08:00
* load the icons of a single achievement each overlay callback invokation, will slow things down during startup
but this avoids having to load the achievement icon during gameplay which causes micro-stutter * avoid loading and resizing the achievement icon each time it's unlocked * Local_Storage: avoid allocating buffers unless `stbi_load()` was successfull
This commit is contained in:
parent
37426bac82
commit
0b86464374
@ -1,9 +1,10 @@
|
|||||||
# 2024/3/11
|
# 2024/3/11
|
||||||
* manage overlay cursor input/clipping and internal frame processing in a better way,
|
* manage overlay cursor input/clipping and internal frame processing in a better way,
|
||||||
should prevent more games from pausing to display notifications
|
should prevent more games from pausing to display notifications
|
||||||
* allow notifications of these types to steal/obscure input:
|
* load the icons of a single achievement each overlay callback invokation, will slow things down during startup
|
||||||
- `notification_type_message`
|
but this avoids having to load the achievement icon during gameplay which causes micro-stutter
|
||||||
- `notification_type_invite`
|
* avoid loading and resizing the achievement icon each time it's unlocked
|
||||||
|
* Local_Storage: avoid allocating buffers unless `stbi_load()` was successfull
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -839,24 +839,23 @@ std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_pa
|
|||||||
std::string Local_Storage::load_image_resized(std::string const& image_path, std::string const& image_data, int resolution)
|
std::string Local_Storage::load_image_resized(std::string const& image_path, std::string const& image_data, int resolution)
|
||||||
{
|
{
|
||||||
std::string resized_image{};
|
std::string resized_image{};
|
||||||
char *resized_img = (char*)malloc(sizeof(char) * resolution * resolution * 4);
|
const size_t resized_img_size = resolution * resolution * 4;
|
||||||
PRINT_DEBUG("Local_Storage::load_image_resized: %s for resized image (%i)\n", (resized_img == nullptr ? "could not allocate memory" : "memory allocated"), (resolution * resolution * 4));
|
|
||||||
|
|
||||||
if (resized_img != nullptr) {
|
|
||||||
if (image_path.length() > 0) {
|
if (image_path.length() > 0) {
|
||||||
int width, height;
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
unsigned char *img = stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
|
unsigned char *img = stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
|
||||||
PRINT_DEBUG("Local_Storage::load_image_resized: \"%s\" %s\n", image_path.c_str(), (img == nullptr ? stbi_failure_reason() : "loaded"));
|
PRINT_DEBUG("Local_Storage::load_image_resized: stbi_load %s '%s'\n", (img == nullptr ? stbi_failure_reason() : "loaded"), image_path.c_str());
|
||||||
if (img != nullptr) {
|
if (img != nullptr) {
|
||||||
stbir_resize_uint8(img, width, height, 0, (unsigned char*)resized_img, resolution, resolution, 0, 4);
|
std::vector<char> out_resized(resized_img_size);
|
||||||
resized_image = std::string(resized_img, resolution * resolution * 4);
|
stbir_resize_uint8(img, width, height, 0, (unsigned char*)&out_resized[0], resolution, resolution, 0, 4);
|
||||||
|
resized_image = std::string((char*)&out_resized[0], out_resized.size());
|
||||||
stbi_image_free(img);
|
stbi_image_free(img);
|
||||||
}
|
}
|
||||||
} else if (image_data.length() > 0) {
|
} else if (image_data.length() > 0) {
|
||||||
stbir_resize_uint8((unsigned char*)image_data.c_str(), 184, 184, 0, (unsigned char*)resized_img, resolution, resolution, 0, 4);
|
std::vector<char> out_resized(resized_img_size);
|
||||||
resized_image = std::string(resized_img, resolution * resolution * 4);
|
stbir_resize_uint8((unsigned char*)image_data.c_str(), 184, 184, 0, (unsigned char*)&out_resized[0], resolution, resolution, 0, 4);
|
||||||
}
|
resized_image = std::string((char*)&out_resized[0], out_resized.size());
|
||||||
free(resized_img);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_LastError();
|
reset_LastError();
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#ifdef EMU_OVERLAY
|
||||||
|
|
||||||
|
#include <future>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include "InGameOverlay/RendererHook.h"
|
||||||
|
|
||||||
static constexpr size_t max_chat_len = 768;
|
static constexpr size_t max_chat_len = 768;
|
||||||
|
|
||||||
enum window_state
|
enum window_state
|
||||||
@ -81,17 +88,12 @@ struct Overlay_Achievement
|
|||||||
std::weak_ptr<uint64_t> icon;
|
std::weak_ptr<uint64_t> icon;
|
||||||
std::weak_ptr<uint64_t> icon_gray;
|
std::weak_ptr<uint64_t> icon_gray;
|
||||||
|
|
||||||
|
// avoids spam loading on failure
|
||||||
constexpr const static int ICON_LOAD_MAX_TRIALS = 3;
|
constexpr const static int ICON_LOAD_MAX_TRIALS = 3;
|
||||||
uint8_t icon_load_trials = ICON_LOAD_MAX_TRIALS;
|
uint8_t icon_load_trials = ICON_LOAD_MAX_TRIALS;
|
||||||
uint8_t icon_gray_load_trials = ICON_LOAD_MAX_TRIALS;
|
uint8_t icon_gray_load_trials = ICON_LOAD_MAX_TRIALS;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
|
||||||
|
|
||||||
#include <future>
|
|
||||||
#include <atomic>
|
|
||||||
#include "InGameOverlay/RendererHook.h"
|
|
||||||
|
|
||||||
struct NotificationsIndexes
|
struct NotificationsIndexes
|
||||||
{
|
{
|
||||||
int top_left = 0, top_center = 0, top_right = 0;
|
int top_left = 0, top_center = 0, top_right = 0;
|
||||||
@ -100,6 +102,8 @@ struct NotificationsIndexes
|
|||||||
|
|
||||||
class Steam_Overlay
|
class Steam_Overlay
|
||||||
{
|
{
|
||||||
|
constexpr static const char ACH_FALLBACK_DIR[] = "achievement_images";
|
||||||
|
|
||||||
Settings* settings;
|
Settings* settings;
|
||||||
SteamCallResults* callback_results;
|
SteamCallResults* callback_results;
|
||||||
SteamCallBacks* callbacks;
|
SteamCallBacks* callbacks;
|
||||||
@ -110,13 +114,17 @@ class Steam_Overlay
|
|||||||
std::map<Friend, friend_window_state, Friend_Less> friends;
|
std::map<Friend, friend_window_state, Friend_Less> friends;
|
||||||
|
|
||||||
// avoids spam loading on failure
|
// avoids spam loading on failure
|
||||||
std::atomic<int32_t> load_achievements_trials = 3;
|
constexpr const static int LOAD_ACHIEVEMENTS_MAX_TRIALS = 3;
|
||||||
|
std::atomic<int32_t> load_achievements_trials = LOAD_ACHIEVEMENTS_MAX_TRIALS;
|
||||||
bool is_ready = false;
|
bool is_ready = false;
|
||||||
bool show_overlay;
|
bool show_overlay;
|
||||||
ENotificationPosition notif_position;
|
ENotificationPosition notif_position;
|
||||||
int h_inset, v_inset;
|
int h_inset, v_inset;
|
||||||
std::string show_url;
|
std::string show_url;
|
||||||
std::vector<Overlay_Achievement> achievements;
|
std::vector<Overlay_Achievement> achievements;
|
||||||
|
// index of the next achievement whose icons will be loaded
|
||||||
|
// used by the callback
|
||||||
|
int next_ach_to_load = 0;
|
||||||
bool show_achievements, show_settings;
|
bool show_achievements, show_settings;
|
||||||
|
|
||||||
// disable input when force_*.txt file is used
|
// disable input when force_*.txt file is used
|
||||||
@ -205,6 +213,9 @@ class Steam_Overlay
|
|||||||
|
|
||||||
bool open_overlay_hook(bool toggle);
|
bool open_overlay_hook(bool toggle);
|
||||||
|
|
||||||
|
bool try_load_ach_icon(Overlay_Achievement &ach);
|
||||||
|
bool try_load_ach_gray_icon(Overlay_Achievement &ach);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_Overlay(Settings* settings, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network);
|
Steam_Overlay(Settings* settings, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network);
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "InGameOverlay/ImGui/imgui.h"
|
#include "InGameOverlay/ImGui/imgui.h"
|
||||||
|
|
||||||
#include "dll/dll.h"
|
#include "dll/dll.h"
|
||||||
@ -565,23 +567,24 @@ bool Steam_Overlay::submit_notification(notification_type type, const std::strin
|
|||||||
|
|
||||||
notifications.emplace_back(notif);
|
notifications.emplace_back(notif);
|
||||||
allow_renderer_frame_processing(true);
|
allow_renderer_frame_processing(true);
|
||||||
switch (type) {
|
// uncomment this block to obscure cursor input and steal focus for these specific notifications
|
||||||
// we want to steal focus for these ones
|
// switch (type) {
|
||||||
case notification_type_message:
|
// // we want to steal focus for these ones
|
||||||
case notification_type_invite:
|
// case notification_type_message:
|
||||||
obscure_cursor_input(true);
|
// case notification_type_invite:
|
||||||
break;
|
// obscure_cursor_input(true);
|
||||||
|
// break;
|
||||||
|
|
||||||
// not effective
|
// // not effective
|
||||||
case notification_type_achievement:
|
// case notification_type_achievement:
|
||||||
case notification_type_auto_accept_invite:
|
// case notification_type_auto_accept_invite:
|
||||||
// nothing
|
// // nothing
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
default:
|
// default:
|
||||||
PRINT_DEBUG("Steam_Overlay::submit_notification error unhandled type %i\n", (int)type);
|
// PRINT_DEBUG("Steam_Overlay::submit_notification error unhandled type %i\n", (int)type);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -869,16 +872,16 @@ void Steam_Overlay::build_notifications(int width, int height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// some extra window flags for each notification type
|
// some extra window flags for each notification type
|
||||||
ImGuiWindowFlags extra_flags = 0;
|
ImGuiWindowFlags extra_flags = ImGuiWindowFlags_NoFocusOnAppearing;
|
||||||
switch (it->type) {
|
switch (it->type) {
|
||||||
// games like "Mafia Definitive Edition" will pause the entire game/scene if focus was stolen
|
// games like "Mafia Definitive Edition" will pause the entire game/scene if focus was stolen
|
||||||
// be less intrusive for notifications that do not require interaction
|
// be less intrusive for notifications that do not require interaction
|
||||||
case notification_type_achievement:
|
case notification_type_achievement:
|
||||||
case notification_type_auto_accept_invite:
|
case notification_type_auto_accept_invite:
|
||||||
extra_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoInputs;
|
case notification_type_message:
|
||||||
|
extra_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoInputs;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case notification_type_message:
|
|
||||||
case notification_type_invite:
|
case notification_type_invite:
|
||||||
// nothing
|
// nothing
|
||||||
break;
|
break;
|
||||||
@ -947,23 +950,24 @@ void Steam_Overlay::build_notifications(int width, int height)
|
|||||||
if ((now - item.start_time) > Notification::show_time) {
|
if ((now - item.start_time) > Notification::show_time) {
|
||||||
PRINT_DEBUG("Steam_Overlay::build_notifications removing a notification\n");
|
PRINT_DEBUG("Steam_Overlay::build_notifications removing a notification\n");
|
||||||
allow_renderer_frame_processing(false);
|
allow_renderer_frame_processing(false);
|
||||||
switch (item.type) {
|
// uncomment this block to restore app input focus
|
||||||
// we want to restore focus for these ones
|
// switch (item.type) {
|
||||||
case notification_type_message:
|
// // we want to restore focus for these ones
|
||||||
case notification_type_invite:
|
// case notification_type_message:
|
||||||
obscure_cursor_input(false);
|
// case notification_type_invite:
|
||||||
break;
|
// obscure_cursor_input(false);
|
||||||
|
// break;
|
||||||
|
|
||||||
// not effective
|
// // not effective
|
||||||
case notification_type_achievement:
|
// case notification_type_achievement:
|
||||||
case notification_type_auto_accept_invite:
|
// case notification_type_auto_accept_invite:
|
||||||
// nothing
|
// // nothing
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
default:
|
// default:
|
||||||
PRINT_DEBUG("Steam_Overlay::build_notifications error unhandled remove for type %i\n", (int)item.type);
|
// PRINT_DEBUG("Steam_Overlay::build_notifications error unhandled remove for type %i\n", (int)item.type);
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1019,6 +1023,62 @@ void Steam_Overlay::invite_friend(uint64 friend_id, class Steam_Friends* steamFr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Steam_Overlay::try_load_ach_icon(Overlay_Achievement &ach)
|
||||||
|
{
|
||||||
|
if (!_renderer) return false;
|
||||||
|
if (!ach.icon.expired()) return true;
|
||||||
|
|
||||||
|
if (ach.icon_load_trials && ach.icon_name.size()) {
|
||||||
|
--ach.icon_load_trials;
|
||||||
|
std::string file_path = std::move(Local_Storage::get_game_settings_path() + ach.icon_name);
|
||||||
|
unsigned long long file_size = file_size_(file_path);
|
||||||
|
if (!file_size) {
|
||||||
|
file_path = std::move(Local_Storage::get_game_settings_path() + Steam_Overlay::ACH_FALLBACK_DIR + "/" + ach.icon_name);
|
||||||
|
file_size = file_size_(file_path);
|
||||||
|
}
|
||||||
|
if (file_size) {
|
||||||
|
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||||
|
if (img.length() > 0) {
|
||||||
|
ach.icon = _renderer->CreateImageResource(
|
||||||
|
(void*)img.c_str(),
|
||||||
|
settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||||
|
if (!ach.icon.expired()) ach.icon_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||||
|
PRINT_DEBUG("Steam_Overlay::try_load_ach_icon '%s' (result=%i)\n", ach.name.c_str(), (int)!ach.icon.expired());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !ach.icon.expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Overlay::try_load_ach_gray_icon(Overlay_Achievement &ach)
|
||||||
|
{
|
||||||
|
if (!_renderer) return false;
|
||||||
|
if (!ach.icon_gray.expired()) return true;
|
||||||
|
|
||||||
|
if (ach.icon_gray_load_trials && ach.icon_gray_name.size()) {
|
||||||
|
--ach.icon_gray_load_trials;
|
||||||
|
std::string file_path = std::move(Local_Storage::get_game_settings_path() + ach.icon_gray_name);
|
||||||
|
unsigned long long file_size = file_size_(file_path);
|
||||||
|
if (!file_size) {
|
||||||
|
file_path = std::move(Local_Storage::get_game_settings_path() + Steam_Overlay::ACH_FALLBACK_DIR + "/" + ach.icon_gray_name);
|
||||||
|
file_size = file_size_(file_path);
|
||||||
|
}
|
||||||
|
if (file_size) {
|
||||||
|
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||||
|
if (img.length() > 0) {
|
||||||
|
ach.icon_gray = _renderer->CreateImageResource(
|
||||||
|
(void*)img.c_str(),
|
||||||
|
settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||||
|
if (!ach.icon_gray.expired()) ach.icon_gray_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
||||||
|
PRINT_DEBUG("Steam_Overlay::try_load_ach_gray_icon '%s' (result=%i)\n", ach.name.c_str(), (int)!ach.icon_gray.expired());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !ach.icon_gray.expired();
|
||||||
|
}
|
||||||
|
|
||||||
// Try to make this function as short as possible or it might affect game's fps.
|
// Try to make this function as short as possible or it might affect game's fps.
|
||||||
void Steam_Overlay::overlay_proc()
|
void Steam_Overlay::overlay_proc()
|
||||||
{
|
{
|
||||||
@ -1157,38 +1217,8 @@ void Steam_Overlay::overlay_proc()
|
|||||||
bool achieved = x.achieved;
|
bool achieved = x.achieved;
|
||||||
bool hidden = x.hidden && !achieved;
|
bool hidden = x.hidden && !achieved;
|
||||||
|
|
||||||
if (x.icon.expired() && x.icon_load_trials) {
|
try_load_ach_icon(x);
|
||||||
--x.icon_load_trials;
|
try_load_ach_gray_icon(x);
|
||||||
std::string file_path = Local_Storage::get_game_settings_path() + x.icon_name;
|
|
||||||
unsigned long long file_size = file_size_(file_path);
|
|
||||||
if (!file_size) {
|
|
||||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + x.icon_name;
|
|
||||||
file_size = file_size_(file_path);
|
|
||||||
}
|
|
||||||
if (file_size) {
|
|
||||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
|
||||||
if (img.length() > 0) {
|
|
||||||
if (_renderer) x.icon = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
|
||||||
if (!x.icon.expired()) x.icon_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (x.icon_gray.expired() && x.icon_gray_load_trials) {
|
|
||||||
--x.icon_gray_load_trials;
|
|
||||||
std::string file_path = Local_Storage::get_game_settings_path() + x.icon_gray_name;
|
|
||||||
unsigned long long file_size = file_size_(file_path);
|
|
||||||
if (!file_size) {
|
|
||||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + x.icon_gray_name;
|
|
||||||
file_size = file_size_(file_path);
|
|
||||||
}
|
|
||||||
if (file_size) {
|
|
||||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
|
||||||
if (img.length() > 0) {
|
|
||||||
if (_renderer) x.icon_gray = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
|
||||||
if (!x.icon_gray.expired()) x.icon_gray_load_trials = Overlay_Achievement::ICON_LOAD_MAX_TRIALS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
@ -1397,8 +1427,15 @@ void Steam_Overlay::UnSetupOverlay()
|
|||||||
if (_renderer) {
|
if (_renderer) {
|
||||||
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay will free any images resources\n");
|
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay will free any images resources\n");
|
||||||
for (auto &ach : achievements) {
|
for (auto &ach : achievements) {
|
||||||
if (!ach.icon.expired()) _renderer->ReleaseImageResource(ach.icon);
|
if (!ach.icon.expired()) {
|
||||||
if (!ach.icon_gray.expired()) _renderer->ReleaseImageResource(ach.icon_gray);
|
_renderer->ReleaseImageResource(ach.icon);
|
||||||
|
ach.icon.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ach.icon_gray.expired()) {
|
||||||
|
_renderer->ReleaseImageResource(ach.icon_gray);
|
||||||
|
ach.icon_gray.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderer = nullptr;
|
_renderer = nullptr;
|
||||||
@ -1567,12 +1604,15 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
|||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
if (!Ready()) return;
|
if (!Ready()) return;
|
||||||
|
|
||||||
|
std::vector<Overlay_Achievement*> found_achs{};
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock2(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock2(global_mutex);
|
||||||
|
|
||||||
std::string ach_name = ach.value("name", std::string());
|
std::string ach_name = ach.value("name", std::string());
|
||||||
for (auto &a : achievements) {
|
for (auto &a : achievements) {
|
||||||
if (a.name == ach_name) {
|
if (a.name == ach_name) {
|
||||||
|
found_achs.push_back(&a);
|
||||||
|
|
||||||
bool achieved = false;
|
bool achieved = false;
|
||||||
uint32 unlock_time = 0;
|
uint32 unlock_time = 0;
|
||||||
get_steam_client()->steam_user_stats->GetAchievementAndUnlockTime(a.name.c_str(), &achieved, &unlock_time);
|
get_steam_client()->steam_user_stats->GetAchievementAndUnlockTime(a.name.c_str(), &achieved, &unlock_time);
|
||||||
@ -1583,32 +1623,16 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!settings->disable_overlay_achievement_notification) {
|
if (!settings->disable_overlay_achievement_notification) {
|
||||||
// Load achievement image
|
for (auto found_ach : found_achs) {
|
||||||
std::weak_ptr<uint64_t> icon_rsrc{};
|
try_load_ach_icon(*found_ach);
|
||||||
std::string icon_path = ach.value("icon", std::string());
|
|
||||||
if (icon_path.size()) {
|
|
||||||
std::string file_path{};
|
|
||||||
unsigned long long file_size = 0;
|
|
||||||
file_path = Local_Storage::get_game_settings_path() + icon_path;
|
|
||||||
file_size = file_size_(file_path);
|
|
||||||
if (!file_size) {
|
|
||||||
file_path = Local_Storage::get_game_settings_path() + "achievement_images/" + icon_path;
|
|
||||||
file_size = file_size_(file_path);
|
|
||||||
}
|
|
||||||
if (file_size) {
|
|
||||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
|
||||||
if (img.length() > 0) {
|
|
||||||
icon_rsrc = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submit_notification(
|
submit_notification(
|
||||||
notification_type_achievement,
|
notification_type_achievement,
|
||||||
ach.value("displayName", std::string()) + "\n" + ach.value("description", std::string()),
|
ach.value("displayName", std::string()) + "\n" + ach.value("description", std::string()),
|
||||||
{},
|
{},
|
||||||
icon_rsrc
|
found_ach->icon
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
notify_sound_user_achievement();
|
notify_sound_user_achievement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1648,7 +1672,7 @@ void Steam_Overlay::RunCallbacks()
|
|||||||
if (achievements_num) {
|
if (achievements_num) {
|
||||||
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS\n");
|
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS\n");
|
||||||
for (unsigned i = 0; i < achievements_num; ++i) {
|
for (unsigned i = 0; i < achievements_num; ++i) {
|
||||||
Overlay_Achievement ach;
|
Overlay_Achievement ach{};
|
||||||
ach.name = steamUserStats->GetAchievementName(i);
|
ach.name = steamUserStats->GetAchievementName(i);
|
||||||
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
|
ach.title = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "name");
|
||||||
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
|
ach.description = steamUserStats->GetAchievementDisplayAttribute(ach.name.c_str(), "desc");
|
||||||
@ -1676,15 +1700,24 @@ void Steam_Overlay::RunCallbacks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// don't punish successfull attempts
|
// don't punish successfull attempts
|
||||||
if (achievements.size()) {
|
if (achievements.size()) load_achievements_trials = Steam_Overlay::LOAD_ACHIEVEMENTS_MAX_TRIALS;
|
||||||
++load_achievements_trials;
|
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS DONE (count=%lu, loaded=%zu)\n", achievements_num, achievements.size());
|
||||||
}
|
|
||||||
PRINT_DEBUG("Steam_Overlay POPULATE OVERLAY ACHIEVEMENTS DONE\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Ready()) return;
|
if (!Ready()) return;
|
||||||
|
|
||||||
|
// load images/icons for the next ach
|
||||||
|
if (next_ach_to_load < achievements.size()) {
|
||||||
|
try_load_ach_icon(achievements[next_ach_to_load]);
|
||||||
|
try_load_ach_gray_icon(achievements[next_ach_to_load]);
|
||||||
|
|
||||||
|
++next_ach_to_load;
|
||||||
|
// this allows the callback to keep trying forever in case the image resource was reset
|
||||||
|
// each icon has a limit though, so it won't slow things down forever
|
||||||
|
if (next_ach_to_load >= achievements.size()) next_ach_to_load = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (overlay_state_changed) {
|
if (overlay_state_changed) {
|
||||||
overlay_state_changed = false;
|
overlay_state_changed = false;
|
||||||
|
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
|
; global font size
|
||||||
Font_Size 13.5
|
Font_Size 13.5
|
||||||
|
; achievement icon size
|
||||||
Icon_Size 64.0
|
Icon_Size 64.0
|
||||||
|
|
||||||
|
; spacing between characters
|
||||||
Font_Glyph_Extra_Spacing_x 1.0
|
Font_Glyph_Extra_Spacing_x 1.0
|
||||||
Font_Glyph_Extra_Spacing_y 0.0
|
Font_Glyph_Extra_Spacing_y 0.0
|
||||||
|
|
||||||
|
; increase these values by 1 if the font is blurry
|
||||||
|
Font_Oversample_H 1
|
||||||
|
Font_Oversample_V 1
|
||||||
|
|
||||||
Notification_R 0.16
|
Notification_R 0.16
|
||||||
Notification_G 0.29
|
Notification_G 0.29
|
||||||
Notification_B 0.48
|
Notification_B 0.48
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
# modified version of ColdClientLoader originally by Rat431
|
|
||||||
[SteamClient]
|
|
||||||
# path to game exe, absolute or relative to the loader
|
|
||||||
Exe=my_app.exe
|
|
||||||
# empty means the folder of the exe
|
|
||||||
ExeRunDir=
|
|
||||||
# any additional args to pass, ex: -dx11, also any args passed to the loader will be passed to the app
|
|
||||||
ExeCommandLine=
|
|
||||||
# IMPORTANT
|
|
||||||
AppId=123
|
|
||||||
|
|
||||||
# path to the steamclient dlls, both must be set,
|
|
||||||
# absolute paths or relative to the loader
|
|
||||||
SteamClientDll=steamclient.dll
|
|
||||||
SteamClient64Dll=steamclient64.dll
|
|
||||||
|
|
||||||
# force inject steamclient dll instead of waiting for the app to load it
|
|
||||||
ForceInjectSteamClient=0
|
|
||||||
|
|
||||||
[Debug]
|
|
||||||
# don't call `ResumeThread()` on the main thread after spawning the .exe
|
|
||||||
ResumeByDebugger=0
|
|
||||||
|
|
||||||
[Extra]
|
|
||||||
# path to a folder containing some dlls to inject into the app upon start
|
|
||||||
# this folder will be traversed recursively
|
|
||||||
# additionally, inside this folder you can create a file called `load_order.txt` and
|
|
||||||
# inside it, specify line by line the order of the dlls that have to be injected
|
|
||||||
# each line should be a relative path of the dll, relative to the injection folder
|
|
||||||
DllsToInjectFolder=extra_dlls.EXAMPLE
|
|
||||||
# don't display an error message when a dll injection fails
|
|
||||||
IgnoreInjectionError=0
|
|
||||||
# don't display an error message if the architecture of the loader is different from the app
|
|
||||||
# this will result in a silent failure if a dll injection didn't succeed
|
|
||||||
# both the loader and the app must have the same arch for the injection to work
|
|
||||||
IgnoreLoaderArchDifference=0
|
|
Loading…
Reference in New Issue
Block a user