Project64 Javascript API
mem
mem.u8|u16|u32|s8|s16|s32|float|double
Arrays for reading and modifying values in virtual memory. Virtual addresses are always used for indeces regardless of type size.
var addr_power = 0x8033B21E

if(mem.u8[addr_power] < 1)
{
    mem.u8[addr_power] = 8
}
mem.getblock(baseAddr, size)
Returns a Buffer object from a block of data of size bytes at baseAddr in virtual memory.
mem.getstring(baseAddr[, maxLen])
Returns a string from a zero-terminated ASCII string at baseAddr in virtual memory.
mem.bindvar(obj, baseAddr, name, type)
Adds property name to obj and "binds" it to the virtual address specified by baseAddr. Valid types are: u8, u16, u32, s8, s16, s32, float, and double.
mem.bindvar(this, 0x8033B21E, 'power', u8)

if(power < 1)
{
    power = 8
}
mem.bindvars(obj, vars)
Adds multiple virtual memory-bound properties to obj. Returns obj.
var mario = mem.bindvars({},
[
    [0x8033B1B0, 'y', float],
    [0x8033B21E, 'power', u8]
])

mario.power = 5
mario.y = 500.00
mem.bindstruct(obj, baseAddr, props)
Adds multiple virtual memory-bound properties to obj. Addresses are determined by type sizes. Returns obj.
var marioPos = mem.bindstruct(this, 0x8033B1AC,
{
    x: float,
    y: float,
    z: float
})
mem.typedef(props)
Returns a "struct" class that may be constructed using the address of a real struct in virtual memory.
const Player = mem.typedef(
{
    health: u32,
    x: float,
    y: float,
    z: float
})

Player.prototype.move = function(x, y, z)
{
    this.x = x
    this.y = y
    this.z = z
}

Player.prototype.heal = function()
{
    this.health = 100;
}

var player = new Player(0x8033B1AC)

player.move(100, 200, 300)
player.heal()
rom
rom.u8|u16|u32|s8|s16|s32|float|double
Arrays for reading values in cartridge ROM. Indexing works in a similar manner to mem's.
var crc1 = rom.u32[0x00000010]
var crc2 = rom.u32[0x00000014]
rom.getblock(baseAddr, size)
Returns a Buffer object from a block of data of size bytes at baseAddr in cartridge ROM.
rom.getstring(baseAddr[, maxLen])
Returns a string from a zero-terminated ASCII string at baseAddr in cartridge ROM.
var romName = rom.getstring(0x00000020)
console.log('Internal ROM name: ' + romName)
events
emulation thread interpreter mode
events.onexec(address, callback)
Adds a CPU execution callback for a virtual address or AddressRange and returns a callback ID. callback will be invoked at the beginning of a CPU step if the program counter is at address. callback receives the program counter address at which the event is fired.
events.onexec(0x802CB1C0, function()
{
    console.log('CPU is calling 0x802CB1C0')
})
events.onexec(ADDR_ANY, function(addr))
{
    // Log every step!
    console.log('CPU is executing ' + addr.hex())
})
emulation thread interpreter mode
events.onread(address, callback)
Adds a CPU read callback for a virtual address or AddressRange and returns a callback ID. callback will be invoked at the beginning of a CPU step if the current instruction is going to read from address. callback receives the virtual address that the CPU is going to read.
events.onread(0x8033B1B0, function()
{
    console.log('CPU is reading 8033B1B0')
})
const addr_range_rom = {start: 0xB0000000, end: 0xB6000000}

