328 lines
10 KiB
C
Raw Normal View History

#ifndef __INCLUDED_STEAM_OVERLAY_H__
#define __INCLUDED_STEAM_OVERLAY_H__
2019-07-25 23:33:07 +02:00
2023-12-27 09:15:10 +02:00
#include "dll/base.h"
2019-08-02 11:16:30 +02:00
#include <map>
2019-08-02 13:02:20 +02:00
#include <queue>
2019-07-25 23:33:07 +02:00
#ifdef EMU_OVERLAY
#include <future>
#include <atomic>
#include <memory>
#include "InGameOverlay/RendererHook.h"
#include "InGameOverlay/ImGui/imgui.h"
2019-08-03 12:58:48 +02:00
static constexpr size_t max_chat_len = 768;
2019-08-02 13:02:20 +02:00
enum window_state
{
window_state_none = 0,
window_state_show = 1<<0,
window_state_invite = 1<<1,
window_state_join = 1<<2,
window_state_lobby_invite = 1<<3,
window_state_rich_invite = 1<<4,
window_state_send_message = 1<<5,
window_state_need_attention = 1<<6,
};
2019-07-25 23:33:07 +02:00
2019-08-02 13:02:20 +02:00
struct friend_window_state
2019-08-02 11:16:30 +02:00
{
int id;
2019-08-02 13:02:20 +02:00
uint8 window_state;
std::string window_title;
2019-08-03 12:58:48 +02:00
union // The invitation (if any)
2019-08-02 11:16:30 +02:00
{
uint64 lobbyId;
char connect[k_cchMaxRichPresenceValueLength];
};
2019-08-03 12:58:48 +02:00
std::string chat_history;
char chat_input[max_chat_len];
2020-01-26 09:46:57 -05:00
bool joinable;
2019-08-02 11:16:30 +02:00
};
struct Friend_Less
{
bool operator()(const Friend& lhs, const Friend& rhs) const
{
return lhs.id() < rhs.id();
}
};
enum class notification_type
{
2024-06-20 05:57:30 +03:00
message,
invite,
achievement,
achievement_progress,
auto_accept_invite,
};
struct Overlay_Achievement
{
// avoids spam loading on failure
constexpr const static int ICON_LOAD_MAX_TRIALS = 3;
std::string name{};
std::string title{};
std::string description{};
std::string icon_name{};
std::string icon_gray_name{};
uint32 progress{};
uint32 max_progress{};
bool hidden{};
bool achieved{};
uint32 unlock_time{};
std::weak_ptr<uint64_t> icon{};
std::weak_ptr<uint64_t> icon_gray{};
uint8_t icon_load_trials = ICON_LOAD_MAX_TRIALS;
uint8_t icon_gray_load_trials = ICON_LOAD_MAX_TRIALS;
};
2019-08-14 14:55:31 +02:00
struct Notification
{
static constexpr float width_percent = 0.25f; // percentage from total width
2024-06-20 05:57:30 +03:00
static constexpr std::chrono::milliseconds default_show_time = std::chrono::milliseconds(6000);
int id{};
uint8 type{};
2024-06-20 05:57:30 +03:00
bool expired = false;
std::chrono::milliseconds start_time{};
std::string message{};
std::pair<const Friend, friend_window_state>* frd{};
std::optional<Overlay_Achievement> ach{};
};
// notification coordinates { x, y }
struct NotificationsCoords
{
std::pair<float, float> top_left{}, top_center{}, top_right{};
std::pair<float, float> bot_left{}, bot_center{}, bot_right{};
};
2019-07-25 23:33:07 +02:00
class Steam_Overlay
{
constexpr static const char ACH_SOUNDS_FOLDER[] = "sounds";
constexpr static const char ACH_FALLBACK_DIR[] = "achievement_images";
constexpr static const int renderer_detector_polling_ms = 100;
class Settings* settings;
class Local_Storage* local_storage;
class SteamCallResults* callback_results;
class SteamCallBacks* callbacks;
class RunEveryRunCB* run_every_runcb;
class Networking* network;
2019-08-02 11:16:30 +02:00
// friend id, show client window (to chat and accept invite maybe)
std::map<Friend, friend_window_state, Friend_Less> friends{};
2019-07-25 23:33:07 +02:00
bool is_ready = false;
ENotificationPosition notif_position = ENotificationPosition::k_EPositionBottomLeft;
int h_inset = 0;
int v_inset = 0;
std::string show_url{};
std::vector<Overlay_Achievement> achievements{};
bool show_overlay = false;
bool show_user_info = false;
bool show_achievements = false;
bool show_settings = false;
2023-12-29 03:55:11 +02:00
// warn when using local save
bool warn_local_save = false;
2023-12-29 03:55:11 +02:00
// warn when app ID = 0
bool warn_bad_appid = false;
char username_text[256]{};
std::atomic<bool> save_settings = false;
int current_language = 0;
std::string warning_message{};
2019-07-25 23:33:07 +02:00
// Callback infos
std::queue<Friend> has_friend_action{};
std::vector<Notification> notifications{};
// used when the button "Invite all" is clicked
std::atomic<bool> invite_all_friends_clicked = false;
bool overlay_state_changed = false;
std::atomic<bool> i_have_lobby = false;
// some stuff has to be initialized once the renderer hook is ready
std::atomic<bool> late_init_imgui = false;
bool late_init_ach_icons = false;
// changed each time a notification is posted or overlay is shown/hidden
std::atomic_uint32_t renderer_frame_processing_requests = 0;
// changed only when overlay is shown/hidden, true means overlay is shown
std::atomic_uint32_t obscure_cursor_requests = 0;
std::future<InGameOverlay::RendererHook_t *> future_renderer{};
InGameOverlay::RendererHook_t *_renderer{};
common_helpers::KillableWorker renderer_detector_delay_thread{};
common_helpers::KillableWorker renderer_hook_init_thread{};
int renderer_hook_timeout_ctr{};
// font stuff
ImFontAtlas fonts_atlas{};
ImFont *font_default{};
ImFont *font_notif{};
ImFontConfig font_cfg{};
ImFontGlyphRangesBuilder font_builder{};
ImVector<ImWchar> ranges{};
std::recursive_mutex overlay_mutex{};
std::atomic<bool> setup_overlay_called = false;
std::map<std::string, std::vector<char>> wav_files{
{ "overlay_achievement_notification.wav", std::vector<char>{} },
{ "overlay_friend_notification.wav", std::vector<char>{} },
};
2019-07-25 23:33:07 +02:00
Steam_Overlay(Steam_Overlay const&) = delete;
Steam_Overlay(Steam_Overlay&&) = delete;
Steam_Overlay& operator=(Steam_Overlay const&) = delete;
Steam_Overlay& operator=(Steam_Overlay&&) = delete;
static void overlay_run_callback(void* object);
static void overlay_networking_callback(void* object, Common_Message* msg);
bool is_friend_joinable(std::pair<const Friend, friend_window_state> &f);
bool got_lobby();
bool submit_notification(
notification_type type,
const std::string &msg,
std::pair<const Friend, friend_window_state> *frd = nullptr,
Overlay_Achievement *ach = nullptr
);
void notify_sound_user_invite(friend_window_state& friend_state);
void notify_sound_user_achievement();
void notify_sound_auto_accept_friend_invite();
2019-09-04 19:31:31 +02:00
2019-08-02 15:26:16 +02:00
// Right click on friend
void build_friend_context_menu(Friend const& frd, friend_window_state &state);
2019-08-02 15:26:16 +02:00
// Double click on friend
void build_friend_window(Friend const& frd, friend_window_state &state);
2024-06-20 05:57:30 +03:00
std::chrono::milliseconds get_notification_duration(notification_type type);
// Notifications like achievements, chat and invitations
2024-06-20 05:57:30 +03:00
void set_next_notification_pos(std::pair<float, float> scrn_size, std::chrono::milliseconds elapsed, std::chrono::milliseconds duration, const Notification &noti, struct NotificationsCoords &coords);
// factor controlling the amount of sliding during the animation, 0 means disabled
2024-06-20 05:57:30 +03:00
float animate_factor(std::chrono::milliseconds elapsed, std::chrono::milliseconds duration);
void add_ach_progressbar(const Overlay_Achievement &ach);
2024-06-20 02:57:39 +03:00
ImVec4 get_notification_bg_rgba_safe();
void build_notifications(float width, float height);
// invite a single friend
void invite_friend(uint64 friend_id, class Steam_Friends* steamFriends, class Steam_Matchmaking* steamMatchmaking);
void request_renderer_detector();
void set_renderer_hook_timeout();
void cleanup_renderer_hook();
bool renderer_hook_proc();
// note: make sure to load all relevant strings before creating the font(s), otherwise some glyphs ranges will be missing
void create_fonts();
void load_audio();
void load_achievements_data();
void initial_load_achievements_icons();
void overlay_state_hook(bool ready);
void allow_renderer_frame_processing(bool state, bool cleaning_up_overlay = false);
void obscure_game_input(bool state);
void add_auto_accept_invite_notification();
void add_invite_notification(std::pair<const Friend, friend_window_state> &wnd_state);
void post_achievement_notification(Overlay_Achievement &ach, bool for_progress);
void add_chat_message_notification(std::string const& message);
void show_test_achievement();
bool open_overlay_hook(bool toggle);
bool try_load_ach_icon(Overlay_Achievement &ach, bool achieved);
void overlay_render_proc();
uint32 apply_global_style_color();
2024-03-19 22:07:43 +02:00
void render_main_window();
void networking_msg_received(Common_Message* msg);
void steam_run_callback();
2019-07-25 23:33:07 +02:00
public:
Steam_Overlay(Settings* settings, Local_Storage *local_storage, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network);
2019-07-25 23:33:07 +02:00
~Steam_Overlay();
2019-07-25 23:33:07 +02:00
bool Ready() const;
2019-07-25 23:33:07 +02:00
bool NeedPresent() const;
2019-07-25 23:33:07 +02:00
void SetNotificationPosition(ENotificationPosition eNotificationPosition);
2019-07-25 23:33:07 +02:00
void SetNotificationInset(int nHorizontalInset, int nVerticalInset);
void SetupOverlay();
void UnSetupOverlay();
2019-07-25 23:33:07 +02:00
void OpenOverlayInvite(CSteamID lobbyId);
void OpenOverlay(const char* pchDialog);
void OpenOverlayWebpage(const char* pchURL);
2019-07-25 23:33:07 +02:00
bool ShowOverlay() const;
void ShowOverlay(bool state);
2019-08-02 11:16:30 +02:00
void SetLobbyInvite(Friend friendId, uint64 lobbyId);
void SetRichInvite(Friend friendId, const char* connect_str);
2019-08-02 11:16:30 +02:00
void FriendConnect(Friend _friend);
void FriendDisconnect(Friend _friend);
2019-09-04 19:31:31 +02:00
void AddAchievementNotification(const std::string &ach_name, nlohmann::json const& ach, bool for_progress);
};
2019-07-25 23:33:07 +02:00
2024-05-03 01:29:57 +03:00
#else // EMU_OVERLAY
2019-08-14 14:55:31 +02:00
class Steam_Overlay
{
public:
Steam_Overlay(Settings* settings, Local_Storage *local_storage, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking* network) {}
2019-08-14 18:11:00 +02:00
~Steam_Overlay() {}
2019-08-14 14:55:31 +02:00
2019-08-14 18:11:00 +02:00
bool Ready() const { return false; }
2019-08-14 14:55:31 +02:00
bool NeedPresent() const { return false; }
void SetNotificationPosition(ENotificationPosition eNotificationPosition) {}
void SetNotificationInset(int nHorizontalInset, int nVerticalInset) {}
void SetupOverlay() {}
void UnSetupOverlay() {}
2019-08-14 14:55:31 +02:00
void OpenOverlayInvite(CSteamID lobbyId) {}
void OpenOverlay(const char* pchDialog) {}
void OpenOverlayWebpage(const char* pchURL) {}
2019-08-14 14:55:31 +02:00
bool ShowOverlay() const { return false; }
2019-08-14 14:55:31 +02:00
void ShowOverlay(bool state) {}
void SetLobbyInvite(Friend friendId, uint64 lobbyId) {}
void SetRichInvite(Friend friendId, const char* connect_str) {}
void FriendConnect(Friend _friend) {}
void FriendDisconnect(Friend _friend) {}
2019-10-15 19:08:14 +02:00
2024-06-06 21:39:31 +03:00
void AddAchievementNotification(const std::string &ach_name, nlohmann::json const& ach, bool for_progress) {}
2019-08-14 14:55:31 +02:00
};
2024-05-03 01:29:57 +03:00
#endif // EMU_OVERLAY
2019-08-14 14:55:31 +02:00
2024-05-03 01:29:57 +03:00
#endif //__INCLUDED_STEAM_OVERLAY_H__