mkdasher / mupen64-rr-lua-

Mupen 64 Lua
GNU General Public License v2.0
32 stars 16 forks source link

API to hook in external tooling #215

Open TimeTravelPenguin opened 1 month ago

TimeTravelPenguin commented 1 month ago

Is there currently support for hooking in an external tool that can control user input? I have been learning Rust and would like to get into playing with algorithms that can perform optimised searches.

I am not sure if this would even be possible as this kind of lower-level systems programming is not my typical domain of interest, so I am not entirely certain how you would typically go about doing it.

As such, I was wondering if it were possible to allow for external tools to connect and serve as a controller, being able to monitor memory, savestates, etc., allowing for autonomous control of Mupen by a 3rd party tool.

Depending on the complexity of Mupen, I assume it would be possible, perhaps through a plugin interface, where the external app would be fed state and would return controller/application input.

If something like this can already be done, I would love to know more about where to look.

Thanks

Aurumaker72 commented 1 month ago

Hi TTP,

there is no official API for full procedural control of Mupen.

However, depending on your requirements, you might be able to get away with generating hotkey presses via SendInput to trigger various actions.

If you only need control over the game input, you can write a custom input plugin in Rust.

TimeTravelPenguin commented 1 month ago

Thanks for your reply.

I'll have to think about what I want to do. I've always wanted to experiment with machine learning in something like SM64, but I don't really want to use vision as the primary input, so I may need to work out how to monitor memory.

If I do get around to this project, I may pop into Discord sometime after November if I need help.

Is there any reference or documentation for Mupen?

Edit: the Discord link in the readme is invalid

Aurumaker72 commented 1 month ago

To read Mupen's memory, you can do it externally via ReadProcessMemory like STROOP, or internally by writing to rdram (memory/memory.h) directly or via the helper functions LoadRDRAMSafe and StoreRDRAMSafe.

Mupen currently has no comprehensive docs so feel free to ask anytime in the discord.

Wade7wastaken commented 1 month ago

Just for fun, here's a proof of concept of reading Mario's speed in Rust using the ReadProcessMemory method mentioned above. You can get the PID of the mupen process using Task Manager's "Details" tab, and the address comes from STROOP (right click on variable > click Show Variable Info > Emulator Address)

[dependencies]
winapi = { version = "0.3.9", features = ["memoryapi", "processthreadsapi", "handleapi"] }
use winapi::{
    ctypes::c_void,
    um::{
        handleapi::CloseHandle, memoryapi::ReadProcessMemory, processthreadsapi::OpenProcess,
        winnt::PROCESS_VM_READ,
    },
};

fn read_float(pid: u32, address: u32) -> f32 {
    let handle = unsafe { OpenProcess(PROCESS_VM_READ, 0, pid) };
    if handle.is_null() {
        panic!("Handle was null");
    }

    let mut buffer = [0u8; 4]; // float is 4 bytes
    let read_result = unsafe {
        ReadProcessMemory(
            handle,
            address as *const c_void,
            buffer.as_mut_ptr() as *mut c_void,
            4, // float is 4 bytes
            &mut 0,
        )
    };

    let close_handle_result = unsafe { CloseHandle(handle) };

    if close_handle_result == 0 {
        eprintln!("Handle didn't close correctly"); // don't panic, we may still have something in read_result
    }

    if read_result == 0 {
        panic!("Read failed");
    }

    f32::from_le_bytes(buffer)
}

fn main() {
    let pid = 9820;
    let address = 0x00BFB184;
    let speed = read_float(pid, address);

    println!("{:?}", speed);
}

Ofc this could be improved with better rust error handling or maybe a generic read function that can read different types (float, s16, etc...), but in my opinion it's better to use C/C++ when using windows apis because you don't have to do any type gymnastics or deal with unsafe.

Madghostek commented 1 month ago

While this is cool, I don't really see the point of hooking into mupen when there is wafel as a library 🤨

TimeTravelPenguin commented 1 month ago

While this is cool, I don't really see the point of hooking into mupen when there is wafel as a library 🤨

Oh, interesting. I have never seen this. However, I don't want to be limited to only SM64. This will be a good place to start, though!