Creating NES bots using FCEUX emulator

FCEUX Server

class pykitml.FCEUXServer(frame_func, quit_func=None, ip='localhost', port=1234)

Server class for making NES bots. Uses FCEUX emulator. Visit https://www.fceux.com for info. You will also need to load client lua script in the emulator.

__init__(frame_func, quit_func=None, ip='localhost', port=1234)
Parameters:
  • frame_func (function) – This function will be called every frame. The function should accept two argument, server (reference to this class) and frame (number of frames executed).
  • quit_func (function) – This function will be executed when the server disconnects from the emulator
  • ip (str) – IP address of the computer.
  • port (int) – Port to listen to.
start()

Starts the server, waits for emulator to connect. Calls frame_func every frame after connection has been established.

frame_advance()

Move to next frame, should be called at the end of frame_func.

get_joypad()
Returns:Joypad button states.
Return type:str
set_joypad(up=False, down=False, left=False, right=False, A=False, B=False, start=False, select=False)

Set joypad button states.

read_mem(addr, signed=False)

Read memory address.

Parameters:
  • addr (int) – The memory address to read
  • signed (bool) – If True, returns signed integer
Returns:

The byte at the address.

Return type:

int

reset()

Resets the emulator, executes a power cycle.

quit(reason='')

Disconnect from emulator.

Parameters:reason (str) – Reason for quitting.
info

Emulator info and lua version.

Lua client script

This script has to be loaded into the emulator after starting the server. (File > Load Lua Script)

fceux_client.lua

local socket = require "socket"

-- Edit to change
ip = 'localhost'
port = '1234'

-- Table for holding lua code snippets from server
func_table = {}

-- Start connection with server
s = socket.connect('localhost', '1234')

-- Helper function to convert table to string
function table_to_string(table)
    str = ''

    for key, value in pairs(table) do
        str = str .. tostring(key) .. ' ' .. tostring(value) .. ' '
    end

    return str
end

-- Helper function to split string into token
function split(inputstr, sep)
    if sep == nil then
            sep = "%s"
    end
    local t={}
    for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
            table.insert(t, str)
    end
    return t
end

-- Helper function to send server message
function send(msg)
    s:send(msg)
end

-- Helper function to receive message from server
function recv(msg)
    local resp, err = s:receive('*l')
    return resp
end

-- Helper function that waits for ackoledgement from server
function wait_for_ack()
    while (recv() ~= 'ACK') do end
end

-- Set the speed of the emulator
emu.speedmode('normal')

-- Server info
send('FCEUX Client '.._VERSION)
wait_for_ack()

-- Main loop
while true do
    local resp = ''

    -- Log frame count
    fcount = string.format('%d', emu.framecount())
    send(fcount)

    -- Parse commands from server
    while (resp ~= 'CONT') do
        resp = recv()

        if(resp == 'JOYPAD') then
            local controller = joypad.read(1)
            send(table_to_string(controller))
        elseif(resp == 'SETJOYPAD') then
            local values = split(recv())
            joypad.set(1, {
                up = (values[1]=='True'), down = (values[2]=='True'),
                left = (values[3]=='True'), right = (values[4]=='True'),
                A = (values[5]=='True'), B = (values[6]=='True'),
                start = (values[7]=='True'), select = (values[8]=='True'),
            })
        elseif(resp == 'MEM') then
            local addr = tonumber(recv())
            send(memory.readbyte(addr))
        elseif(resp == 'RES') then
            emu.softreset()
        else
            break
        end
    end

    emu.frameadvance()
end

Example bot to spam the ‘A’ button

import pykitml as pk

def on_frame(server, frame):
    # Spam A and start button
    if(frame%10 < 5): server.set_joypad(A=True, start=True)
    else: server.set_joypad(A=False, start=False)

    # Print joypad
    print(server.get_joypad())

    # Continue emulation
    server.frame_advance()

# Intialize and start server
server = pk.FCEUXServer(on_frame)
print(server.info)
server.start()

Start this script, then run the FCEUX emulator. Open any NES ROM (File > Open ROM) and then load the lua client script (File > Load Lua Script). The bot will continuously spam the A button.

Example bot to spam the ‘A’ button, second way

import pykitml as pk

# Instantiate server
server = pk.FCEUXServer(None)

try:
    while True:
        # Intialize frame, get frame count
        frame = server.init_frame()

        # Spam A and start button
        if(frame%10 < 5): server.set_joypad(A=True, start=True)
        else: server.set_joypad(A=False, start=False)

        # Print joypad
        print(server.get_joypad())

        # Continue emulation
        server.frame_advance()

except BrokenPipeError:
    server.quit('Client has quit.')
except KeyboardInterrupt:
    server.quit()