events.onread(addr_range_rom, function(addr)
{
    console.log('CPU is reading ROM ' + addr)
})
emulation thread interpreter mode
events.onwrite(address, callback)
Adds a CPU write callback for a virtual address or AddressRange and returns a callback ID. callback will be invoked at the beginning of a CPU step if the current instruction is going to write to address. callback receives the virtual address that the CPU is going to write to.
events.onwrite(0x8033B1B0, function()
{
    console.log('CPU is modifying 8033B1B0')
})
events.onwrite({0xB0000000, 0x90000000}, function(addr)
{
    console.log(gpr.pc.hex() + ': wrote to cartridge ' + addr.hex());
})
emulation thread
events.ondraw(callback)
Adds a callback which will be invoked immediately after Project64 requests a screen update from the graphics plugin. Returns a callback ID.
events.ondraw(function()
{
    console.log('Frame drawn')
})
events.remove(callbackId)
Removes a registered callback by its ID.
var callbackId = events.onexec(0x80000180, function()
{
    // Only invoked once
    console.log('Interrupt fired')
    events.remove(callbackId)
})
debug
debug.breakhere()
Pauses emulation and opens the debugger window. Useful for creating conditional breakpoints.
events.onexec(0x802CB1C0, function()
{
    if(gpr.a0 == 0)
    {
        console.log('0 passed to 0x802CB1C0, breaking')
        debug.breakhere()
    }
})
fs
fs.open(path, mode)
Opens the file pointed to by path in the mode specified by mode. Returns a file descriptor on success or false if the operation failed.
var fd = fs.open('log.txt', 'w')
Valid modes:
r or rb           Open file for reading.
w or wb           Truncate to zero length or create file for writing.
a or ab           Append; open or create file for writing at end-of-file.
r+ or rb+ or r+b  Open file for update (reading and writing).
w+ or wb+ or w+b  Truncate to zero length or create file for update.
a+ or ab+ or a+b  Append; open or create file for update, writing at end-of-file.

http://pubs.opengroup.org/onlinepubs/009695399/functions/fopen.html
fs.close(fd)
Closes the file referenced by fd.
fs.write(fd, buffer[, offset[, length[, position]]])
Writes buffer to the file referenced by fd. Returns the number of bytes written.
var fd = fs.open('log.txt', 'w')
fs.write(fd, 'Hello world!\n')
fs.close(fd)
var buf = mem.getblock(0x8033B400, 4 * 32)
var fd = fs.open('data.bin', 'wb')
fs.write(fd, buf)
fs.close(fd)
fs.writeFile(path, buffer)
Writes buffer to the file pointed to by path. Returns true if the operation was successful or false if the operation failed.
fs.read(fd, buffer, offset, length, position)
Reads the file referenced by fd into buffer. Returns the number of bytes read.
var buf = new Buffer(128)
var fd = fs.open('data.bin', 'rb')
var nBytesRead = fs.read(fd, buf, 0, buf.length, 0)
fs.close(fd)
fs.readFile(path)
Reads the file pointed to by path. Returns a Buffer object representing the file, or false if the operation failed.
fs.fstat(fd)
Returns an fs.Stats object describing the file referenced by fd.
var stats = fs.fstat(fd)
console.log('size: ' + stats.size)
fs.stat(path)
Returns an fs.Stats object describing the file or directory pointed to by path. Returns false if the operation failed..
fs.unlink(path)
Deletes a file. Returns true if the operation was successful.
fs.mkdir(path)
Creates a directory. Returns true if the operation was successful.
fs.rmdir(path)
Removes a directory. The directory must be empty. Returns true if the operation was successful.
fs.readdir(path)
Returns an array of file names in the directory pointed to by path. Returns false if the operation failed.
fs.Stats
stats.dev ID of the device the file resides on
stats.ino inode number
stats.mode File permissions
stats.nlink Number of links to the file
stats.uid User ID
stats.gid Group ID
stats.rdev Device ID (if file is character or block special)
stats.size Size of the file in bytes
stats.atimeMs Last access timestamp in milliseconds
stats.mtimeMs Last modification timestamp in milliseconds
stats.ctimeMs Creation timestamp in milliseconds
stats.atime JS Date object representing the last access time
stats.mtime JS Date object representing the last modification time
stats.ctime JS Date object representing the creation time
stats.isDirectory()
Returns true if the fs.Stats object describes a directory.
stats.isFile()
Returns true if the fs.Stats object describes a regular file.
console
console.print(text)
Prints text to the script console.
console.print('Hello world\n')
console.log(text[, text2, ...])
Concatenates all provided text arguments with spaces and prints the result to the script console with a trailing newline.
console.log('Hello', 'world')
console.clear()
Clears all previously printed text from the script console.
alert
alert(message[, caption])
Shows a message box with an optional caption. The calling thread will be blocked until the message box is dismissed.
alert('Hello world') // Blocks the script's thread

