KittyPBoxx / pokeemerald-net-demo

Demo of emerald network functions using a connection to a wii
MIT License
75 stars 5 forks source link

Will online battles be implemented? #4

Open Bkrouse95 opened 1 month ago

Bkrouse95 commented 1 month ago

Is it possible to connect to players online from the Pokemon center?

KittyPBoxx commented 1 month ago

None of the standard link cable / wireless adapter features work online. Those communication sync up constantly so would fail due to network latency.

Getting online trading working meant writing a writing a new trade function that doesn't care about latency. The same would be required for all the other link cable features and some of them are quite difficult. For example I wrote function to try and make online battles work without needing to constantly communicate but every time someone did a turn with multiple actions (e.g baton pass, where you do a move, then switch) the games would end up out of sync with each other. 😞

I will probably get record mixing and online battles working in the future but that would be 2025

Bkrouse95 commented 1 month ago

Appreciate the reply, great job on what you've got so far. Going to try and get it to work on my expansion fork. Gen 3 online battles are coming eventually

KittyPBoxx commented 1 month ago

Not tried building on the expansion myself but MelonSpeedruns sent me a change they'd done to get it compiling.

at a minimum there are only 6 files of my changes that you need.

  1. src/main.c -> WaitForVBlank optimization changes (you may already have this)
  2. include/net_conn.h -> net_conn header file
  3. src/net_conn.c -> net_conn main file (you will need to remove some of those network functions you're not using to get it to compile)
  4. data/specials.inc -> the new special function definition to call network tasks
  5. include/constants/network.h -> for network constants
  6. include/gba/io_reg.h -> register definitions for serial communication

your io_reg.h file in network seems to be missing the #define TIMER_COUNTUP 0x04 define by default expansion has the FRONTIER_PARTY_SIZE set to 3, and not 6 like your code expects in Task_DownloadBattleProcess


case DOWNLOAD_BATTLE_FINISH: // Process the data (create the ereader data from what is now stored in gStringVar3)
default:
{
u32 i;
u32 offset = 0;
        FillEReaderTrainerWithPlayerData();
        StringFill(gSaveBlock2Ptr->frontier.ereaderTrainer.name, CHAR_SPACER, PLAYER_NAME_LENGTH);
        StringCopy_PlayerName(gSaveBlock2Ptr->frontier.ereaderTrainer.name, trainerName);
        gSaveBlock2Ptr->frontier.ereaderTrainer.facilityClass = FACILITY_CLASS_RS_BRENDAN;           

        gSpecialVar_0x8003 = 1;

        for (i = 0; i < DOWNLOAD_TRAINER_PARTY_SIZE; i++)
        {
                offset = DOWNLOAD_TRAINER_POKEMON_SIZE * i;

                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].species  = (u16) (gStringVar3[ 0 + offset] | gStringVar3[ 1 + offset] << 8);
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].level    =        gStringVar3[ 2 + offset]                                 ;
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].heldItem = (u16) (gStringVar3[ 3 + offset] | gStringVar3[ 4 + offset] << 8);
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[0] = (u16) (gStringVar3[ 5 + offset] | gStringVar3[ 6 + offset] << 8);
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[1] = (u16) (gStringVar3[ 7 + offset] | gStringVar3[ 8 + offset] << 8);
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[2] = (u16) (gStringVar3[ 9 + offset] | gStringVar3[10 + offset] << 8);
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[3] = (u16) (gStringVar3[11 + offset] | gStringVar3[12 + offset] << 8);

                StringFill(gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].nickname, CHAR_SPACER, POKEMON_NAME_LENGTH);

                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].nickname[0] = gStringVar3[13 + offset];
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].nickname[1] = gStringVar3[14 + offset];
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].nickname[2] = gStringVar3[15 + offset];
                gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].nickname[3] = 0xFF;

                // Basic validation to make sure we got something sensible back from the server/wii (ideally this would be a checksum from the server)
                if (gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].species > NUM_SPECIES || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].level > MAX_LEVEL || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].heldItem > ITEMS_COUNT || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[0] > MOVES_COUNT || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[1] > MOVES_COUNT || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[2] > MOVES_COUNT || 
                    gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].moves[3] > MOVES_COUNT )
                {
                    gSpecialVar_0x8003 = 0;
                }
        }

            // Basic validation to make sure we got something sensible back from the server/wii
            if (gSaveBlock2Ptr->frontier.ereaderTrainer.party[0].species == 0)
                gSpecialVar_0x8003 = 0;

        sSendRecvMgr.state = NET_CONN_STATE_DONE;
        break;
    }

