the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1//
2// Class to handle and manage integration with social networks.
3// 4J Studios Ltd, 2011.
4// Andy West
5//
6
7
8#include "stdafx.h"
9#include "SocialManager.h"
10#include <assert.h>
11#include <xgraphics.h>
12#include "..\Sentient\SentientManager.h"
13
14///////////////////////////////////////////////////////////////////////////
15// Constants.
16///////////////////////////////////////////////////////////////////////////
17
18// Table of SDK IDs for the social networks.
19static const DWORD kaSocialNetworkIDS[ eNumSocialNetworks ] =
20{
21 2, // eFacebook
22};
23
24// WESTY : Not sure if we even need to get social access key!
25/*
26// Table of social network permissions that we will required to post.
27static const LPCWSTR kaSocialNetworkRequiredPermissions[ eNumSocialNetworks ] =
28{
29 L"publish_stream", // eFacebook
30};
31
32
33// Default size to use for social network access key text.
34static const DWORD kDefaultAccessKeyTextSize = 64;
35*/
36
37
38///////////////////////////////////////////////////////////////////////////
39// Static members intialisation.
40///////////////////////////////////////////////////////////////////////////
41
42// Initialise static instance pointer.
43CSocialManager* CSocialManager::m_pInstance = 0;
44
45
46
47
48///////////////////////////////////////////////////////////////////////////
49// Class functions.
50///////////////////////////////////////////////////////////////////////////
51
52// Get singleton instance.
53CSocialManager* CSocialManager::Instance()
54{
55 if ( m_pInstance == 0 ) // Is this the first time?
56 {
57 m_pInstance = new CSocialManager; // Create the singleton instance.
58 }
59 return m_pInstance;
60}
61
62// Default constructor.
63CSocialManager::CSocialManager()
64{
65 m_eCurrState = eStateUnitialised;
66 m_dwSocialPostingCapability = 0;
67
68// WESTY : Not sure if we even need to get social access key!
69/*
70 m_pAccessKeyText = NULL;
71 m_dwAccessKeyTextSize = 0;
72*/
73
74 m_pMainImageBuffer = NULL;
75 m_dwMainImageBufferSize = 0;
76
77 m_PostPreviewImage.pBytes = NULL;
78 m_dwCurrRequestUser = -1;
79
80 ZeroMemory(m_wchTitleA,sizeof(WCHAR)*MAX_SOCIALPOST_CAPTION);
81 ZeroMemory(m_wchCaptionA,sizeof(WCHAR)*MAX_SOCIALPOST_CAPTION);
82 ZeroMemory(m_wchDescA,sizeof(WCHAR)*MAX_SOCIALPOST_DESC);
83
84}
85
86
87// To be called once during game init.
88void CSocialManager::Initialise()
89{
90 assert( m_eCurrState == eStateUnitialised );
91 m_eCurrState = eStateReady;
92
93}
94
95
96void CSocialManager::Tick()
97{
98 switch( m_eCurrState )
99 {
100 case eStateUnitialised:
101 // Nothing to do.
102 break;
103
104 case eStateReady:
105 // Nothing to do.
106 break;
107
108 case eStateGetPostingCapability:
109 {
110 // Poll for result.
111 DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false );
112
113 switch( dwResult )
114 {
115 case ERROR_SUCCESS:
116 app.DebugPrintf( "XSocialGetCapabilities - SUCCESS - FLAGS = %d\n", m_dwSocialPostingCapability );
117 m_eCurrState = eStateReady;
118 break;
119
120 case ERROR_IO_INCOMPLETE:
121 // Still on going.
122 break;
123
124 default:
125 // Some kind of error occured.
126 app.DebugPrintf( "XSocialGetCapabilities - FAILED\n", m_dwSocialPostingCapability );
127 // WESTY: TO DO: Get error code, and possibly extened error code to figure out what went wrong.
128 //assert( false );
129 m_eCurrState = eStateReady;
130 break;
131 }
132 }
133 break;
134
135
136 case eStatePostingImage:
137 {
138 // Poll for result.
139 DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false );
140
141 switch( dwResult )
142 {
143 case ERROR_SUCCESS:
144 TelemetryManager->RecordMediaShareUpload(m_dwCurrRequestUser, ESen_MediaDestination_Facebook, eSen_MediaType_Picture);
145
146 app.DebugPrintf( "Facebook image post success!!!\n" );
147 DestroyMainPostImage();
148 DestroyPreviewPostImage();
149
150 // Award for successful post.
151 ProfileManager.Award( m_dwCurrRequestUser, eAward_socialPost );
152
153 m_eCurrState = eStateReady;
154 break;
155
156 case ERROR_IO_INCOMPLETE:
157 // Still on going.
158 break;
159
160 default:
161 // For some reason, the operation did not complete.
162 // SDK docs give no indication why this may be, but could be user cancelled the operation.
163 app.DebugPrintf( "Facebook image post failure!!!\n" );
164 DestroyMainPostImage();
165 DestroyPreviewPostImage();
166 m_eCurrState = eStateReady;
167 break;
168 }
169 }
170 break;
171
172 case eStatePostingLink:
173 {
174 // Poll for result.
175 DWORD dwResult = XGetOverlappedResult( &( m_Overlapped ), &( m_dwOverlappedResultCode ), false );
176
177 switch( dwResult )
178 {
179 case ERROR_SUCCESS:
180 app.DebugPrintf( "Facebook link post success!!!\n" );
181
182 // Award for successful post.
183 ProfileManager.Award( m_dwCurrRequestUser, eAward_socialPost );
184
185 m_eCurrState = eStateReady;
186 break;
187
188 case ERROR_IO_INCOMPLETE:
189 // Still on going.
190 break;
191
192 default:
193 // For some reason, the operation did not complete.
194 // SDK docs give no indication why this may be, but could be user cancelled the operation.
195 app.DebugPrintf( "Facebook link post failure!!!\n" );
196 m_eCurrState = eStateReady;
197 break;
198 }
199 }
200 break;
201
202 default:
203 // Unhandled state!
204 assert( false );
205 break;
206 }
207}
208
209
210// Find out if we are allowed to post to social networks.
211bool CSocialManager::RefreshPostingCapability()
212{
213 bool bResult = false;
214
215 if ( m_eCurrState != eStateReady )
216 {
217 return bResult;
218 }
219
220 // Test for titles ability to post to social networks.
221
222 // Test for titles ability to post to social networks.
223
224 XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) );
225
226 DWORD dwResult = XSocialGetCapabilities( &( m_dwSocialPostingCapability ), &( m_Overlapped ) );
227
228 switch( dwResult )
229 {
230 case ERROR_IO_PENDING:
231 bResult = true;
232 m_eCurrState = eStateGetPostingCapability;
233 break;
234
235 case ERROR_FUNCTION_FAILED:
236 {
237 // Hmm ... why would it fail, and what are we meant to do about it?
238 DWORD dwExtendedError = XGetOverlappedExtendedError( &( m_Overlapped ) );
239 app.DebugPrintf( "XSocialGetCapabilities ASYNC : FAILED : Extended Error %d\n", dwExtendedError );
240 //assert( false );
241 }
242 break;
243
244 default:
245 {
246 // Should never get in here.
247 DWORD dwExtendedError = XGetOverlappedExtendedError( &( m_Overlapped ) );
248 app.DebugPrintf( "XSocialGetCapabilities ASYNC : FAILED : Extended Error %d\n", dwExtendedError );
249 //assert( false );
250 }
251 break;
252 }
253
254 return bResult;
255}
256
257
258
259bool CSocialManager::IsTitleAllowedToPostAnything()
260{
261 assert( m_eCurrState != eStateUnitialised );
262
263 return( m_dwSocialPostingCapability != 0 );
264}
265
266
267bool CSocialManager::IsTitleAllowedToPostImages()
268{
269 assert( m_eCurrState != eStateUnitialised );
270
271 return( ( m_dwSocialPostingCapability & XSOCIAL_CAPABILITY_POSTIMAGE ) != 0 );
272}
273
274
275bool CSocialManager::IsTitleAllowedToPostLinks()
276{
277 assert( m_eCurrState != eStateUnitialised );
278
279 return( ( m_dwSocialPostingCapability & XSOCIAL_CAPABILITY_POSTLINK ) != 0 );
280}
281
282bool CSocialManager::AreAllUsersAllowedToPostImages()
283{
284 // catch no user being signed in to LIVE here too (or a local disconnect)
285 BOOL bUserAllowedToPost=FALSE;
286
287 for(int i=0;i<XUSER_MAX_COUNT;i++)
288 {
289 if(ProfileManager.IsSignedInLive(i))
290 {
291 XUserCheckPrivilege(i,XPRIVILEGE_SOCIAL_NETWORK_SHARING ,&bUserAllowedToPost);
292 if(bUserAllowedToPost==FALSE)
293 {
294 return false;
295 }
296 }
297 }
298 return bUserAllowedToPost?true:false;
299}
300
301
302
303// Ensure this is only done after posting is complete.
304void CSocialManager::DestroyMainPostImage()
305{
306 delete [] m_PostImageParams.pFullImage;
307 m_PostImageParams.pFullImage=NULL;
308 m_dwMainImageBufferSize=0;
309 }
310
311void CSocialManager::DestroyPreviewPostImage()
312{
313 XPhysicalFree( (void *)m_PostPreviewImage.pBytes );
314 m_PostPreviewImage.pBytes = NULL;
315}
316
317void CSocialManager::SetSocialPostText(LPCWSTR pwchTitle, LPCWSTR pwchCaption, LPCWSTR pwchDesc)
318{
319 wstring wTemp;
320
321 ZeroMemory(m_wchTitleA,sizeof(WCHAR)*(MAX_SOCIALPOST_CAPTION+1));
322 ZeroMemory(m_wchCaptionA,sizeof(WCHAR)*(MAX_SOCIALPOST_CAPTION+1));
323 ZeroMemory(m_wchDescA,sizeof(WCHAR)*(MAX_SOCIALPOST_DESC+1));
324 wTemp = pwchTitle;
325 memcpy(m_wchTitleA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR));
326 wTemp = pwchCaption;
327 memcpy(m_wchCaptionA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR));
328 wTemp = pwchDesc;
329 memcpy(m_wchDescA,wTemp.c_str(),wTemp.length()*sizeof(WCHAR));
330}
331
332bool CSocialManager::PostLinkToSocialNetwork( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect )
333{
334 if ( m_eCurrState != eStateReady )
335 {
336 return false;
337 }
338
339 // Ensure title is actually allowed to post links ... should always be the case, but we have to check for TCR.
340 if ( IsTitleAllowedToPostLinks() == false )
341 {
342 //assert( false );
343 return false;
344 }
345
346 // Ensure dwUserIndex is sensible.
347 if ( dwUserIndex > 3 )
348 {
349 //assert( false );
350 return false;
351 }
352
353 // Store user index for award on successful post.
354 m_dwCurrRequestUser = dwUserIndex;
355
356 // Required for kinect only.
357 DWORD dwUserTrackingIndex = 0;
358 if ( bUsingKinect )
359 {
360 // WESTY - Will need a method to get this.
361 dwUserTrackingIndex = 0;
362 }
363
364 bool bResult = false;
365
366// CreatePreviewImage();
367
368 // SDK social post flags....
369 // XSOCIAL_POST_USERGENERATEDCONTENT
370 // XSOCIAL_POST_KINECTCONTENT
371 // XSOCIAL_POST_GAMECONTENT
372 // XSOCIAL_POST_ACHIEVEMENTCONTENT
373 // XSOCIAL_POST_MEDIACONTENT
374
375 // 4J Stu - MessageText is not a member of the struct in the header of the latest XDK 20871.6
376 // The documentation hasn't changed though...
377 //m_PostLinkParams.MessageText = L"This is a test link post.";
378 m_PostLinkParams.TitleText = L"Test Title";
379 m_PostLinkParams.TitleURL = L"http:\\www.4jstudios.com";
380 m_PostLinkParams.PictureCaption = L"Test Picture Caption";
381 m_PostLinkParams.PictureDescription = L"Test Picture Description";
382 m_PostLinkParams.PictureURL = L"http:\\www.4jstudios.com";
383 m_PostLinkParams.PreviewImage = m_PostPreviewImage;
384 m_PostLinkParams.Flags = ( XSOCIAL_POST_GAMECONTENT | XSOCIAL_POST_USERGENERATEDCONTENT ); // WESTY: Need to set correct flags for content type.
385 m_PostLinkParams.Size = sizeof( m_PostLinkParams );
386
387
388 // BEGIN: Asyncronous function call version
389 DWORD dwResult;
390
391 XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) );
392
393 if ( bUsingKinect )
394 {
395 dwResult = XShowNuiSocialNetworkLinkPostUI( dwUserTrackingIndex, dwUserIndex, &( m_PostLinkParams ), &( m_Overlapped ) );
396 }
397 else // using normal controller UI
398 {
399 dwResult = XShowSocialNetworkLinkPostUI( dwUserIndex, &( m_PostLinkParams ), &( m_Overlapped ) );
400 }
401
402 switch( dwResult )
403 {
404 case ERROR_IO_PENDING:
405 bResult = true;
406 m_eCurrState = eStatePostingLink;
407 break;
408
409 case ERROR_FUNCTION_FAILED:
410 // Hmm ... why would it fail, and what are we meant to do about it? Get extended error code!?
411 DestroyMainPostImage();
412 DestroyPreviewPostImage();
413 //assert( false );
414 break;
415
416 default:
417 // Should never get in here.
418 DestroyMainPostImage();
419 DestroyPreviewPostImage();
420 assert( false );
421 break;
422 }
423 // END: Asyncronous function call version
424
425 return bResult;
426}
427
428bool CSocialManager::PostImageToSocialNetwork( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect )
429{
430 if ( m_eCurrState != eStateReady )
431 {
432 return false;
433 }
434
435 // Ensure title is actually allowed to post images ... should always be the case, but we have to check for TCR.
436 if ( IsTitleAllowedToPostImages() == false )
437 {
438 //assert( false );
439 return false;
440 }
441
442 // Ensure dwUserIndex is sensible.
443 if ( dwUserIndex > 3 )
444 {
445 //assert( false );
446 return false;
447 }
448
449 // Store user index for award on successful post.
450 m_dwCurrRequestUser = dwUserIndex;
451
452 // Required for kinect only.
453 DWORD dwUserTrackingIndex = 0;
454 if ( bUsingKinect )
455 {
456 // WESTY - Will need a method to get this.
457 dwUserTrackingIndex = 0;
458 }
459
460 bool bResult = false;
461
462 PBYTE pbData=NULL;
463 DWORD dwDataSize;
464
465 app.GetScreenshot(dwUserIndex,&pbData,&dwDataSize);
466 app.GetPreviewImage(dwUserIndex,&m_PostPreviewImage);
467
468 // SDK social post flags....
469 // XSOCIAL_POST_USERGENERATEDCONTENT
470 // XSOCIAL_POST_KINECTCONTENT
471 // XSOCIAL_POST_GAMECONTENT
472 // XSOCIAL_POST_ACHIEVEMENTCONTENT
473 // XSOCIAL_POST_MEDIACONTENT
474
475 // 4J Stu - MessageText is not a member of the struct in the header of the latest XDK 20871.6
476 // The documentation hasn't changed though...
477 //m_PostImageParams.MessageText = L"This is a test image post.";
478 m_PostImageParams.TitleText = m_wchTitleA;
479 m_PostImageParams.PictureCaption = m_wchCaptionA;
480 m_PostImageParams.PictureDescription = m_wchDescA;
481 m_PostImageParams.PreviewImage = m_PostPreviewImage;
482 m_PostImageParams.Flags = ( XSOCIAL_POST_GAMECONTENT | XSOCIAL_POST_USERGENERATEDCONTENT ); // WESTY: Need to set correct flags for content type.
483 m_PostImageParams.pFullImage = pbData;//m_pMainImageBuffer;
484 m_PostImageParams.FullImageByteCount = dwDataSize;//m_dwMainImageBufferSize;
485 m_PostImageParams.Size = sizeof( m_PostImageParams );
486
487 // BEGIN: Asyncronous function call version
488 DWORD dwResult;
489
490 XMemSet( &m_Overlapped, 0, sizeof(XOVERLAPPED) );
491
492 if ( bUsingKinect )
493 {
494 dwResult = XShowNuiSocialNetworkImagePostUI( dwUserTrackingIndex, dwUserIndex, &( m_PostImageParams ), &( m_Overlapped ) );
495 }
496 else // using normal controller UI
497 {
498 dwResult = XShowSocialNetworkImagePostUI( dwUserIndex, &( m_PostImageParams ), &( m_Overlapped ) );
499 }
500
501 switch( dwResult )
502 {
503 case ERROR_IO_PENDING:
504 bResult = true;
505 m_eCurrState = eStatePostingImage;
506 break;
507
508 case ERROR_FUNCTION_FAILED:
509 // Hmm ... why would it fail, and what are we meant to do about it? Get extended error code!?
510 DestroyMainPostImage();
511 DestroyPreviewPostImage();
512 //assert( false );
513 break;
514
515 default:
516 // Should never get in here.
517 DestroyMainPostImage();
518 DestroyPreviewPostImage();
519 assert( false );
520 break;
521 }
522 // END: Asyncronous function call version
523
524
525 return bResult;
526}
527
528// WESTY : Not sure if we even need to get social access key!
529/*
530// It is unclear from the sdk docs what this is actually used for.
531// So far we have only created a syncronous version of this function, and the xbox functionality does not seem to work yet!
532bool CSocialManager::GetSocialNetworkAccessKey( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect, DWORD dwUserTrackingIndex, bool bShowNetworkSignin )
533{
534 bool bReturn = false;
535
536 DWORD dwResult;
537
538 // Ensure that we free any previously used access key buffer.
539 if ( m_pAccessKeyText != NULL )
540 {
541 delete [] m_pAccessKeyText;
542 m_pAccessKeyText = NULL;
543 }
544
545 // Get social network ID and permissions.
546 DWORD dwSocialNetworkID = kaSocialNetworkIDS[ eSocialNetwork ];
547 LPCWSTR pRequiredPermissions = kaSocialNetworkRequiredPermissions[ eSocialNetwork ];
548
549 // Allocate buffer for social network access key text.
550 m_dwAccessKeyTextSize = kDefaultAccessKeyTextSize;
551 m_pAccessKeyText = new wchar_t [ m_dwAccessKeyTextSize ];
552
553 if ( bShowNetworkSignin )
554 {
555 if ( bUsingKinect )
556 {
557 dwResult = XShowNuiSocialGetUserToken( dwUserTrackingIndex, dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
558
559 // If buffer for key text was not large enough, reallocate buffer that is large enough and try again.
560 if ( dwResult == ERROR_INSUFFICIENT_BUFFER )
561 {
562 delete [] m_pAccessKeyText;
563 m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ];
564 dwResult = XShowNuiSocialGetUserToken( dwUserTrackingIndex, dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
565 }
566 }
567 else // using standard controller interface.
568 {
569 dwResult = XShowSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
570
571 // If buffer for key text was not large enough, reallocate buffer that is large enough and try again.
572 if ( dwResult == ERROR_INSUFFICIENT_BUFFER )
573 {
574 delete [] m_pAccessKeyText;
575 m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ];
576 dwResult = XShowSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
577 }
578 }
579 }
580 else // we are trying to obtain cached user access key.
581 {
582 dwResult = XSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
583
584 // If buffer for key text was not large enough, reallocate buffer that is large enough and try again.
585 if ( dwResult == ERROR_INSUFFICIENT_BUFFER )
586 {
587 delete [] m_pAccessKeyText;
588 m_pAccessKeyText = new wchar_t[ m_dwAccessKeyTextSize ];
589 dwResult = XSocialGetUserToken( dwUserIndex, dwSocialNetworkID, pRequiredPermissions, m_pAccessKeyText, &( m_dwAccessKeyTextSize ), NULL );
590 }
591 }
592
593 // Check result.
594 if ( dwResult != ERROR_SUCCESS )
595 {
596 switch( dwResult )
597 {
598 // ERROR_OUT_MEMORY does not seem to exist, despite being mentioned in the XDK docs.
599 //case ERROR_OUT_MEMORY:
600 // // Not much we can do about this?!
601 // assert( false );
602 // break;
603
604 case ERROR_INVALID_PARAMETER:
605 // dwUserIndex or dwSocialNetworkID are incorrect!
606 assert( false );
607 break;
608
609 case ERROR_ACCESS_DENIED:
610 // Either no user is signed in, or title not allowed to use social posting (the latter should never occur!).
611 break;
612
613 case ERROR_FUNCTION_FAILED:
614 // dwTrackingID is not valid. Kinect only. Not sure what we would do about this one?
615 assert( false );
616 break;
617
618 case ERROR_INSUFFICIENT_BUFFER:
619 // This should not be possible, we already resized the buffer and retried if it was too small.
620 assert( false );
621 break;
622
623 case ERROR_GRACEFUL_DISCONNECT:
624 // User disconnected before process was complete.
625 break;
626
627 case ERROR_CANCELLED:
628 // User cancelled the request.
629 break;
630
631 case ERROR_BAD_NET_RESP:
632 // Error in access, or some kind of network related error.
633 // Need to display warning??
634 assert( false );
635 break;
636
637 default:
638 // Should never get here.
639 assert( false );
640 break;
641 }
642 }
643 else // success
644 {
645 bReturn = true;
646 }
647
648 return bReturn;
649}
650*/
651
652// WESTY : Not sure if we even need to get social access key!
653/*
654
655// It is unclear from the sdk docs what this is actually used for.
656// So far we have only created a syncronous version of this function, and the xbox functionality does not seem to work yet!
657bool CSocialManager::ObtainSocialNetworkAccessKey( ESocialNetwork eSocialNetwork, DWORD dwUserIndex, bool bUsingKinect )
658{
659 if ( m_eCurrState != eStateReady )
660 {
661 return false;
662 }
663
664 // Ensure dwUserIndex is sensible.
665 if ( dwUserIndex > 3 )
666 {
667 assert( false );
668 return false;
669 }
670
671 // Kinect user tracking index.
672 DWORD dwUserTrackingIndex = 0;
673 if ( bUsingKinect )
674 {
675 // WESTY - Will need a method to get this.
676 dwUserTrackingIndex = 0;
677 }
678
679 // Try first of all to obtain cached user key.
680 bool bSocialNetworkAccessKeyAvailable = GetSocialNetworkAccessKey( eSocialNetwork, dwUserIndex, bUsingKinect, dwUserTrackingIndex, false );
681
682 if ( bSocialNetworkAccessKeyAvailable == false )
683 {
684 // No chached user key, so we will try the UI version to signin to social network?
685 bSocialNetworkAccessKeyAvailable = GetSocialNetworkAccessKey( eSocialNetwork, dwUserIndex, bUsingKinect, dwUserTrackingIndex, true );
686 }
687
688 return bSocialNetworkAccessKeyAvailable;
689}
690*/