openrac_gaddr
Since 1.0Typetypedef uint32_t openrac_gaddr;+Example (1)
static void pad_process_report(openrac_gaddr pad, openrac_gaddr report, int32_t size) {
++s_reports;
s_pad_original(pad, report, size);
}You are reading the docs of SDK 1.7.0, an older release. See the latest (1.11.0).
Reference · SDK 1.7.0
openrac_mod.h. A mod is built against this header alone. Each item says which interface version added it; check api->api_minor before you use something newer than your manifest's api| Name | Value | What it is |
|---|---|---|
| OPENRAC_MOD_API_MAJOR | 1 | The interface's major version. Changes when anything in the table changes or goes. |
| OPENRAC_MOD_API_MINOR | 7 | The interface's minor version, which this header describes. It grows when something is added at the end of the table.Show what each version added (7)Hide
|
| OPENRAC_MOD_TARGET_MINOR | OPENRAC_MOD_API_MINOR | The interface a mod is built for, what its openrac_mod_query reports:Moreits manifest's "api" minor, which the SDK's openrac_add_mod passes in, else this header's. A mod for 1.1 built with a newer SDK thus still loads on a port of 1.1 (and uses nothing newer without checking api->api_minor). |
| OPENRAC_MOD_EXPORT | __declspec(dllexport) or __attribute__((visibility("default"))) | Since 1.0 Marks an entry point of the mod's library as exported, whatever the build's default visibility. |
typedef uint32_t openrac_gaddr;static void pad_process_report(openrac_gaddr pad, openrac_gaddr report, int32_t size) {
++s_reports;
s_pad_original(pad, report, size);
}typedef struct openrac_mod openrac_mod;#include "openrac/openrac_mod.h"
#include "openrac/games/rac1.h"
OPENRAC_MOD_DEFINE("my-mod", "0.1.0") /* openrac_mod_query: the interface version, the id */
OPENRAC_MOD_EXPORT int openrac_mod_load(const openrac_api* api, openrac_mod* mod) {
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "this mod is for Ratchet & Clank");
return 1; /* not loaded; the reason is shown */
}
api->log(mod, OPENRAC_LOG_INFO, "hello");
return 0; /* loaded */
} * counts. It changes nothing in the game.
*
* How it works: OPENRAC_MOD_DEFINE writes openrac_mod_query; openrac_mod_load keeps the table and
* the handle in file-level variables (the port calls the mod's functions on the game's thread, one
* at a time, so no lock is needed), takes the hook point and the callback, and logs a line;
* openrac_mod_unload logs the totals at exit. Written in C, so the whole mod is plain C99 against
* openrac_mod.h and games/rac1.h.
*/
#include <stdio.h>
#include <string.h>| Name | Value | What it is |
|---|---|---|
| OPENRAC_LOG_DEBUG | 0 | Since 1.0 The levels of openrac_api.log, from the most to the least talkative. |
| OPENRAC_LOG_INFO | 1 | |
| OPENRAC_LOG_WARN | 2 | |
| OPENRAC_LOG_ERROR | 3 | |
| OPENRAC_HOOK_OK | 0 | Since 1.0 The results of openrac_api.hook. |
| OPENRAC_HOOK_UNKNOWN | (-1) | This port has no hook point of that name (on this disc). |
| OPENRAC_HOOK_SIGNATURE | (-2) | The hook point's signature is another than the one asked for. |
| OPENRAC_HOOK_TOO_LATE | (-3) | Hooks are taken in openrac_mod_load only. |
| OPENRAC_HOOK_TAKEN | (-4) | Since 1.4 Another mod has it already: the views (on_views) and the Vulkan device (setup_vulkan) are one mod's each. |
size; the mod sets the rest (OPENRAC_MOD_DEFINE does).| Member | What it is |
|---|---|
| uint32_t size | sizeof(openrac_mod_info), set by the port. |
| uint32_t api_major | OPENRAC_MOD_API_MAJOR as the mod was built. |
| uint32_t api_minor | OPENRAC_MOD_TARGET_MINOR as the mod was built. |
| const char* id | The manifest's id: the port checks they agree. Static storage in the mod. |
| const char* version | The mod's version, as its manifest's. Static storage in the mod. |
snprintf(
line,
sizeof line,
"counting on %s/%s, a line every %lld ticks",
api->game,
api->version,
(long long)s_every
);
api->log(mod, OPENRAC_LOG_INFO, line);| Name | Value | What it is |
|---|---|---|
| OPENRAC_KEY_COUNT | 512 | Since 1.2 The number of entries of openrac_input.keys. A key is its USB HID usage, the same on every layout and system (openrac/keys.h names them: "KeyW", "Space", "ShiftLeft"). |
| OPENRAC_KEY_HELD | 1u | Since 1.2 The key is down: a bit of an openrac_input.keys[k] entry. |
| OPENRAC_KEY_PRESSED | 2u | Since 1.2 The key went down since the last tick (a tap shorter than a tick too): a bit of an openrac_input.keys[k] entry. |
| OPENRAC_MOUSE_LEFT | 1u | Since 1.2 The bits of openrac_input.mouse_held and mouse_pressed. |
| OPENRAC_MOUSE_MIDDLE | 2u | |
| OPENRAC_MOUSE_RIGHT | 4u | |
| OPENRAC_MOUSE_BACK | 8u | The side button nearer the wrist (X1). |
| OPENRAC_MOUSE_FORWARD | 16u | The other side button (X2). |
| OPENRAC_INPUT_KEYBOARD | 1u | Since 1.2 A device of openrac_api.take_input: the port's own keyboard table stops driving pad 0. |
| OPENRAC_INPUT_MOUSE | 2u | Since 1.2 A device of openrac_api.take_input: the mod uses the mouse in play. Reserved: the port has no mouse use of its own in play. |
pointer_x on are 1.3's, and exist only when size reaches them.| Member | What it is |
|---|---|
| uint32_t size | sizeof(openrac_input) as the port was built: a newer port's is larger. |
| uint32_t tick | Counts the ticks: a new value, a new state. |
| uint8_t keys[OPENRAC_KEY_COUNT] | By HID usage: OPENRAC_KEY_HELD | OPENRAC_KEY_PRESSED. |
| uint32_t mouse_held | The OPENRAC_MOUSE_* buttons down now. |
| uint32_t mouse_pressed | The OPENRAC_MOUSE_* buttons that went down since the last tick. |
| float mouse_dx | The mouse's motion since the last tick, in the system's pixels: raw (no pointer acceleration) while captured; y grows downward. |
| float mouse_dy | (as above) |
| float wheel_x | The wheel since the last tick, in notches: x > 0 to the right, y > 0 away from the player (up), whatever the system's scroll direction. |
| float wheel_y | (as above) |
| uint8_t focused | 1 when the game's window has the keyboard; while not, nothing is held. |
| uint8_t captured | 1 when the cursor is captured: hidden, kept in the window, motion relative. |
| uint8_t overlay | 1 when the port's own overlay or menu has the input now (F3): leave it alone. |
| uint8_t reserved | Padding; zero. |
| float pointer_x | Since 1.3 (check size first): where the cursor is over the game's 4:3 picture, 0..1 across and down (outside it below 0 or above 1), as the game's 2D screen of 512 by 416 pixels has it:Morex * 512, y * 416 is the game's pixel. Meaningful while the cursor is not captured. |
| float pointer_y | (as above) |
| uint8_t pointer_inside | Since 1.3: 1 when the cursor is over the picture, in the focused window. |
| uint8_t reserved2[3] | Padding; zero. |
static void pad(void* user, int port, uint8_t* report, int size) {
const openrac_input* in = s_api->input(); /* this tick's keys and mouse */
if (port == 0 && openrac_bind_held(in, s_jump)) {
report[1] &= (uint8_t)~0x40; /* Cross held (bit 14: a clear bit is held) */
}
/* in->mouse_dx, mouse_dy: the motion since the last tick; wheel_x, wheel_y in notches */
}| Name | Value | What it is |
|---|---|---|
| OPENRAC_GRAPHICS_NONE | 0 | No window yet, or none at all (a test, a server). |
| OPENRAC_GRAPHICS_OPENGL | 1 | The desktop's OpenGL 4.1 core profile. |
| OPENRAC_GRAPHICS_OPENGL_ES | 2 | OpenGL ES 3.2 (Android, or OPENRAC_GL_API=es). |
| OPENRAC_GRAPHICS_VULKAN | 3 | The port's Vulkan renderer (OPENRAC_GL_API=vulkan). |
| Member | What it is |
|---|---|
| uint32_t size | sizeof(openrac_graphics) as the port was built: a newer port's is larger. |
| uint32_t backend | An OPENRAC_GRAPHICS_* value. |
| void *(*gl_proc)(const char *name) | OpenGL and OpenGL ES: the context's functions by name (SDL_GL_GetProcAddress); null for Vulkan and without a window. The context is current on the game's thread. |
| void *vk_instance | Vulkan: the backend's instance, physical device, device and graphics queue, its family and its index in the family, and the vkGetInstanceProcAddr they were made with;Morenull and 0 otherwise. While a mod has views (on_views) the port submits to the queue on the game's thread only, so a mod's own use of it there (OpenXR's xrEndFrame) needs no lock. |
| void *vk_physical_device | (as above) |
| void *vk_device | (as above) |
| void *vk_queue | (as above) |
| uint32_t vk_queue_family | (as above) |
| uint32_t vk_queue_index | (as above) |
| void *vk_get_instance_proc_addr | (as above) |
| Name | Value | What it is |
|---|---|---|
| OPENRAC_VIEW_MAX | 4 | Since 1.4 The most views a frame draws (openrac_view_source.begin's max). |
| OPENRAC_VIEW_FULL | 0 | The game's whole picture: the world, with the 2D (HUD, text, menus, fades) over it at the game's 4:3 shape in its middle. |
| OPENRAC_VIEW_WORLD | 1 | The world alone, without the 2D. |
| OPENRAC_VIEW_2D | 2 | The 2D alone, over transparent black (alpha 0 where nothing is drawn): for a panel. Give it the game's 4:3 shape; the eye pose and field of view are not used. |
image_layout in openrac_view_source.begin; the port sets the ones after as it draws.| Member | What it is |
|---|---|
| uint32_t kind | An OPENRAC_VIEW_* value. |
| int32_t width | The picture's size in pixels, each from 1 to 8192. |
| int32_t height | (as above) |
| float position[3] | The eye relative to the game's camera, in the camera's view space (OpenXR's and OpenGL's: X right, Y up, looking down -Z), in the game's units:Morea position, and an orientation as a quaternion x, y, z, w. The identity (0 0 0, 0 0 0 1) is the game's own camera; an all-zero orientation counts as the identity. |
| float orientation[4] | (as above) |
| float angle_left | The field of view as OpenXR's XrFovf gives it:Morethe angles of its left, right, top and bottom edges from straight ahead, in radians (left and down negative). All zero: the game's own vertical one, at the view's shape. |
| float angle_right | (as above) |
| float angle_up | (as above) |
| float angle_down | (as above) |
| uint32_t texture | Where the picture goes, in the backend's own terms (openrac_api.graphics), copied as its bytes with no conversion of colour (an sRGB image gets the game's picture as it is shown):More- OpenGL:texture, a GL_TEXTURE_2D of the port's context, RGBA8 or SRGB8_ALPHA8, at least width by height (an OpenXR swapchain image); - Vulkan: image, a VkImage of the port's device, VK_FORMAT_R8G8B8A8_UNORM or _SRGB, exactly width by height, usable as a transfer destination, which the port finds in image_layout (a VkImageLayout) and leaves in it. Zero and null: the picture is drawn only into the port's own texture (picture). |
| void *image | (as above) |
| uint32_t image_layout | (as above) |
| uint32_t drawn | Set by the port: 1 when this frame drew the view anew;More0 when it showed the last frame's picture again (a frame the port draws no world in, as the pause menu's repeated frames), and then that picture is copied again. |
| uint32_t picture | Set by the port: its own GL texture holding the view (with OpenGL), until the next frame. |
| uint32_t reserved[3] | Padding; zero. |
user is passed back to each. Every function is called on the game's thread, with the graphics context current.| Member | What it is |
|---|---|
| uint32_t size | sizeof(openrac_view_source) as the mod was built. |
| void *user | (as above) |
| int (*begin)(void *user, openrac_view *views, int max) | Called in each frame the port draws the game's scene (each refresh, between the game's ticks too), after the window's picture is recorded:Morefills views[0] to views[n - 1] (n at mostmax) and returns n; 0 draws none this frame. The place for OpenXR's xrWaitFrame, xrBeginFrame, xrLocateViews and xrAcquireSwapchainImage. Frames that show a movie or a still picture instead of the scene do not call it. |
| void (*end)(void *user, const openrac_view *views, int count) | Called once the frame that drew them is submitted to the GPU (after the window's picture is shown), with the views begin gave and what the port set in them:Morethe place for xrReleaseSwapchainImage and xrEndFrame. Called after everybegin, even one that returned 0 or a frame that drew nothing. |
| void (*closing)(void *user) | Called once before the graphics context goes (the window closes): let go of everything made with it (OpenXR's session and swapchains). Optional. |
user is passed back to each. The functions are called when the window opens, after openrac_mod_load, on the game's thread: the mod's manifest says "vulkan_device": true so that it loads before the window. Pointers stand for the Vulkan types named, and int32_t for VkResult.| Member | What it is |
|---|---|
| uint32_t size | sizeof(openrac_vulkan_setup) as the mod was built. |
| void *user | (as above) |
| int32_t (*create_instance)(void *user, void *get_instance_proc_addr, const void *create_info, void **instance) | Makes the instance from create_info (a const VkInstanceCreateInfo*, the port's: the extensions and the API version it needs) in place of vkCreateInstance, through get_instance_proc_addr (a PFN_vkGetInstanceProcAddr), and sets *instance.MoreReturns a VkResult; anything but VK_SUCCESS (0) and the port draws with OpenGL instead. Optional. |
| void *(*physical_device)(void *user, void *instance) | Returns the VkPhysicalDevice to draw on, of instance; null lets the port choose. The port refuses a device it cannot draw with (and draws with OpenGL instead). Optional. |
| int32_t (*create_device)(void *user, void *get_instance_proc_addr, void *physical_device, const void *create_info, void **device) | Makes the device from create_info (a const VkDeviceCreateInfo*, the port's) on physical_device in place of vkCreateDevice, and sets *device. Returns a VkResult, as create_instance. Optional. |
typedef void (*openrac_frame_fn)(void* user);user pointer the mod gave.typedef void (*openrac_tick_boundary_fn)(void* user, uint32_t tick);typedef void (*openrac_pad_fn)(void* user, int port, uint8_t* report, int size);user pointer the mod gave. report is the report as the console's pad library hands it to the game (its bytes, size of them), which the callback may change before the game reads it; port is the controller's port, 0 or 1.uint32_t size;uint16_t api_major;
uint16_t api_minor;const char* game;#include "openrac/openrac_mod.h"
#include "openrac/games/rac1.h"
OPENRAC_MOD_DEFINE("my-mod", "0.1.0") /* openrac_mod_query: the interface version, the id */
OPENRAC_MOD_EXPORT int openrac_mod_load(const openrac_api* api, openrac_mod* mod) {
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "this mod is for Ratchet & Clank");
return 1; /* not loaded; the reason is shown */
}
api->log(mod, OPENRAC_LOG_INFO, "hello");
return 0; /* loaded */
}/* The hook point and the memory it reads are Ratchet & Clank's: refuse any other game. */
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "frame-counter is for Ratchet & Clank (rac1)");
return 1;
}const char* version;snprintf(
line,
sizeof line,
"counting on %s/%s, a line every %lld ticks",
api->game,
api->version,
(long long)s_every
);
api->log(mod, OPENRAC_LOG_INFO, line);const char* openrac_version;const char* platform;uint8_t* memory;// Once a game tick: read or change game memory through mod.memory().
mod.on_frame([] {});void log(openrac_mod* mod, int level, const char* text);
// how a call looks
api->log(mod, level, text);level is an OPENRAC_LOG_* value.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.level (int)text (const char*)Constants it uses
#include "openrac/openrac_mod.h"
#include "openrac/games/rac1.h"
OPENRAC_MOD_DEFINE("my-mod", "0.1.0") /* openrac_mod_query: the interface version, the id */
OPENRAC_MOD_EXPORT int openrac_mod_load(const openrac_api* api, openrac_mod* mod) {
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "this mod is for Ratchet & Clank");
return 1; /* not loaded; the reason is shown */
}
api->log(mod, OPENRAC_LOG_INFO, "hello");
return 0; /* loaded */
} sizeof line,
"%llu ticks, %llu pad reports, level %d",
(unsigned long long)s_ticks,
(unsigned long long)s_reports,
s_api->loaded_level()
);
s_api->log(s_mod, s_verbose ? OPENRAC_LOG_INFO : OPENRAC_LOG_DEBUG, line);
}void fail(openrac_mod* mod, const char* reason);
// how a call looks
api->fail(mod, reason);Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.reason (const char*)#include "openrac/openrac_mod.h"
#include "openrac/games/rac1.h"
OPENRAC_MOD_DEFINE("my-mod", "0.1.0") /* openrac_mod_query: the interface version, the id */
OPENRAC_MOD_EXPORT int openrac_mod_load(const openrac_api* api, openrac_mod* mod) {
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "this mod is for Ratchet & Clank");
return 1; /* not loaded; the reason is shown */
}
api->log(mod, OPENRAC_LOG_INFO, "hello");
return 0; /* loaded */
}static openrac_rac1_Hero_SetPlanarVelocity s_original;
static void my_velocity(float angle) {
s_original(angle); /* the game's own, or the mod before yours */
}
/* in openrac_mod_load: */
if (OPENRAC_RAC1_HOOK(api, mod, Hero_SetPlanarVelocity, my_velocity, &s_original) != OPENRAC_HOOK_OK) {
api->fail(mod, "no Hero_SetPlanarVelocity in this OpenRAC");
return 1;
}int setting_bool(openrac_mod* mod, const char* key);
int64_t setting_int(openrac_mod* mod, const char* key);
double setting_float(openrac_mod* mod, const char* key);
const char* setting_string(openrac_mod* mod, const char* key);s_verbose = api->setting_bool(mod, "verbose");s_every = api->setting_int(mod, "every");int hook(
openrac_mod* mod,
const char* name,
const char* signature,
void* replacement,
void** original
);
// how a call looks
int result = api->hook(mod, name, signature, replacement, original);name (games/<game>.h: its name and signature) for replacement, a function of the hook point's signature, which signature spells.*original to what the replacement goes on to: the game's own function, or the replacement of a mod loaded earlier, so the mod loaded last runs first. Only during openrac_mod_load.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.name (const char*)signature (const char*)replacement (void*)original (void**)Returns
Results and errors
mod.hook<openrac::rac1::Hero_TurnToHeading>(
[trace, &mod](auto original, int32_t m, float accel, float damping, float limit) {
if (trace) mod.info("turning");
original(m, accel, damping, limit);
});// A hook: the lambda gets the way on (the game's function, or a mod's loaded earlier) first,
// then the hook point's arguments. An exception thrown here is logged, and the original runs.
mod.hook<openrac::rac1::Hero_SetPlanarVelocity>([](auto original, float angle) {
// ... before the game's own ...
original(angle);
// ... after it ...
});int on_frame(openrac_mod* mod, openrac_frame_fn fn, void* user);
// how a call looks
int result = api->on_frame(mod, fn, user);fn(user) after each game tick, in load order. Only during openrac_mod_load.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.fn (openrac_frame_fn)user (void*)Returns
static void tick(void* user) { /* after each game tick */ }
static void pad(void* user, int port, uint8_t* report, int size) { /* change report[] */ }
api->on_frame(mod, tick, NULL);
api->on_pad(mod, pad, NULL);api->on_frame(mod, on_frame, NULL);int on_pad(openrac_mod* mod, openrac_pad_fn fn, void* user);
// how a call looks
int result = api->on_pad(mod, fn, user);fn(user, port, report, size) for each pad report, before the game reads it, in load order. Only during openrac_mod_load.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.fn (openrac_pad_fn)user (void*)Returns
static void tick(void* user) { /* after each game tick */ }
static void pad(void* user, int port, uint8_t* report, int size) { /* change report[] */ }
api->on_frame(mod, tick, NULL);
api->on_pad(mod, pad, NULL);void* function(const char* name);
// how a call looks
void* result = api->function(name);Parameters
name (const char*)Returns
void* function_at(openrac_gaddr address);
// how a call looks
void* result = api->function_at(address);Parameters
address (openrac_gaddr)Returns
openrac_gaddr relocate_data(openrac_gaddr address);
openrac_gaddr relocate_level_data(int level, openrac_gaddr address);Returns
level's program (OPENRAC_LDATA).int loaded_level();
// how a call looks
int result = api->loaded_level();Returns
snprintf(
line,
sizeof line,
"%llu ticks, %llu pad reports, level %d",
(unsigned long long)s_ticks,
(unsigned long long)s_reports,
s_api->loaded_level()
);
s_api->log(s_mod, s_verbose ? OPENRAC_LOG_INFO : OPENRAC_LOG_DEBUG, line);
}openrac_gaddr stack_push(uint32_t size, openrac_gaddr* saved);
// how a call looks
openrac_gaddr result = api->stack_push(size, saved);Parameters
size (uint32_t)saved (openrac_gaddr*)Returns
size bytes (aligned to 16) of room on the game's stack for a call that takes the address of a local, and keeps the stack as it was in *saved. Returns the room's address.void stack_pop(openrac_gaddr saved);
// how a call looks
api->stack_pop(saved);Parameters
saved (openrac_gaddr)Returns
saved is what it stored.const openrac_input* input();
// how a call looks
const openrac_input* result = api->input();Returns
static void pad(void* user, int port, uint8_t* report, int size) {
const openrac_input* in = s_api->input(); /* this tick's keys and mouse */
if (port == 0 && openrac_bind_held(in, s_jump)) {
report[1] &= (uint8_t)~0x40; /* Cross held (bit 14: a clear bit is held) */
}
/* in->mouse_dx, mouse_dy: the motion since the last tick; wheel_x, wheel_y in notches */
}int take_input(openrac_mod* mod, uint32_t devices);
// how a call looks
int result = api->take_input(mod, devices);devices (OPENRAC_INPUT_*) from the port: with OPENRAC_INPUT_KEYBOARD the port's own keyboard table (WASD, Space, ...) no longer presses pad 0's buttons, and the mod presses them through on_pad instead. A gamepad goes on as before; the port's window keys (F3, F11) stay the port's.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.devices (uint32_t)Returns
Results and errors
/* in openrac_mod_load: */
s_jump = openrac_bind_from_name(api->setting_string(mod, "jump")); /* one bind; split a pair at ',' */
api->take_input(mod, OPENRAC_INPUT_KEYBOARD); /* the port's own WASD table stops */
api->capture_mouse(mod, 1); /* hidden cursor, relative motion */void capture_mouse(openrac_mod* mod, int capture);
// how a call looks
api->capture_mouse(mod, capture);capture 1: hidden, held in the window, motion relative, as a game's mouse look wants it) or let go (0).Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.capture (int)/* in openrac_mod_load: */
s_jump = openrac_bind_from_name(api->setting_string(mod, "jump")); /* one bind; split a pair at ',' */
api->take_input(mod, OPENRAC_INPUT_KEYBOARD); /* the port's own WASD table stops */
api->capture_mouse(mod, 1); /* hidden cursor, relative motion */const openrac_graphics * graphics();
// how a call looks
const openrac_graphics * result = api->graphics();Returns
Constants it uses
int on_views(openrac_mod* mod, const openrac_view_source* source);
// how a call looks
int result = api->on_views(mod, source);source (openrac_view_source), with OpenGL and Vulkan. While a mod has views, the Vulkan renderer draws on the game's thread.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.source (const openrac_view_source*)Returns
int setup_vulkan(openrac_mod* mod, const openrac_vulkan_setup* setup);
// how a call looks
int result = api->setup_vulkan(mod, setup);setup (openrac_vulkan_setup) when the window opens, so that the mod can share it. Without Vulkan (OpenGL, a build without it) nothing is called.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.setup (const openrac_vulkan_setup*)Returns
int menu_entry(
openrac_mod* mod,
const char* label,
openrac_menu_fn fn,
void* user
);
// how a call looks
int result = api->menu_entry(mod, label, fn, user);label (ASCII, up to 31 characters) to the game's front-end menu, which opens a page of the mod's own:fn(user, frame) each frame it is open (openrac_menu_fn). Ratchet & Clank has it in the title's Options list, after the port's own entries (Video, and Planets with developer tools). A game whose front end the port does not know shows none.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.label (const char*)fn (openrac_menu_fn)user (void*)Returns
void menu_rect(
openrac_mod* mod,
int x,
int y,
int width,
int height,
uint32_t rgba
);
// how a call looks
api->menu_rect(mod, x, y, width, height, rgba);width by height pixels whose top left is (x, y) on the menu page (OPENRAC_MENU_WIDTH by OPENRAC_MENU_HEIGHT) with rgba (OPENRAC_RGBA), blended by its alpha; what is outside the page is left out. Only during the mod's own menu callback; ignored otherwise.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.x (int)y (int)width (int)height (int)rgba (uint32_t)Constants it uses
void menu_text(
openrac_mod* mod,
int x,
int y,
int size,
uint32_t rgba,
const char* text
);
// how a call looks
api->menu_text(mod, x, y, size, rgba, text);text (ASCII; a newline starts a line below) on the menu page with its first character's top left at (x, y), each character OPENRAC_MENU_CHAR_WIDTH by OPENRAC_MENU_CHAR_HEIGHT times size (1 to 8), in rgba. Only during the mod's own menu callback; ignored otherwise.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.x (int)y (int)size (int)rgba (uint32_t)text (const char*)Constants it uses
int on_tick_boundary(
openrac_mod* mod,
openrac_tick_boundary_fn fn,
void* user
);
// how a call looks
int result = api->on_tick_boundary(mod, fn, user);fn(user, tick) after the game's vertical-blank handlers have run, the port's tick boundary, the only place the savestate calls below are accepted (openrac_tick_boundary_fn).Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.fn (openrac_tick_boundary_fn)user (void*)Returns
Results and errors
size_t savestate_size();
// how a call looks
size_t result = api->savestate_size();Returns
size_tint savestate_save(void* out, size_t size);
// how a call looks
int result = api->savestate_save(out, size);out, size being savestate_size(). Only inside on_tick_boundary; returns 0 on success. The bytes are private to this process and build, not for a cold restore or another version.Parameters
out (void*)size (size_t)Returns
intint savestate_load(const void* data, size_t size);
// how a call looks
int result = api->savestate_load(data, size);Parameters
data (const void*)size (size_t)Returns
intint ui_page(openrac_mod* mod, uint32_t flags, openrac_ui_fn fn, void* user);
// how a call looks
int result = api->ui_page(mod, flags, fn, user);flags), with nothing on it yet (ui_set), whose events go to fn(user, page, event) (openrac_ui_fn).Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.flags (uint32_t)fn (openrac_ui_fn)user (void*)Returns
int ui_main_item(
openrac_mod* mod,
const char* after,
const char* label,
int page
);
// how a call looks
int result = api->ui_main_item(mod, after, label, page);label to the title's main menu, after its own item after (OPENRAC_UI_NEW_GAME, OPENRAC_UI_LOAD_GAME, OPENRAC_UI_OPTIONS), which opens the mod's page. Two after the same item go in the order they were added.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.after (const char*)label (const char*)page (int)Returns
after, no label, a page that is not the mod's, or past OPENRAC_UI_MAIN_ITEMS_MAX, or OPENRAC_HOOK_TOO_LATE after openrac_mod_load.int ui_set(openrac_mod* mod, int page, const openrac_ui_content* content);
// how a call looks
int result = api->ui_set(mod, page, content);content on the mod's page (openrac_ui_content), in place of what it had: shown at once if the page is on the screen. Any time. The cursor stays on its item (on the last when there are fewer, and off a TEXT).Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.page (int)content (const openrac_ui_content*)Returns
Results and errors
int ui_open(openrac_mod* mod, int page);
// how a call looks
int result = api->ui_open(mod, page);page, a level under a page the main menu opened or in place of one under it; a page that is on a level above goes back to it. OPENRAC_UI_GO_BACK goes back a level, as Triangle does.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.page (int)Returns
Results and errors
int ui_confirm(
openrac_mod* mod,
int page,
const char* question,
uint32_t tag
);
// how a call looks
int result = api->ui_confirm(mod, page, question, tag);page is on the screen: asks question with the game's prompt box in place of the list, the footer saying Cross is yes and Triangle no; the answer is an OPENRAC_UI_ANSWER with tag.Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.page (int)question (const char*)tag (uint32_t)Returns
Results and errors
int ui_cursor(openrac_mod* mod, int page, int item);
// how a call looks
int result = api->ui_cursor(mod, page, item);Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.page (int)item (int)Returns
page (-1 for a page that is not the mod's), after moving it to item when that is 0 or more and an item the cursor takes.int ui_sound(openrac_mod* mod, int sound);
// how a call looks
int result = api->ui_sound(mod, sound);Parameters
mod (openrac_mod*): your mod's handle, as openrac_mod_load got it.sound (int)Returns
typedef void (*openrac_mod_query_fn)(openrac_mod_info* info);info's api_major, api_minor, id and version. Called before the mod is loaded. Required; OPENRAC_MOD_DEFINE writes it.typedef int (*openrac_mod_load_fn)(const openrac_api* api, openrac_mod* mod);api, and keeps mod for the calls that are its own. Returns 0 to load, non-zero to refuse (after openrac_api.fail gave the reason). Required.typedef void (*openrac_mod_unload_fn)(void);| Name | Value | What it is |
|---|---|---|
| OPENRAC_MOD_QUERY | "openrac_mod_query" | Since 1.0 The names the entry points are exported under, for the port's lookup. |
| OPENRAC_MOD_LOAD | "openrac_mod_load" | |
| OPENRAC_MOD_UNLOAD | "openrac_mod_unload" |
#define OPENRAC_G(api, a) ((void*)((api)->memory + (openrac_gaddr)(a)))#define OPENRAC_GREF(api, T, a) (*(T*)OPENRAC_G(api, a))T.#define OPENRAC_MOD_DEFINE(mod_id, mod_version) ...mod_id and mod_version are string literals, the manifest's.#include "openrac/openrac_mod.h"
#include "openrac/games/rac1.h"
OPENRAC_MOD_DEFINE("my-mod", "0.1.0") /* openrac_mod_query: the interface version, the id */
OPENRAC_MOD_EXPORT int openrac_mod_load(const openrac_api* api, openrac_mod* mod) {
if (strcmp(api->game, "rac1") != 0) {
api->fail(mod, "this mod is for Ratchet & Clank");
return 1; /* not loaded; the reason is shown */
}
api->log(mod, OPENRAC_LOG_INFO, "hello");
return 0; /* loaded */
} *
* An example mod that uses each part of the interface (sdk/README.md): it refuses a game it is not
* for, reads a bool and an int setting, counts the game's ticks with on_frame, and takes a hook
* point, counting the calls and going on to what it replaced. Every `every` ticks it logs both
* counts. It changes nothing in the game.
*
* How it works: OPENRAC_MOD_DEFINE writes openrac_mod_query; openrac_mod_load keeps the table and
* the handle in file-level variables (the port calls the mod's functions on the game's thread, one
* at a time, so no lock is needed), takes the hook point and the callback, and logs a line;
* openrac_mod_unload logs the totals at exit. Written in C, so the whole mod is plain C99 against
* openrac_mod.h and games/rac1.h.
*/
#include <stdio.h>Generated from sdk/include/openrac/openrac_mod.h at sdk-v1.7.0. Edit this page or report a problem.