mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 05:04:01 +08:00
* revert the previous change and force-display a mouse cursor inside the overlay, Truberbrook and others won't show a cursor in the overlay by default
* attempt to fix the crash when closing the app, use global object with bigger life time and avoid local states * attempt to fix usage of invalid/outdated window size when displaying notifications * lock overlay mutex everywhere to avoid sync problems * lock global emu mutex in the relevant places when using client APIs * only change the ImGui ini and round corner settings once
This commit is contained in:
parent
66d1fab36f
commit
c19fc81e84
@ -88,6 +88,7 @@ struct Overlay_Achievement
|
|||||||
|
|
||||||
#ifdef EMU_OVERLAY
|
#ifdef EMU_OVERLAY
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <atomic>
|
||||||
#include "InGameOverlay/RendererHook.h"
|
#include "InGameOverlay/RendererHook.h"
|
||||||
|
|
||||||
struct NotificationsIndexes {
|
struct NotificationsIndexes {
|
||||||
@ -108,8 +109,7 @@ class Steam_Overlay
|
|||||||
|
|
||||||
// avoids spam loading on failure
|
// avoids spam loading on failure
|
||||||
std::atomic<int32_t> load_achievements_trials = 3;
|
std::atomic<int32_t> load_achievements_trials = 3;
|
||||||
bool setup_overlay_called;
|
bool is_ready = false;
|
||||||
bool is_ready;
|
|
||||||
bool show_overlay;
|
bool show_overlay;
|
||||||
ENotificationPosition notif_position;
|
ENotificationPosition notif_position;
|
||||||
int h_inset, v_inset;
|
int h_inset, v_inset;
|
||||||
@ -127,7 +127,7 @@ class Steam_Overlay
|
|||||||
bool warn_bad_appid;
|
bool warn_bad_appid;
|
||||||
|
|
||||||
char username_text[256];
|
char username_text[256];
|
||||||
std::atomic_bool save_settings;
|
std::atomic<bool> save_settings;
|
||||||
|
|
||||||
int current_language;
|
int current_language;
|
||||||
|
|
||||||
@ -136,17 +136,14 @@ class Steam_Overlay
|
|||||||
// Callback infos
|
// Callback infos
|
||||||
std::queue<Friend> has_friend_action;
|
std::queue<Friend> has_friend_action;
|
||||||
std::vector<Notification> notifications;
|
std::vector<Notification> notifications;
|
||||||
std::recursive_mutex notifications_mutex;
|
|
||||||
std::atomic<bool> have_notifications;
|
|
||||||
// used when the button "Invite all" is clicked
|
// used when the button "Invite all" is clicked
|
||||||
std::atomic<bool> invite_all_friends_clicked = false;
|
std::atomic<bool> invite_all_friends_clicked = false;
|
||||||
|
|
||||||
bool overlay_state_changed;
|
bool overlay_state_changed;
|
||||||
|
|
||||||
std::recursive_mutex overlay_mutex;
|
|
||||||
std::atomic<bool> i_have_lobby;
|
std::atomic<bool> i_have_lobby;
|
||||||
std::future<InGameOverlay::RendererHook_t*> future_renderer;
|
std::future<InGameOverlay::RendererHook_t*> future_renderer;
|
||||||
InGameOverlay::RendererHook_t* _renderer;
|
InGameOverlay::RendererHook_t *_renderer;
|
||||||
|
|
||||||
Steam_Overlay(Steam_Overlay const&) = delete;
|
Steam_Overlay(Steam_Overlay const&) = delete;
|
||||||
Steam_Overlay(Steam_Overlay&&) = delete;
|
Steam_Overlay(Steam_Overlay&&) = delete;
|
||||||
@ -162,6 +159,8 @@ class Steam_Overlay
|
|||||||
bool FriendJoinable(std::pair<const Friend, friend_window_state> &f);
|
bool FriendJoinable(std::pair<const Friend, friend_window_state> &f);
|
||||||
bool IHaveLobby();
|
bool IHaveLobby();
|
||||||
|
|
||||||
|
bool submit_notification(notification_type type, const std::string &msg, std::pair<const Friend, friend_window_state> *frd = nullptr, const std::weak_ptr<uint64_t> &icon = {});
|
||||||
|
|
||||||
void NotifySoundUserInvite(friend_window_state& friend_state);
|
void NotifySoundUserInvite(friend_window_state& friend_state);
|
||||||
void NotifySoundUserAchievement();
|
void NotifySoundUserAchievement();
|
||||||
void NotifySoundAutoAcceptFriendInvite();
|
void NotifySoundAutoAcceptFriendInvite();
|
||||||
@ -211,7 +210,7 @@ public:
|
|||||||
void FriendConnect(Friend _friend);
|
void FriendConnect(Friend _friend);
|
||||||
void FriendDisconnect(Friend _friend);
|
void FriendDisconnect(Friend _friend);
|
||||||
|
|
||||||
void AddMessageNotification(std::string const& message);
|
void AddChatMessageNotification(std::string const& message);
|
||||||
void AddAchievementNotification(nlohmann::json const& ach);
|
void AddAchievementNotification(nlohmann::json const& ach);
|
||||||
void AddInviteNotification(std::pair<const Friend, friend_window_state> &wnd_state);
|
void AddInviteNotification(std::pair<const Friend, friend_window_state> &wnd_state);
|
||||||
void AddAutoAcceptInviteNotification();
|
void AddAutoAcceptInviteNotification();
|
||||||
@ -254,7 +253,7 @@ public:
|
|||||||
void FriendConnect(Friend _friend) {}
|
void FriendConnect(Friend _friend) {}
|
||||||
void FriendDisconnect(Friend _friend) {}
|
void FriendDisconnect(Friend _friend) {}
|
||||||
|
|
||||||
void AddMessageNotification(std::string const& message) {}
|
void AddChatMessageNotification(std::string const& message) {}
|
||||||
void AddAchievementNotification(nlohmann::json const& ach) {}
|
void AddAchievementNotification(nlohmann::json const& ach) {}
|
||||||
void AddInviteNotification(std::pair<const Friend, friend_window_state> &wnd_state) {}
|
void AddInviteNotification(std::pair<const Friend, friend_window_state> &wnd_state) {}
|
||||||
void AddAutoAcceptInviteNotification() {}
|
void AddAutoAcceptInviteNotification() {}
|
||||||
|
@ -64,6 +64,10 @@ ImFontAtlas fonts_atlas{};
|
|||||||
ImFont *font_default{};
|
ImFont *font_default{};
|
||||||
ImFont *font_notif{};
|
ImFont *font_notif{};
|
||||||
|
|
||||||
|
std::recursive_mutex overlay_mutex{};
|
||||||
|
std::atomic<bool> setup_overlay_called = false;
|
||||||
|
|
||||||
|
|
||||||
int find_free_id(std::vector<int> & ids, int base)
|
int find_free_id(std::vector<int> & ids, int base)
|
||||||
{
|
{
|
||||||
std::sort(ids.begin(), ids.end());
|
std::sort(ids.begin(), ids.end());
|
||||||
@ -129,7 +133,6 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
|
|||||||
callbacks(callbacks),
|
callbacks(callbacks),
|
||||||
run_every_runcb(run_every_runcb),
|
run_every_runcb(run_every_runcb),
|
||||||
network(network),
|
network(network),
|
||||||
setup_overlay_called(false),
|
|
||||||
show_overlay(false),
|
show_overlay(false),
|
||||||
is_ready(false),
|
is_ready(false),
|
||||||
notif_position(ENotificationPosition::k_EPositionBottomLeft),
|
notif_position(ENotificationPosition::k_EPositionBottomLeft),
|
||||||
@ -183,7 +186,7 @@ bool Steam_Overlay::Ready() const
|
|||||||
|
|
||||||
bool Steam_Overlay::NeedPresent() const
|
bool Steam_Overlay::NeedPresent() const
|
||||||
{
|
{
|
||||||
return true;
|
return !settings->disable_overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::SetNotificationPosition(ENotificationPosition eNotificationPosition)
|
void Steam_Overlay::SetNotificationPosition(ENotificationPosition eNotificationPosition)
|
||||||
@ -200,10 +203,10 @@ void Steam_Overlay::SetNotificationInset(int nHorizontalInset, int nVerticalInse
|
|||||||
|
|
||||||
void Steam_Overlay::SetupOverlay()
|
void Steam_Overlay::SetupOverlay()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Steam_Overlay::SetupOverlay\n");
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
if (!setup_overlay_called) {
|
PRINT_DEBUG("Steam_Overlay::SetupOverlay\n");
|
||||||
setup_overlay_called = true;
|
bool not_called = false;
|
||||||
|
if (setup_overlay_called.compare_exchange_weak(not_called, true)) {
|
||||||
future_renderer = InGameOverlay::DetectRenderer();
|
future_renderer = InGameOverlay::DetectRenderer();
|
||||||
PRINT_DEBUG("Steam_Overlay::SetupOverlay requested renderer detector/hook\n");
|
PRINT_DEBUG("Steam_Overlay::SetupOverlay requested renderer detector/hook\n");
|
||||||
}
|
}
|
||||||
@ -212,47 +215,63 @@ void Steam_Overlay::SetupOverlay()
|
|||||||
|
|
||||||
void Steam_Overlay::UnSetupOverlay()
|
void Steam_Overlay::UnSetupOverlay()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay\n");
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
InGameOverlay::StopRendererDetection();
|
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay\n");
|
||||||
if (!Ready() && future_renderer.valid()) {
|
bool called = true;
|
||||||
if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) {
|
if (setup_overlay_called.compare_exchange_weak(called, false)) {
|
||||||
future_renderer.get(); // to invalidate the future object
|
InGameOverlay::StopRendererDetection();
|
||||||
InGameOverlay::FreeDetector();
|
if (!Ready() && future_renderer.valid()) {
|
||||||
|
if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) {
|
||||||
|
future_renderer.get(); // to invalidate the future object
|
||||||
|
InGameOverlay::FreeDetector();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (_renderer) {
|
||||||
if (_renderer) {
|
for (auto &ach : achievements) {
|
||||||
for (auto &ach : achievements) {
|
if (!ach.icon.expired()) _renderer->ReleaseImageResource(ach.icon);
|
||||||
if (!ach.icon.expired()) _renderer->ReleaseImageResource(ach.icon);
|
if (!ach.icon_gray.expired()) _renderer->ReleaseImageResource(ach.icon_gray);
|
||||||
if (!ach.icon_gray.expired()) _renderer->ReleaseImageResource(ach.icon_gray);
|
}
|
||||||
|
_renderer = nullptr;
|
||||||
|
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay freed all images\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderer = nullptr;
|
|
||||||
PRINT_DEBUG("Steam_Overlay::UnSetupOverlay freed all images\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called initially and when window size is updated
|
||||||
void Steam_Overlay::HookReady(bool ready)
|
void Steam_Overlay::HookReady(bool ready)
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("Steam_Overlay::HookReady %i\n", (int)ready);
|
// NOTE usage of local objects here cause an exception when this is called with false state
|
||||||
|
// the reason is that by the time this hook is called, the object would've been already destructed
|
||||||
|
// this is why we check this global state
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
|
|
||||||
|
if (!setup_overlay_called) return;
|
||||||
|
|
||||||
is_ready = ready;
|
is_ready = ready;
|
||||||
|
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
PRINT_DEBUG("Steam_Overlay::HookReady %i\n", (int)ready);
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
|
|
||||||
// disable loading the default ini file
|
static bool initialized_imgui = false;
|
||||||
io.IniFilename = NULL;
|
if (ready && !initialized_imgui) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
|
initialized_imgui = true;
|
||||||
|
|
||||||
// Disable round window
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
style.WindowRounding = 0.0;
|
ImGuiStyle &style = ImGui::GetStyle();
|
||||||
|
|
||||||
|
// disable loading the default ini file
|
||||||
|
io.IniFilename = NULL;
|
||||||
|
|
||||||
|
// Disable round window
|
||||||
|
style.WindowRounding = 0.0;
|
||||||
|
|
||||||
|
// TODO: Uncomment this and draw our own cursor (cosmetics)
|
||||||
|
//io.WantSetMousePos = false;
|
||||||
|
//io.MouseDrawCursor = false;
|
||||||
|
//io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Uncomment this and draw our own cursor (cosmetics)
|
|
||||||
//io.WantSetMousePos = false;
|
|
||||||
//io.MouseDrawCursor = false;
|
|
||||||
//io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::OpenOverlayInvite(CSteamID lobbyId)
|
void Steam_Overlay::OpenOverlayInvite(CSteamID lobbyId)
|
||||||
@ -285,6 +304,7 @@ bool Steam_Overlay::ShowOverlay() const
|
|||||||
return show_overlay;
|
return show_overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called when the user presses SHIFT + TAB
|
||||||
bool Steam_Overlay::OpenOverlayHook(bool toggle)
|
bool Steam_Overlay::OpenOverlayHook(bool toggle)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
@ -301,19 +321,30 @@ void Steam_Overlay::ShowOverlay(bool state)
|
|||||||
if (!Ready() || show_overlay == state)
|
if (!Ready() || show_overlay == state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
show_overlay = state;
|
||||||
|
overlay_state_changed = true;
|
||||||
|
|
||||||
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
|
|
||||||
// this is very important, it doesn't just prevent input confusion between game's window
|
// this is very important, it doesn't just prevent input confusion between game's window
|
||||||
// and overlay's window, but internally it calls the necessary fuctions to properly update
|
// and overlay's window, but internally it calls the necessary fuctions to properly update
|
||||||
// ImGui window size
|
// ImGui window size
|
||||||
if (state) {
|
if (state) {
|
||||||
|
// force draw the cursor, otherwise games like Truberbrook will not have an overlay cursor
|
||||||
|
io.MouseDrawCursor = true;
|
||||||
|
// clip the cursor
|
||||||
_renderer->HideAppInputs(true);
|
_renderer->HideAppInputs(true);
|
||||||
|
// allow internal frmae processing
|
||||||
_renderer->HideOverlayInputs(false);
|
_renderer->HideOverlayInputs(false);
|
||||||
} else {
|
} else {
|
||||||
|
io.MouseDrawCursor = false;
|
||||||
|
// don't clip the cursor
|
||||||
_renderer->HideAppInputs(false);
|
_renderer->HideAppInputs(false);
|
||||||
_renderer->HideOverlayInputs(true);
|
// only stop internal frame processing when our state flag == false, and we don't have notifications
|
||||||
|
if (notifications.empty()) {
|
||||||
|
_renderer->HideOverlayInputs(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
show_overlay = state;
|
|
||||||
overlay_state_changed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::NotifySoundUserInvite(friend_window_state& friend_state)
|
void Steam_Overlay::NotifySoundUserInvite(friend_window_state& friend_state)
|
||||||
@ -419,38 +450,51 @@ void Steam_Overlay::FriendDisconnect(Friend _friend)
|
|||||||
friends.erase(it);
|
friends.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::AddMessageNotification(std::string const& message)
|
bool Steam_Overlay::submit_notification(notification_type type, const std::string &msg, std::pair<const Friend, friend_window_state> *frd, const std::weak_ptr<uint64_t> &icon)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
if (settings->disable_overlay_friend_notification) return;
|
PRINT_DEBUG("Steam_Overlay::submit_notification %i, '%s'\n", (int)type, msg.c_str());
|
||||||
int id = find_free_notification_id(notifications);
|
int id = find_free_notification_id(notifications);
|
||||||
if (id != 0)
|
if (id == 0) {
|
||||||
{
|
PRINT_DEBUG("Steam_Overlay::submit_notification error no free id to create a notification window\n");
|
||||||
Notification notif;
|
return false;
|
||||||
notif.id = id;
|
|
||||||
notif.type = notification_type_message;
|
|
||||||
notif.message = message;
|
|
||||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
|
||||||
notifications.emplace_back(notif);
|
|
||||||
have_notifications = true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
PRINT_DEBUG("Steam_Overlay error no free id to create a notification window\n");
|
// this is very important, internally it calls the necessary fuctions to properly update
|
||||||
|
// ImGui window size, change it here since we want the next OverlayProc to have a full window size
|
||||||
|
// otherwise notification position will relative to an outdated window size
|
||||||
|
_renderer->HideOverlayInputs(false);
|
||||||
|
|
||||||
|
Notification notif{};
|
||||||
|
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
notif.id = id;
|
||||||
|
notif.type = type;
|
||||||
|
notif.message = msg;
|
||||||
|
notif.frd = frd;
|
||||||
|
notif.icon = icon;
|
||||||
|
|
||||||
|
notifications.emplace_back(notif);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Overlay::AddChatMessageNotification(std::string const &message)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
|
if (settings->disable_overlay_friend_notification) return;
|
||||||
|
|
||||||
|
submit_notification(notification_type_message, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show a notification when the user unlocks an achievement
|
// show a notification when the user unlocks an achievement
|
||||||
void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock2(global_mutex);
|
||||||
if (!settings->disable_overlay_achievement_notification) {
|
if (!settings->disable_overlay_achievement_notification) {
|
||||||
int id = find_free_notification_id(notifications);
|
// Load achievement image
|
||||||
if (id != 0)
|
std::weak_ptr<uint64_t> icon_rsrc{};
|
||||||
{
|
if (_renderer) {
|
||||||
Notification notif;
|
|
||||||
notif.id = id;
|
|
||||||
notif.type = notification_type_achievement;
|
|
||||||
|
|
||||||
// Load achievement image
|
|
||||||
std::string file_path = Local_Storage::get_game_settings_path() + ach["icon"].get<std::string>();
|
std::string file_path = Local_Storage::get_game_settings_path() + ach["icon"].get<std::string>();
|
||||||
unsigned long long file_size = file_size_(file_path);
|
unsigned long long file_size = file_size_(file_path);
|
||||||
if (!file_size) {
|
if (!file_size) {
|
||||||
@ -460,18 +504,18 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
|||||||
if (file_size) {
|
if (file_size) {
|
||||||
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
std::string img = Local_Storage::load_image_resized(file_path, "", settings->overlay_appearance.icon_size);
|
||||||
if (img.length() > 0) {
|
if (img.length() > 0) {
|
||||||
if (_renderer) notif.icon = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
icon_rsrc = _renderer->CreateImageResource((void*)img.c_str(), settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notif.message = ach["displayName"].get<std::string>() + "\n" + ach["description"].get<std::string>();
|
|
||||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
|
||||||
notifications.emplace_back(notif);
|
|
||||||
NotifySoundUserAchievement();
|
|
||||||
have_notifications = true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
PRINT_DEBUG("Steam_Overlay error no free id to create a notification window\n");
|
submit_notification(
|
||||||
|
notification_type_achievement,
|
||||||
|
ach["displayName"].get<std::string>() + "\n" + ach["description"].get<std::string>(),
|
||||||
|
{},
|
||||||
|
icon_rsrc
|
||||||
|
);
|
||||||
|
NotifySoundUserAchievement();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ach_name = ach.value("name", "");
|
std::string ach_name = ach.value("name", "");
|
||||||
@ -488,59 +532,31 @@ void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
|||||||
|
|
||||||
void Steam_Overlay::AddInviteNotification(std::pair<const Friend, friend_window_state>& wnd_state)
|
void Steam_Overlay::AddInviteNotification(std::pair<const Friend, friend_window_state>& wnd_state)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
if (settings->disable_overlay_friend_notification) return;
|
if (settings->disable_overlay_friend_notification) return;
|
||||||
int id = find_free_notification_id(notifications);
|
|
||||||
if (id != 0)
|
|
||||||
{
|
|
||||||
Notification notif;
|
|
||||||
notif.id = id;
|
|
||||||
notif.type = notification_type_invite;
|
|
||||||
notif.frd = &wnd_state;
|
|
||||||
|
|
||||||
{
|
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
||||||
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
auto &first_friend = wnd_state.first;
|
||||||
auto &first_friend = wnd_state.first;
|
auto &name = first_friend.name();
|
||||||
auto &name = first_friend.name();
|
snprintf(tmp, sizeof(tmp), translationInvitedYouToJoinTheGame[current_language], name.c_str(), (uint64)first_friend.id());
|
||||||
snprintf(tmp, sizeof(tmp), translationInvitedYouToJoinTheGame[current_language], name.c_str(), (uint64)first_friend.id());
|
|
||||||
notif.message = tmp;
|
submit_notification(notification_type_invite, tmp, &wnd_state);
|
||||||
}
|
|
||||||
|
|
||||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
|
||||||
notifications.emplace_back(notif);
|
|
||||||
have_notifications = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
PRINT_DEBUG("Steam_Overlay error no free id to create a notification window\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::AddAutoAcceptInviteNotification()
|
void Steam_Overlay::AddAutoAcceptInviteNotification()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
int id = find_free_notification_id(notifications);
|
|
||||||
if (id != 0)
|
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
||||||
{
|
snprintf(tmp, sizeof(tmp), "%s", translationAutoAcceptFriendInvite[current_language]);
|
||||||
Notification notif{};
|
|
||||||
notif.id = id;
|
submit_notification(notification_type_auto_accept_invite, tmp);
|
||||||
notif.type = notification_type_auto_accept_invite;
|
NotifySoundAutoAcceptFriendInvite();
|
||||||
|
|
||||||
{
|
|
||||||
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
|
||||||
snprintf(tmp, sizeof(tmp), "%s", translationAutoAcceptFriendInvite[current_language]);
|
|
||||||
notif.message = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
|
||||||
notifications.emplace_back(notif);
|
|
||||||
NotifySoundAutoAcceptFriendInvite();
|
|
||||||
have_notifications = true;
|
|
||||||
} else {
|
|
||||||
PRINT_DEBUG("Steam_Overlay error no free id to create an auto-accept notification window\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Steam_Overlay::FriendJoinable(std::pair<const Friend, friend_window_state> &f)
|
bool Steam_Overlay::FriendJoinable(std::pair<const Friend, friend_window_state> &f)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
Steam_Friends* steamFriends = get_steam_client()->steam_friends;
|
Steam_Friends* steamFriends = get_steam_client()->steam_friends;
|
||||||
|
|
||||||
if( std::string(steamFriends->GetFriendRichPresence((uint64)f.first.id(), "connect")).length() > 0 )
|
if( std::string(steamFriends->GetFriendRichPresence((uint64)f.first.id(), "connect")).length() > 0 )
|
||||||
@ -556,6 +572,7 @@ bool Steam_Overlay::FriendJoinable(std::pair<const Friend, friend_window_state>
|
|||||||
|
|
||||||
bool Steam_Overlay::IHaveLobby()
|
bool Steam_Overlay::IHaveLobby()
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
Steam_Friends* steamFriends = get_steam_client()->steam_friends;
|
Steam_Friends* steamFriends = get_steam_client()->steam_friends;
|
||||||
if (std::string(steamFriends->GetFriendRichPresence(settings->get_local_steam_id(), "connect")).length() > 0)
|
if (std::string(steamFriends->GetFriendRichPresence(settings->get_local_steam_id(), "connect")).length() > 0)
|
||||||
return true;
|
return true;
|
||||||
@ -782,96 +799,90 @@ void Steam_Overlay::SetNextNotificationPos(float width, float height, float font
|
|||||||
|
|
||||||
void Steam_Overlay::BuildNotifications(int width, int height)
|
void Steam_Overlay::BuildNotifications(int width, int height)
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||||
|
|
||||||
float font_size = ImGui::GetFontSize();
|
float font_size = ImGui::GetFontSize();
|
||||||
|
|
||||||
std::queue<Friend> friend_actions_temp{};
|
std::queue<Friend> friend_actions_temp{};
|
||||||
|
|
||||||
{
|
NotificationsIndexes idx{};
|
||||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
for (auto it = notifications.begin(); it != notifications.end(); ++it) {
|
||||||
|
auto elapsed_notif = now - it->start_time;
|
||||||
|
|
||||||
NotificationsIndexes idx{};
|
if ( elapsed_notif < Notification::fade_in) { // still appearing (fading in)
|
||||||
for (auto it = notifications.begin(); it != notifications.end(); ++it)
|
float alpha = settings->overlay_appearance.notification_a * (elapsed_notif.count() / static_cast<float>(Notification::fade_in.count()));
|
||||||
{
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
|
||||||
auto elapsed_notif = now - it->start_time;
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, alpha));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
|
||||||
if ( elapsed_notif < Notification::fade_in) {
|
} else if ( elapsed_notif > Notification::fade_out_start) { // fading out
|
||||||
float alpha = settings->overlay_appearance.notification_a * (elapsed_notif.count() / static_cast<float>(Notification::fade_in.count()));
|
float alpha = settings->overlay_appearance.notification_a * ((Notification::show_time - elapsed_notif).count() / static_cast<float>(Notification::fade_out.count()));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, alpha));
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, alpha));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
|
||||||
}
|
} else { // still in the visible time limit
|
||||||
else if ( elapsed_notif > Notification::fade_out_start) {
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, settings->overlay_appearance.notification_a));
|
||||||
float alpha = settings->overlay_appearance.notification_a * ((Notification::show_time - elapsed_notif).count() / static_cast<float>(Notification::fade_out.count()));
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, settings->overlay_appearance.notification_a));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, alpha));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, settings->overlay_appearance.notification_a*2));
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, alpha));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, alpha*2));
|
|
||||||
} else {
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, settings->overlay_appearance.notification_a));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(settings->overlay_appearance.notification_r, settings->overlay_appearance.notification_g, settings->overlay_appearance.notification_b, settings->overlay_appearance.notification_a));
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(255, 255, 255, settings->overlay_appearance.notification_a*2));
|
|
||||||
}
|
|
||||||
|
|
||||||
SetNextNotificationPos(width, height, font_size, (notification_type)it->type, idx);
|
|
||||||
ImGui::SetNextWindowSize(ImVec2( width * Notification::width_percent, Notification::height * font_size ));
|
|
||||||
std::string wnd_name = "NotiPopupShow" + std::to_string(it->id);
|
|
||||||
ImGui::Begin(wnd_name.c_str(), nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus |
|
|
||||||
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoDecoration);
|
|
||||||
|
|
||||||
switch (it->type) {
|
|
||||||
case notification_type_achievement:
|
|
||||||
{
|
|
||||||
if (!it->icon.expired()) {
|
|
||||||
ImGui::BeginTable("imgui_table", 2);
|
|
||||||
ImGui::TableSetupColumn("imgui_table_image", ImGuiTableColumnFlags_WidthFixed, settings->overlay_appearance.icon_size);
|
|
||||||
ImGui::TableSetupColumn("imgui_table_text");
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, settings->overlay_appearance.icon_size);
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(0);
|
|
||||||
ImGui::Image((ImU64)*it->icon.lock().get(), ImVec2(settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size));
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
ImGui::TextWrapped("%s", it->message.c_str());
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
} else {
|
|
||||||
ImGui::TextWrapped("%s", it->message.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case notification_type_invite:
|
|
||||||
{
|
|
||||||
ImGui::TextWrapped("%s", it->message.c_str());
|
|
||||||
if (ImGui::Button(translationJoin[current_language]))
|
|
||||||
{
|
|
||||||
it->frd->second.window_state |= window_state_join;
|
|
||||||
friend_actions_temp.push(it->frd->first);
|
|
||||||
it->start_time = std::chrono::seconds(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case notification_type_message:
|
|
||||||
ImGui::TextWrapped("%s", it->message.c_str());
|
|
||||||
break;
|
|
||||||
case notification_type_auto_accept_invite:
|
|
||||||
ImGui::TextWrapped("%s", it->message.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
ImGui::PopStyleColor(3);
|
|
||||||
}
|
}
|
||||||
notifications.erase(std::remove_if(notifications.begin(), notifications.end(), [&now](Notification &item) {
|
|
||||||
return (now - item.start_time) > Notification::show_time;
|
SetNextNotificationPos(width, height, font_size, (notification_type)it->type, idx);
|
||||||
}), notifications.end());
|
ImGui::SetNextWindowSize(ImVec2( width * Notification::width_percent, Notification::height * font_size ));
|
||||||
|
|
||||||
|
std::string wnd_name = "NotiPopupShow" + std::to_string(it->id);
|
||||||
|
ImGui::Begin(wnd_name.c_str(), nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||||
|
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoDecoration);
|
||||||
|
|
||||||
have_notifications = !notifications.empty();
|
switch (it->type) {
|
||||||
|
case notification_type_achievement: {
|
||||||
|
if (!it->icon.expired()) {
|
||||||
|
ImGui::BeginTable("imgui_table", 2);
|
||||||
|
ImGui::TableSetupColumn("imgui_table_image", ImGuiTableColumnFlags_WidthFixed, settings->overlay_appearance.icon_size);
|
||||||
|
ImGui::TableSetupColumn("imgui_table_text");
|
||||||
|
ImGui::TableNextRow(ImGuiTableRowFlags_None, settings->overlay_appearance.icon_size);
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
ImGui::Image((ImU64)*it->icon.lock().get(), ImVec2(settings->overlay_appearance.icon_size, settings->overlay_appearance.icon_size));
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
ImGui::TextWrapped("%s", it->message.c_str());
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
} else {
|
||||||
|
ImGui::TextWrapped("%s", it->message.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case notification_type_invite: {
|
||||||
|
ImGui::TextWrapped("%s", it->message.c_str());
|
||||||
|
if (ImGui::Button(translationJoin[current_language]))
|
||||||
|
{
|
||||||
|
it->frd->second.window_state |= window_state_join;
|
||||||
|
friend_actions_temp.push(it->frd->first);
|
||||||
|
it->start_time = std::chrono::seconds(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case notification_type_message:
|
||||||
|
ImGui::TextWrapped("%s", it->message.c_str());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case notification_type_auto_accept_invite:
|
||||||
|
ImGui::TextWrapped("%s", it->message.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// erase all notifications whose visible time exceeded the max
|
||||||
|
notifications.erase(std::remove_if(notifications.begin(), notifications.end(), [&now](Notification &item) {
|
||||||
|
return (now - item.start_time) > Notification::show_time;
|
||||||
|
}), notifications.end());
|
||||||
|
|
||||||
if (!friend_actions_temp.empty()) {
|
if (!friend_actions_temp.empty()) {
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
|
||||||
while (!friend_actions_temp.empty()) {
|
while (!friend_actions_temp.empty()) {
|
||||||
has_friend_action.push(friend_actions_temp.front());
|
has_friend_action.push(friend_actions_temp.front());
|
||||||
friend_actions_temp.pop();
|
friend_actions_temp.pop();
|
||||||
@ -967,20 +978,24 @@ void Steam_Overlay::OverlayProc()
|
|||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
if (show_overlay) {
|
// Set the overlay windows to the size of the game window
|
||||||
// Set the overlay windows to the size of the game window
|
// only if we have a reason (full overlay or just some notification)
|
||||||
|
if (show_overlay || notifications.size()) {
|
||||||
ImGui::SetNextWindowPos({ 0,0 });
|
ImGui::SetNextWindowPos({ 0,0 });
|
||||||
ImGui::SetNextWindowSize({ io.DisplaySize.x, io.DisplaySize.y });
|
ImGui::SetNextWindowSize({ io.DisplaySize.x, io.DisplaySize.y });
|
||||||
|
ImGui::SetNextWindowBgAlpha(0.60);
|
||||||
ImGui::SetNextWindowBgAlpha(0.50);
|
|
||||||
|
|
||||||
ImGui::PushFont(font_default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_notifications) {
|
if (notifications.size()) {
|
||||||
ImGui::PushFont(font_notif);
|
ImGui::PushFont(font_notif);
|
||||||
BuildNotifications(io.DisplaySize.x, io.DisplaySize.y);
|
BuildNotifications(io.DisplaySize.x, io.DisplaySize.y);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
// after showing all notifications, and if we won't show the overlay
|
||||||
|
// then disable frame rendering
|
||||||
|
if (notifications.empty() && !show_overlay) {
|
||||||
|
_renderer->HideOverlayInputs(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ******************** exit early if we shouldn't show the overlay
|
// ******************** exit early if we shouldn't show the overlay
|
||||||
@ -989,6 +1004,8 @@ void Steam_Overlay::OverlayProc()
|
|||||||
}
|
}
|
||||||
// ********************
|
// ********************
|
||||||
|
|
||||||
|
//ImGui::SetNextWindowFocus();
|
||||||
|
ImGui::PushFont(font_default);
|
||||||
bool show = true;
|
bool show = true;
|
||||||
|
|
||||||
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
char tmp[TRANSLATION_BUFFER_SIZE]{};
|
||||||
@ -1057,7 +1074,6 @@ void Steam_Overlay::OverlayProc()
|
|||||||
|
|
||||||
ImGui::LabelText("##label", "%s", translationFriends[current_language]);
|
ImGui::LabelText("##label", "%s", translationFriends[current_language]);
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
|
||||||
if (!friends.empty()) {
|
if (!friends.empty()) {
|
||||||
if (i_have_lobby) {
|
if (i_have_lobby) {
|
||||||
std::string inviteAll(translationInviteAll[current_language]);
|
std::string inviteAll(translationInviteAll[current_language]);
|
||||||
@ -1275,7 +1291,7 @@ void Steam_Overlay::Callback(Common_Message *msg)
|
|||||||
friend_info->second.window_state |= window_state_need_attention;
|
friend_info->second.window_state |= window_state_need_attention;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddMessageNotification(friend_info->first.name() + ": " + steam_message.message());
|
AddChatMessageNotification(friend_info->first.name() + ": " + steam_message.message());
|
||||||
NotifySoundUserInvite(friend_info->second);
|
NotifySoundUserInvite(friend_info->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1284,6 +1300,7 @@ void Steam_Overlay::Callback(Common_Message *msg)
|
|||||||
void Steam_Overlay::RunCallbacks()
|
void Steam_Overlay::RunCallbacks()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock2(global_mutex);
|
||||||
if (Ready() && !achievements.size() && load_achievements_trials > 0) {
|
if (Ready() && !achievements.size() && load_achievements_trials > 0) {
|
||||||
--load_achievements_trials;
|
--load_achievements_trials;
|
||||||
Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
|
Steam_User_Stats* steamUserStats = get_steam_client()->steam_user_stats;
|
||||||
@ -1348,9 +1365,6 @@ void Steam_Overlay::RunCallbacks()
|
|||||||
_renderer->OverlayProc = [this]() { OverlayProc(); };
|
_renderer->OverlayProc = [this]() { OverlayProc(); };
|
||||||
_renderer->OverlayHookReady = [this](InGameOverlay::OverlayHookState state) {
|
_renderer->OverlayHookReady = [this](InGameOverlay::OverlayHookState state) {
|
||||||
PRINT_DEBUG("Steam_Overlay hook state changed %i\n", (int)state);
|
PRINT_DEBUG("Steam_Overlay hook state changed %i\n", (int)state);
|
||||||
if (state == InGameOverlay::OverlayHookState::Removing) {
|
|
||||||
_renderer = nullptr;
|
|
||||||
}
|
|
||||||
HookReady(state == InGameOverlay::OverlayHookState::Ready || state == InGameOverlay::OverlayHookState::Reset);
|
HookReady(state == InGameOverlay::OverlayHookState::Ready || state == InGameOverlay::OverlayHookState::Reset);
|
||||||
};
|
};
|
||||||
bool started = _renderer->StartHook(overlay_toggle_callback, overlay_toggle_keys, &fonts_atlas);
|
bool started = _renderer->StartHook(overlay_toggle_callback, overlay_toggle_keys, &fonts_atlas);
|
||||||
|
Loading…
Reference in New Issue
Block a user