1 /*---------------------------------------------------------------------------*
2   Project:  RevolutionDWC Demos
3   File:     ./frienddata/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:    Friend data demo
18  *
19  * This demo builds a friend relationship by exchanging friend codes.
20  * Formed friendships are saved in NAND memory and restored at the next startup.
21  *
22  * Procedure for forming a friend relationship using this demo
23  *
24  *    1. Run the demo on each of two consoles
25  *    2. Press "A" on each and enter the other one's friend code
26  *    3. Press "X" to save and exit
27  *    4. Startup again (the friend relationship will be formed during login)
28  *    5. Press "X" to save and exit
29  *
30  * Version:  1.4.16  Revised program to check for duplicate friend codes.
31  *
32  */
33 #include "../../common/include/common.h"
34 
35 // Constant Declarations
36 //---------------------------------------------------------
37 
38 // Variable Declarations
39 //---------------------------------------------------------
40 
41 /// Structure that contains the player information
42 static struct tagPlayerInfo
43 {
44 
45     /// User data
46     DWCUserData     userdata;
47 
48     /// Friend data
49     DWCFriendData   friendlist[FRIEND_LIST_LEN];
50 
51 }
52 s_playerinfo ATTRIBUTE_ALIGN(32);
53 
54 
55 // Function Prototype
56 //---------------------------------------------------------
57 static int GetAvailableFriendListIndex( void );
58 static BOOL CheckForDuplicatedFriendData( DWCFriendData* data );
59 static void DispFriendList( void );
60 static BOOL update( void );
61 static void loginCallback(DWCError error, int profileID, void * param);
62 static void updateCallback(DWCError error, BOOL isChanged, void* param);
63 
64 
65 /**
66  * Gets an empty index on the friend roster.
67  *
68  * Return value:   Available index in the friend roster.
69  *          Returns -1 if there is no available index.
70  */
GetAvailableFriendListIndex(void)71 static int GetAvailableFriendListIndex( void )
72 {
73     int i;
74 
75     for ( i = 0; i < FRIEND_LIST_LEN; i++ )
76     {
77 
78         if ( !DWC_IsValidFriendData( &s_playerinfo.friendlist[i] ) )
79             return i;
80 
81     }
82 
83     return -1;
84 }
85 
86 
87 /**
88  * Check through the friend roster to see if the friend is already registered.
89  *
90  * Param:  data -  The friend data to check
91  *
92  * Return value:  TRUE: Does not exist in the roster
93  * Return value:  FALSE: Already exists in the roster
94  */
CheckForDuplicatedFriendData(DWCFriendData * data)95 static BOOL CheckForDuplicatedFriendData( DWCFriendData* data )
96 {
97     int i;
98 
99     for ( i = 0; i < FRIEND_LIST_LEN; i++ )
100     {
101 
102         if ( DWC_IsEqualFriendData( &s_playerinfo.friendlist[i], data ) )
103             return FALSE;
104 
105     }
106 
107     return TRUE;
108 }
109 
110 
111 /**
112  * Display the friend roster.
113  */
DispFriendList(void)114 static void DispFriendList( void )
115 {
116     int  i;
117 
118     for ( i = 0; i < FRIEND_LIST_LEN; i++ )
119     {
120 
121         if ( !DWC_IsValidFriendData( &s_playerinfo.friendlist[i] ) )
122             continue;
123 
124         DWCDemoPrintf( " #%02d:  ", i );
125         DWC_ReportFriendData(   &s_playerinfo.userdata,
126                                 &s_playerinfo.friendlist[i] );
127     }
128 
129     DWCDemoPrintf( "\n");
130 
131 }
132 
133 /**
134  * The callback function called during login
135  */
loginCallback(DWCError error,int profileID,void * param)136 static void loginCallback(DWCError error, int profileID, void * param)
137 {
138     DWCDemoPrintf( "Login callback : %d\n", error );
139 
140     if ( error == DWC_ERROR_NONE )
141     {
142 
143         // When the login is successful
144         //
145         DWCDemoPrintf( "Login Success. ProfileID=%d\n", profileID );
146 
147     }
148     else
149     {
150 
151         // When the login failed
152         //
153         DWCDemoPanic( "Login Failed\n" );
154     }
155 
156     // Set the loop ended flag
157     *((BOOL*)param) = TRUE;
158 
159 }
160 
update(void)161 static BOOL update( void )
162 {
163 
164     static u32 padlast = 0;	// The previous pressed state
165     u32 pad;				// The current pressed state
166     u32 padtrig;			// Keys whose state changed from the last time
167     u32 padpressed;			// Newly-pressed keys
168     u32 padreleased;		// Newly-released keys
169 
170     static u32	cursor = 0;
171     static u8	cfriendcode[12];
172     static u64	friendcode;
173 
174     static u8	delindex = 0;
175 
176     static enum
177     {
178         STATE_MENU,
179         STATE_SELECT,
180         STATE_ADD_FRIEND,
181         STATE_ADD_FRIEND_INPUT,
182         STATE_ADD_FRIEND_PROCESS,
183         STATE_DEL_FRIEND,
184         STATE_DEL_FRIEND_INPUT,
185         STATE_DEL_FRIEND_PROCESS
186     }
187     state = STATE_MENU;
188 
189     int i;
190 
191 
192     // Read key input
193     pad = DWCDemoPadRead();
194     padtrig = padlast ^ pad;
195     padpressed = padtrig & pad;
196     padreleased = padtrig & ~pad;
197 
198 
199     switch ( state )
200     {
201 
202     case STATE_MENU:
203         DWCDemoPrintf("\n");
204         DWCDemoPrintf("--------------------------------\n");
205         DWCDemoPrintf("- DWC Friend Data Demo         -\n");
206         DWCDemoPrintf("--------------------------------\n");
207         DWCDemoPrintf("A:  add friend\n");
208         DWCDemoPrintf("B:  del friend\n");
209         DWCDemoPrintf("Y:  update server\n");
210         DWCDemoPrintf("X:  save & exit\n");
211         state = STATE_SELECT;
212         break;
213 
214     case STATE_SELECT:
215 
216         if ( padpressed & DWCDEMO_KEY_A )
217         {
218 
219             state = STATE_ADD_FRIEND;
220             break;
221 
222         }
223         else if ( padpressed & DWCDEMO_KEY_B )
224         {
225 
226             state = STATE_DEL_FRIEND;
227             break;
228 
229         }
230         else if ( padpressed & DWCDEMO_KEY_Y )
231         {
232 
233             // By calling this asynchronous function, friend information stored locally and on the server are synchronized.
234             //
235             DWC_UpdateServersAsync(	NULL,
236                                     updateCallback,	NULL,
237                                     NULL, NULL,
238                                     NULL, NULL);
239 
240             DWCDemoPrintf( "DWC_UpdateServersAsync\n" );
241             state = STATE_MENU;
242             break;
243 
244         }
245         else if ( padpressed & DWCDEMO_KEY_X )
246         {
247 
248             // Quit
249             return FALSE;
250 
251         }
252         break;
253 
254     case STATE_ADD_FRIEND:
255 
256         DWCDemoPrintf("Please the input friend code.\n");
257         DWCDemoPrintf("Arrow: input number\n");
258         DWCDemoPrintf("A: OK\n");
259         DWCDemoPrintf("B: Cancel\n");
260         state = STATE_ADD_FRIEND_INPUT;
261 
262         break;
263 
264     case STATE_ADD_FRIEND_INPUT:
265 
266         if ( padpressed & DWCDEMO_KEY_UP )
267         {
268             cfriendcode[cursor] = (u8)((cfriendcode[cursor] + 1) % 10);
269         }
270         else if ( padpressed & DWCDEMO_KEY_DOWN )
271         {
272             cfriendcode[cursor] = (u8)(cfriendcode[cursor] == 0 ? 9 : (cfriendcode[cursor] - 1));
273         }
274         else if ( padpressed & DWCDEMO_KEY_LEFT )
275         {
276             cursor = cursor == 0 ? 11 : (cursor - 1);
277         }
278         else if ( padpressed & DWCDEMO_KEY_RIGHT )
279         {
280             cursor = (cursor + 1) % 12;
281         }
282         else if ( padpressed & DWCDEMO_KEY_A )
283         {
284 
285             friendcode = 0;
286 
287             for ( i=0; i<12; i++ )
288                 friendcode = friendcode * 10 + cfriendcode[i];
289 
290             DWCDemoPrintf( "Add friend(%012llu)\n", friendcode );
291 
292             state = STATE_ADD_FRIEND_PROCESS;
293 
294             break;
295 
296         }
297         else if ( padpressed & DWCDEMO_KEY_B )
298         {
299             DWCDemoPrintf( "canceled\n" );
300             state = STATE_MENU;
301         }
302         else
303             break;
304 
305         {
306             char tmpbuf[0xff];
307 
308             sprintf( tmpbuf, "" );
309 
310             for ( i=0; i<12; i++ )
311                 sprintf( tmpbuf, "%s%d", tmpbuf, cfriendcode[i] );
312             sprintf( tmpbuf, "%s\n", tmpbuf );
313 
314             for ( i=0; i<12; i++ )
315                 sprintf( tmpbuf, "%s%c", tmpbuf, " ~"[cursor==i] );
316             sprintf( tmpbuf, "%s\n", tmpbuf );
317 
318             DWCDemoPrintf( tmpbuf );
319         }
320 
321         break;
322 
323     case STATE_ADD_FRIEND_PROCESS:
324 
325         if ( DWC_CheckFriendKey( &s_playerinfo.userdata,
326                                  friendcode ) )
327         {
328             int index;
329 
330             index = GetAvailableFriendListIndex();
331 
332             if ( index != -1 )
333             {
334 
335                 if ( DWC_CanChangeFriendList() )
336                 {
337                     DWCFriendData newdata;
338 
339                     DWC_CreateFriendKeyToken( &newdata, friendcode );
340 
341                     // Checks if the friend is already present in the friend roster, and if not, adds the friend
342                     if ( CheckForDuplicatedFriendData( &newdata ) )
343                     {
344                         s_playerinfo.friendlist[index] = newdata;
345                     }
346                     else
347                     {
348                         DWCDemoPrintf( "dupulicating friend code\n" );
349                     }
350 
351                 }
352                 else
353                 {
354                     // If the friend roster is in an uneditable state, return to the input phase
355                     DWCDemoPrintf( "The friends list is locked now. Retry later.\n" );
356                     state = STATE_ADD_FRIEND_INPUT;
357                     break;
358 
359                 }
360 
361             }
362             else
363             {
364 
365                 DWCDemoPrintf( "Too many friends:)\n" );
366 
367             }
368 
369         }
370         else
371         {
372 
373             DWCDemoPrintf( "invalid friend code\n" );
374 
375         }
376 
377         state = STATE_MENU;
378 
379         break;
380 
381     case STATE_DEL_FRIEND:
382 
383         DWCDemoPrintf("Input index to delete.\n");
384         DWCDemoPrintf("Arrow: input number\n");
385         DWCDemoPrintf("A: OK\n");
386         DWCDemoPrintf("B: Cancel\n");
387         DWCDemoPrintf( "index=%d\n", delindex );
388         DispFriendList();
389         state = STATE_DEL_FRIEND_INPUT;
390         break;
391 
392     case STATE_DEL_FRIEND_INPUT:
393 
394         if ( padpressed & DWCDEMO_KEY_UP )
395         {
396             delindex = (u8)((delindex + 1) % FRIEND_LIST_LEN);
397         }
398         else if ( padpressed & DWCDEMO_KEY_DOWN )
399         {
400             delindex = (u8)(delindex == 0 ? (FRIEND_LIST_LEN-1) : (delindex - 1));
401         }
402         else if ( padpressed & DWCDEMO_KEY_A )
403         {
404 
405             DWCDemoPrintf( "delete #%d\n", delindex );
406             state = STATE_DEL_FRIEND_PROCESS;
407 
408         }
409         else if ( padpressed & DWCDEMO_KEY_B )
410         {
411 
412             DWCDemoPrintf( "canceled\n" );
413             state = STATE_MENU;
414 
415         }
416         else
417             break;
418 
419         DWCDemoPrintf( "index=%d\n", delindex );
420 
421         break;
422 
423     case STATE_DEL_FRIEND_PROCESS:
424 
425         if ( DWC_CanChangeFriendList() )
426         {
427             DWC_DeleteBuddyFriendData( &s_playerinfo.friendlist[delindex] );
428         }
429         else
430         {
431             // If the friend roster is in an uneditable state, return to the input phase
432             DWCDemoPrintf( "The friends list is locked now. Retry later.\n" );
433             state = STATE_DEL_FRIEND;
434             break;
435 
436         }
437 
438         state = STATE_MENU;
439 
440         break;
441 
442     }
443 
444 
445 
446     // Save the current state
447     padlast = pad;
448 
449     return TRUE;
450 }
451 
updateCallback(DWCError error,BOOL isChanged,void * param)452 static void updateCallback(DWCError error, BOOL isChanged, void* param)
453 {
454     (void)param;
455     (void)isChanged;
456 
457     if ( error == DWC_ERROR_NONE )
458     {
459         // Successful synchronous processing of friend roster.
460         DWCDemoPrintf( "Update Servers succeeded.\n" );
461 
462     }
463     else
464     {
465         DWCDemoPrintf("Error\n");
466     }
467 }
468 
469 //=============================================================================
470 /*!
471  *	@brief	Main
472  */
473 //=============================================================================
DWCDemoMain()474 void DWCDemoMain()
475 {
476 
477     u64 friendcode;
478     BOOL exitflag = FALSE;
479 
480 
481     // Load user data from NAND
482     //
483     DWCDemoPrintf("Loading userdata from NAND...\n");
484     DWCDemoUpdate();
485 
486     DWCDemoLoadNAND(    SAVEDATA_FILENAME,
487                         0,
488                         (u8*)&s_playerinfo,
489                         sizeof( s_playerinfo ) );
490 
491 
492     // Check if user data is valid
493     //
494     if ( !DWC_CheckUserData( &s_playerinfo.userdata ) )
495     {
496 
497         // If valid user data had not been saved
498         //
499 
500         // Create user data.
501         DWCDemoPrintf("Creating new UserData\n");
502         DWCDemoUpdate();
503 
504         DWC_CreateUserData( &s_playerinfo.userdata );
505 
506         // Initialize the friend roster
507         DWCi_Np_CpuClear32( &s_playerinfo.friendlist,
508                             sizeof( s_playerinfo.friendlist ) );
509 
510     }
511 
512     DWC_ReportUserData( &s_playerinfo.userdata );
513 
514     // Perform friend match initialization
515     //
516     DWC_InitFriendsMatch( NULL,
517                           &s_playerinfo.userdata,
518                           GAME_PRODUCTID,
519                           GAME_NAME,
520                           GAME_SECRET_KEY,
521                           0,
522                           0,
523                           s_playerinfo.friendlist,
524                           FRIEND_LIST_LEN );
525 
526     // Start login processing
527     //
528     DWC_LoginAsync(	(u16*)L"name",
529                     NULL,
530                     loginCallback,
531                     &exitflag );
532 
533     // Wait until login has completed
534     //
535     while ( !exitflag )
536     {
537 
538         DWC_ProcessFriendsMatch();
539 
540         DWCDemoUpdate();
541 
542     }
543 
544     // Get your own friend code
545     //
546     // If login completed normally, the profile ID was probably acquired
547     // If it failed, 0 is returned
548     //
549     friendcode = DWC_CreateFriendKey( &s_playerinfo.userdata );
550     DWCDemoPrintf("My friend code is : %012llu\n", friendcode );
551     DWCDemoUpdate();
552 
553     // Main loop
554     //
555     //
556     //
557     //
558     while ( update() )
559     {
560 
561         DWC_ProcessFriendsMatch();
562 
563         DWCDemoUpdate();
564 
565     }
566 
567     // Shut down communications
568     //
569     DWC_ShutdownFriendsMatch();
570 
571 
572     // Save user data to NAND.
573     //
574 
575     // Clear the change flag
576     DWC_ClearDirtyFlag( &s_playerinfo.userdata );
577 
578     // Save to NAND
579     DWCDemoSaveNAND(    SAVEDATA_FILENAME,
580                         0,
581                         (u8*)&s_playerinfo,
582                         sizeof( s_playerinfo ) );
583 
584 }
585