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