the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 805 lines 31 kB view raw
1//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 2//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 3//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 4//// PARTICULAR PURPOSE. 5//// 6//// Copyright (c) Microsoft Corporation. All rights reserved 7#include "stdafx.h" 8#include "ChatIntegrationLayer.h" 9#include "DQRNetworkManager.h" 10#include <robuffer.h> 11 12using namespace Windows::Foundation; 13using namespace Windows::Xbox::System; 14 15// To integrate the Chat DLL in your game, you can use this ChatIntegrationLayer class with modifications, 16// or create your own design your own class using the code in this file a guide. 17std::shared_ptr<ChatIntegrationLayer> GetChatIntegrationLayer() 18{ 19 static std::shared_ptr<ChatIntegrationLayer> chatIntegrationLayerInstance; 20 if (chatIntegrationLayerInstance == nullptr) 21 { 22 chatIntegrationLayerInstance.reset( new ChatIntegrationLayer() ); 23 } 24 25 return chatIntegrationLayerInstance; 26} 27 28ChatIntegrationLayer::ChatIntegrationLayer() 29{ 30 ZeroMemory( m_chatVoicePacketsStatistic, sizeof(m_chatVoicePacketsStatistic) ); 31} 32 33void ChatIntegrationLayer::InitializeChatManager( 34 __in bool combineCaptureBuffersIntoSinglePacket, 35 __in bool useKinectAsCaptureSource, 36 __in bool applySoundEffectsToCapturedAudio, 37 __in bool applySoundEffectsToChatRenderedAudio, 38 DQRNetworkManager *pDQRNet 39 ) 40{ 41 m_pDQRNet = pDQRNet; 42 { 43 Concurrency::critical_section::scoped_lock lock(m_chatPacketStatsLock); 44 ZeroMemory( m_chatVoicePacketsStatistic, sizeof(m_chatVoicePacketsStatistic) ); 45 } 46 47 m_chatManager = ref new Microsoft::Xbox::GameChat::ChatManager(); 48 m_chatManager->ChatSettings->DiagnosticsTraceLevel = Microsoft::Xbox::GameChat::GameChatDiagnosticsTraceLevel::Verbose; 49 50 // Optionally, change the default settings below as desired by commenting out and editing any of the following lines 51 // Otherwise these defaults are used. 52 // 53 // m_chatManager = ref new Microsoft::Xbox::GameChat::ChatManager( ChatSessionPeriod::ChatPeriodOf40Milliseconds ); 54 // m_chatManager->ChatSettings->AudioThreadPeriodInMilliseconds = 40; 55 // m_chatManager->ChatSettings->AudioThreadAffinityMask = XAUDIO2_DEFAULT_PROCESSOR; // <- this means is core 5, same as the default XAudio2 core 56 // m_chatManager->ChatSettings->AudioThreadPriority = THREAD_PRIORITY_TIME_CRITICAL; 57 // m_chatManager->ChatSettings->AudioEncodingQuality = Windows::Xbox::Chat::EncodingQuality::Normal; 58 // m_chatManager->ChatSettings->DiagnosticsTraceLevel = Microsoft::Xbox::GameChat::GameChatDiagnosticsTraceLevel::Verbose; 59 m_chatManager->ChatSettings->CombineCaptureBuffersIntoSinglePacket = combineCaptureBuffersIntoSinglePacket; // if unset, it defaults to TRUE 60 m_chatManager->ChatSettings->UseKinectAsCaptureSource = useKinectAsCaptureSource; // if unset, it defaults to FALSE 61 m_chatManager->ChatSettings->PreEncodeCallbackEnabled = applySoundEffectsToCapturedAudio; // if unset, it defaults to FALSE 62 m_chatManager->ChatSettings->PostDecodeCallbackEnabled = applySoundEffectsToChatRenderedAudio; // if unset, it defaults to FALSE 63 64 InitializeCriticalSection(&m_csAddedUsers); 65 66 std::weak_ptr<ChatIntegrationLayer> weakPtrToThis = shared_from_this(); 67 68#ifdef PROFILE 69 m_chatManager->ChatSettings->PerformanceCountersEnabled = true; 70#endif 71 72 // Upon enter constrained mode, mute everyone. 73 // Upon leaving constrained mode, unmute everyone who was previously muted. 74 m_tokenResourceAvailabilityChanged = Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged += 75 ref new EventHandler< Platform::Object^ >( [weakPtrToThis] (Platform::Object^, Platform::Object^ ) 76 { 77 // Using a std::weak_ptr instead of 'this' to avoid dangling pointer if caller class is released. 78 // Simply unregistering the callback in the destructor isn't enough to prevent a dangling pointer 79 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 80 if( sharedPtrToThis != nullptr ) 81 { 82 if (Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Constrained) 83 { 84 if( sharedPtrToThis->m_chatManager != nullptr ) 85 { 86 sharedPtrToThis->m_chatManager->MuteAllUsersFromAllChannels(); 87 } 88 } 89 else if(Windows::ApplicationModel::Core::CoreApplication::ResourceAvailability == Windows::ApplicationModel::Core::ResourceAvailability::Full) 90 { 91 if( sharedPtrToThis->m_chatManager != nullptr ) 92 { 93 sharedPtrToThis->m_chatManager->UnmuteAllUsersFromAllChannels(); 94 95 // The title should remember who was muted so when the Resume even occurs 96 // to avoid unmuting users who has been previously muted. Simply re-mute them here 97 } 98 } 99 } 100 }); 101 102 m_tokenOnDebugMessage = m_chatManager->OnDebugMessage += 103 ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::DebugMessageEventArgs^>( 104 [weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args ) 105 { 106 // Using a std::weak_ptr instead of 'this' to avoid dangling pointer if caller class is released. 107 // Simply unregistering the callback in the destructor isn't enough to prevent a dangling pointer 108 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 109 if( sharedPtrToThis != nullptr ) 110 { 111 sharedPtrToThis->OnDebugMessageReceived(args); 112 } 113 }); 114 115 m_tokenOnOutgoingChatPacketReady = m_chatManager->OnOutgoingChatPacketReady += 116 ref new Windows::Foundation::EventHandler<Microsoft::Xbox::GameChat::ChatPacketEventArgs^>( 117 [weakPtrToThis] ( Platform::Object^, Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args ) 118 { 119 // Using a std::weak_ptr instead of 'this' to avoid dangling pointer if caller class is released. 120 // Simply unregistering the callback in the destructor isn't enough to prevent a dangling pointer 121 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 122 if( sharedPtrToThis != nullptr ) 123 { 124 sharedPtrToThis->OnOutgoingChatPacketReady(args); 125 } 126 }); 127 128 m_tokenOnCompareUniqueConsoleIdentifiers = m_chatManager->OnCompareUniqueConsoleIdentifiers += 129 ref new Microsoft::Xbox::GameChat::CompareUniqueConsoleIdentifiersHandler( 130 [weakPtrToThis] ( Platform::Object^ obj1, Platform::Object^ obj2 ) 131 { 132 // Using a std::weak_ptr instead of 'this' to avoid dangling pointer if caller class is released. 133 // Simply unregistering the callback in the destructor isn't enough to prevent a dangling pointer 134 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 135 if( sharedPtrToThis != nullptr ) 136 { 137 return sharedPtrToThis->CompareUniqueConsoleIdentifiers(obj1, obj2); 138 } 139 else 140 { 141 return false; 142 } 143 }); 144 145 m_tokenUserAudioDeviceAdded = WXS::User::AudioDeviceAdded += 146 ref new Windows::Foundation::EventHandler<WXS::AudioDeviceAddedEventArgs^>( 147 [weakPtrToThis] ( Platform::Object^, WXS::AudioDeviceAddedEventArgs^ value ) 148 { 149 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 150 if( sharedPtrToThis != nullptr ) 151 { 152 sharedPtrToThis->EvaluateDevicesForUser(value->User); 153 } 154 }); 155 156 m_tokenUserAudioDeviceRemoved = WXS::User::AudioDeviceRemoved += 157 ref new Windows::Foundation::EventHandler<WXS::AudioDeviceRemovedEventArgs^>( 158 [weakPtrToThis] ( Platform::Object^, WXS::AudioDeviceRemovedEventArgs^ value ) 159 { 160 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 161 if( sharedPtrToThis != nullptr ) 162 { 163 sharedPtrToThis->EvaluateDevicesForUser(value->User); 164 } 165 }); 166 167 m_tokenUserAudioDeviceChanged = WXS::User::AudioDeviceChanged += 168 ref new Windows::Foundation::EventHandler<WXS::AudioDeviceChangedEventArgs^>( 169 [weakPtrToThis] ( Platform::Object^, WXS::AudioDeviceChangedEventArgs^ value ) 170 { 171 std::shared_ptr<ChatIntegrationLayer> sharedPtrToThis(weakPtrToThis.lock()); 172 if( sharedPtrToThis != nullptr ) 173 { 174 sharedPtrToThis->EvaluateDevicesForUser(value->User); 175 } 176 }); 177 178 //m_tokenSuspending = Windows::ApplicationModel::Core::CoreApplication::Suspending += 179 // ref new EventHandler< Windows::ApplicationModel::SuspendingEventArgs^ >( [weakPtrToThis] (Platform::Object^, Windows::ApplicationModel::SuspendingEventArgs^ args) 180 //{ 181 // // Upon Suspending, nothing needs to be done 182 //}); 183 184 //m_tokenResuming = Windows::ApplicationModel::Core::CoreApplication::Resuming += 185 // ref new EventHandler< Platform::Object^ >( [weakPtrToThis] (Platform::Object^, Windows::ApplicationModel::SuspendingEventArgs^ args) 186 //{ 187 // // Upon Resuming, re-initialize the network, and reinitialize the chat session 188 //}); 189} 190 191 192void ChatIntegrationLayer::Shutdown() 193{ 194 if( m_chatManager != nullptr ) 195 { 196 m_chatManager->OnDebugMessage -= m_tokenOnDebugMessage; 197 m_chatManager->OnOutgoingChatPacketReady -= m_tokenOnOutgoingChatPacketReady; 198 m_chatManager->OnCompareUniqueConsoleIdentifiers -= m_tokenOnCompareUniqueConsoleIdentifiers; 199 Windows::ApplicationModel::Core::CoreApplication::ResourceAvailabilityChanged -= m_tokenResourceAvailabilityChanged; 200 if( m_chatManager->ChatSettings->PreEncodeCallbackEnabled ) 201 { 202 m_chatManager->OnPreEncodeAudioBuffer -= m_tokenOnPreEncodeAudioBuffer; 203 } 204 if( m_chatManager->ChatSettings->PostDecodeCallbackEnabled ) 205 { 206 m_chatManager->OnPostDecodeAudioBuffer -= m_tokenOnPostDecodeAudioBuffer; 207 } 208 WXS::User::AudioDeviceAdded -= m_tokenUserAudioDeviceAdded; 209 WXS::User::AudioDeviceRemoved -= m_tokenUserAudioDeviceRemoved; 210 WXS::User::AudioDeviceChanged -= m_tokenUserAudioDeviceChanged; 211 212 DeleteCriticalSection(&m_csAddedUsers); 213 214 m_chatManager = nullptr; 215 } 216} 217 218void ChatIntegrationLayer::OnDebugMessageReceived( 219 __in Microsoft::Xbox::GameChat::DebugMessageEventArgs^ args 220 ) 221{ 222 // To integrate the Chat DLL in your game, 223 // change this to false and remove the LogComment calls, 224 // or integrate with your game's own UI/debug message logging system 225 bool outputToUI = false; 226 227 if( outputToUI ) 228 { 229 if (args->ErrorCode == S_OK ) 230 { 231 m_pDQRNet->LogComment(L"GameChat: " + args->Message); 232 } 233 else 234 { 235 m_pDQRNet->LogCommentWithError(L"GameChat: " + args->Message, args->ErrorCode); 236 } 237 } 238 else 239 { 240 // The string appear in the Visual Studio Output window 241#ifndef _CONTENT_PACKAGE 242 OutputDebugString( args->Message->Data() ); 243#endif 244 } 245} 246 247void ChatIntegrationLayer::GameUI_RecordPacketStatistic( 248 __in Microsoft::Xbox::GameChat::ChatMessageType messageType, 249 __in ChatPacketType chatPacketType 250 ) 251{ 252 uint32 messageTypeInt = static_cast<uint32>(messageType); 253 if( messageType > Microsoft::Xbox::GameChat::ChatMessageType::InvalidMessage ) 254 { 255 return; 256 } 257 258 { 259 Concurrency::critical_section::scoped_lock lock(m_chatPacketStatsLock); 260 m_chatVoicePacketsStatistic[static_cast<int>(chatPacketType)][messageTypeInt]++; 261 } 262} 263 264int ChatIntegrationLayer::GameUI_GetPacketStatistic( 265 __in Microsoft::Xbox::GameChat::ChatMessageType messageType, 266 __in ChatPacketType chatPacketType 267 ) 268{ 269 uint32 messageTypeInt = static_cast<uint32>(messageType); 270 if( messageType > Microsoft::Xbox::GameChat::ChatMessageType::InvalidMessage ) 271 { 272 return 0; 273 } 274 275 { 276 Concurrency::critical_section::scoped_lock lock(m_chatPacketStatsLock); 277 return m_chatVoicePacketsStatistic[static_cast<int>(chatPacketType)][messageTypeInt]; 278 } 279} 280 281void ChatIntegrationLayer::OnOutgoingChatPacketReady( 282 __in Microsoft::Xbox::GameChat::ChatPacketEventArgs^ args 283 ) 284{ 285 byte *bytes; 286 int byteCount; 287 288 GetBufferBytes(args->PacketBuffer, &bytes); 289 byteCount = args->PacketBuffer->Length; 290 unsigned int address = 0; 291 if( !args->SendPacketToAllConnectedConsoles ) 292 { 293 address = safe_cast<unsigned int>(args->UniqueTargetConsoleIdentifier); 294 } 295 m_pDQRNet->SendBytesChat(address, bytes, byteCount, args->SendReliable, args->SendInOrder, args->SendPacketToAllConnectedConsoles); 296 297 GameUI_RecordPacketStatistic( args->ChatMessageType, ChatPacketType::OutgoingPacket ); 298 299} 300 301void ChatIntegrationLayer::OnIncomingChatMessage( 302 unsigned int sessionAddress, 303 Platform::Array<byte>^ message 304 ) 305{ 306 // To integrate the Chat DLL in your game, change the following code to use your game's network layer. 307 // Ignore the OnChatMessageReceived event as that is specific to this sample's simple network layer. 308 // Instead your title should upon receiving a packet, extract the chat message from it, and then call m_chatManager->ProcessIncomingChatMessage as shown below 309 // You will need to isolate chat messages to be unique from the rest of you game's other message types. 310 311 // uniqueRemoteConsoleIdentifier is a Platform::Object^ and can be cast or unboxed to most types. 312 // What exactly you use doesn't matter, but optimally it would be something that uniquely identifies a console on in the session. 313 // A Windows::Xbox::Networking::SecureDeviceAssociation^ is perfect to use if you have access to it. 314 315 // This is how you would convert from byte array to a IBuffer^ 316 // 317 // Windows::Storage::Streams::IBuffer^ destBuffer = ref new Windows::Storage::Streams::Buffer( sourceByteBufferSize ); 318 // byte* destBufferBytes = nullptr; 319 // GetBufferBytes( destBuffer, &destBufferBytes ); 320 // errno_t err = memcpy_s( destBufferBytes, destBuffer->Capacity, sourceByteBuffer, sourceByteBufferSize ); 321 // THROW_HR_IF(err != 0, E_FAIL); 322 // destBuffer->Length = sourceByteBufferSize; 323 324 // This is how you would convert from an int to a Platform::Object^ 325 // Platform::Object obj = IntToPlatformObject(5); 326 327 Windows::Storage::Streams::IBuffer^ chatMessage = ArrayToBuffer(message); 328 Platform::Object^ uniqueRemoteConsoleIdentifier = (Platform::Object^)sessionAddress; 329 330 if( m_chatManager != nullptr ) 331 { 332 Microsoft::Xbox::GameChat::ChatMessageType chatMessageType = m_chatManager->ProcessIncomingChatMessage(chatMessage, uniqueRemoteConsoleIdentifier); 333 334 GameUI_RecordPacketStatistic( chatMessageType, ChatPacketType::IncomingPacket ); 335 } 336} 337 338// Only add people who intend to play. 339void ChatIntegrationLayer::AddAllLocallySignedInUsersToChatClient( 340 __in uint8 channelIndex, 341 __in Windows::Foundation::Collections::IVectorView<Windows::Xbox::System::User^>^ locallySignedInUsers 342 ) 343{ 344 // To integrate the Chat DLL in your game, 345 // add all locally signed in users to the chat client 346 for each( Windows::Xbox::System::User^ user in locallySignedInUsers ) 347 { 348 if( user != nullptr ) 349 { 350// LogComment(L"Adding Local User to Chat Client"); 351 AddLocalUserToChatChannel( channelIndex, user ); 352 } 353 } 354} 355 356ChatIntegrationLayer::AddedUser::AddedUser(Windows::Xbox::System::IUser^ user, bool canCaptureAudio) 357{ 358 m_user = user; 359 m_canCaptureAudio = canCaptureAudio; 360} 361 362 363void ChatIntegrationLayer::AddLocalUser( __in Windows::Xbox::System::IUser^ user ) 364{ 365 // Check we haven't added already 366 for( int i = 0; i < m_addedUsers.size(); i++ ) 367 { 368 if( m_addedUsers[i]->m_user->XboxUserId == user->XboxUserId ) 369 { 370 return; 371 } 372 } 373 374 bool kinectAvailable = false; 375 Windows::Kinect::KinectSensor^ sensor = Windows::Kinect::KinectSensor::GetDefault(); 376 if( sensor ) 377 { 378 sensor->Open(); 379 if( sensor->IsAvailable ) 380 { 381 kinectAvailable = true; 382 m_pDQRNet->LogComment(L"Evaluated that kinect is available\n"); 383 } 384 sensor->Close(); 385 } 386 387 EnterCriticalSection(&m_csAddedUsers); 388 // First establish whether we have an appropriate audio device at this time 389 bool canCaptureAudio = false; 390 for each( WXS::IAudioDeviceInfo^ audioDevice in user->AudioDevices ) 391 { 392 m_pDQRNet->LogComment(L"Evaluating device " + audioDevice->DeviceCategory.ToString() + L" " + 393 audioDevice->DeviceType.ToString() + L" " + 394 audioDevice->Id + L" " + 395 audioDevice->Sharing.ToString() + L" " + 396 audioDevice->IsMicrophoneMuted.ToString() + L"\n"); 397 398 // Consider shared devices only if kinect is actually available - every machine seems to claim a shared device whether kinect is attached or not 399 if( ( audioDevice->DeviceType == WXS::AudioDeviceType::Capture ) && ( kinectAvailable || ( audioDevice->Sharing != WXS::AudioDeviceSharing::Shared) ) ) 400 { 401 canCaptureAudio = true; 402 } 403 } 404 405 // If we can capture audio initially, then register with the chat session. Otherwise we'll reevaluate this situation when audio devices change 406 if( canCaptureAudio ) 407 { 408 AddLocalUserToChatChannel( 0 , user ); 409 } 410 411 // Add to vector of users that we are tracking in the chat system 412 m_addedUsers.push_back(new AddedUser(user, canCaptureAudio)); 413 LeaveCriticalSection(&m_csAddedUsers); 414} 415 416// Remove from our list of tracked users, if the user is already there 417void ChatIntegrationLayer::RemoveLocalUser( __in Windows::Xbox::System::IUser^ user ) 418{ 419 EnterCriticalSection(&m_csAddedUsers); 420 for( auto it = m_addedUsers.begin(); it != m_addedUsers.end(); it++ ) 421 { 422 if( (*it)->m_user->XboxUserId == user->XboxUserId ) 423 { 424 delete (*it); 425 m_addedUsers.erase(it); 426 LeaveCriticalSection(&m_csAddedUsers); 427 return; 428 } 429 } 430 LeaveCriticalSection(&m_csAddedUsers); 431} 432 433// This is called when the audio devices for a user change in any way, and establishes whether we can now capture audio. Any change in this status from before will cause the user to be added/removed from the chat session. 434void ChatIntegrationLayer::EvaluateDevicesForUser(__in Windows::Xbox::System::IUser^ user ) 435{ 436 bool kinectAvailable = false; 437 Windows::Kinect::KinectSensor^ sensor = Windows::Kinect::KinectSensor::GetDefault(); 438 if( sensor ) 439 { 440 sensor->Open(); 441 if( sensor->IsAvailable ) 442 { 443 kinectAvailable = true; 444 m_pDQRNet->LogComment(L"Evaluated that kinect is available\n"); 445 } 446 sensor->Close(); 447 } 448 449 EnterCriticalSection(&m_csAddedUsers); 450 for( int i = 0; i < m_addedUsers.size(); i++ ) 451 { 452 AddedUser *addedUser = m_addedUsers[i]; 453 if( addedUser->m_user->XboxUserId == user->XboxUserId ) 454 { 455 bool canCaptureAudio = false; 456 for each( WXS::IAudioDeviceInfo^ audioDevice in addedUser->m_user->AudioDevices ) 457 { 458 // Consider shared devices only if kinect is actually available - every machine seems to claim a shared device whether kinect is attached or not 459 if( ( audioDevice->DeviceType == WXS::AudioDeviceType::Capture ) && ( kinectAvailable || ( audioDevice->Sharing != WXS::AudioDeviceSharing::Shared) ) ) 460 { 461 canCaptureAudio = true; 462 break; 463 } 464 } 465 if( canCaptureAudio != addedUser->m_canCaptureAudio ) 466 { 467 if( canCaptureAudio ) 468 { 469 AddLocalUserToChatChannel(0, addedUser->m_user ); 470 } 471 else 472 { 473 RemoveUserFromChatChannel(0, addedUser->m_user ); 474 } 475 addedUser->m_canCaptureAudio = canCaptureAudio; 476 LeaveCriticalSection(&m_csAddedUsers); 477 return; 478 } 479 } 480 } 481 LeaveCriticalSection(&m_csAddedUsers); 482} 483 484void ChatIntegrationLayer::AddLocalUserToChatChannel( 485 __in uint8 channelIndex, 486 __in Windows::Xbox::System::IUser^ user 487 ) 488{ 489 // Adds a local user to a specific channel. 490 491 // This is helper function waits for the task to cm_chatManageromplete so shouldn't be called from the UI thread 492 // Remove the .wait() and return the result of concurrency::create_task() if you want to call it from the UI thread 493 // and chain PPL tasks together 494 495 m_pDQRNet->LogComment( L">>>>>>>>>>>>> AddLocalUserToChatChannel" ); 496 if( m_chatManager != nullptr ) 497 { 498 auto asyncOp = m_chatManager->AddLocalUserToChatChannelAsync( channelIndex, user ); 499 concurrency::create_task( asyncOp ) 500 .then( [this] ( concurrency::task<void> t ) 501 { 502 // Error handling 503 try 504 { 505 t.get(); 506 } 507 catch ( Platform::Exception^ ex ) 508 { 509 m_pDQRNet->LogCommentWithError( L"AddLocalUserToChatChannelAsync failed", ex->HResult ); 510 } 511 }) 512 .wait(); 513 } 514} 515 516void ChatIntegrationLayer::RemoveRemoteConsole( 517 unsigned int address 518 ) 519{ 520 // uniqueConsoleIdentifier is a Platform::Object^ and can be cast or unboxed to most types. 521 // What exactly you use doesn't matter, but optimally it would be something that uniquely identifies a console on in the session. 522 // A Windows::Xbox::Networking::SecureDeviceAssociation^ is perfect to use if you have access to it. 523 524 // This is how you would convert from an int to a Platform::Object^ 525 // Platform::Object obj = IntToPlatformObject(5); 526 527 // This is helper function waits for the task to complete so shouldn't be called from the UI thread 528 // Remove the .wait() and return the result of concurrency::create_task() if you want to call it from the UI thread 529 // and chain PPL tasks together 530 531 Platform::Object^ uniqueRemoteConsoleIdentifier = (Platform::Object^)address; 532 533 if( m_chatManager != nullptr ) 534 { 535 auto asyncOp = m_chatManager->RemoveRemoteConsoleAsync( uniqueRemoteConsoleIdentifier ); 536 concurrency::create_task( asyncOp ).then( [this] ( concurrency::task<void> t ) 537 { 538 // Error handling 539 try 540 { 541 t.get(); 542 } 543 catch ( Platform::Exception^ ex ) 544 { 545 m_pDQRNet->LogCommentWithError( L"RemoveRemoteConsoleAsync failed", ex->HResult ); 546 } 547 }) 548 .wait(); 549 } 550} 551 552void ChatIntegrationLayer::RemoveUserFromChatChannel( 553 __in uint8 channelIndex, 554 __in Windows::Xbox::System::IUser^ user 555 ) 556{ 557 if( m_chatManager != nullptr ) 558 { 559 // This is helper function waits for the task to complete so shouldn't be called from the UI thread 560 // Remove the .wait() and return the result of concurrency::create_task() if you want to call it from the UI thread 561 // and chain PPL tasks together 562 563 auto asyncOp = m_chatManager->RemoveLocalUserFromChatChannelAsync( channelIndex, user ); 564 concurrency::create_task( asyncOp ).then( [this] ( concurrency::task<void> t ) 565 { 566 // Error handling 567 try 568 { 569 t.get(); 570 } 571 catch ( Platform::Exception^ ex ) 572 { 573 m_pDQRNet->LogCommentWithError( L"RemoveLocalUserFromChatChannelAsync failed", ex->HResult ); 574 } 575 }) 576 .wait(); 577 } 578} 579 580void ChatIntegrationLayer::OnNewSessionAddressAdded( 581 __in unsigned int address 582 ) 583{ 584 m_pDQRNet->LogCommentFormat( L">>>>>>>>>>>>> OnNewSessionAddressAdded (%d)",address ); 585 Platform::Object^ uniqueConsoleIdentifier = (Platform::Object^)address; 586 /// Call this when a new console connects. 587 /// This adds this console to the chat layer 588 if( m_chatManager != nullptr ) 589 { 590 m_chatManager->HandleNewRemoteConsole(uniqueConsoleIdentifier ); 591 } 592} 593 594Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::GameChat::ChatUser^>^ ChatIntegrationLayer::GetChatUsers() 595{ 596 if( m_chatManager != nullptr ) 597 { 598 return m_chatManager->GetChatUsers(); 599 } 600 601 return nullptr; 602} 603 604bool ChatIntegrationLayer::HasMicFocus() 605{ 606 if( m_chatManager != nullptr ) 607 { 608 return m_chatManager->HasMicFocus; 609 } 610 611 return false; 612} 613 614Platform::Object^ ChatIntegrationLayer::IntToPlatformObject( 615 __in int val 616 ) 617{ 618 return (Platform::Object^)val; 619 620 // You can also do the same using a PropertyValue. 621 //return Windows::Foundation::PropertyValue::CreateInt32(val); 622} 623 624int ChatIntegrationLayer::PlatformObjectToInt( 625 __in Platform::Object^ uniqueRemoteConsoleIdentifier 626 ) 627{ 628 return safe_cast<int>( uniqueRemoteConsoleIdentifier ); 629 630 // You can also do the same using a PropertyValue. 631 //return safe_cast<Windows::Foundation::IPropertyValue^>(uniqueRemoteConsoleIdentifier)->GetInt32(); 632} 633 634void ChatIntegrationLayer::HandleChatChannelChanged( 635 __in uint8 oldChatChannelIndex, 636 __in uint8 newChatChannelIndex, 637 __in Microsoft::Xbox::GameChat::ChatUser^ chatUser 638 ) 639{ 640 // We remember if the local user was currently muted from all channels. And when we switch channels, 641 // we ensure that the state persists. For remote users, title should implement this themselves 642 // based on title game design if they want to persist the muting state. 643 644 bool wasUserMuted = false; 645 IUser^ userBeingRemoved = nullptr; 646 647 if (chatUser != nullptr && chatUser->IsLocal) 648 { 649 wasUserMuted = chatUser->IsMuted; 650 userBeingRemoved = chatUser->User; 651 if (userBeingRemoved != nullptr) 652 { 653 RemoveUserFromChatChannel(oldChatChannelIndex, userBeingRemoved); 654 AddLocalUserToChatChannel(newChatChannelIndex, userBeingRemoved); 655 } 656 } 657 658 // If the local user was muted earlier, get the latest chat users and mute him again on the newly added channel. 659 if (wasUserMuted && userBeingRemoved != nullptr) 660 { 661 auto chatUsers = GetChatUsers(); 662 if (chatUsers != nullptr ) 663 { 664 for (UINT chatUserIndex = 0; chatUserIndex < chatUsers->Size; chatUserIndex++) 665 { 666 Microsoft::Xbox::GameChat::ChatUser^ chatUser = chatUsers->GetAt(chatUserIndex); 667 if( chatUser != nullptr && (chatUser->XboxUserId == userBeingRemoved->XboxUserId) ) 668 { 669 m_chatManager->MuteUserFromAllChannels(chatUser); 670 break; 671 } 672 } 673 } 674 } 675} 676 677void ChatIntegrationLayer::ChangeChatUserMuteState( 678 __in Microsoft::Xbox::GameChat::ChatUser^ chatUser 679 ) 680{ 681 /// Helper function to swap the mute state of a specific chat user 682 if( m_chatManager != nullptr && chatUser != nullptr) 683 { 684 if (chatUser->IsMuted) 685 { 686 m_chatManager->UnmuteUserFromAllChannels(chatUser); 687 } 688 else 689 { 690 m_chatManager->MuteUserFromAllChannels(chatUser); 691 } 692 } 693} 694 695Microsoft::Xbox::GameChat::ChatUser^ ChatIntegrationLayer::GetChatUserByXboxUserId( 696 __in Platform::String^ xboxUserId 697 ) 698{ 699 Windows::Foundation::Collections::IVectorView<Microsoft::Xbox::GameChat::ChatUser^>^ chatUsers = GetChatUsers(); 700 for each (Microsoft::Xbox::GameChat::ChatUser^ chatUser in chatUsers) 701 { 702 if (chatUser != nullptr && ( chatUser->XboxUserId == xboxUserId ) ) 703 { 704 return chatUser; 705 } 706 } 707 708 return nullptr; 709} 710 711 712bool ChatIntegrationLayer::CompareUniqueConsoleIdentifiers( 713 __in Platform::Object^ uniqueRemoteConsoleIdentifier1, 714 __in Platform::Object^ uniqueRemoteConsoleIdentifier2 715 ) 716{ 717 if (uniqueRemoteConsoleIdentifier1 == nullptr || uniqueRemoteConsoleIdentifier2 == nullptr) 718 { 719 return false; 720 } 721 722 // uniqueRemoteConsoleIdentifier is a Platform::Object^ and can be cast or unboxed to most types. 723 // We're using XRNS addresses, which are unsigned ints 724 unsigned int address1 = safe_cast<unsigned int>(uniqueRemoteConsoleIdentifier1); 725 unsigned int address2 = safe_cast<unsigned int>(uniqueRemoteConsoleIdentifier2); 726 return address1 == address2; 727} 728 729Microsoft::Xbox::GameChat::ChatPerformanceCounters^ ChatIntegrationLayer::GetChatPerformanceCounters() 730{ 731 if( m_chatManager != nullptr && 732 m_chatManager->ChatSettings != nullptr && 733 m_chatManager->ChatSettings->PerformanceCountersEnabled ) 734 { 735 return m_chatManager->ChatPerformanceCounters; 736 } 737 738 return nullptr; 739} 740 741void ChatIntegrationLayer::OnControllerPairingChanged( Windows::Xbox::Input::ControllerPairingChangedEventArgs^ args ) 742{ 743#if 0 744 auto controller = args->Controller; 745 if ( controller ) 746 { 747 if ( controller->Type == L"Windows.Xbox.Input.Gamepad" ) 748 { 749 // Either add the user or sign one in 750 User^ user = args->User; 751 if ( user != nullptr ) 752 { 753 g_sampleInstance->GetLoggingUI()->LogCommentToUI("OnControllerPairingChanged: " + user->DisplayInfo->Gamertag); 754 AddLocalUserToChatChannel( 755 g_sampleInstance->GetUISelectionChatChannelIndex(), 756 user 757 ); 758 } 759 } 760 } 761#endif 762} 763 764void ChatIntegrationLayer::ToggleRenderTargetVolume() 765{ 766 // Simple toggle logic to just show usage of LocalRenderTargetVolume property 767 static bool makeRenderTargetVolumeQuiet = false; 768 makeRenderTargetVolumeQuiet = !makeRenderTargetVolumeQuiet; 769 770 auto chatUsers = GetChatUsers(); 771 if (chatUsers != nullptr ) 772 { 773 for (UINT chatUserIndex = 0; chatUserIndex < chatUsers->Size; chatUserIndex++) 774 { 775 Microsoft::Xbox::GameChat::ChatUser^ chatUser = chatUsers->GetAt(chatUserIndex); 776 if( chatUser != nullptr && chatUser->IsLocal ) 777 { 778 chatUser->LocalRenderTargetVolume = ( makeRenderTargetVolumeQuiet ) ? 0.1f : 1.0f; 779 } 780 } 781 } 782} 783 784 785void ChatIntegrationLayer::GetBufferBytes( __in Windows::Storage::Streams::IBuffer^ buffer, __out byte** ppOut ) 786{ 787 if ( ppOut == nullptr || buffer == nullptr ) 788 { 789 throw ref new Platform::InvalidArgumentException(); 790 } 791 792 *ppOut = nullptr; 793 794 Microsoft::WRL::ComPtr<IInspectable> srcBufferInspectable(reinterpret_cast<IInspectable*>( buffer )); 795 Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> srcBufferByteAccess; 796 srcBufferInspectable.As(&srcBufferByteAccess); 797 srcBufferByteAccess->Buffer(ppOut); 798} 799 800Windows::Storage::Streams::IBuffer^ ChatIntegrationLayer::ArrayToBuffer( __in Platform::Array<byte>^ array ) 801{ 802 Windows::Storage::Streams::DataWriter^ writer = ref new Windows::Storage::Streams::DataWriter(); 803 writer->WriteBytes(array); 804 return writer->DetachBuffer(); 805}