Shared Memory Specs
For programmers out there--this is how I've done the shared memory and external input.
The memory is shared in the file mappings: "fceu.GameMemBlock" (128k), "fceu.RAM" (2k), "fceu.BotInput" (4k), "fceu.XBuf" (the graphics buffer) (256*256+8), "fceu.ROM" (varies), "fceu.VROM" (varies). Probably the RAM and the BotInput are the only things you'll need to open.
You will want to use OpenFileMapping to get the data. This is a Windows NT kernel function, and so should be available under this name (or a very similar name) in whatever programming language you are using. Example in C/C++:
#include "windows.h"
int main(int argc, char* argv[])
{
HANDLE mapBotInput;
unsigned int * BotInput;
//Get the shared memory
mapBotInput = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, "fceu.BotInput");
if(!mapBotInput)
{
//Error
}
//Get a pointer to it
BotInput = (unsigned int *) MapViewOfFile(mapBotInput, FILE_MAP_WRITE, 0, 0, 0);
if(!BotInput)
{
//Error
}
//Now BotInput[] is available for reading/writing.
//Cleanup
UnmapViewOfFile(mapBotInput);
CloseHandle(mapBotInput);
BotInput = NULL;
}
The external input is read from fceu.BotInput. This is an array of 1024 uint32s. I'll use BotInput[x] to refer to the x-th value (0-based). A value of '0' in BotInput[0] means it's safe to write to BotInput. BotInput[1] through [1023] store the input in chronological order. The input format is: high word = 1 means load state (low word ignored currently), high word = 0 means 1 frame of input, where the 4th byte is controller 1 and the 3rd is controller 2. After writing the input, write the length of the input (i.e. the highest x such that BotInput[x] contains data) in BotInput[0]. (This is a good place to let your program idle, so windows will give the CPU to FCEU!) Then FCEU will run the input, writing '0' to BotInput[0] when it's done. Code is probably more explanatory:
if(BotInput[0])
{
BotPointer++;
switch(BotInput[BotPointer] >> 16)
{
case 0:
joy[0] = BotInput[BotPointer] & 255;
joy[1] = BotInput[BotPointer] >> 8;
joy[2] = joy[3] = 0;
FCEUI_FrameAdvance();
break;
case 1:
FCEUI_LoadState(0);
break;
default:
break;
}
if(BotPointer >= BotInput[0] || BotPointer >= 1023)
{
BotInput[0] = 0;
BotPointer = 0;
}
}
For the controller button values:
#define JOY_A 1 #define JOY_B 2 #define JOY_SELECT 4 #define JOY_START 8 #define JOY_UP 0x10 #define JOY_DOWN 0x20 #define JOY_LEFT 0x40 #define JOY_RIGHT 0x80
If you're confused by "high word" and "low word" or whatver, note that LoadState is just a value of 65536, player 1 A is 1, player 1 right is 128, player 2 A is 256, player 2 right is 32768.
I recommend always loading the save state when you start your bot, so you know where you're starting from!
Example bot code:
BotInput[1] = 65536; //Load state
BotInput[2] = 1; //First frame = player 1 A
BotInput[3] = 2; //Second frame = player 1 B
BotInput[4] = 3; //Third frame = player 1 AB
BotInput[0] = 4; //Tell FCEU to read 4 values from BotInput
while(BotInput[0] != 0) //Wait for FCEU to write 0 to BotInput[0]
{
Sleep(1); //It's a good idea to idle while you wait.
}
//Now you can write to BotInput again.