1 /*---------------------------------------------------------------------------*
2 Project: RevolutionDWC Demos
3 File: ./match_anybody/src/main.c
4
5 Copyright 2005-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 *---------------------------------------------------------------------------*/
14 /**
15 *
16 *
17 * Brief comment: This is a sample of Anybody matchmaking (matchmaking with friends unspecified).
18 *
19 * Performs Anybody matchmaking over the internet.
20 * When matchmaking completes, communication is used to exchange positions between oneself and other parties.
21 * One's own position can be moved by pressing Up/Down/Left/Right on the +Control Pad.
22 *
23 * Version: 1.4.10: Removed login processing timeouts.
24 */
25 #include "../../common/include/common.h"
26
27 #define NO_FRIEND // Do not load friend information
28
29 #define USE_RECV_TIMEOUT // Use DWC_SetRecvTimeoutTime
30 #ifdef USE_RECV_TIMEOUT
31 #define RECV_TIMEOUT_TIME (1000*30)
32 #define KEEPALIVE_INTERVAL (RECV_TIMEOUT_TIME/5)
33 #endif
34
35 //#define USE_RELIABLE // Perform reliable communications
36
37 // Constant Declarations
38 //---------------------------------------------------------
39
40 /// Enumerator that indicates the connection type
41 typedef enum{
42 SCCONNECT_NULL,
43 SCCONNECT_NORMAL,
44 SCCONNECT_GROUPID
45 }SCCONNECT;
46
47 /// Enumerator that indicates status
48 typedef enum{
49 STATE_INIT,
50 STATE_START,
51 #ifndef NO_FRIEND
52 STATE_UPDATE_FRIENDS,
53 #endif
54 STATE_ONLINE,
55 STATE_MATCHING,
56 STATE_COMMUNICATING,
57 STATE_ERROR
58 }MATCHINGTESTSTATE;
59
60 /// Enumerator that indicates the present suspension state
61 typedef enum{
62 SUSPEND_NONE, // not suspended
63 SUSPEND_YES, // waiting in a suspended state
64 SUSPEND_NO // waiting in an unsuspended state
65 }SUSPEND_STATE;
66
67 #define MAX_PLAYERS 12 // Number of connected players including yourself
68 #define FRIENDNUM 32 // Number of friends
69 #define SIZE_SEND_BUFFER 512 // Size of send buffer
70 #define SIZE_RECV_BUFFER 4 * 1024 // Size of receive buffer
71 #define TIMEOUT (60 * 300) // Timeout duration (frames)
72 #define USER_TYPE_MALE 1 // Type used to attempt matchmaking
73 #define USER_TYPE_FEMALE 2 // Type used to attempt matchmaking
74 #define USER_MAX_MALE 2 // Maximum player count for the attempt type (male)
75 #define USER_MAX_FEMALE 2 // Maximum player count for the attempt type (female)
76 #define APP_CONNECTION_KEEPALIVE_TIME 30000
77
78 #define MATCHING_FILTER_KEY "DEMONAME" // Key configured in the matchmaking filter.
79 #define MATCHING_FILTER_VAL "match_anybody" // Value configured in the matchmaking filter.
80
81
82 // Variable Declarations
83 //---------------------------------------------------------
84 static MATCHINGTESTSTATE s_state; // Status
85 static SUSPEND_STATE suspend_state; // Suspension state
86 static int s_counter; // Timeout counter
87
88 #ifdef NO_FRIEND
89 static DWCUserData s_userdata; // User data
90 static DWCFriendData s_friends[FRIENDNUM]; // Friend data
91 #else
92 /// Structure that contains the player information
93 static struct tagPlayerInfo
94 {
95
96 /// User data
97 DWCUserData userdata;
98
99 /// Friend data
100 DWCFriendData friendlist[FRIEND_LIST_LEN];
101
102 }
103 s_playerinfo ATTRIBUTE_ALIGN(32);
104 #endif
105
106
107 // Position data structure exchanged through communications.
108 static struct Position
109 {
110 s32 xpos;
111 s32 ypos;
112 }
113 s_position[ MAX_PLAYERS ]; // Position data saved locally.
114
115 static u8 s_send_buf[ SIZE_SEND_BUFFER ]; // Send buffer
116 static u8 s_recv_buf[ MAX_PLAYERS-1 ][ SIZE_RECV_BUFFER ];// Receive buffer
117 static u32 s_groupID = 0; // Group ID
118 static SCCONNECT s_connect; // Connection network structure
119 static BOOL suspend_first = TRUE;
120 static u8 force_stop = 0; // Temporary stop flag
121 static BOOL useAttemptCallback = FALSE; // Flag used to attempt matchmaking
122 static u8 male = USER_TYPE_MALE; // Parameters used to attempt matchmaking (male: 1, female: 2)
123 static DWCTopologyType s_topologyType = DWC_TOPOLOGY_TYPE_HYBRID; // Network topology to use
124
125 // Application-specific data sample to pass to the communication callback
126 typedef struct tagCommunicationData
127 {
128 s32 count;
129 }
130 CommunicationData;
131 CommunicationData s_commData;
132
133
134 // Function Prototype
135 //---------------------------------------------------------
136 static void getUserData( DWCUserData * userdata );
137 static void loginCallback(DWCError error, int profileID, void * param);
138 static void matchedCallback(DWCError error, BOOL cancel, void* param );
139 static void closeCallback(DWCError error, BOOL isLocal, BOOL isServer, u8 aid, int index, void* param);
140 static void sendCallback( int size, u8 aid, void* param );
141 static void recvCallback( u8 aid, u8* buffer, int size, void* param );
142 static void suspendCallback(DWCSuspendResult result, BOOL suspend, void* data);
143 static BOOL connectAttemptCallback( u8* data, void* param );
144
145
146 /**
147 * Creates user data.
148 *
149 * Once created, user data is usually saved in NAND flash memory and loaded at the next startup, but for simplicity user data is created each time the system starts in this sample.
150 *
151 *
152 *
153 * Refer to the demos located in "userdata" for saving user data to and loading user data from NAND flash memory.
154 *
155 */
156 #ifdef NO_FRIEND
getUserData(DWCUserData * userdata)157 static void getUserData( DWCUserData * userdata )
158 {
159
160 // Create user data.
161 DWC_CreateUserData( userdata );
162 DWC_ClearDirtyFlag( userdata );
163
164 }
165 #else
LoadFromNAND(void)166 BOOL LoadFromNAND( void )
167 {
168
169 // Load from NAND
170 //
171 DWCDemoPrintf("Loading from NAND...\n");
172
173 DWCDemoLoadNAND( "playerinfo",
174 0,
175 (u8*)&s_playerinfo,
176 sizeof( s_playerinfo ) );
177
178 // Check if user data is valid
179 //
180 if ( DWC_CheckUserData( &s_playerinfo.userdata ) )
181 {
182
183 // It was valid, so output the user data and return TRUE
184 DWC_ReportUserData( &s_playerinfo.userdata );
185 return TRUE;
186
187 }
188
189 // If valid user data had not been saved
190 //
191 // This demo cannot do anything if there are no friends
192 //
193 DWCDemoPrintf( "No valid userdata found.\n" );
194
195 return FALSE;
196 }
197 #endif
198
199 /**
200 * This is the callback invoked after data transmission.
201 */
sendCallback(int size,u8 aid,void * param)202 static void sendCallback( int size, u8 aid, void* param )
203 {
204 CommunicationData* commData = (CommunicationData*)param;
205 commData->count++; // Add if data was sent
206 DWCDemoPrintf( "Send Callback aid:%d, size:%d mycount:%d\n", aid, size, commData->count );
207 }
208
209 /**
210 * This is the callback invoked at data reception.
211 */
recvCallback(u8 aid,u8 * buffer,int size,void * param)212 static void recvCallback( u8 aid, u8* buffer, int size, void* param)
213 {
214 //
215 // Save the received data.
216 //
217 // Eight bytes of data were sent in; storing a 4-byte X coordinate and a 4-byte Y coordinate.
218 //
219 if ( size == 8 )
220 {
221 CommunicationData* commData = (CommunicationData*)param;
222 commData->count--; // Subtract if data was received
223 s_position[ aid ].xpos = (s32)DWCi_LEtoHl(((u32*)buffer)[0]);
224 s_position[ aid ].ypos = (s32)DWCi_LEtoHl(((u32*)buffer)[1]);
225
226 DWCDemoPrintf( "[aid:%d] x:% 8d y:% 8d mycount:%d\n",
227 aid,
228 s_position[ aid ].xpos,
229 s_position[ aid ].ypos,
230 commData->count);
231 }
232 else
233 {
234
235 DWCDemoPrintf( "invalid recv data size\n" );
236
237 }
238 }
239
240 /**
241 * The callback function invoked at disconnection.
242 */
closeCallback(DWCError error,BOOL isLocal,BOOL isServer,u8 aid,int index,void * param)243 static void closeCallback(DWCError error, BOOL isLocal, BOOL isServer, u8 aid, int index, void* param)
244 {
245 (void)isLocal;
246 (void)isServer;
247 (void)param;
248
249 DWCDemoPrintf( "Closed Callback err:%d, aid:%d, idx:%d\n",
250 error, aid, index );
251 }
252
253 #ifndef NO_FRIEND
254 // Friend roster synchronization completion callback
updateServersCallback(DWCError error,BOOL isChanged,void * param)255 static void updateServersCallback(DWCError error, BOOL isChanged, void* param)
256 {
257 if (error == DWC_ERROR_NONE)
258 {
259 // Successful synchronous processing of friend roster.
260 // The friend roster must be saved if it has been modified
261 if (isChanged)
262 {
263 // Save to NAND
264 DWCDemoSaveNAND("playerinfo", 0, (u8*)&s_playerinfo, sizeof(s_playerinfo));
265 }
266 s_state = STATE_ONLINE;
267
268 }
269 else
270 {
271 DWCDemoPrintf("Update friend data Failed\n");
272 s_state = STATE_ERROR;
273 }
274 }
275
276 // Friend roster delete callback
deleteFriendCallback(int deletedIndex,int srcIndex,void * param)277 static void deleteFriendCallback(int deletedIndex, int srcIndex, void* param)
278 {
279 DWC_Printf(DWC_REPORTFLAG_TEST, "friend[%d] was deleted (equal friend[%d]).\n", deletedIndex, srcIndex);
280 // Save to NAND
281 DWCDemoSaveNAND("playerinfo", 0, (u8*)&s_playerinfo, sizeof(s_playerinfo));
282 }
283 #endif
284
285 /**
286 * The callback function called during login
287 */
loginCallback(DWCError error,int profileID,void * param)288 static void loginCallback(DWCError error, int profileID, void * param)
289 {
290 (void)param;
291
292 DWCDemoPrintf( "Login callback : %d\n", error );
293
294 if ( error == DWC_ERROR_NONE )
295 {
296
297 // When the login is successful
298 //
299 DWCDemoPrintf( "Login Success. ProfileID=%d\n", profileID );
300
301 // Specify the callback function.
302 DWC_SetConnectionClosedCallback( closeCallback, NULL );
303 DWC_SetUserSendCallback( sendCallback, &s_commData );
304 DWC_SetUserRecvCallback( recvCallback, &s_commData );
305
306 #ifdef NO_FRIEND
307 s_state = STATE_ONLINE;
308 #else
309 // Synchronize the local friend roster with the server friend roster
310 if (!DWC_UpdateServersAsync(
311 NULL,
312 updateServersCallback, NULL,
313 NULL, NULL,
314 deleteFriendCallback, NULL))
315 {
316 // Failed to start synchronization
317 DWCDemoPrintf( "DWC_UpdateServersAsync() call Failed\n" );
318 s_state = STATE_ERROR;
319 return;
320 }
321 s_state = STATE_UPDATE_FRIENDS;
322 #endif
323
324 }
325 else
326 {
327
328 // When the login failed
329 //
330 DWCDemoPrintf( "Login Failed\n" );
331
332 s_state = STATE_ERROR;
333
334 }
335 }
336
337 /**
338 * The callback function invoked whenever a client connection is started.
339 */
newClientCallback(int index,void * param)340 static void newClientCallback(int index, void* param )
341 {
342 (void)param;
343
344 DWCDemoPrintf( "New Client is connecting(idx %d)...\n", index);
345 }
346
347 /**
348 * The callback function invoked whenever a client connection is completed.
349 */
matchedSCCallback(DWCError error,BOOL cancel,BOOL self,BOOL isServer,int index,void * param)350 static void matchedSCCallback(DWCError error, BOOL cancel, BOOL self, BOOL isServer, int index, void* param )
351 {
352 (void)param;
353
354 DWCDemoPrintf( "Match err:%d, cancel:%d, self:%d isServer:%d index:%d \n", error, cancel, self, isServer, index );
355
356 if ( error == DWC_ERROR_NONE )
357 {
358
359 if (cancel == TRUE)
360 {
361 if (self == TRUE && isServer == FALSE)
362 {
363 s_state = STATE_ONLINE;
364 }
365 return;
366 }
367
368 // s_currentPlayerNum++;
369 // DWCDemoPrintf( "%d players connected.\n", s_currentPlayerNum );
370
371 /* if(s_currentPlayerNum == MAX_PLAYERS)*/ {
372
373 u8* pAidList;
374 int num = DWC_GetAIDList(&pAidList);
375 int i, j;
376 for (i = 0, j = 0; i < num; i++)
377 {
378 if (pAidList[i] == DWC_GetMyAID())
379 {
380 j++;
381 continue;
382 }
383
384 // Set a receive buffer for AIDs other than the local host's
385 DWC_SetRecvBuffer( pAidList[i], &s_recv_buf[i-j], SIZE_RECV_BUFFER );
386 #ifdef USE_RECV_TIMEOUT
387 DWC_SetRecvTimeoutTime(pAidList[i], RECV_TIMEOUT_TIME);
388 #endif
389 }
390
391 s_state = STATE_COMMUNICATING;
392 }
393 // Use this timing to get the group ID
394 s_groupID = DWC_GetGroupID();
395 }
396 else if (error == DWC_ERROR_SC_CONNECT_BLOCK)
397 {
398 // When local host was fumbled because of a difference in connection speed
399 int errorCode;
400 DWCErrorType errorType;
401
402 DWC_GetLastErrorEx(&errorCode, &errorType);
403 DWCDemoPrintf("DWC_GetLastErrorEx ErrorCode:%d ErrorType:%d\n", errorCode, (int)errorType);
404 DWCDemoPrintf( "DWC_ERROR_SC_CONNECT_BLOCK\n" );
405 DWC_ClearError();
406 s_state = STATE_ONLINE;
407 }
408 else if ( error == DWC_ERROR_NOT_FRIEND_SERVER )
409 {
410 DWCDemoPrintf( "Server not found\n" );
411
412 s_state = STATE_ERROR;
413 }
414 else
415 {
416 DWCDemoPrintf( "Match Error\n" );
417
418 s_state = STATE_ERROR;
419 }
420
421 }
422
423 // Callback to suspend matchmaking
stopSCCallback(void * param)424 static void stopSCCallback(void* param)
425 {
426 (void)param;
427 DWCDemoPrintf( "stopSCCallback called.\n");
428 }
429
430 // Callback invoked during an NN check
connectAttemptCallback(u8 * data,void * param)431 static BOOL connectAttemptCallback( u8* data, void* param )
432 {
433 // Check with the condition that there are no more than 2 males and 2 females
434 int numAid;
435 u8* aidList;
436 u8 userData[DWC_CONNECTION_USERDATA_LEN];
437 int i;
438 int maleCount = 0; // Number of males
439 int femaleCount = 0; // Number of females
440
441 (void) param;
442
443 numAid = DWC_GetAIDList(&aidList);
444 for (i = 0; i < numAid; i++)
445 {
446 DWC_GetConnectionUserData(aidList[i], userData);
447 if (userData[0] == USER_TYPE_MALE)
448 maleCount++;
449 else if (userData[0] == USER_TYPE_FEMALE)
450 femaleCount++;
451 }
452
453 if (data[0] == USER_TYPE_MALE && maleCount < USER_MAX_MALE)
454 return TRUE;
455 else if (data[0] == USER_TYPE_FEMALE && femaleCount < USER_MAX_FEMALE)
456 return TRUE;
457 else
458 return FALSE;
459 }
460
461 // Callback invoked when suspending is complete
suspendCallback(DWCSuspendResult result,BOOL suspend,void * data)462 static void suspendCallback(DWCSuspendResult result, BOOL suspend, void* data)
463 {
464 (void)data;
465 if (result == DWC_SUSPEND_SUCCESS)
466 {
467 DWCDemoPrintf("<SAMPLE> suspend successfly. suspend is (%s).\n", suspend ? "TRUE" : "FALSE");
468 }
469 else
470 {
471 DWCDemoPrintf("<SAMPLE> suspend error! result is (%d). suspend is (%s).\n", result, suspend ? "TRUE" : "FALSE");
472 }
473 suspend_state = SUSPEND_NONE;
474 }
475
476 #ifdef USE_RECV_TIMEOUT
userRecvTimeoutCallback(u8 aid,void * param)477 static void userRecvTimeoutCallback(u8 aid, void* param)
478 {
479 CommunicationData* commData = (CommunicationData*)param;
480 DWCDemoPrintf("aid (%d) is timeout. mycount is %d\n", aid, commData->count);
481 }
482 #endif
483
484 /**
485 * Main
486 */
DWCDemoMain()487 void DWCDemoMain()
488 {
489 int i;
490 BOOL firsttime = TRUE;
491 u32 padlast; // The previous pressed state
492 u32 pad = 0; // The current pressed state
493 u32 padtrig; // Keys whose state changed from the last time
494 u32 padpressed; // Newly-pressed keys
495 u32 padreleased; // Newly-released keys
496 u8 userData[DWC_CONNECTION_USERDATA_LEN];
497
498 // Initializes the position data.
499 //------------------------------
500 for ( i=0; i<MAX_PLAYERS; i++ )
501 {
502
503 s_position[ i ].xpos = 0;
504 s_position[ i ].ypos = 0;
505
506 }
507
508 // Initialize communication data
509 s_commData.count = 0;
510
511 #ifdef NO_FRIEND
512 // Get user data.
513 //------------------------------
514 getUserData( &s_userdata );
515
516 // Perform friend match initialization
517 //------------------------------
518 DWC_InitFriendsMatch( NULL,
519 &s_userdata,
520 GAME_PRODUCTID,
521 GAME_NAME,
522 GAME_SECRET_KEY,
523 0,
524 0,
525 s_friends,
526 FRIENDNUM );
527
528 #else
529 // Get user data and the Friend Roster.
530 //------------------------------
531 if ( !LoadFromNAND() )
532 {
533
534 // Quit
535 return;
536
537 }
538
539 // Perform friend match initialization
540 //------------------------------
541 DWC_InitFriendsMatch( NULL,
542 &s_playerinfo.userdata,
543 GAME_PRODUCTID,
544 GAME_NAME,
545 GAME_SECRET_KEY,
546 0,
547 0,
548 s_playerinfo.friendlist,
549 FRIEND_LIST_LEN );
550 #endif
551
552 // Start login processing
553 //------------------------------
554 DWC_LoginAsync( (u16*)L"name",
555 NULL,
556 loginCallback,
557 NULL );
558
559 // Initialize the status.
560 s_state = STATE_START;
561 s_counter = 0;
562
563 #ifdef USE_RECV_TIMEOUT
564 DWC_SetUserRecvTimeoutCallback(userRecvTimeoutCallback, &s_commData);
565 #endif
566 DWC_SetConnectionKeepAliveTime(APP_CONNECTION_KEEPALIVE_TIME);
567
568 // Main loop
569 while (1)
570 {
571 // Key input
572 // Save the current state
573 padlast = pad;
574 pad = DWCDemoPadRead();
575 padtrig = padlast ^ pad;
576 padpressed = padtrig & pad;
577 padreleased = padtrig & ~pad;
578
579 if ( s_state >= STATE_MATCHING )
580 {
581 if ( force_stop )
582 {
583 if ( padpressed & DWCDEMO_KEY_Z )
584 {
585 DWCDemoPrintf("force stop OFF.\n");
586 force_stop = 0;
587 }
588 else
589 continue;
590 }
591 else
592 {
593 if ( padpressed & DWCDEMO_KEY_Z )
594 {
595 DWCDemoPrintf("force stop ON.\n");
596 force_stop = 1;
597 }
598 }
599 }
600
601 DWC_ProcessFriendsMatch();
602
603 if (DWC_GetLastErrorEx(NULL, NULL) != DWC_ERROR_NONE)
604 goto error;
605
606 switch ( s_state )
607 {
608
609 // Processing login
610 //
611 case STATE_START:
612
613 // Wait until loginCallback() is invoked.
614 break;
615
616 case STATE_ONLINE:
617 if ( firsttime )
618 {
619 DWCDemoPrintf("\n");
620 DWCDemoPrintf("--------------------------------\n");
621 DWCDemoPrintf("- Anybody Match Demo -\n");
622 DWCDemoPrintf("--------------------------------\n");
623 DWCDemoPrintf("A: Start\n");
624 DWCDemoPrintf("B: Set Hybrid mode\n");
625 DWCDemoPrintf("X: Set Star mode\n");
626 DWCDemoPrintf("Z: Set Fullmesh mode\n");
627 DWCDemoPrintf("Y: Connect to server from groupID\n");
628 //DWCDemoPrintf("START: Connect to server from groupID(fast)\n");
629 DWCDemoPrintf(" groupID is %d\n", s_groupID);
630 DWCDemoPrintf("LEFT: Start with attempt callback(male)\n");
631 DWCDemoPrintf("RIGHT: Start with attempt callback(female)\n");
632 DWCDemoPrintf("DOWN: exit demo\n");
633 DWCDemoPrintf("\n");
634 firsttime = FALSE;
635 suspend_state = SUSPEND_NONE;
636 }
637 if ( padpressed & DWCDEMO_KEY_A )
638 {
639 DWCDemoPrintf("Start (normal)\n");
640 useAttemptCallback = FALSE;
641 s_state = STATE_MATCHING;
642 firsttime = TRUE;
643 s_connect = SCCONNECT_NORMAL;
644 }
645 else if ( padpressed & DWCDEMO_KEY_B )
646 {
647 DWCDemoPrintf("DWC_TOPOLOGY_TYPE_HYBRID set.\n");
648 s_topologyType = DWC_TOPOLOGY_TYPE_HYBRID;
649 firsttime = TRUE;
650 }
651 else if ( padpressed & DWCDEMO_KEY_X )
652 {
653 DWCDemoPrintf("DWC_TOPOLOGY_TYPE_STAR set.\n");
654 s_topologyType = DWC_TOPOLOGY_TYPE_STAR;
655 firsttime = TRUE;
656 }
657 else if ( padpressed & DWCDEMO_KEY_Z )
658 {
659 DWCDemoPrintf("DWC_TOPOLOGY_TYPE_FULLMESH set.\n");
660 s_topologyType = DWC_TOPOLOGY_TYPE_FULLMESH;
661 firsttime = TRUE;
662 }
663 else if ( padpressed & DWCDEMO_KEY_LEFT )
664 {
665 DWCDemoPrintf("Start with attempt callback(male)\n");
666 useAttemptCallback = TRUE;
667 s_state = STATE_MATCHING;
668 firsttime = TRUE;
669 s_connect = SCCONNECT_NORMAL;
670 male = USER_TYPE_MALE;
671 }
672 else if ( padpressed & DWCDEMO_KEY_RIGHT )
673 {
674 DWCDemoPrintf("Start with attempt callback(female)\n");
675 useAttemptCallback = TRUE;
676 s_state = STATE_MATCHING;
677 firsttime = TRUE;
678 s_connect = SCCONNECT_NORMAL;
679 male = USER_TYPE_FEMALE;
680 }
681 else if ( padpressed & DWCDEMO_KEY_Y )
682 {
683 if ( s_groupID )
684 {
685 // Connect through a group ID
686 DWCDemoPrintf("Start (groupID : %d)\n", s_groupID);
687 s_state = STATE_MATCHING;
688 firsttime = TRUE;
689 s_connect = SCCONNECT_GROUPID;
690 }
691 // Nothing happens when the group ID is 0
692 }
693 else if ( padpressed & DWCDEMO_KEY_DOWN )
694 {
695 // Quit
696 goto exit;
697 }
698 break;
699
700 // Matchmaking in progress
701 //
702 case STATE_MATCHING:
703
704 if ( firsttime )
705 {
706 extern char* g_argv1;
707 char* filterString;
708 char addFilter[128];
709
710 if (g_argv1 == NULL)
711 filterString = FILTER_STRING;
712 else
713 filterString = g_argv1;
714
715 snprintf(addFilter, sizeof(addFilter), "str_key='%s'", filterString);
716
717 // Set values depending on the UserType
718 userData[0] = male;
719 // unused, but for testing
720 userData[1] = 5;
721 userData[2] = 120;
722 userData[3] = 254;
723 switch (s_connect)
724 {
725 case SCCONNECT_NORMAL:
726 DWCDemoPrintf("DWC_ConnectToAnybodyAsync\n");
727
728 // Set the index key.
729 DWC_AddMatchKeyString( 0, "str_key", filterString );
730
731 // Begin matchmaking.
732 DWC_ConnectToAnybodyAsync( s_topologyType, // Connection network structure
733 (u8)MAX_PLAYERS, // The number of people to matchmake.
734 addFilter, //
735 matchedSCCallback, //
736 NULL,
737 newClientCallback,
738 NULL,
739 NULL, //
740 NULL, //
741 useAttemptCallback ? connectAttemptCallback : NULL,
742 userData,
743 NULL ); //
744
745 break;
746 case SCCONNECT_GROUPID:
747 // Connect to the server through a group ID
748 DWC_ConnectToGameServerByGroupID( s_topologyType, // Connection network structure
749 s_groupID, // Group ID
750 matchedSCCallback, //
751 NULL,
752 newClientCallback,
753 NULL,
754 useAttemptCallback ? connectAttemptCallback : NULL,
755 userData,
756 NULL ); //
757 break;
758 }
759 suspend_first = TRUE;
760 firsttime = FALSE;
761 }
762
763 if (padpressed & DWCDEMO_KEY_B)
764 {
765 if (DWC_CancelMatch() == TRUE)
766 {
767 DWCDemoPrintf("DWC_CancelMatch() called.\n");
768 s_state = STATE_ONLINE;
769 firsttime = TRUE;
770 }
771 else
772 {
773 DWCDemoPrintf("cannot call DWC_CancelMatch() now.\n");
774 }
775 break;
776 }
777 break;
778
779
780 // Communicating
781 //
782 case STATE_COMMUNICATING:
783
784 {
785 u8 me;
786 struct Position sendPos;
787
788 // Get one's own AID.
789 me = DWC_GetMyAID();
790
791 // Check input.
792
793 // Return ONLINE
794 if ( padpressed & DWCDEMO_KEY_B )
795 {
796 DWC_CloseAllConnectionsHard();
797 s_state = STATE_ONLINE;
798 firsttime = TRUE;
799 break;
800 }
801
802 if ( pad & DWCDEMO_KEY_UP ) s_position[ me ].ypos--;
803 if ( pad & DWCDEMO_KEY_DOWN ) s_position[ me ].ypos++;
804 if ( pad & DWCDEMO_KEY_LEFT ) s_position[ me ].xpos--;
805 if ( pad & DWCDEMO_KEY_RIGHT ) s_position[ me ].xpos++;
806
807 {
808 // Forcibly send data at intervals shorter than the receive timeout interval because there is a keep-alive timeout.
809 //
810 static int lastKeepAliveSent = 0;
811 int now = (int)DWCi_Np_TicksToMilliSeconds(DWCi_Np_GetTick());
812 if (lastKeepAliveSent == 0 || (now - lastKeepAliveSent) > KEEPALIVE_INTERVAL)
813 {
814 pad |= DWCDEMO_KEY_UP;
815 lastKeepAliveSent = now;
816 }
817 }
818
819 // Send a new position to the communication partner when there is input.
820 if ( pad & ( DWCDEMO_KEY_UP | DWCDEMO_KEY_DOWN
821 | DWCDEMO_KEY_LEFT | DWCDEMO_KEY_RIGHT ) )
822 {
823
824 sendPos.xpos = (s32)DWCi_HtoLEl((u32)s_position[ me ].xpos);
825 sendPos.ypos = (s32)DWCi_HtoLEl((u32)s_position[ me ].ypos);
826 // Send one's own position to all other parties.
827 #ifdef USE_RELIABLE
828 DWC_SendReliableBitmap( DWC_GetAIDBitmap(),
829 (const void*)&sendPos,
830 sizeof( s32 ) * 2 );
831 #else
832 DWC_SendUnreliableBitmap( DWC_GetAIDBitmap(),
833 (const void*)&sendPos,
834 sizeof( s32 ) * 2 );
835 #endif
836 }
837 // Disconnect communications and return to ONLINE if the cancel button is pressed.
838 //
839 if ( pad & DWCDEMO_KEY_B )
840 {
841 DWC_CloseAllConnectionsHard();
842 s_state = STATE_ONLINE;
843 }
844
845 // Suspend matchmaking with Y
846 if ( pad & DWCDEMO_KEY_Y )
847 {
848 // Temporarily suspend
849 DWC_RequestSuspendMatchAsync(TRUE, suspendCallback, NULL);
850 suspend_state = SUSPEND_YES;
851 }
852 else if ( pad & DWCDEMO_KEY_X )
853 {
854 // Begin accepting again
855 DWC_RequestSuspendMatchAsync(FALSE, suspendCallback, NULL);
856 suspend_state = SUSPEND_NO;
857 }
858 }
859 break;
860
861 // Error occurred
862 //
863 case STATE_ERROR:
864
865 goto error;
866
867 }
868
869 // Display information on the bottom-most line
870 {
871 #define FPS_COUNT_MAX (5)
872 static int cnt = 0;
873 static int frameTimeBuf = 0;
874 static int frameCnt = 0;
875 static int lastTime = 0;
876 static int msecPerFrame = 0;
877 int now = (int)DWCi_Np_TicksToMilliSeconds(DWCi_Np_GetTick());
878
879 if (DWC_GetServerAID() != DWC_INVALID_AID)
880 DWCDemoPrintfToFixedRow("GetServerAID=%d,IsServerMyself=%s %02d(%d)", DWC_GetServerAID(), DWC_IsServerMyself() ? "Y" : "N",
881 cnt%60, msecPerFrame);
882 else
883 DWCDemoPrintfToFixedRow("Svr:unknown. %02d(%d)", cnt%60, msecPerFrame);
884
885 cnt++;
886 frameTimeBuf += now - lastTime;
887 lastTime = now;
888
889 frameCnt++;
890 if (frameCnt == FPS_COUNT_MAX)
891 {
892 frameCnt = 0;
893 msecPerFrame = frameTimeBuf / FPS_COUNT_MAX;
894 frameTimeBuf = 0;
895 }
896 }
897
898 // Flush the DWCDemoPrintf output.
899 DWCDemoUpdate();
900
901 #ifdef _WIN32
902 // Display information in the title bar
903 DWCViewInfoToTitle();
904 #endif
905 }
906
907 exit:
908
909 // Quit
910 DWC_ShutdownFriendsMatch();
911
912 return;
913
914 error:
915
916 // Error processing
917 {
918
919 int errorCode;
920 DWCErrorType errorType;
921
922 if ( DWC_GetLastErrorEx( &errorCode, &errorType ) != DWC_ERROR_NONE )
923 {
924
925 DWCDemoPrintf( "DWC_GetLastErrorEx ErrorCode:%d ErrorType:%d\n",
926 errorCode,
927 (int)errorType );
928
929 // Clear the errors.
930 DWC_ClearError();
931
932 }
933
934 }
935
936 // Quit
937
938 DWC_ShutdownFriendsMatch();
939
940 return;
941
942 }
943