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