Enhanced JavaScript environment for PlayStation 2™
AthenaEnv is a project that seeks to facilitate and at the same time brings a complete kit for users to create homebrew software for PlayStation 2 using the JavaScript language. It has dozens of built-in functions, both for creating games and apps. The main advantage over using AthenaEnv project instead of the pure PS2SDK is above all the practicality, you will use one of the simplest possible languages to create what you have in mind, besides not having to compile, just script and test, fast and simple.
New types are always being added and this list can grow a lot over time, so stay tuned.
In this section you will have some information about how to code using AthenaEnv, from prerequisites to useful functions and information about the language.
Using AthenaEnv you only need one way to code and one way to test your code, that is, if you want, you can even create your code on PS2, but I'll leave some recommendations below.
How to enable HostFS on PCSX2 1.7.0:
• (old) WxWidgets:
• Qt version:
Qt recommendation: Enable console output
Oh, and I also have to mention that an essential prerequisite for using AthenaEnv is knowing how to code in JavaScript.
Hello World:
const font = new Font("default");
os.setInterval(() => { // Basically creates an infinite loop, similar to while true(you can use it too).
Screen.clear(); // Clear screen for the next frame.
font.print(0, 0, "Hello World!"); // x, y, text
Screen.flip(); // Updates the screen.
}, 0);
See more examples at AthenaEnv samples.
AthenaEnv uses a slightly modified version of the QuickJS interpreter for JavaScript language, which means that it brings almost modern JavaScript features so far.
Float32
This project introduces a (old)new data type for JavaScript: single floats. Despite being less accurate than the classic doubles for number semantics, they are important for performance on the PS2, as the console only processes 32-bit floats on its FPU.
You can write single floats on AthenaEnv following the syntax below:
let test_float = 15.0f; // The 'f' suffix makes QuickJS recognizes it as a single float.
or
let test_float = Math.fround(15.0); // Math.fround returns real single floats on Athena.
How to run it
Athena is basically a JavaScript loader, so it loads .js files. It runs "main.js" by default, but you can run other file names by passing it as the first argument when launching the ELF file.
If you try to just download it on releases tab and run it, that's what you will see:
That's the default dashboard, coded in default main.js file. It searchs JavaScript files with the first line containing the following structure:
// {"name": "App name", "author": "Who did it?", "version": "04012023", "icon": "app_icon.png", "file": "my_app.js"}
// Now you can freely code below:
Once it was found, it will appear on the dashboard app list.
Error reporting system
Athena has a consistent error system, which is capable of pointing the error type, custom message, files, lines and it even has a color code.
EvalError:
SyntaxError:
TypeError:
ReferenceError:
RangeError:
InternalError:
URIError:
AggregateError:
Below is the list of usable functions of AthenaEnv project currently, this list is constantly being updated.
P.S.: Italic parameters refer to optional parameters
The std module provides wrappers to the libc stdlib.h and stdio.h and a few other utilities.
Available exports:
Enumeration object containing the integer value of common errors (additional error codes may be defined):
std.EINVAL
std.EIO
std.EACCES
std.EEXIST
std.ENOSPC
std.ENOSYS
std.EBUSY
std.ENOENT
std.EPERM
std.EPIPE
std.strerror(errno) - Return a string that describes the error errno.
std.gc() - Manually invoke the cycle removal algorithm. The cycle removal algorithm is automatically started when needed, so this function is useful in case of specific memory constraints or for testing.
std.parseExtJSON(str) - Parse str using a superset of JSON.parse. The following extensions are accepted:
• Single line and multiline comments
• unquoted properties (ASCII-only Javascript identifiers)
• trailing comma in array and object definitions
• single quoted strings
• \f and \v are accepted as space characters
• leading plus in numbers
• octal (0o prefix) and hexadecimal (0x prefix) numbers
FILE prototype:
Construction:
let file = std.open(filename, flags);
filename - Path to the file, E.g.: "samples/test.txt".
flags - File mode, E.g.: "w", "r", "wb", "rb", etc.
let file = std.open("test.txt", "w");
close() - Close the file. Return 0 if OK or -errno in case of I/O error.
puts(str) - Outputs the string with the UTF-8 encoding.
printf(fmt, ...args) - Formatted printf. • The same formats as the standard C library printf are supported. Integer format types (e.g. %d) truncate the Numbers or BigInts to 32 bits. Use the l modifier (e.g. %ld) to truncate to 64 bits.
flush() - Flush the buffered file.
seek(offset, whence) - Seek to a give file position (whence is std.SEEK_*). offset can be a number or a bigint. Return 0 if OK or -errno in case of I/O error.
tell() - Return the current file position.
tello() - Return the current file position as a bigint.
eof() - Return true if end of file.
fileno() - Return the associated OS handle.
error() - Return true if there was an error.
clearerr() - Clear the error indication.
read(buffer, position, length) - Read length bytes from the file to the ArrayBuffer buffer at byte position position (wrapper to the libc fread).
write(buffer, position, length) - Write length bytes to the file from the ArrayBuffer buffer at byte position position (wrapper to the libc fwrite).
getline() - Return the next line from the file, assuming UTF-8 encoding, excluding the trailing line feed.
readAsString(max_size = undefined) - Read max_size bytes from the file and return them as a string assuming UTF-8 encoding. If max_size is not present, the file is read up its end.
getByte() - Return the next byte from the file. Return -1 if the end of file is reached.
putByte(c) - Write one byte to the file.
The os module provides Operating System specific functions:
Available exports:
let fd = os.open(filename, flags, mode = 0o666) - Open a file. Return a handle or < 0 if error.
Flags:
• os.O_RDONLY
• os.O_WRONLY
• os.O_RDWR
• os.O_APPEND
• os.O_CREAT
• os.O_EXCL
• os.O_TRUNC
POSIX open flags.
os.close(fd) - Close the file handle fd.
os.seek(fd, offset, whence) - Seek in the file. Use std.SEEK_* for whence. offset is either a number or a bigint. If offset is a bigint, a bigint is returned too.
os.read(fd, buffer, offset, length) - Read length bytes from the file handle fd to the ArrayBuffer buffer at byte position offset. Return the number of read bytes or < 0 if error.
os.write(fd, buffer, offset, length) - Write length bytes to the file handle fd from the ArrayBuffer buffer at byte position offset. Return the number of written bytes or < 0 if error.
os.remove(filename) - Remove a file. Return 0 if OK or -errno.
os.rename(oldname, newname) - Rename a file. Return 0 if OK or -errno.
os.realpath(path) - Return [str, err] where str is the canonicalized absolute pathname of path and err the error code.
os.getcwd() - Return [str, err] where str is the current working directory and err the error code.
os.chdir(path) - Change the current directory. Return 0 if OK or -errno.
os.mkdir(path, mode = 0o777) - Create a directory at path. Return 0 if OK or -errno.
os.stat(path), os.lstat(path) - Return [obj, err] where obj is an object containing the file status of path. err is the error code. The following fields are defined in obj: dev, ino, mode, nlink, uid, gid, rdev, size, blocks, atime, mtime, ctime. The times are specified in milliseconds since 1970. lstat() is the same as stat() excepts that it returns information about the link itself.
Constants to interpret the mode property returned by stat(). They have the same value as in the C system header sys/stat.h.
• os.S_IFMT
• os.S_IFIFO
• os.S_IFCHR
• os.S_IFDIR
• os.S_IFBLK
• os.S_IFREG
• os.S_IFSOCK
• os.S_IFLNK
• os.S_ISGID
• os.S_ISUID
os.utimes(path, atime, mtime) - Change the access and modification times of the file path. The times are specified in milliseconds since 1970. Return 0 if OK or -errno.
os.readdir(path) - Return [array, err] where array is an array of strings containing the filenames of the directory path. err is the error code.
os.setReadHandler(fd, func) - Add a read handler to the file handle fd. func is called each time there is data pending for fd. A single read handler per file handle is supported. Use func = null to remove the handler.
os.setWriteHandler(fd, func) - Add a write handler to the file handle fd. func is called each time data can be written to fd. A single write handler per file handle is supported. Use func = null to remove the handler.
os.sleep(delay_ms) - Sleep during delay_ms milliseconds.
os.setTimeout(func, delay) - Call the function func after delay ms. Return a handle to the timer.
os.setInterval(func, interval) - Call the function func at specified intervals (in milliseconds). Return a handle to the timer.
os.setImmediate(func) - Executes a given function immediately.
os.clearTimeout(handle) - Cancel a timer.
os.clearInterval(handle) - Cancel a interval.
os.clearImmediate(handle) - Cancel a immediate execution.
os.platform - Return a string representing the platform: "linux", "darwin", "win32", "ps2" or "js".
Construction:
var test = new Image("owl.png", VRAM);
Properties:
Methods:
var loaded = image.ready();
ImageList
Construction:
var async_list = new ImageList(); // This constructor creates a new thread and a queue to load images in background, avoid building multiple ImageList objects.
Methods:
async_list.process();
• Remember to enable zbuffering on screen mode, put the line of code below
• Default NTSC mode(3D enabled):
const canvas = Screen.getMode();
canvas.zbuffering = true;
canvas.psmz = Z16S;
Screen.setMode(canvas);
Construction:
var model = new RenderObject(mesh, *texture*)
/* Load simple WaveFront OBJ files or vertex arrays.
MTL is supported on OBJs (including per-vertex colors and multi-texturing).
If you don't have a MTL file but you want to bind a texture on it,
just pass the image as a second argument if you want to use it. */
Methods:
Properties:
Camera
Lights
You have 4 lights to use in 3D scenes, use set to configure them.
Construction:
var font = new Font(path); // It supports png, bmp, jpg, otf, ttf.
path - Path to a font file, E.g.: "images/atlas.png", "fonts/font.png".
var osdfnt = new Font(); //Load BIOS font, not available for all console models
var font = new Font("Segoe UI.ttf"); //Load trueType font
Properties:
Methods:
Buttons list:
• Pads.SELECT
• Pads.START
• Pads.UP
• Pads.RIGHT
• Pads.DOWN
• Pads.LEFT
• Pads.TRIANGLE
• Pads.CIRCLE
• Pads.CROSS
• Pads.SQUARE
• Pads.L1
• Pads.R1
• Pads.L2
• Pads.R2
• Pads.L3
• Pads.R3
var pad = Pads.get(port) - Returns a pad object:
Properties:
• pad.btns - Button state on the current check.
• pad.old_btns = Button state on the last check.
• pad.lx - Left analog horizontal position (left = -127, default = 0, right = 128).
• pad.ly - Left analog vertical position (up = -127, default = 0, down = 128).
• pad.rx - Right analog horizontal position (left = -127, default = 0, right = 128).
• pad.ry - Right analog vertical position (up = -127, default = 0, down = 128).
Methods:
• update() - Updates all pads pressed and stick positions data.
• pressed(button) - Checks if a button is being pressed (continuously).
• justPressed(button) - Checks if a button was pressed only once.
• setEventHandler() - Sets the pad object to listen events defined by Pads.newEvent, so it doesn't need to be updated.
let event_id = Pads.newEvent(button, kind, function) - Creates an asynchronous pad event, returns the event id. Remember to set the pad object event handler first!
Pad event kinds:
• Pads.PRESSED
• Pads.JUST_PRESSED
• Pads.NON_PRESSED
Pads.deleteEvent(event_id) - Deletes the event created by Pads.newEvent.
let type = Pads.getType(port) - Gets gamepad type in the specified port.
Pad Types:
• Pads.DIGITAL
• Pads.ANALOG
• Pads.DUALSHOCK
let press = Pads.getPressure(port, button) - Get button pressure level.
Pads.rumble(port, big, small) - Rumble your gamepad.
var listdir = System.listDir(path)
• listdir[index].name - return file name on indicated index(string)
• listdir[index].size - return file size on indicated index(integer)
• listdir[index].directory - return if indicated index is a file or a directory(bool)
System.removeDirectory(path)
System.copyFile(source, dest)
System.moveFile(source, dest)
System.rename(source, dest)
System.sleep(sec)
System.exitToBrowser()
System.setDarkMode(value)
var temps = System.getTemperature() // It only works with SCPH-500XX and later models.
var info = System.getMCInfo(slot)
• info.type
• info.freemem
• info.format
var ee_info = System.getCPUInfo()
• ee_info.implementation
• ee_info.revision
• ee_info.FPUimplementation
• ee_info.FPUrevision
• ee_info.ICacheSize
• ee_info.DCacheSize
• ee_info.RAMSize
• ee_info.MachineSize
var gs_info = System.getGPUInfo()
• gs_info.id
• gs_info.revision
var ram_usage = System.getMemoryStats()
• ram_usage.core - Kernel + Native code size in RAM
• ram_usage.nativeStack - Kernel + Native stack size
• ram_usage.allocs - Dynamic allocated memory tracking
• ram_usage.used - All above, but combined
Asynchronous functions:
var result = IOP.loadModule(fname, arg_len, args)
var result = IOP.loadModuleBuffer(mod_buf, arg_len, args)
IOP.loadDefaultModule(mod_id)
• IOP.keyboard - USB Keyboard
• IOP.mouse - USB Mouse
• IOP.freeram - IOP RAM Info
• IOP.ds34bt - Bluetooth DualShock 3/4 pads
• IOP.ds34usb - USB DualShock 3/4 pads
• IOP.network - Network drivers
• IOP.pads - DualShock 1/2 pads
• IOP.memcard - Memory Card
• IOP.audio - Audio driver
• IOP.usb_mass - USB Mass storage, supports FAT32 and exFAT
• IOP.cdfs - Disc driver
• IOP.hdd - Internal HDD driver
• IOP.boot_device - Storage device used to boot Athena
IOP.reset()
var stats = IOP.getMemoryStats() - P.S.: Requires IOP.loadDefaultModule(IOP.freeram) first!
• stats.free
• stats.used
Network.init(ip, netmask, gateway, dns)
Network.init("192.168.0.10", "255.255.255.0", "192.168.0.1", "192.168.0.1"); //Static mode
Network.init(); //DHCP Mode, dynamic.
var conf = Network.getConfig()
Returns conf.ip, conf.netmask, conf.gateway, conf.dns.
Network.deinit()
Shutdown network module.
Construction:
var r = new Request();
Properties:
Methods:
Asynchronous methods:
Construction:
var s = new Socket(AF_INET, SOCK_STREAM);
Methods:
Construction:
var s = new WebSocket("wss://example.com");
Methods:
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
git checkout -b feature/AwesomeFeature
)git commit -m 'Add some AwesomeFeature'
)git push origin feature/AwesomeFeature
)Distributed under GNU GPL-3.0 License. See LICENSE
for more information.
Daniel Santos - @danadsees - danielsantos346@gmail.com
Project Link: https://github.com/DanielSant0s/AthenaEnv
Here are some direct and indirect thanks to the people who made the project viable!