gTasks[taskId].func = Task_NetworkTaskLoop;

} }`

Bkrouse95 commented 1 month ago

Thank you I tried a few times but got hung up on some compiling errors regarding FillEreaderTrainerWithPlayerData and Task_StartNetworkTask. Thank you again

KittyPBoxx commented 1 month ago

I don't think Task_StartNetworkTask is used anymore so can just be deleted.

This section can be removed too because it won't work for the expansion

else
{
     gSaveBlock2Ptr->frontier.ereaderTrainer.party[i].species = 0;
}

As for FillEreaderTrainerWithPlayerData it would need to not be marked as static or unused anymore and also declared in battle_tower.h

Bkrouse95 commented 1 month ago

I made the above changes and appears i'm down to 2 things. /opt/devkitpro/devkitARM/bin/../libexec/gcc/arm-none-eabi/14.1.0/cc1 -quiet -o build/modern/src/net_conn.o src/net_conn.c In file included from include/global.h:11, from src/net_conn.c:1: include/constants/flags.h:1565:9: warning: "FLAG_ROUTE101CHARMANDER" redefined 1565 | #define FLAG_ROUTE101CHARMANDER (SYSTEM_FLAGS + 0xC1) // Route101 Charmander | ^~~~~~~ include/constants/flags.h:48:9: note: this is the location of the previous definition 48 | #define FLAG_ROUTE101CHARMANDER 0x23 // Unused Flag | ^~~~~~~ src/net_conn.c: In function 'Task_DownloadBattleProcess': src/net_conn.c:682:13: error: implicit declaration of function 'FillEReaderTrainerWithPlayerData' [-Wimplicit-function-declaration] 682 | FillEReaderTrainerWithPlayerData(); | ^~~~~~~~ src/net_conn.c: In function 'Task_PostMailProcess': src/net_conn.c:1216:17: warning: unused variable 'i' [-Wunused-variable] 1216 | u32 i; | ^ make: [Makefile:403: build/modern/src/net_conn.o] Error 1 make: Deleting file 'build/modern/src/net_conn.o'

I guess I just don't know what to put for "i" and where to change it, and i'm not sure how to change FillEreaderTrainerWithPlayerData from static. I think im close to being able to compile expansion 1.9.3 with your online code.

KittyPBoxx commented 1 month ago

That looks like 1 actual issue and 2 warnings that are stopping the compile because it's running in strict mode.


  1. FLAG_ROUTE101CHARMANDER , that's not even my code. But you can see the it's doing a define on line 48 then replacing that definition on line 1565 of the same file.

Basically, the compiler is warning you something is wrong because the constant gets defined then overwritten before it's even used. To fix this you could change line 48 to be FLAG_UNUSED_0x023


  1. Unused u32 i. A variable called i is getting defined in the function but it's never getting used.

The compiler is warning you because the variable is being created for no reason. You can just delete u32 i; from line 1216 . Be careful to only delete it from the case POST_MAIL_FINISH: part of the switch statement (as 'i' is also defined in the POST_MAIL_SEND_REQUEST case where it is actually used.


  1. implicit declaration of FillEReaderTrainerWithPlayerData. net_conn.c has no knowledge of a function with that name.

The compiler is saying that the function FillEReaderTrainerWithPlayerData is being called but the file net_conn.c doesn't know about the function. This is because the function is declared in battle_tower.c

To let net_conn.c access the function from battle_tower.c you need to make sure a few conditions are met.

Bkrouse95 commented 1 month ago

Thank you. I will try this tomorrow. Appreciate the help

Bkrouse95 commented 1 month ago

Hey that actually worked. I have the emerald expansion 1.9.3 and your net demo compiled together.

Bkrouse95 commented 1 month ago

image Was able to connect 2 instances on a local machine no problem. I did remove the net mail script because even after making sure I added include script menu.h I could not get rid of the undefined reference.