the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 651 lines 23 kB view raw
1#include "stdafx.h" 2 3#include "DQRNetworkManager.h" 4#include "PartyController.h" 5#include <collection.h> 6#include <ppltasks.h> 7#include <ws2tcpip.h> 8#include "..\Minecraft.World\StringHelpers.h" 9#include "base64.h" 10 11#ifdef _DURANGO 12#include "..\Minecraft.World\DurangoStats.h" 13#endif 14 15#include "ChatIntegrationLayer.h" 16 17using namespace Concurrency; 18using namespace Windows::Foundation::Collections; 19 20DQRNetworkManagerEventHandlers::DQRNetworkManagerEventHandlers(DQRNetworkManager *pDQRNet) 21{ 22 m_pDQRNet = pDQRNet; 23} 24 25void DQRNetworkManagerEventHandlers::Setup(WXNRs::Session^ session) 26{ 27 try 28 { 29 m_dataReceivedToken = session->DataReceived += ref new Windows::Foundation::EventHandler<WXNRs::DataReceivedEventArgs^>(this, &DQRNetworkManagerEventHandlers::DataReceivedHandler); 30 m_sessionStatusToken = session->SessionStatusUpdate += ref new Windows::Foundation::EventHandler<WXNRs::SessionStatusUpdateEventArgs^>(this, &DQRNetworkManagerEventHandlers::SessionStatusUpdateHandler); 31 m_sessionAddressToken = session->SessionAddressDataChanged += ref new Windows::Foundation::EventHandler<WXNRs::SessionAddressDataChangedEventArgs^>(this, &DQRNetworkManagerEventHandlers::SessionAddressDataChangedHandler); 32 m_addedSessionToken = session->AddedSessionAddress += ref new Windows::Foundation::EventHandler<WXNRs::AddedSessionAddressEventArgs^>(this, &DQRNetworkManagerEventHandlers::AddedSessionAddressHandler); 33 m_removedSessionToken = session->RemovedSessionAddress += ref new Windows::Foundation::EventHandler<WXNRs::RemovedSessionAddressEventArgs^>(this, &DQRNetworkManagerEventHandlers::RemovedSessionAddressHandler); 34 m_globalDataToken = session->GlobalSessionDataChanged += ref new Windows::Foundation::EventHandler<WXNRs::GlobalSessionDataChangedEventArgs^>(this, &DQRNetworkManagerEventHandlers::GlobalSessionDataChangedHandler); 35 } 36 catch(Platform::COMException^ ex) 37 { 38 // swallow exceptions 39 } 40 catch(...) 41 { 42 // swallow exceptions 43 } 44} 45 46void DQRNetworkManagerEventHandlers::Pulldown(WXNRs::Session^ session) 47{ 48 try 49 { 50 session->DataReceived -= m_dataReceivedToken; 51 session->SessionStatusUpdate -= m_sessionStatusToken; 52 session->SessionAddressDataChanged -= m_sessionAddressToken; 53 session->AddedSessionAddress -= m_addedSessionToken; 54 session->RemovedSessionAddress -= m_removedSessionToken; 55 session->GlobalSessionDataChanged -= m_globalDataToken; 56 } 57 catch(Platform::COMException^ ex) 58 { 59 // swallow exceptions 60 } 61 catch(...) 62 { 63 // swallow exceptions 64 } 65} 66 67// This event handler is called directly by the realtime session layer, when data is received. We split this data into into data that is meant to be 68// handled internally by the DQRNetworkManager, and that which is meant to be passed on to the game itself as communication between players. 69void DQRNetworkManagerEventHandlers::DataReceivedHandler(Platform::Object^ session, WXNRs::DataReceivedEventArgs^ args) 70{ 71// DQRNetworkManager::LogCommentFormat(L"DataReceivedHandler session addr: 0x%x (%d bytes)",args->SessionAddress,args->Data->Length); 72 73 if (session == m_pDQRNet->m_XRNS_Session) 74 { 75 EnterCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 76 DQRNetworkManager::RTS_Message rtsMessage; 77 if( args->ChannelId == WXNRs::ChannelId::DefaultChatReceive ) 78 { 79 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_DATA_RECEIVED_CHAT; 80 } 81 else 82 { 83 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_DATA_RECEIVED; 84 } 85 rtsMessage.m_sessionAddress = args->SessionAddress; 86 rtsMessage.m_dataSize = args->Data->Length; 87 rtsMessage.m_pucData = (unsigned char *)malloc(rtsMessage.m_dataSize); 88 memcpy( rtsMessage.m_pucData, args->Data->Data, rtsMessage.m_dataSize ); 89 m_pDQRNet->m_RTSMessageQueueIncoming.push(rtsMessage); 90 LeaveCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 91 } 92} 93 94// This event handler is called by the realtime session layer, when session address data is updated. We don't currently use session address data. 95void DQRNetworkManagerEventHandlers::SessionAddressDataChangedHandler(Platform::Object^ session, WXNRs::SessionAddressDataChangedEventArgs^ args) 96{ 97 DQRNetworkManager::LogComment(L"SessionAddressDataChangedHandler"); 98} 99 100// This event handler is called by the realtime session layer when a session changes status. We use this to determine that a connection has been made made to the host, 101// and the case when a connection has been terminated. 102void DQRNetworkManagerEventHandlers::SessionStatusUpdateHandler(Platform::Object^ session, WXNRs::SessionStatusUpdateEventArgs^ args) 103{ 104 DQRNetworkManager::LogComment(L"SessionStatusUpdateHandler"); 105 if (m_pDQRNet->m_XRNS_Session == session) 106 { 107 switch(args->NewStatus) 108 { 109 case WXNRs::SessionStatus::Active: 110 { 111 DQRNetworkManager::LogComment(L"Session active"); 112 m_pDQRNet->m_XRNS_LocalAddress = m_pDQRNet->m_XRNS_Session->LocalSessionAddress; 113 m_pDQRNet->m_XRNS_OldestAddress = m_pDQRNet->m_XRNS_Session->OldestSessionAddress; 114 EnterCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 115 DQRNetworkManager::RTS_Message rtsMessage; 116 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_STATUS_ACTIVE; 117 rtsMessage.m_sessionAddress = 0; 118 rtsMessage.m_dataSize = 0; 119 rtsMessage.m_pucData = 0; 120 m_pDQRNet->m_RTSMessageQueueIncoming.push(rtsMessage); 121 LeaveCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 122 } 123 break; 124 case WXNRs::SessionStatus::Terminated: 125 { 126 DQRNetworkManager::LogComment(L"Session terminated"); 127 EnterCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 128 DQRNetworkManager::RTS_Message rtsMessage; 129 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_STATUS_TERMINATED; 130 rtsMessage.m_sessionAddress = 0; 131 rtsMessage.m_dataSize = 0; 132 rtsMessage.m_pucData = 0; 133 m_pDQRNet->m_RTSMessageQueueIncoming.push(rtsMessage); 134 LeaveCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 135 } 136 break; 137 case WXNRs::SessionStatus::Activating: 138 DQRNetworkManager::LogComment(L"Session activating"); 139 break; 140 case WXNRs::SessionStatus::Terminating: 141 DQRNetworkManager::LogComment(L"Session terminating"); 142 break; 143 } 144 } 145} 146 147// This event is called from the realtime session layer to notify any clients that a new endpoint has been connected into the network mesh. 148void DQRNetworkManagerEventHandlers::AddedSessionAddressHandler(Platform::Object^ session, WXNRs::AddedSessionAddressEventArgs^ args) 149{ 150 DQRNetworkManager::LogCommentFormat(L"AddedSessionAddressHandler session address 0x%x",args->SessionAddress); 151 EnterCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 152 DQRNetworkManager::RTS_Message rtsMessage; 153 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_ADDED_SESSION_ADDRESS; 154 rtsMessage.m_sessionAddress = args->SessionAddress; 155 rtsMessage.m_dataSize = 0; 156 rtsMessage.m_pucData = 0; 157 m_pDQRNet->m_RTSMessageQueueIncoming.push(rtsMessage); 158 LeaveCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 159} 160 161// This event is called from the realtime session layer to notify any clients that an endpoint has been removed from the network mesh. 162void DQRNetworkManagerEventHandlers::RemovedSessionAddressHandler(Platform::Object^ session, WXNRs::RemovedSessionAddressEventArgs^ args) 163{ 164 DQRNetworkManager::LogCommentFormat(L"RemovedSessionAddressHandler session address 0x%x", args->SessionAddress); 165 EnterCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 166 DQRNetworkManager::RTS_Message rtsMessage; 167 rtsMessage.m_eType = DQRNetworkManager::eRTSMessageType::RTS_MESSAGE_REMOVED_SESSION_ADDRESS; 168 rtsMessage.m_sessionAddress = args->SessionAddress; 169 rtsMessage.m_dataSize = 0; 170 rtsMessage.m_pucData = 0; 171 m_pDQRNet->m_RTSMessageQueueIncoming.push(rtsMessage); 172 LeaveCriticalSection(&m_pDQRNet->m_csRTSMessageQueueIncoming); 173} 174 175// This event is called from the realtime session layer when session global data has been updated. We don't currently use global session data. 176void DQRNetworkManagerEventHandlers::GlobalSessionDataChangedHandler(Platform::Object^ session, WXNRs::GlobalSessionDataChangedEventArgs^ args) 177{ 178 DQRNetworkManager::LogComment(L"GlobalSessionDataChangedHandler"); 179} 180 181void DQRNetworkManager::UpdateRTSStats() 182{ 183 Platform::Array<unsigned int> ^sessionAddresses = nullptr; 184 try 185 { 186 sessionAddresses = m_XRNS_Session->GetAllRemoteSessionAddresses(WXNRs::RemoteSessionAddressStateOptions::All, WXNRs::RemoteSessionAddressConnectivityOptions::All); 187 } 188 catch(Platform::COMException^ ex) 189 { 190 // swallow exceptions 191 } 192 catch(...) 193 { 194 // swallow exceptions 195 } 196 197 if( sessionAddresses ) 198 { 199 unsigned int totalBytes = 0; 200 unsigned int totalSends = 0; 201 for( unsigned int i = 0; i < sessionAddresses->Length; i++ ) 202 { 203 try 204 { 205 totalBytes += m_XRNS_Session->GetSendChannelOutstandingBytes(sessionAddresses->get(i), WXNRs::ChannelId::DefaultGameSend ); 206 totalSends += m_XRNS_Session->GetSendChannelOutstandingSends(sessionAddresses->get(i), WXNRs::ChannelId::DefaultGameSend ); 207 } 208 catch(Platform::COMException^ ex) 209 { 210 // swallow exceptions 211 } 212 catch(...) 213 { 214 // swallow exceptions 215 } 216 } 217 m_RTS_Stat_totalBytes = totalBytes; 218 m_RTS_Stat_totalSends = totalSends; 219 } 220 else 221 { 222 m_RTS_Stat_totalBytes = 0; 223 m_RTS_Stat_totalSends = 0; 224 } 225} 226 227void DQRNetworkManager::ProcessRTSMessagesIncoming() 228{ 229 EnterCriticalSection(&m_csRTSMessageQueueIncoming); 230 while(m_RTSMessageQueueIncoming.size() > 0 ) 231 { 232 RTS_Message message = m_RTSMessageQueueIncoming.front(); 233 switch( message.m_eType ) 234 { 235 case eRTSMessageType::RTS_MESSAGE_DATA_RECEIVED: 236 Process_RTS_MESSAGE_DATA_RECEIVED(message); 237 break; 238 case eRTSMessageType::RTS_MESSAGE_DATA_RECEIVED_CHAT: 239 Process_RTS_MESSAGE_DATA_RECEIVED_CHAT(message); 240 break; 241 case eRTSMessageType::RTS_MESSAGE_ADDED_SESSION_ADDRESS: 242 Process_RTS_MESSAGE_ADDED_SESSION_ADDRESS(message); 243 break; 244 case eRTSMessageType::RTS_MESSAGE_REMOVED_SESSION_ADDRESS: 245 Process_RTS_MESSAGE_REMOVED_SESSION_ADDRESS(message); 246 break; 247 case eRTSMessageType::RTS_MESSAGE_STATUS_ACTIVE: 248 Process_RTS_MESSAGE_STATUS_ACTIVE(message); 249 break; 250 case eRTSMessageType::RTS_MESSAGE_STATUS_TERMINATED: 251 Process_RTS_MESSAGE_STATUS_TERMINATED(message); 252 break; 253 default: 254 break; 255 } 256 m_RTSMessageQueueIncoming.pop(); 257 } 258 LeaveCriticalSection(&m_csRTSMessageQueueIncoming); 259}; 260 261void DQRNetworkManager::Process_RTS_MESSAGE_DATA_RECEIVED(RTS_Message &message) 262{ 263 DQRConnectionInfo *connectionInfo; 264 if( m_isHosting ) 265 { 266 connectionInfo = m_sessionAddressToConnectionInfoMapHost[message.m_sessionAddress]; 267 } 268 else 269 { 270 connectionInfo = &m_connectionInfoClient; 271 } 272 273 // Handle any header data, and actual data, in our stream. Data is as follows: 274 // Byte 0 Byte 1 275 // fccsssss ssssssss 276 // 277 // Where: f is 0 if this is normal data send (to be passed up to the game), or is 1 if this is to be internally processed 278 // cc is the channel number that the data belongs to (0 to 3 representing actual player indices) 279 // sssssssssssss is the count of data bytes to follow (range 0 - 8191) 280 BYTE *pNextByte = message.m_pucData; 281 BYTE *pEndByte = pNextByte + message.m_dataSize; 282 do 283 { 284 BYTE byte = *pNextByte; 285 switch( connectionInfo->m_state ) 286 { 287 case DQRConnectionInfo::ConnectionState_HeaderByte0: 288 connectionInfo->m_currentChannel = ( byte >> 5 ) & 3; 289 connectionInfo->m_internalFlag = ( ( byte & 0x80 ) == 0x80 ); 290 291 // Byte transfer mode. Bits 0-4 of this byte represent the upper 5 bits of our count of bytes to transfer... lower 8-bits will follow 292 connectionInfo->m_bytesRemaining = ((int)( byte & 0x1f )) << 8; 293 connectionInfo->m_state = DQRConnectionInfo::ConnectionState_HeaderByte1; 294 connectionInfo->m_internalDataState = DQRConnectionInfo::ConnectionState_InternalHeaderByte; 295 pNextByte++; 296 break; 297 case DQRConnectionInfo::ConnectionState_HeaderByte1: 298 // Add in the lower 8 bits of our byte count, the upper 5 were obtained from the first header byte. 299 connectionInfo->m_bytesRemaining |= byte; 300 301 // If there isn't any data following, then just go back to the initial state expecting another header byte. 302 if( connectionInfo->m_bytesRemaining == 0 ) 303 { 304 connectionInfo->m_state = DQRConnectionInfo::ConnectionState_HeaderByte0; 305 } 306 else 307 { 308 connectionInfo->m_state = DQRConnectionInfo::ConnectionState_ReadBytes; 309 } 310 pNextByte++; 311 break; 312 case DQRConnectionInfo::ConnectionState_ReadBytes: 313 // At this stage we can send up to connectionInfo->m_bytesRemaining bytes, or the number of bytes that we have remaining in the data received, whichever is lowest. 314 int bytesInBuffer = (int)(pEndByte - pNextByte); 315 int bytesToReceive = ( ( connectionInfo->m_bytesRemaining < bytesInBuffer ) ? connectionInfo->m_bytesRemaining : bytesInBuffer ); 316 317 if( connectionInfo->m_internalFlag ) 318 { 319 BytesReceivedInternal(connectionInfo, message.m_sessionAddress, pNextByte, bytesToReceive ); 320 } 321 else 322 { 323 BytesReceived(connectionInfo->m_smallId[connectionInfo->m_currentChannel], pNextByte, bytesToReceive ); 324 } 325 326 // Adjust counts and pointers 327 pNextByte += bytesToReceive; 328 connectionInfo->m_bytesRemaining -= bytesToReceive; 329 330 // Set state back to expect a header if there is no more data bytes to receive 331 if( connectionInfo->m_bytesRemaining == 0 ) 332 { 333 connectionInfo->m_state = DQRConnectionInfo::ConnectionState_HeaderByte0; 334 } 335 break; 336 } 337 } while (pNextByte != pEndByte); 338 339 free(message.m_pucData); 340} 341 342void DQRNetworkManager::Process_RTS_MESSAGE_DATA_RECEIVED_CHAT(RTS_Message &message) 343{ 344 if( m_chat ) 345 { 346 m_chat->OnIncomingChatMessage(message.m_sessionAddress, Platform::ArrayReference<BYTE>(message.m_pucData, message.m_dataSize) ); 347 free(message.m_pucData); 348 } 349} 350 351void DQRNetworkManager::Process_RTS_MESSAGE_ADDED_SESSION_ADDRESS(RTS_Message &message) 352{ 353 if( m_chat ) 354 { 355 m_chat->OnNewSessionAddressAdded(message.m_sessionAddress); 356 } 357 358 // New session address - add a mapping for it 359 if( m_isHosting ) 360 { 361 auto it = m_sessionAddressToConnectionInfoMapHost.find(message.m_sessionAddress); 362 DQRConnectionInfo *connectionInfo; 363 if( it == m_sessionAddressToConnectionInfoMapHost.end() ) 364 { 365 connectionInfo = new DQRConnectionInfo(); 366 367 m_sessionAddressToConnectionInfoMapHost[message.m_sessionAddress] = connectionInfo; 368 } 369 else 370 { 371 // This shouldn't happen as we should be removing mappings as session addresses are removed. 372 connectionInfo = it->second; 373 connectionInfo->Reset(); 374 } 375 376 } 377} 378 379void DQRNetworkManager::Process_RTS_MESSAGE_REMOVED_SESSION_ADDRESS(RTS_Message &message) 380{ 381 if( m_chat ) 382 { 383 m_chat->RemoveRemoteConsole(message.m_sessionAddress); 384 } 385 386 if( m_isHosting ) 387 { 388 auto it = m_sessionAddressToConnectionInfoMapHost.find(message.m_sessionAddress); 389 390 if( it != m_sessionAddressToConnectionInfoMapHost.end() ) 391 { 392 delete it->second; 393 m_sessionAddressToConnectionInfoMapHost.erase(it); 394 RemoveRoomSyncPlayersWithSessionAddress(message.m_sessionAddress); 395 SendRoomSyncInfo(); 396 } 397 } 398 else 399 { 400 // As the client, if we are disonnected from the host, then it is all over. Proceed as if leaving the room. 401 if( message.m_sessionAddress == m_hostSessionAddress ) 402 { 403 LeaveRoom(); 404 } 405 } 406} 407 408void DQRNetworkManager::Process_RTS_MESSAGE_STATUS_ACTIVE(RTS_Message &message) 409{ 410 // When we detect that the session has become active, we start sending unreliable packets, until we get some data back. This is because there is an issue with the 411 // realtime session layer where it is telling us that the connection is active a bit to early, and it will disconnect if it receives a packet that must be reliable in this 412 // state. 413 if( !m_isHosting ) 414 { 415 m_firstUnreliableSendTime = 0; 416 m_hostSessionAddress = m_XRNS_OldestAddress; 417 // Also initialise the status of this connection 418 m_connectionInfoClient.Reset(); 419 SetState(DQRNetworkManager::DNM_INT_STATE_JOINING_SENDING_UNRELIABLE); 420 } 421} 422 423void DQRNetworkManager::Process_RTS_MESSAGE_STATUS_TERMINATED(RTS_Message &message) 424{ 425 if( m_state == DQRNetworkManager::DNM_INT_STATE_JOINING_WAITING_FOR_ACTIVE_SESSION ) 426 { 427 m_joinCreateSessionAttempts++; 428 if( m_joinCreateSessionAttempts > DQRNetworkManager::JOIN_CREATE_SESSION_MAX_ATTEMPTS ) 429 { 430 SetState(DQRNetworkManager::DNM_INT_STATE_JOINING_FAILED); 431 } 432 else 433 { 434 SetState(DQRNetworkManager::DNM_INT_STATE_JOINING_GET_SDA); 435 } 436 } 437} 438 439int DQRNetworkManager::_RTSDoWorkThread(void* lpParameter) 440{ 441 DQRNetworkManager *pDQR = (DQRNetworkManager *)lpParameter; 442 return pDQR->RTSDoWorkThread(); 443} 444 445static const DWORD XRNS_TERMINATE_LOCAL_SESSION_FLAG_IMMEDIATE = 0x00000001; 446int DQRNetworkManager::RTSDoWorkThread() 447{ 448 do 449 { 450 if( m_XRNS_Session ) 451 { 452 try 453 { 454 m_XRNS_Session->DoWork(20); 455 } 456 catch(Platform::COMException^ ex) 457 { 458 // swallow exceptions 459 } 460 catch(...) 461 { 462 // swallow exceptions 463 } 464 UpdateRTSStats(); 465 } 466 else 467 { 468 Sleep(20); 469 } 470 ProcessRTSMessagesOutgoing(); 471 } while(true); 472} 473 474void DQRNetworkManager::ProcessRTSMessagesOutgoing() 475{ 476 EnterCriticalSection(&m_csRTSMessageQueueOutgoing); 477 while(m_RTSMessageQueueOutgoing.size() > 0 ) 478 { 479 RTS_Message message = m_RTSMessageQueueOutgoing.front(); 480 switch( message.m_eType ) 481 { 482 case eRTSMessageType::RTS_MESSAGE_START_CLIENT: 483 Process_RTS_MESSAGE_START_CLIENT(message); 484 break; 485 case eRTSMessageType::RTS_MESSAGE_START_HOST: 486 Process_RTS_MESSAGE_START_HOST(message); 487 break; 488 case eRTSMessageType::RTS_MESSAGE_TERMINATE: 489 Process_RTS_MESSAGE_TERMINATE(message); 490 break; 491 case eRTSMessageType::RTS_MESSAGE_SEND_DATA: 492 Process_RTS_MESSAGE_SEND_DATA(message); 493 break; 494 default: 495 break; 496 } 497 m_RTSMessageQueueOutgoing.pop(); 498 } 499 LeaveCriticalSection(&m_csRTSMessageQueueOutgoing); 500}; 501 502void DQRNetworkManager::Process_RTS_MESSAGE_START_CLIENT(RTS_Message &message) 503{ 504 if( m_XRNS_Session ) 505 { 506 m_eventHandlers->Pulldown(m_XRNS_Session); 507 // Close XRNS session 508 try 509 { 510 m_XRNS_Session->TerminateLocalSession(XRNS_TERMINATE_LOCAL_SESSION_FLAG_IMMEDIATE); 511 } 512 catch(Platform::COMException^ ex) 513 { 514 // swallow exceptions 515 } 516 catch(...) 517 { 518 // swallow exceptions 519 } 520 521 m_XRNS_Session = nullptr; 522 } 523 524 m_XRNS_Session = ref new WXNRs::Session( m_localSocketAddress, m_remoteSocketAddress, MAX_PLAYERS_IN_TEMPLATE, 0); 525 m_XRNS_Session->MinSendRate = 512000; 526 527 LogCommentFormat(L"connect retry period %d retries %d, data retry count %d, data retry timeout %d\n",m_XRNS_Session->ConnectRetryPeriod,m_XRNS_Session->MaxConnectRetries,m_XRNS_Session->MaxDataRetries,m_XRNS_Session->MinDataRetryTimeout); 528 529 m_XRNS_Session->MaxConnectRetries = 50; // 50 at 100ms intervals = 5 seconds of attempting to connect 530 531 m_eventHandlers->Setup(m_XRNS_Session); 532} 533 534void DQRNetworkManager::Process_RTS_MESSAGE_START_HOST(RTS_Message &message) 535{ 536 m_XRNS_Session = ref new WXNRs::Session( m_localSocketAddress, MAX_PLAYERS_IN_TEMPLATE, 0); 537 m_XRNS_Session->MinSendRate = 512000; 538 m_XRNS_Session->MaxConnectRetries = 50; // 50 at 100ms intervals = 5 seconds of attempting to connect 539 m_eventHandlers->Setup(m_XRNS_Session); 540} 541 542void DQRNetworkManager::Process_RTS_MESSAGE_TERMINATE(RTS_Message &message) 543{ 544 if( m_XRNS_Session ) 545 { 546 m_eventHandlers->Pulldown(m_XRNS_Session); 547 // Close XRNS session 548 try 549 { 550 m_XRNS_Session->TerminateLocalSession(XRNS_TERMINATE_LOCAL_SESSION_FLAG_IMMEDIATE); 551 } 552 catch(Platform::COMException^ ex) 553 { 554 // swallow exceptions 555 } 556 catch(...) 557 { 558 // swallow exceptions 559 } 560 561 m_XRNS_Session = nullptr; 562 } 563} 564 565void DQRNetworkManager::Process_RTS_MESSAGE_SEND_DATA(RTS_Message &message) 566{ 567 if( m_XRNS_Session ) 568 { 569 unsigned int sessionAddress = message.m_sessionAddress; 570 571 try 572 { 573 if( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_BROADCAST_MODE ) 574 { 575 sessionAddress = m_XRNS_Session->LocalSessionAddress; 576 } 577 578 m_XRNS_Session->Send( ( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_GAME_CHANNEL ) ? WXNRs::ChannelId::DefaultGameSend : WXNRs::ChannelId::DefaultChatSend, 579 ( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_BROADCAST_MODE ) ? WXNRs::SendExceptionType::ExcludedAddresses : WXNRs::SendExceptionType::IncludedAddresses, 580 Platform::ArrayReference<unsigned int>(&message.m_sessionAddress, 1), 581 Platform::ArrayReference<BYTE>(message.m_pucData, message.m_dataSize), 582 0, 583 ( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_RELIABLE ) ? WXNRs::Send_Reliability::Reliable : WXNRs::Send_Reliability::NonReliable, 584 ( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_SEQUENTIAL ) ? WXNRs::Send_Sequence::Sequential : WXNRs::Send_Sequence::NonSequential, 585 WXNRs::Send_Ack::AckNormal, 586 ( message.m_flags & eRTSFlags::RTS_MESSAGE_FLAG_COALESCE ) ? WXNRs::Send_Coalesce::CoalesceDelay : WXNRs::Send_Coalesce::CoalesceNever, 587 WXNRs::Send_MiscState::NoMiscState ); 588 } 589 catch(Platform::COMException^ ex) 590 { 591 // swallow exceptions 592 } 593 catch(...) 594 { 595 // swallow exceptions 596 } 597 } 598 free(message.m_pucData); 599} 600 601void DQRNetworkManager::RTS_StartCient() 602{ 603 EnterCriticalSection(&m_csRTSMessageQueueOutgoing); 604 RTS_Message message; 605 message.m_eType = eRTSMessageType::RTS_MESSAGE_START_CLIENT; 606 message.m_pucData = NULL; 607 message.m_dataSize = 0; 608 m_RTSMessageQueueOutgoing.push(message); 609 LeaveCriticalSection(&m_csRTSMessageQueueOutgoing); 610} 611 612void DQRNetworkManager::RTS_StartHost() 613{ 614 EnterCriticalSection(&m_csRTSMessageQueueOutgoing); 615 RTS_Message message; 616 message.m_eType = eRTSMessageType::RTS_MESSAGE_START_HOST; 617 message.m_pucData = NULL; 618 message.m_dataSize = 0; 619 m_RTSMessageQueueOutgoing.push(message); 620 LeaveCriticalSection(&m_csRTSMessageQueueOutgoing); 621} 622 623void DQRNetworkManager::RTS_Terminate() 624{ 625 EnterCriticalSection(&m_csRTSMessageQueueOutgoing); 626 RTS_Message message; 627 message.m_eType = eRTSMessageType::RTS_MESSAGE_TERMINATE; 628 message.m_pucData = NULL; 629 message.m_dataSize = 0; 630 m_RTSMessageQueueOutgoing.push(message); 631 LeaveCriticalSection(&m_csRTSMessageQueueOutgoing); 632} 633 634void DQRNetworkManager::RTS_SendData(unsigned char *pucData, unsigned int dataSize, unsigned int sessionAddress, bool reliable, bool sequential, bool coalesce, bool broadcastMode, bool gameChannel ) 635{ 636 EnterCriticalSection(&m_csRTSMessageQueueOutgoing); 637 RTS_Message message; 638 message.m_eType = eRTSMessageType::RTS_MESSAGE_SEND_DATA; 639 message.m_pucData = (unsigned char *)malloc(dataSize); 640 memcpy(message.m_pucData, pucData, dataSize); 641 message.m_dataSize = dataSize; 642 message.m_sessionAddress = sessionAddress; 643 message.m_flags = 0; 644 if( reliable ) message.m_flags |= eRTSFlags::RTS_MESSAGE_FLAG_RELIABLE; 645 if( sequential ) message.m_flags |= eRTSFlags::RTS_MESSAGE_FLAG_SEQUENTIAL; 646 if( coalesce ) message.m_flags |= eRTSFlags::RTS_MESSAGE_FLAG_COALESCE; 647 if( broadcastMode ) message.m_flags |= eRTSFlags::RTS_MESSAGE_FLAG_BROADCAST_MODE; 648 if( gameChannel ) message.m_flags |= eRTSFlags::RTS_MESSAGE_FLAG_GAME_CHANNEL; 649 m_RTSMessageQueueOutgoing.push(message); 650 LeaveCriticalSection(&m_csRTSMessageQueueOutgoing); 651}