#ifndef __INCLUDED_STEAM_OVERLAY_H__ #define __INCLUDED_STEAM_OVERLAY_H__ #include "dll/base.h" #include #include #ifdef EMU_OVERLAY #include #include #include #include "InGameOverlay/RendererHook.h" static constexpr size_t max_chat_len = 768; 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, }; struct friend_window_state { int id; uint8 window_state; std::string window_title; union // The invitation (if any) { uint64 lobbyId; char connect[k_cchMaxRichPresenceValueLength]; }; std::string chat_history; char chat_input[max_chat_len]; bool joinable; }; struct Friend_Less { bool operator()(const Friend& lhs, const Friend& rhs) const { return lhs.id() < rhs.id(); } }; enum notification_type { notification_type_message = 0, notification_type_invite, notification_type_achievement, notification_type_auto_accept_invite, }; struct Notification { static constexpr float width_percent = 0.25f; // percentage from total width static constexpr float height = 6.5f; static constexpr std::chrono::milliseconds fade_in = std::chrono::milliseconds(2000); static constexpr std::chrono::milliseconds fade_out = std::chrono::milliseconds(2000); static constexpr std::chrono::milliseconds show_time = std::chrono::milliseconds(6000) + fade_in + fade_out; static constexpr std::chrono::milliseconds fade_out_start = show_time - fade_out; int id; uint8 type; std::chrono::seconds start_time; std::string message; std::pair* frd; std::weak_ptr icon; }; struct Overlay_Achievement { std::string name; std::string title; std::string description; std::string icon_name; std::string icon_gray_name; bool hidden; bool achieved; uint32 unlock_time; std::weak_ptr icon; std::weak_ptr icon_gray; // avoids spam loading on failure constexpr const static int ICON_LOAD_MAX_TRIALS = 3; uint8_t icon_load_trials = ICON_LOAD_MAX_TRIALS; uint8_t icon_gray_load_trials = ICON_LOAD_MAX_TRIALS; }; struct NotificationsIndexes { int top_left = 0, top_center = 0, top_right = 0; int bot_left = 0, bot_center = 0, bot_right = 0; }; class Steam_Overlay { constexpr static const char ACH_SOUNDS_FOLDER[] = "sounds"; constexpr static const char ACH_FALLBACK_DIR[] = "achievement_images"; class Settings* settings; class Local_Storage* local_storage; class SteamCallResults* callback_results; class SteamCallBacks* callbacks; class RunEveryRunCB* run_every_runcb; class Networking* network; // friend id, show client window (to chat and accept invite maybe) std::map friends{}; bool is_ready = false; ENotificationPosition notif_position = ENotificationPosition::k_EPositionBottomLeft; int h_inset = 0; int v_inset = 0; std::string show_url{}; std::vector achievements{}; bool show_overlay = false; bool show_achievements = false; bool show_settings = false; // warn when using local save bool warn_local_save = false; // warn when app ID = 0 bool warn_bad_appid = false; char username_text[256]{}; std::atomic save_settings = false; int current_language = 0; std::string warning_message{}; // Callback infos std::queue has_friend_action{}; std::vector notifications{}; // used when the button "Invite all" is clicked std::atomic invite_all_friends_clicked = false; bool overlay_state_changed = false; std::atomic i_have_lobby = false; // some stuff has to be initialized once the renderer hook is ready std::atomic 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; constexpr static const int renderer_detector_polling_ms = 100; std::future future_renderer{}; InGameOverlay::RendererHook_t *_renderer{}; 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 &f); bool got_lobby(); bool submit_notification(notification_type type, const std::string &msg, std::pair *frd = nullptr, const std::weak_ptr &icon = {}); void notify_sound_user_invite(friend_window_state& friend_state); void notify_sound_user_achievement(); void notify_sound_auto_accept_friend_invite(); // Right click on friend void build_friend_context_menu(Friend const& frd, friend_window_state &state); // Double click on friend void build_friend_window(Friend const& frd, friend_window_state &state); // Notifications like achievements, chat and invitations void set_next_notification_pos(float width, float height, float font_size, notification_type type, struct NotificationsIndexes &idx); void build_notifications(int width, int height); // invite a single friend void invite_friend(uint64 friend_id, class Steam_Friends* steamFriends, class Steam_Matchmaking* steamMatchmaking); void request_renderer_detector(); void renderer_detector_delay_thread(); void renderer_hook_init_thread(); // 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 &wnd_state); void add_chat_message_notification(std::string const& message); bool open_overlay_hook(bool toggle); bool try_load_ach_icon(Overlay_Achievement &ach, bool achieved); void overlay_render_proc(); void render_main_window(); void networking_msg_received(Common_Message* msg); void steam_run_callback(); public: Steam_Overlay(Settings* settings, Local_Storage *local_storage, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking *network); ~Steam_Overlay(); bool Ready() const; bool NeedPresent() const; void SetNotificationPosition(ENotificationPosition eNotificationPosition); void SetNotificationInset(int nHorizontalInset, int nVerticalInset); void SetupOverlay(); void UnSetupOverlay(); void OpenOverlayInvite(CSteamID lobbyId); void OpenOverlay(const char* pchDialog); void OpenOverlayWebpage(const char* pchURL); bool ShowOverlay() const; 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); void AddAchievementNotification(nlohmann::json const& ach); }; #else class Steam_Overlay { public: Steam_Overlay(Settings* settings, Local_Storage *local_storage, SteamCallResults* callback_results, SteamCallBacks* callbacks, RunEveryRunCB* run_every_runcb, Networking* network) {} ~Steam_Overlay() {} bool Ready() const { return false; } bool NeedPresent() const { return false; } void SetNotificationPosition(ENotificationPosition eNotificationPosition) {} void SetNotificationInset(int nHorizontalInset, int nVerticalInset) {} void SetupOverlay() {} void UnSetupOverlay() {} void OpenOverlayInvite(CSteamID lobbyId) {} void OpenOverlay(const char* pchDialog) {} void OpenOverlayWebpage(const char* pchURL) {} bool ShowOverlay() const { return false; } 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) {} void AddAchievementNotification(nlohmann::json const& ach) {} }; #endif #endif//__INCLUDED_STEAM_OVERLAY_H__