the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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}