events.onexec(0x80000180, function()
{
    alert('Interrupt fired!') // Blocks the emulation thread
})
screen
screen.print(x, y, text)
Prints text to the screen at the provided x and y coordinates. Should be called from an events.ondraw callback. (Unstable!)
events.ondraw(function()
{
    screen.print(20, 20, 'power: ' + mem.u8[0x8033B21E])
})
gpr
gpr.r0|at|v0|v1|a0 ...
gpr[0|1|2 ...]
Variables representing the lower 32 bits of each general purpose register.
events.onexec(0x802CB1C0, function()
{
    if(gpr.a0 == 2)
    {
        gpr.a0 = 3
    }
})
gpr.pc
Variable representing the CPU's program counter.
gpr.hi
Variable representing the lower 32 bits of the HI register.
gpr.lo
Variable representing the lower 32 bits of the LO register.
ugpr
ugpr.r0|at|v0|v1|a0 ...
ugpr[0|1|2 ...]
Variables representing the upper 32 bits of each general purpose register.
ugpr.hi
Variable representing the upper 32 bits of the HI register.
ugpr.lo
Variable representing the upper 32 bits of the LO register.
fpr
fpr.f0|f1|f2|f3|f4 ...
fpr[0|1|2 ...]
Variables representing the 32-bit floating point registers.
events.onexec(0x802CB1C0, function()
{
    if(gpr.f0 == 2.0)
    {
        gpr.f0 = 3.0
    }
})
dfpr
dfpr.f0|f2|f4|f6 ...
dfpr[0|2|4 ...]
Variables representing the 64-bit floating point registers.
Server
new Server(settings)
Creates a new server socket. If port is provided in settings, the server will start listening immediately.
var server = new Server({port: 80})
server.listen(port)
Binds the server socket to a port and starts listening.
server.on('connection', callback)
Starts accepting clients. When a client is accepted, a Socket object for it is created and passed to callback.
server.on('connection', function(socket)
{
    socket.on('data', function(data)
    {
        socket.write('hello')
    })
})
Socket
new Socket([fd])
Creates a new socket object.
socket.connect(settings[, callback])
Connects the socket to the host and port specified by the settings object. The default values for the host and port are "127.0.0.1" and 80 respectively.
socket.write(data[, callback])
Writes data to the socket.
socket.on('data', callback)
Starts reading data from the socket asynchronously. When data arrives, it is passed to callback as a Buffer object.
socket.on('close', callback)
AddressRange
new AddressRange(start, end)
Creates an immutable object with start and end address properties.
The following AddressRange objects are defined globally:
ADDR_ANY              0x00000000 : 0x100000000 Any 32-bit address

ADDR_ANY_KUSEG        0x00000000 : 0x80000000  MIPS user mode TLB mapped segment
ADDR_ANY_KSEG0        0x80000000 : 0xA0000000  MIPS cached unmapped segment
ADDR_ANY_KSEG1        0xA0000000 : 0xC0000000  MIPS uncached unmapped segment
ADDR_ANY_KSEG2        0xC0000000 : 0x100000000 MIPS kernel mode TLB mapped segment

ADDR_ANY_RDRAM        0x80000000 : 0x80800000 Cached RDRAM
ADDR_ANY_RDRAM_UNC    0xA0000000 : 0xA0800000 Uncached RDRAM

ADDR_ANY_CART_ROM     0x90000000 : 0x96000000 Cached cartridge ROM
ADDR_ANY_CART_ROM_UNC 0xB0000000 : 0xB6000000 Uncached cartridge ROM
Number
number.hex([nChars])
Returns a hexadecimal string representation of the number object. The resulting string is prepended with zeroes until its character length meets nChars or 8 by default.
var sm64EntryPC = rom.u32[0x00000008]
console.log('Entry: ' + sm64EntryPC.hex()) // "Entry: 80246000"