retroarch_write_ram
Write byte values to a specified memory address in a running emulated game via RetroArch's Network Control Interface. Disables hardcore mode for the session.
Instructions
Write to CHEEVOS memory address space. Fire-and-forget — RetroArch sends no acknowledgement for this command. Disables hardcore mode for the session.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | ||
| bytes | Yes |
Implementation Reference
- src/tools.ts:222-225 (handler)Handler for retroarch_write_ram: calls ra.writeRam() and returns a success message indicating fire-and-forget (no ack).
case "retroarch_write_ram": { await ra.writeRam(p.address as number, p.bytes as number[]); return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`); } - src/tools.ts:84-99 (schema)Schema registration for retroarch_write_ram: defines inputSchema with required 'address' (integer) and 'bytes' (array of 0-255, 1-4096 items).
{ name: "retroarch_write_ram", description: "Write to CHEEVOS memory address space. Fire-and-forget — RetroArch sends no acknowledgement for this command. Disables hardcore mode for the session.", inputSchema: { type: "object", required: ["address", "bytes"], properties: { address: { type: "integer" }, bytes: { type: "array", items: { type: "integer", minimum: 0, maximum: 255 }, minItems: 1, maxItems: 4096, }, }, }, - src/tools.ts:176-246 (registration)Registration of all tools via ListToolsRequestSchema (line 177) and CallToolRequestSchema (line 179) handlers. retroarch_write_ram is dispatched at line 222.
export function registerTools(server: Server, ra: RetroArchClient): void { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args = {} } = req.params; const p = args as Record<string, unknown>; switch (name) { case "retroarch_ping": { const v = await ra.getVersion(); return ok(`OK — RetroArch ${v}`); } case "retroarch_get_status": { const s = await ra.getStatus(); if (s.state === "contentless") return ok("No content loaded"); return ok( `State: ${s.state}\n` + `System: ${s.system}\n` + `Game: ${s.game}\n` + `CRC32: ${s.crc32 ?? "(none reported)"}`, ); } case "retroarch_get_config": { const v = await ra.getConfigParam(p.name as string); return ok(`${p.name} = ${v}`); } case "retroarch_read_memory": { const bytes = await ra.readMemory(p.address as number, p.length as number); const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0").toUpperCase()).join(" "); return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\n${hex}`); } case "retroarch_write_memory": { const n = await ra.writeMemory(p.address as number, p.bytes as number[]); return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`); } case "retroarch_read_ram": { const bytes = await ra.readRam(p.address as number, p.length as number); const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0").toUpperCase()).join(" "); return ok(`${addrHex(p.address as number)} [${bytes.length} bytes, CHEEVOS]:\n${hex}`); } case "retroarch_write_ram": { await ra.writeRam(p.address as number, p.bytes as number[]); return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`); } case "retroarch_pause_toggle": await ra.pauseToggle(); return ok("Pause toggled"); case "retroarch_frame_advance": await ra.frameAdvance(); return ok("Advanced one frame"); case "retroarch_reset": await ra.reset(); return ok("Game reset"); case "retroarch_screenshot": await ra.screenshot(); return ok("Screenshot saved to RetroArch's configured screenshot directory"); case "retroarch_show_message": { await ra.showMessage(p.message as string); return ok(`Showed: ${p.message}`); } case "retroarch_save_state_current": await ra.saveStateCurrent(); return ok("Saved to current slot"); case "retroarch_load_state_current": await ra.loadStateCurrent(); return ok("Loaded from current slot"); case "retroarch_load_state_slot": await ra.loadStateSlot(p.slot as number); return ok(`Loaded from slot ${p.slot}`); case "retroarch_state_slot_plus": await ra.stateSlotPlus(); return ok("Incremented current slot"); case "retroarch_state_slot_minus": await ra.stateSlotMinus(); return ok("Decremented current slot"); default: throw new Error(`Unknown tool: ${name}`); } }); } - src/retroarch.ts:181-187 (helper)Helper function writeRam() in RetroArchClient: sends WRITE_CORE_RAM command via UDP fire-and-forget. No reply expected.
/** Memory write via CHEEVOS address space. No reply — fire-and-forget. */ async writeRam(addr: number, bytes: Uint8Array | number[]): Promise<void> { if (bytes.length === 0) throw new Error("at least one byte required"); if (bytes.length > 4096) throw new Error("byte count exceeds 4096 limit"); const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join(" "); await this.send(`WRITE_CORE_RAM 0x${addr.toString(16)} ${hex}`); }