diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Xbox/Social/SocialManager.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Xbox/Social/SocialManager.cpp')
| -rw-r--r-- | Minecraft.Client/Xbox/Social/SocialManager.cpp | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/Minecraft.Client/Xbox/Social/SocialManager.cpp b/Minecraft.Client/Xbox/Social/SocialManager.cpp new file mode 100644 index 00000000..b7a108bc --- /dev/null +++ b/Minecraft.Client/Xbox/Social/SocialManager.cpp @@ -0,0 +1,690 @@ +// +// Class to handle and manage integration with social networks. +// 4J Studios Ltd, 2011. +// Andy West +// + + +#include "stdafx.h" +#include "SocialManager.h" +#include <assert.h> +#include <xgraphics.h> +#include "..\Sentient\SentientManager.h" + +/////////////////////////////////////////////////////////////////////////// +// Constants. +/////////////////////////////////////////////////////////////////////////// + +// Table of SDK IDs for the social networks. +static const DWORD kaSocialNetworkIDS[ eNumSocialNetworks ] = +{ + 2, // eFacebook +}; + +// WESTY : Not sure if we even need to get social access key! +/* +// Table of social network permissions that we will required to post. +static const LPCWSTR kaSocialNetworkRequiredPermissions[ eNumSocialNetworks ] = +{ + L"publish_stream", // eFacebook +}; + + +// Default size to use for social network access key text. +static const DWORD kDefaultAccessKeyTextSize = 64; +*/ + + +/////////////////////////////////////////////////////////////////////////// +// Static members intialisation. +/////////////////////////////////////////////////////////////////////////// + +// Initialise static instance pointer. +CSocialManager* CSocialManager::m_pInstance = 0; + + + + +/////////////////////////////////////////////////////////////////////////// +// Class functions. +/////////////////////////////////////////////////////////////////////////// + +// Get singleton instance. +CSocialManager* CSocialManager::Instance() +{ + if ( m_pInstance == 0 ) // Is this the first time? + { + m_pInstance = new CSocialManager; // Create the singleton instance. + } + return m_pInstance; +} + +// Default constructor. +CSocialManager::CSocialManager() +{ + m_eCurrState = eStateUnitialised; + m_dwSocialPostingCapability = 0; + +// WESTY : Not sure if we even need to get social access key! +/* + m_pAccessKeyText = NULL; + m_dwAccessKeyTextSize = 0; +*/ + + m_pMainImageBuffer = NULL; + m_dwMainImageBufferSize = 0; + + m_PostPreviewImage.pBytes = NULL; + m_dwCurrRequestUser = -1; + + ZeroMemory(m_wchTitleA,sizeof(WCHAR)*MAX_SOCIALPOST_CAPTION); + ZeroMemory(m_wchCaptionA,sizeof(WCHAR)*MAX_SOCIALPOST_CAPTION); + ZeroMemory(m_wchDescA,sizeof(WCHAR)*MAX_SOCIALPOST_DESC); + +} + + +// To be called once during game init. +void CSocialManager::Initialise() +{ + assert( m_eCurrState == eStateUnitialised ); + m_eCurrState = eStateReady; + +} + + +void CSocialManager::Tick() +{ + switch( m_eCurrState ) + { + case eStateUnitialised: + // Nothing to do. + break; + + case eStateReady: + // Nothing to do. + break; + + case eStateGetPostingCapability: + { + // Poll for result. + DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false ); + + switch( dwResult ) + { + case ERROR_SUCCESS: + app.DebugPrintf( "XSocialGetCapabilities - SUCCESS - FLAGS = %d\n", m_dwSocialPostingCapability ); + m_eCurrState = eStateReady; + break; + + case ERROR_IO_INCOMPLETE: + // Still on going. + break; + + default: + // Some kind of error occured. + app.DebugPrintf( "XSocialGetCapabilities - FAILED\n", m_dwSocialPostingCapability ); + // WESTY: TO DO: Get error code, and possibly extened error code to figure out what went wrong. + //assert( false ); + m_eCurrState = eStateReady; + break; + } + } + break; + + + case eStatePostingImage: + { + // Poll for result. + DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false ); + + switch( dwResult ) + { + case ERROR_SUCCESS: + TelemetryManager->RecordMediaShareUpload(m_dwCurrRequestUser, ESen_MediaDestination_Facebook, eSen_MediaType_Picture); + + app.DebugPrintf( "Facebook image post success!!!\n" ); + DestroyMainPostImage(); + DestroyPreviewPostImage(); + + // Award for successful post. + ProfileManager.Award( m_dwCurrRequestUser, eAward_socialPost ); + + m_eCurrState = eStateReady; + break; + + case ERROR_IO_INCOMPLETE: + // Still on going. + break; + + default: + // For some reason, the operation did not complete. + // SDK docs give no indication why this may be, but could be user cancelled the operation. + app.DebugPrintf( "Facebook image post failure!!!\n" ); + DestroyMainPostImage(); + DestroyPreviewPostImage(); + m_eCurrState = eStateReady; + break; + } + } + break; + + case eStatePostingLink: + { + // Poll for result. + DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false ); + + switch( dwResult ) + { + case ERROR_SUCCESS: + app.DebugPrintf( "Facebook link post success!!!\n" ); + + // Award for successful post. + ProfileManager.Award( m_dwCurrRequestUser, eAward_socialPost ); + + m_eCurrState = eStateReady; + break; + + case ERROR_IO_INCOMPLETE: + // Still on going. + break; + + default: + // For some reason, the operation did not complete. + // SDK docs give no indication why this may be, but could be user cancelled the operation. + app.DebugPrintf( "Facebook link post failure!!!\n" ); + m_eCurrState = eStateReady; + break; + } + } + break; + + default: + // Unhandled state! + assert( false ); + break; + } +} + + +// Find out if we are allowed to post to social networks. +bool CSocialManager::RefreshPostingCapability() +{ + bool bResult = false; + + if ( m_eCurrState != eStateReady ) + { + return bResult; + } + + // Test for titles ability to post to social networks. + + // Test for titles ability to post to social networks. + + XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) ); + + DWORD dwResult = XSocialGetCapabilities( &( m_dwSocialPostingCapability ), &( m_Overlapped ) ); + + switch( dwResult ) + { + case ERROR_IO_PENDING: + bResult = true; + m_eCurrState = eStateGetPostingCapability; + break; + + case ERROR_FUNCTION_FAILED: + { + // Hmm ... why would it fail, and what are we meant to do about it? + DWORD dwExtendedError = XGetOverlappedExtendedError( &( m_Overlapped ) ); + app.DebugPrintf( "XSocialGetCapabilities ASYNC : FAILED : Extended Error %d\n", dwExtendedError ); + //assert( false ); + } + break; + + default: + { + // Should never get in here. + DWORD dwExtendedError = XGetOverlappedExtendedError( &( m_Overlapped ) ); + app.DebugPrintf( "XSocialGetCapabilities ASYNC : FAILED : Extended Error %d\n", dwExtendedError ); + //assert( false ); + } + break; + } + + return bResult; +} + + + +bool CSocialManager::IsTitleAllowedToPostAnything() +{ + assert( m_eCurrState != eStateUnitialised ); + + return( m_dwSocialPostingCapability != 0 ); +} + + +bool CSocialManager::IsTitleAllowedToPostImages() +{ + assert( m_eCurrState != eStateUnitialised ); + + return( ( m_dwSocialPostingCapability & XSOCIAL_CAPABILITY_POSTIMAGE ) != 0 ); +} + + +bool CSocialManager::IsTitleAllowedToPostLinks() +{ + assert( m_eCurrState != eStateUnitialised ); + + return( ( m_dwSocialPostingCapability & XSOCIAL_CAPABILITY_POSTLINK ) != 0 ); +} + +bool CSocialManager::AreAllUsersAllowedToPostImages() +{ + // catch no user being signed in to LIVE here too (or a local disconnect) + BOOL bUserAllowedToPost=FALSE; + + for(int i=0;i<XUSER_MAX_COUNT;i++) + { + if(ProfileManager.IsSignedInLive(i)) + { + XUserCheckPrivilege(i,XPRIVILEGE_SOCIAL_NETWORK_SHARING ,&bUserAllowedToPost); + if(bUserAllowedToPost==FALSE) + { + return false; + } + } + } + return bUserAllowedToPost?true:false; +} + + + +// Ensure this is only done after posting is complete. +void CSocialManager::DestroyMainPostImage() +{ + delete [] m_PostImageParams.pFullImage; + m_PostImageParams.pFullImage=NULL; + m_dwMainImageBufferSize=0; + } + +void CSocialManager::DestroyPreviewPostImage() +{ + XPhysicalFree( (void *)m_PostPreviewImage.pBytes ); + m_PostPreviewImage.pBytes = NULL; +} + +void CSocialManager::SetSocialPostText(LPCWSTR pwchTitle, LPCWSTR pwchCaption, LPCWSTR pwchDesc) +{ + wstring wTemp; + + ZeroMemory(m_wchTitleA,sizeof(WCHAR)*(MAX_SOCIALPOST_CAPTION+1)); + ZeroMemory(m_wchCaptionA,sizeof(WCHAR)*(MAX_SOCIALPOST_CAPTION+1)); + ZeroMemory(m_wchDescA,sizeof(WCHAR)*(MAX_SOCIALPOST_DESC+1)); + wTemp = pwchTitle; + memcpy(m_wchTitleA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR)); + wTemp = pwchCaption; + memcpy(m_wchCaptionA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR)); + wTemp = pwchDesc; + memcpy(m_wchDescA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR)); +} + +bool CSocialManager::PostLinkToSocialNetwork( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect ) +{ + if ( m_eCurrState != eStateReady ) + { + return false; + } + + // Ensure title is actually allowed to post links ... should always be the case, but we have to check for TCR. + if ( IsTitleAllowedToPostLinks() == false ) + { + //assert( false ); + return false; + } + + // Ensure dwUserIndex is sensible. + if ( dwUserIndex > 3 ) + { + //assert( false ); + return false; + } + + // Store user index for award on successful post. + m_dwCurrRequestUser = dwUserIndex; + + // Required for kinect only. + DWORD dwUserTrackingIndex = 0; + if ( bUsingKinect ) + { + // WESTY - Will need a method to get this. + dwUserTrackingIndex = 0; + } + + bool bResult = false; + +// CreatePreviewImage(); + + // SDK social post flags.... + // XSOCIAL_POST_USERGENERATEDCONTENT + // XSOCIAL_POST_KINECTCONTENT + // XSOCIAL_POST_GAMECONTENT + // XSOCIAL_POST_ACHIEVEMENTCONTENT + // XSOCIAL_POST_MEDIACONTENT + + // 4J Stu - MessageText is not a member of the struct in the header of the latest XDK 20871.6 + // The documentation hasn't changed though... + //m_PostLinkParams.MessageText = L"This is a test link post."; + m_PostLinkParams.TitleText = L"Test Title"; + m_PostLinkParams.TitleURL = L"http:\\www.4jstudios.com"; + m_PostLinkParams.PictureCaption = L"Test Picture Caption"; + m_PostLinkParams.PictureDescription = L"Test Picture Description"; + m_PostLinkParams.PictureURL = L"http:\\www.4jstudios.com"; + m_PostLinkParams.PreviewImage = m_PostPreviewImage; + m_PostLinkParams.Flags = ( XSOCIAL_POST_GAMECONTENT | XSOCIAL_POST_USERGENERATEDCONTENT ); // WESTY: Need to set correct flags for content type. + m_PostLinkParams.Size = sizeof( m_PostLinkParams ); + + + // BEGIN: Asyncronous function call version + DWORD dwResult; + + XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) ); + + if ( bUsingKinect ) + { + dwResult = XShowNuiSocialNetworkLinkPostUI( dwUserTrackingIndex, dwUserIndex, &( m_PostLinkParams ), &( m_Overlapped ) ); + } + else // using normal controller UI + { + dwResult = XShowSocialNetworkLinkPostUI( dwUserIndex, &( m_PostLinkParams ), &( m_Overlapped ) ); + } + + switch( dwResult ) + { + case ERROR_IO_PENDING: + bResult = true; + m_eCurrState = eStatePostingLink; + break; + + case ERROR_FUNCTION_FAILED: + // Hmm ... why would it fail, and what are we meant to do about it? Get extended error code!? + DestroyMainPostImage(); + DestroyPreviewPostImage(); + //assert( false ); + break; + + default: + // Should never get in here. + DestroyMainPostImage(); + DestroyPreviewPostImage(); + assert( false ); + break; + } + // END: Asyncronous function call version + + return bResult; +} + +bool CSocialManager::PostImageToSocialNetwork( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect ) +{ + if ( m_eCurrState != eStateReady ) + { + return false; + } + + // Ensure title is actually allowed to post images ... should always be the case, but we have to check for TCR. + if ( IsTitleAllowedToPostImages() == false ) + { + //assert( false ); + return false; + } + + // Ensure dwUserIndex is sensible. + if ( dwUserIndex > 3 ) + { + //assert( false ); + return false; + } + + // Store user index for award on successful post. + m_dwCurrRequestUser = dwUserIndex; + + // Required for kinect only. + DWORD dwUserTrackingIndex = 0; + if ( bUsingKinect ) + { + // WESTY - Will need a method to get this. + dwUserTrackingIndex = 0; + } + + bool bResult = false; + + PBYTE pbData=NULL; + DWORD dwDataSize; + + app.GetScreenshot(dwUserIndex,&pbData,&dwDataSize); + app.GetPreviewImage(dwUserIndex,&m_PostPreviewImage); + + // SDK social post flags.... + // XSOCIAL_POST_USERGENERATEDCONTENT + // XSOCIAL_POST_KINECTCONTENT + // XSOCIAL_POST_GAMECONTENT + // XSOCIAL_POST_ACHIEVEMENTCONTENT + // XSOCIAL_POST_MEDIACONTENT + + // 4J Stu - MessageText is not a member of the struct in the header of the latest XDK 20871.6 + // The documentation hasn't changed though... + //m_PostImageParams.MessageText = L"This is a test image post."; + m_PostImageParams.TitleText = m_wchTitleA; + m_PostImageParams.PictureCaption = m_wchCaptionA; + m_PostImageParams.PictureDescription = m_wchDescA; + m_PostImageParams.PreviewImage = m_PostPreviewImage; + m_PostImageParams.Flags = ( XSOCIAL_POST_GAMECONTENT | XSOCIAL_POST_USERGENERATEDCONTENT ); // WESTY: Need to set correct flags for content type. + m_PostImageParams.pFullImage = pbData;//m_pMainImageBuffer; + m_PostImageParams.FullImageByteCount = dwDataSize;//m_dwMainImageBufferSize; + m_PostImageParams.Size = sizeof( m_PostImageParams ); + + // BEGIN: Asyncronous function call version + DWORD dwResult; + + XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) ); + + if ( bUsingKinect ) + { + dwResult = XShowNuiSocialNetworkImagePostUI( dwUserTrackingIndex, dwUserIndex, &( m_PostImageParams ), &( m_Overlapped ) ); + } + else // using normal controller UI + { + dwResult = XShowSocialNetworkImagePostUI( dwUserIndex, &( m_PostImageParams ), &( m_Overlapped ) ); + } + + switch( dwResult ) + { + case ERROR_IO_PENDING: + bResult = true; + m_eCurrState = eStatePostingImage; + break; + + case ERROR_FUNCTION_FAILED: + // Hmm ... why would it fail, and what are we meant to do about it? Get extended error code!? + DestroyMainPostImage(); + DestroyPreviewPostImage(); + //assert( false ); + break; + + default: + // Should never get in here. + DestroyMainPostImage(); + DestroyPreviewPostImage(); + assert( false ); + break; + } + // END: Asyncronous function call version + + + return bResult; +} + +// WESTY : Not sure if we even need to get social access key! +/* +// It is unclear from the sdk docs what this is actually used for. +// So far we have only created a syncronous version of this function, and the xbox functionality does not seem to work yet! +bool CSocialManager::GetSocialNetworkAccessKey( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect, DWORD dwUserTrackingIndex, bool bShowNetworkSignin ) +{ + bool bReturn = false; + + DWORD dwResult; + + // Ensure that we free any previously used access key buffer. + if ( m_pAccessKeyText != NULL ) + { + delete [] m_pAccessKeyText; + m_pAccessKeyText = NULL; + } + + // Get social network ID and permissions. + DWORD dwSocialNetworkID = kaSocialNetworkIDS[ eSocialNetwork ]; + LPCWSTR pRequiredPermissions = kaSocialNetworkRequiredPermissions[ eSocialNetwork ]; + + // Allocate buffer for social network access key text. + m_dwAccessKeyTextSize = kDefaultAccessKeyTextSize; + m_pAccessKeyText = new wchar_t [ m_dwAccessKeyTextSize ]; + + if ( bShowNetworkSignin ) + { + if ( bUsingKinect ) + { + dwResult = XShowNuiSocialGetUserToken( dwUserTrackingIndex, dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + + // If buffer for key text was not large enough, reallocate buffer that is large enough and try again. + if ( dwResult == ERROR_INSUFFICIENT_BUFFER ) + { + delete [] m_pAccessKeyText; + m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ]; + dwResult = XShowNuiSocialGetUserToken( dwUserTrackingIndex, dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + } + } + else // using standard controller interface. + { + dwResult = XShowSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + + // If buffer for key text was not large enough, reallocate buffer that is large enough and try again. + if ( dwResult == ERROR_INSUFFICIENT_BUFFER ) + { + delete [] m_pAccessKeyText; + m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ]; + dwResult = XShowSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + } + } + } + else // we are trying to obtain cached user access key. + { + dwResult = XSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + + // If buffer for key text was not large enough, reallocate buffer that is large enough and try again. + if ( dwResult == ERROR_INSUFFICIENT_BUFFER ) + { + delete [] m_pAccessKeyText; + m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ]; + dwResult = XSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL ); + } + } + + // Check result. + if ( dwResult != ERROR_SUCCESS ) + { + switch( dwResult ) + { + // ERROR_OUT_MEMORY does not seem to exist, despite being mentioned in the XDK docs. + //case ERROR_OUT_MEMORY: + // // Not much we can do about this?! + // assert( false ); + // break; + + case ERROR_INVALID_PARAMETER: + // dwUserIndex or dwSocialNetworkID are incorrect! + assert( false ); + break; + + case ERROR_ACCESS_DENIED: + // Either no user is signed in, or title not allowed to use social posting (the latter should never occur!). + break; + + case ERROR_FUNCTION_FAILED: + // dwTrackingID is not valid. Kinect only. Not sure what we would do about this one? + assert( false ); + break; + + case ERROR_INSUFFICIENT_BUFFER: + // This should not be possible, we already resized the buffer and retried if it was too small. + assert( false ); + break; + + case ERROR_GRACEFUL_DISCONNECT: + // User disconnected before process was complete. + break; + + case ERROR_CANCELLED: + // User cancelled the request. + break; + + case ERROR_BAD_NET_RESP: + // Error in access, or some kind of network related error. + // Need to display warning?? + assert( false ); + break; + + default: + // Should never get here. + assert( false ); + break; + } + } + else // success + { + bReturn = true; + } + + return bReturn; +} +*/ + +// WESTY : Not sure if we even need to get social access key! +/* + +// It is unclear from the sdk docs what this is actually used for. +// So far we have only created a syncronous version of this function, and the xbox functionality does not seem to work yet! +bool CSocialManager::ObtainSocialNetworkAccessKey( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect ) +{ + if ( m_eCurrState != eStateReady ) + { + return false; + } + + // Ensure dwUserIndex is sensible. + if ( dwUserIndex > 3 ) + { + assert( false ); + return false; + } + + // Kinect user tracking index. + DWORD dwUserTrackingIndex = 0; + if ( bUsingKinect ) + { + // WESTY - Will need a method to get this. + dwUserTrackingIndex = 0; + } + + // Try first of all to obtain cached user key. + bool bSocialNetworkAccessKeyAvailable = GetSocialNetworkAccessKey( eSocialNetwork, dwUserIndex, bUsingKinect, dwUserTrackingIndex, false ); + + if ( bSocialNetworkAccessKeyAvailable == false ) + { + // No chached user key, so we will try the UI version to signin to social network? + bSocialNetworkAccessKeyAvailable = GetSocialNetworkAccessKey( eSocialNetwork, dwUserIndex, bUsingKinect, dwUserTrackingIndex, true ); + } + + return bSocialNetworkAccessKeyAvailable; +} +*/ |
