diff --git a/Include/xsapi-c/leaderboard_c.h b/Include/xsapi-c/leaderboard_c.h index 1169164c..aa95cabc 100644 --- a/Include/xsapi-c/leaderboard_c.h +++ b/Include/xsapi-c/leaderboard_c.h @@ -166,12 +166,12 @@ typedef struct XblLeaderboardRow uint32_t rank; /// - /// The global rank of the player. + /// The global rank of the player. If globalrank is 0, then the user has no global rank. /// uint32_t globalRank; /// - /// UTF-8 encoded values for each column in the leaderboard row for the player. + /// UTF-8 encoded JSON values for each column in the leaderboard row for the player. /// _Field_z_ const char** columnValues; diff --git a/Include/xsapi-c/services_c.h b/Include/xsapi-c/services_c.h index 3109c4b9..d2d0c741 100644 --- a/Include/xsapi-c/services_c.h +++ b/Include/xsapi-c/services_c.h @@ -34,4 +34,6 @@ #include #include #include -#include \ No newline at end of file +#if XSAPI_NOTIFICATION_SERVICE +#include +#endif \ No newline at end of file diff --git a/Include/xsapi-cpp/impl/notification.hpp b/Include/xsapi-cpp/impl/notification.hpp index 28e6d70a..cb464c04 100644 --- a/Include/xsapi-cpp/impl/notification.hpp +++ b/Include/xsapi-cpp/impl/notification.hpp @@ -4,7 +4,8 @@ #pragma once #include "public_utils.h" -NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN +NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_BEGIN +#if XSAPI_NOTIFICATION_SERVICE notification_service::notification_service(_In_ XblContextHandle contextHandle) { XblContextDuplicateHandle(contextHandle, &m_xblContext); @@ -12,6 +13,9 @@ notification_service::notification_service(_In_ XblContextHandle contextHandle) notification_service::~notification_service() { +#if !XSAPI_UNIT_TESTS + unsubscribe_from_notifications().wait(); +#endif XblContextCloseHandle(m_xblContext); } @@ -48,32 +52,32 @@ inline invite_notification_event_args::invite_notification_event_args(_In_ const { } -const string_t& invite_notification_event_args::invited_xbox_user_id() const +string_t invite_notification_event_args::invited_xbox_user_id() const { return Utils::StringTFromUint64(m_gameInviteArgs.invitedXboxUserId); } -const string_t& invite_notification_event_args::sender_xbox_user_id() const +string_t invite_notification_event_args::sender_xbox_user_id() const { return Utils::StringTFromUint64(m_gameInviteArgs.senderXboxUserId); } -const string_t& invite_notification_event_args::sender_gamertag() const +string_t invite_notification_event_args::sender_gamertag() const { return Utils::StringTFromUtf8(m_gameInviteArgs.senderGamertag); } -const string_t& invite_notification_event_args::invite_handle_id() const +string_t invite_notification_event_args::invite_handle_id() const { return Utils::StringTFromUtf8(m_gameInviteArgs.inviteHandleId); } -const string_t& invite_notification_event_args::invite_protocol() const +string_t invite_notification_event_args::invite_protocol() const { return Utils::StringTFromUtf8(m_gameInviteArgs.inviteProtocol); } -const utility::datetime& invite_notification_event_args::expiration() const +utility::datetime invite_notification_event_args::expiration() const { return Utils::DatetimeFromTimeT(m_gameInviteArgs.expiration); } @@ -88,42 +92,42 @@ inline achievement_unlocked_notification_event_args::achievement_unlocked_notifi { } -const string_t& achievement_unlocked_notification_event_args::name() const +string_t achievement_unlocked_notification_event_args::name() const { return Utils::StringTFromUtf8(m_achievementUnlock.achievementName); } -const string_t achievement_unlocked_notification_event_args::id() const +string_t achievement_unlocked_notification_event_args::id() const { return Utils::StringTFromUtf8(m_achievementUnlock.achievementId); } -const string_t& achievement_unlocked_notification_event_args::description() const +string_t achievement_unlocked_notification_event_args::description() const { return Utils::StringTFromUtf8(m_achievementUnlock.achievementDescription); } -const string_t& achievement_unlocked_notification_event_args::icon_url() const +string_t achievement_unlocked_notification_event_args::icon_url() const { return Utils::StringTFromUtf8(m_achievementUnlock.achievementIcon); } -const uint64_t achievement_unlocked_notification_event_args::gamerscore() const +uint64_t achievement_unlocked_notification_event_args::gamerscore() const { return m_achievementUnlock.gamerscore; } -const string_t& achievement_unlocked_notification_event_args::deeplink() const +string_t achievement_unlocked_notification_event_args::deeplink() const { return Utils::StringTFromUtf8(m_achievementUnlock.deepLink); } -const string_t& achievement_unlocked_notification_event_args::xbox_user_id() const +string_t achievement_unlocked_notification_event_args::xbox_user_id() const { return Utils::StringTFromUint64(m_achievementUnlock.xboxUserId); } -const utility::datetime& achievement_unlocked_notification_event_args::unlockTime() const +utility::datetime achievement_unlocked_notification_event_args::unlockTime() const { return Utils::DatetimeFromTimeT(m_achievementUnlock.timeUnlocked); } @@ -144,7 +148,6 @@ pplx::task> notification_service::subscribe_to_notificati ) { auto xblContext = m_xblContext; - void* context = m_xblContext; m_inviteHandler = multiplayerInviteHandler; m_achievementUnlockedHandler = achievementUnlockHandler; @@ -158,7 +161,7 @@ pplx::task> notification_service::subscribe_to_notificati auto service = static_cast(context); service->game_invite_handler()(resultInviteArgs); }, - context + shared_from_this().get() ); delete(asyncWrapper); @@ -171,7 +174,7 @@ pplx::task> notification_service::subscribe_to_notificati auto service = static_cast(context); service->achievement_unlock_handler()(achievementUnlockArgs); }, - context + shared_from_this().get() ); return asyncWrapper->Task(S_OK); @@ -200,4 +203,5 @@ pplx::task> notification_service::unsubscribe_from_notifi return asyncWrapper->Task(S_OK); } #endif +#endif NAMESPACE_MICROSOFT_XBOX_SERVICES_NOTIFICATION_CPP_END \ No newline at end of file diff --git a/Include/xsapi-cpp/impl/xbox_live_context.hpp b/Include/xsapi-cpp/impl/xbox_live_context.hpp index 298031e9..07945f3a 100644 --- a/Include/xsapi-cpp/impl/xbox_live_context.hpp +++ b/Include/xsapi-cpp/impl/xbox_live_context.hpp @@ -11,8 +11,9 @@ #include "xsapi-cpp/xbox_live_context.h" #include "xsapi-cpp/events.h" +#if XSAPI_NOTIFICATION_SERVICE #include "xsapi-cpp/notification_service.h" - +#endif NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN xbox_live_context::xbox_live_context(_In_ XblUserHandle user) @@ -21,11 +22,12 @@ xbox_live_context::xbox_live_context(_In_ XblUserHandle user) if (FAILED(hr)) throw std::runtime_error("XblContextCreateHandle failed"); XblSetApiType(XblApiType::XblCPPApi); +#if XSAPI_NOTIFICATION_SERVICE // Unlike the rest of the services, notification_service needs to maintain state // That is because of the differences between C-APIs for subscribing for RTA events // and the C++ subscribe_to_notifications call m_notificationService = std::make_shared(m_handle); - +#endif } xbox_live_context::xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle) @@ -34,10 +36,12 @@ xbox_live_context::xbox_live_context(_In_ XblContextHandle xboxLiveContextHandle if (FAILED(hr)) throw std::runtime_error("XblContextCreateHandle failed"); XblSetApiType(XblApiType::XblCPPApi); +#if XSAPI_NOTIFICATION_SERVICE // Unlike the rest of the services, notification_service needs to maintain state // That is because of the differences between C-APIs for subscribing for RTA events // and the C++ subscribe_to_notifications call m_notificationService = std::make_shared(m_handle); +#endif } xbox_live_context::~xbox_live_context() @@ -52,6 +56,13 @@ XblUserHandle xbox_live_context::user() return userHandle; } +XblContextHandle xbox_live_context::handle() +{ + XblContextHandle contextHandle = nullptr; + XblContextDuplicateHandle(m_handle, &contextHandle); + return contextHandle; +} + string_t xbox_live_context::xbox_live_user_id() { stringstream_t ss; @@ -137,7 +148,7 @@ presence::presence_service xbox_live_context::presence_service() return presence::presence_service(m_handle); } -#if HC_PLATFORM == HC_PLATFORM_WIN32 +#if XSAPI_NOTIFICATION_SERVICE std::shared_ptr xbox_live_context::notification_service() { return m_notificationService; diff --git a/Include/xsapi-cpp/notification_service.h b/Include/xsapi-cpp/notification_service.h index 3141b70b..8ab82e22 100644 --- a/Include/xsapi-cpp/notification_service.h +++ b/Include/xsapi-cpp/notification_service.h @@ -16,12 +16,12 @@ class xbox_live_context; class invite_notification_event_args { public: - inline const string_t& invited_xbox_user_id() const; - inline const string_t& sender_xbox_user_id() const; - inline const string_t& sender_gamertag() const; - inline const string_t& invite_handle_id() const; - inline const string_t& invite_protocol() const; - inline const utility::datetime& expiration() const; + inline string_t invited_xbox_user_id() const; + inline string_t sender_xbox_user_id() const; + inline string_t sender_gamertag() const; + inline string_t invite_handle_id() const; + inline string_t invite_protocol() const; + inline utility::datetime expiration() const; inline const multiplayer::multiplayer_session_reference session_reference() const; /// @@ -36,14 +36,14 @@ class invite_notification_event_args class achievement_unlocked_notification_event_args { public: - inline const string_t& name() const; - inline const string_t id() const; - inline const string_t& description() const; - inline const string_t& icon_url() const; - inline const uint64_t gamerscore() const; - inline const string_t& deeplink() const; - inline const string_t& xbox_user_id() const; - inline const utility::datetime& unlockTime() const; + inline string_t name() const; + inline string_t id() const; + inline string_t description() const; + inline string_t icon_url() const; + inline uint64_t gamerscore() const; + inline string_t deeplink() const; + inline string_t xbox_user_id() const; + inline utility::datetime unlockTime() const; achievement_unlocked_notification_event_args(_In_ const XblAchievementUnlockEvent& achievementUnlockEvent); diff --git a/Include/xsapi-cpp/xbox_live_context.h b/Include/xsapi-cpp/xbox_live_context.h index fbd2bf90..f735b9e6 100644 --- a/Include/xsapi-cpp/xbox_live_context.h +++ b/Include/xsapi-cpp/xbox_live_context.h @@ -17,7 +17,9 @@ #include "xsapi-cpp/matchmaking.h" #include "xsapi-cpp/user_statistics.h" #include "xsapi-cpp/string_verify.h" +#if XSAPI_NOTIFICATION_SERVICE #include "xsapi-cpp/notification_service.h" +#endif NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_BEGIN @@ -45,6 +47,14 @@ class xbox_live_context /// inline XblUserHandle user(); + /// + /// Returns a copy of the associated Xbox Live context handle. + /// + /// + /// It is the caller's responsibility to close the returned handle. + /// + inline XblContextHandle handle(); + /// /// Returns the current user's Xbox Live User ID. /// @@ -126,7 +136,7 @@ class xbox_live_context /// inline presence::presence_service presence_service(); -#if HC_PLATFORM == HC_PLATFORM_WIN32 +#if XSAPI_NOTIFICATION_SERVICE /// /// A service for receiving notifications. /// @@ -151,7 +161,9 @@ class xbox_live_context private: XblContextHandle m_handle = nullptr; +#if XSAPI_NOTIFICATION_SERVICE std::shared_ptr m_notificationService; +#endif }; NAMESPACE_MICROSOFT_XBOX_SERVICES_CPP_END diff --git a/Source/Services/Common/xbox_live_context.cpp b/Source/Services/Common/xbox_live_context.cpp index 31b262fe..86e6602e 100644 --- a/Source/Services/Common/xbox_live_context.cpp +++ b/Source/Services/Common/xbox_live_context.cpp @@ -13,7 +13,9 @@ #include "xbox_live_app_config_internal.h" #include "xbox_live_context_settings_internal.h" #include "title_storage_internal.h" +#if XSAPI_NOTIFICATION_SERVICE #include "notification_internal.h" +#endif using namespace xbox::services; using namespace xbox::services::system; @@ -280,10 +282,12 @@ std::shared_ptr XblContext::PresenceService() return m_presenceService; } +#if XSAPI_NOTIFICATION_SERVICE std::shared_ptr XblContext::NotificationService() { return m_notificationService; } +#endif std::shared_ptr XblContext::MultiplayerActivityService() noexcept { diff --git a/Source/Services/Common/xbox_live_context_internal.h b/Source/Services/Common/xbox_live_context_internal.h index 4594cdaa..c82fa60d 100644 --- a/Source/Services/Common/xbox_live_context_internal.h +++ b/Source/Services/Common/xbox_live_context_internal.h @@ -18,7 +18,9 @@ #include "string_service_internal.h" #include "social_internal.h" #include "multiplayer_activity_internal.h" +#if XSAPI_NOTIFICATION_SERVICE #include "notification_internal.h" +#endif NAMESPACE_MICROSOFT_XBOX_SERVICES_MATCHMAKING_CPP_BEGIN namespace legacy @@ -100,10 +102,12 @@ struct XblContext : public std::enable_shared_from_this, public xbox /// std::shared_ptr PresenceService(); +#if XSAPI_NOTIFICATION_SERVICE /// /// A service used for delivering notifications. /// std::shared_ptr NotificationService(); +#endif /// /// A service for storing data in the cloud. @@ -161,7 +165,7 @@ struct XblContext : public std::enable_shared_from_this, public xbox std::shared_ptr m_notificationService; #elif HC_PLATFORM == HC_PLATFORM_ANDROID || HC_PLATFORM == HC_PLATFORM_IOS std::shared_ptr m_notificationService; -#else +#elif XSAPI_NOTIFICATION_SERVICE std::shared_ptr m_notificationService; #endif diff --git a/Source/Services/Leaderboard/leaderboard_row.cpp b/Source/Services/Leaderboard/leaderboard_row.cpp index 586ed68b..c30f9dbd 100644 --- a/Source/Services/Leaderboard/leaderboard_row.cpp +++ b/Source/Services/Leaderboard/leaderboard_row.cpp @@ -136,7 +136,10 @@ const xsapi_internal_vector& LeaderboardRow::ColumnValues int rank = 0; int globalRank = 0; RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "rank", rank, true)); - RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "globalrank", globalRank, false)); + if (json.IsObject() && json.HasMember("globalrank") && !json["globalrank"].IsNull()) + { + RETURN_HR_IF_FAILED(JsonUtils::ExtractJsonInt(json, "globalrank", globalRank, false)); + } xsapi_internal_vector values; if (json.IsObject() && json.HasMember("value") && !json["value"].IsNull()) { diff --git a/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp b/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp index 8ad6906b..6d47df35 100644 --- a/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp +++ b/Source/Services/MultiplayerActivity/multiplayer_activity_api.cpp @@ -4,10 +4,15 @@ #include "pch.h" #include "xbox_live_context_internal.h" #include "multiplayer_activity_internal.h" +#if XSAPI_NOTIFICATION_SERVICE #include "notification_internal.h" +#endif using namespace xbox::services::multiplayer_activity; + +#if XSAPI_NOTIFICATION_SERVICE using namespace xbox::services::notification; +#endif STDAPI XblMultiplayerActivityUpdateRecentPlayers( _In_ XblContextHandle xblContextHandle, diff --git a/Source/Services/Notification/RTA/notification_subscription.cpp b/Source/Services/Notification/RTA/notification_subscription.cpp index 1a4cffba..62124706 100644 --- a/Source/Services/Notification/RTA/notification_subscription.cpp +++ b/Source/Services/Notification/RTA/notification_subscription.cpp @@ -108,7 +108,7 @@ void NotificationSubscription::OnEvent( } else if (data.HasMember("KickNotification")) { - XalUserGetTokenAndSignatureArgs args; + XalUserGetTokenAndSignatureArgs args{}; args.forceRefresh = true; args.url = "https://xboxlive.com/"; args.method = "GET"; diff --git a/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp b/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp index 17336397..920fc8c4 100644 --- a/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp +++ b/Source/Services/RealTimeActivityManager/real_time_activity_connection.cpp @@ -620,8 +620,10 @@ void Connection::ConnectCompleteHandler(WebsocketResult result) noexcept std::unique_lock lock{ sharedThis->m_lock }; if ((std::chrono::system_clock::now() - sharedThis->m_connectTime).count() >= CONNECTION_TIMEOUT_MS) { + auto socket = sharedThis->m_websocket; + lock.unlock(); // Disconnect so that auto-reconnect logic kicks in - sharedThis->m_websocket->Disconnect(); + socket->Disconnect(); } } }, diff --git a/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp b/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp index 948dd03c..3a94dc0a 100644 --- a/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp +++ b/Tests/ApiExplorer/APIs/apis_xblc_leaderboard.cpp @@ -96,6 +96,7 @@ int XblLeaderboardGetLeaderboardAsync_Lua(lua_State *L) for (auto column = 0u; column < leaderboard->rows[row].columnValuesCount; ++column) { + // Each column value is in JSON format rowText << leaderboard->rows[row].columnValues[column] << "\t"; } LogToFile(rowText.str().data()); // CODE SNIP SKIP diff --git a/Tests/ApiExplorer/Shared/mem_hook.cpp b/Tests/ApiExplorer/Shared/mem_hook.cpp index 35b892f5..2b44ae7b 100644 --- a/Tests/ApiExplorer/Shared/mem_hook.cpp +++ b/Tests/ApiExplorer/Shared/mem_hook.cpp @@ -5,7 +5,7 @@ #define TRACK_UNHOOKED_ALLOCS 1 -#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK +#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX) #include #include #include @@ -382,7 +382,7 @@ void ApiRunerMemHook::LogUnhookedStats() bool ApiRunerMemHook::IsStackInXSAPI(StackInfo& stackInfo) { -#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK +#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX) GetStackTrace(stackInfo); bool foundInXsapi = false; @@ -420,7 +420,7 @@ bool ApiRunerMemHook::IsStackInXSAPI(StackInfo& stackInfo) void ApiRunerMemHook::GetStackTrace(StackInfo &stackInfo) { -#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK +#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX) void* stack[TRACE_MAX_STACK_FRAMES] = { 0 }; WORD numberOfFrames = CaptureStackBackTrace(0, TRACE_MAX_STACK_FRAMES, stack, NULL); stackInfo.stackSize = numberOfFrames < 64 ? numberOfFrames : 64; @@ -459,7 +459,7 @@ void ApiRunerMemHook::GetStackTrace(StackInfo &stackInfo) #endif } -#if HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK +#if HC_PLATFORM == HC_PLATFORM_WIN32 || (HC_PLATFORM == HC_PLATFORM_GDK && !_GAMING_XBOX) bool ApiRunerMemHook::IsStackFramesInsideTestCode(StackInfo* pStackInfo) { for (int i = 0; i < pStackInfo->stackSize; i++)