/*---------------------------------------------------------------------------* Project: RevolutionDWC Demos File: ./frienddata/src/main.c Copyright 2005-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ /** * * * Brief comment: Friend data demo * * This demo builds a friend relationship by exchanging friend codes. * Formed friendships are saved in NAND memory and restored at the next startup. * * Procedure for forming a friend relationship using this demo * * 1. Run the demo on each of two consoles * 2. Press "A" on each and enter the other one's friend code * 3. Press "X" to save and exit * 4. Startup again (the friend relationship will be formed during login) * 5. Press "X" to save and exit * * Version: 1.4.16 Revised program to check for duplicate friend codes. * */ #include "../../common/include/common.h" // Constant Declarations //--------------------------------------------------------- // Variable Declarations //--------------------------------------------------------- /// Structure that contains the player information static struct tagPlayerInfo { /// User data DWCUserData userdata; /// Friend data DWCFriendData friendlist[FRIEND_LIST_LEN]; } s_playerinfo ATTRIBUTE_ALIGN(32); // Function Prototype //--------------------------------------------------------- static int GetAvailableFriendListIndex( void ); static BOOL CheckForDuplicatedFriendData( DWCFriendData* data ); static void DispFriendList( void ); static BOOL update( void ); static void loginCallback(DWCError error, int profileID, void * param); static void updateCallback(DWCError error, BOOL isChanged, void* param); /** * Gets an empty index on the friend roster. * * Return value: Available index in the friend roster. * Returns -1 if there is no available index. */ static int GetAvailableFriendListIndex( void ) { int i; for ( i = 0; i < FRIEND_LIST_LEN; i++ ) { if ( !DWC_IsValidFriendData( &s_playerinfo.friendlist[i] ) ) return i; } return -1; } /** * Check through the friend roster to see if the friend is already registered. * * Param: data - The friend data to check * * Return value: TRUE: Does not exist in the roster * Return value: FALSE: Already exists in the roster */ static BOOL CheckForDuplicatedFriendData( DWCFriendData* data ) { int i; for ( i = 0; i < FRIEND_LIST_LEN; i++ ) { if ( DWC_IsEqualFriendData( &s_playerinfo.friendlist[i], data ) ) return FALSE; } return TRUE; } /** * Display the friend roster. */ static void DispFriendList( void ) { int i; for ( i = 0; i < FRIEND_LIST_LEN; i++ ) { if ( !DWC_IsValidFriendData( &s_playerinfo.friendlist[i] ) ) continue; DWCDemoPrintf( " #%02d: ", i ); DWC_ReportFriendData( &s_playerinfo.userdata, &s_playerinfo.friendlist[i] ); } DWCDemoPrintf( "\n"); } /** * The callback function called during login */ static void loginCallback(DWCError error, int profileID, void * param) { DWCDemoPrintf( "Login callback : %d\n", error ); if ( error == DWC_ERROR_NONE ) { // When the login is successful // DWCDemoPrintf( "Login Success. ProfileID=%d\n", profileID ); } else { // When the login failed // DWCDemoPanic( "Login Failed\n" ); } // Set the loop ended flag *((BOOL*)param) = TRUE; } static BOOL update( void ) { static u32 padlast = 0; // The previous pressed state u32 pad; // The current pressed state u32 padtrig; // Keys whose state changed from the last time u32 padpressed; // Newly-pressed keys u32 padreleased; // Newly-released keys static u32 cursor = 0; static u8 cfriendcode[12]; static u64 friendcode; static u8 delindex = 0; static enum { STATE_MENU, STATE_SELECT, STATE_ADD_FRIEND, STATE_ADD_FRIEND_INPUT, STATE_ADD_FRIEND_PROCESS, STATE_DEL_FRIEND, STATE_DEL_FRIEND_INPUT, STATE_DEL_FRIEND_PROCESS } state = STATE_MENU; int i; // Read key input pad = DWCDemoPadRead(); padtrig = padlast ^ pad; padpressed = padtrig & pad; padreleased = padtrig & ~pad; switch ( state ) { case STATE_MENU: DWCDemoPrintf("\n"); DWCDemoPrintf("--------------------------------\n"); DWCDemoPrintf("- DWC Friend Data Demo -\n"); DWCDemoPrintf("--------------------------------\n"); DWCDemoPrintf("A: add friend\n"); DWCDemoPrintf("B: del friend\n"); DWCDemoPrintf("Y: update server\n"); DWCDemoPrintf("X: save & exit\n"); state = STATE_SELECT; break; case STATE_SELECT: if ( padpressed & DWCDEMO_KEY_A ) { state = STATE_ADD_FRIEND; break; } else if ( padpressed & DWCDEMO_KEY_B ) { state = STATE_DEL_FRIEND; break; } else if ( padpressed & DWCDEMO_KEY_Y ) { // By calling this asynchronous function, friend information stored locally and on the server are synchronized. // DWC_UpdateServersAsync( NULL, updateCallback, NULL, NULL, NULL, NULL, NULL); DWCDemoPrintf( "DWC_UpdateServersAsync\n" ); state = STATE_MENU; break; } else if ( padpressed & DWCDEMO_KEY_X ) { // Quit return FALSE; } break; case STATE_ADD_FRIEND: DWCDemoPrintf("Please the input friend code.\n"); DWCDemoPrintf("Arrow: input number\n"); DWCDemoPrintf("A: OK\n"); DWCDemoPrintf("B: Cancel\n"); state = STATE_ADD_FRIEND_INPUT; break; case STATE_ADD_FRIEND_INPUT: if ( padpressed & DWCDEMO_KEY_UP ) { cfriendcode[cursor] = (u8)((cfriendcode[cursor] + 1) % 10); } else if ( padpressed & DWCDEMO_KEY_DOWN ) { cfriendcode[cursor] = (u8)(cfriendcode[cursor] == 0 ? 9 : (cfriendcode[cursor] - 1)); } else if ( padpressed & DWCDEMO_KEY_LEFT ) { cursor = cursor == 0 ? 11 : (cursor - 1); } else if ( padpressed & DWCDEMO_KEY_RIGHT ) { cursor = (cursor + 1) % 12; } else if ( padpressed & DWCDEMO_KEY_A ) { friendcode = 0; for ( i=0; i<12; i++ ) friendcode = friendcode * 10 + cfriendcode[i]; DWCDemoPrintf( "Add friend(%012llu)\n", friendcode ); state = STATE_ADD_FRIEND_PROCESS; break; } else if ( padpressed & DWCDEMO_KEY_B ) { DWCDemoPrintf( "canceled\n" ); state = STATE_MENU; } else break; { char tmpbuf[0xff]; sprintf( tmpbuf, "" ); for ( i=0; i<12; i++ ) sprintf( tmpbuf, "%s%d", tmpbuf, cfriendcode[i] ); sprintf( tmpbuf, "%s\n", tmpbuf ); for ( i=0; i<12; i++ ) sprintf( tmpbuf, "%s%c", tmpbuf, " ~"[cursor==i] ); sprintf( tmpbuf, "%s\n", tmpbuf ); DWCDemoPrintf( tmpbuf ); } break; case STATE_ADD_FRIEND_PROCESS: if ( DWC_CheckFriendKey( &s_playerinfo.userdata, friendcode ) ) { int index; index = GetAvailableFriendListIndex(); if ( index != -1 ) { if ( DWC_CanChangeFriendList() ) { DWCFriendData newdata; DWC_CreateFriendKeyToken( &newdata, friendcode ); // Checks if the friend is already present in the friend roster, and if not, adds the friend if ( CheckForDuplicatedFriendData( &newdata ) ) { s_playerinfo.friendlist[index] = newdata; } else { DWCDemoPrintf( "dupulicating friend code\n" ); } } else { // If the friend roster is in an uneditable state, return to the input phase DWCDemoPrintf( "The friends list is locked now. Retry later.\n" ); state = STATE_ADD_FRIEND_INPUT; break; } } else { DWCDemoPrintf( "Too many friends:)\n" ); } } else { DWCDemoPrintf( "invalid friend code\n" ); } state = STATE_MENU; break; case STATE_DEL_FRIEND: DWCDemoPrintf("Input index to delete.\n"); DWCDemoPrintf("Arrow: input number\n"); DWCDemoPrintf("A: OK\n"); DWCDemoPrintf("B: Cancel\n"); DWCDemoPrintf( "index=%d\n", delindex ); DispFriendList(); state = STATE_DEL_FRIEND_INPUT; break; case STATE_DEL_FRIEND_INPUT: if ( padpressed & DWCDEMO_KEY_UP ) { delindex = (u8)((delindex + 1) % FRIEND_LIST_LEN); } else if ( padpressed & DWCDEMO_KEY_DOWN ) { delindex = (u8)(delindex == 0 ? (FRIEND_LIST_LEN-1) : (delindex - 1)); } else if ( padpressed & DWCDEMO_KEY_A ) { DWCDemoPrintf( "delete #%d\n", delindex ); state = STATE_DEL_FRIEND_PROCESS; } else if ( padpressed & DWCDEMO_KEY_B ) { DWCDemoPrintf( "canceled\n" ); state = STATE_MENU; } else break; DWCDemoPrintf( "index=%d\n", delindex ); break; case STATE_DEL_FRIEND_PROCESS: if ( DWC_CanChangeFriendList() ) { DWC_DeleteBuddyFriendData( &s_playerinfo.friendlist[delindex] ); } else { // If the friend roster is in an uneditable state, return to the input phase DWCDemoPrintf( "The friends list is locked now. Retry later.\n" ); state = STATE_DEL_FRIEND; break; } state = STATE_MENU; break; } // Save the current state padlast = pad; return TRUE; } static void updateCallback(DWCError error, BOOL isChanged, void* param) { (void)param; (void)isChanged; if ( error == DWC_ERROR_NONE ) { // Successful synchronous processing of friend roster. DWCDemoPrintf( "Update Servers succeeded.\n" ); } else { DWCDemoPrintf("Error\n"); } } //============================================================================= /*! * @brief Main */ //============================================================================= void DWCDemoMain() { u64 friendcode; BOOL exitflag = FALSE; // Load user data from NAND // DWCDemoPrintf("Loading userdata from NAND...\n"); DWCDemoUpdate(); DWCDemoLoadNAND( SAVEDATA_FILENAME, 0, (u8*)&s_playerinfo, sizeof( s_playerinfo ) ); // Check if user data is valid // if ( !DWC_CheckUserData( &s_playerinfo.userdata ) ) { // If valid user data had not been saved // // Create user data. DWCDemoPrintf("Creating new UserData\n"); DWCDemoUpdate(); DWC_CreateUserData( &s_playerinfo.userdata ); // Initialize the friend roster DWCi_Np_CpuClear32( &s_playerinfo.friendlist, sizeof( s_playerinfo.friendlist ) ); } DWC_ReportUserData( &s_playerinfo.userdata ); // Perform friend match initialization // DWC_InitFriendsMatch( NULL, &s_playerinfo.userdata, GAME_PRODUCTID, GAME_NAME, GAME_SECRET_KEY, 0, 0, s_playerinfo.friendlist, FRIEND_LIST_LEN ); // Start login processing // DWC_LoginAsync( (u16*)L"name", NULL, loginCallback, &exitflag ); // Wait until login has completed // while ( !exitflag ) { DWC_ProcessFriendsMatch(); DWCDemoUpdate(); } // Get your own friend code // // If login completed normally, the profile ID was probably acquired // If it failed, 0 is returned // friendcode = DWC_CreateFriendKey( &s_playerinfo.userdata ); DWCDemoPrintf("My friend code is : %012llu\n", friendcode ); DWCDemoUpdate(); // Main loop // // // // while ( update() ) { DWC_ProcessFriendsMatch(); DWCDemoUpdate(); } // Shut down communications // DWC_ShutdownFriendsMatch(); // Save user data to NAND. // // Clear the change flag DWC_ClearDirtyFlag( &s_playerinfo.userdata ); // Save to NAND DWCDemoSaveNAND( SAVEDATA_FILENAME, 0, (u8*)&s_playerinfo, sizeof( s_playerinfo ) ); }