Project Anatomy - jam1garner/cargo-mextk GitHub Wiki

Next up, you may or may not be asking: "What are all these files in my project? What do they do?". Regardless of whether you're asking, that's what this page will answer.

The project template looks something like...

├── Cargo.toml
├── Mextk.toml
└── src
    └── lib.rs

So! Let's go through what everything in each of these files does.

Cargo.toml:

[package]
name = "my_project"
version = "0.1.0"
authors = []
edition = "2018"

[dependencies]
mextk = "0.1"

The Cargo.toml file is a standard part of any Rust project. It contains all the information you need to build the Rust code itself. Most parts should be self explanatory, although if you're curious about more details see The Cargo Manifest Reference.

Most notable here is:

[dependencies]
mextk = "0.1"

Which indicates we are pulling in a Rust library called mextk. If we want to take a look at its documentation, we can go to https://docs.rs/mextk to see the documentation. All Rust libraries have documentation automatically uploaded to docs.rs

Mextk.toml

# cargo-mextk template

# overrides Fox
dat = "PlFx.dat"

# use fighter symbols to allow overriding relevant code
symbols = "fighter"

The Mextk.toml file tells cargo-mextk the Melee-specific information needed to compile our code. This includes which dat file we are modifying, as well as what symbols we need. In this case, since the default template modifies Fox, it replaces PlFx.dat (Player Fox) and needs the symbols for "fighter" hooks.

A full list of possible values for the symbols key:

  • "css"
  • "event"
  • "fighter"
  • "stage"
  • "item"
  • "kirby"
  • "major_scene"
  • "minor_scene"
  • "tournament"

lib.rs

The src/lib.rs file contains all of the code our mod will include. Currently it is in a very rough state, however this will improve over time as more parts of the modding process are abstracted out. The default contents at time of writing (minus a bit of stuff before/after that you can ignore) is currently:

use mextk::sys::{GOBJ, OSReport};

#[no_mangle]
pub extern "C" fn OnLoad(_: *const GOBJ) {
    unsafe {
        OSReport("Hello World\0".as_ptr() as _);
    }
}

So what does each line do?

use mextk::sys::{GOBJ, OSReport};

This imports the GOBJ struct and the OSReport function from the "sys" module of mextk. The sys module is where the raw bindings to the raw m-ex C API live. They aren't very idiomatic Rust but contain everything you'll need to write mods. Over time, more of the sys module will be abstracted and be brought out to the mextk crate itself. If you're interested in the documentation for the sys module, see https://docs.rs/mextk-sys for a full listing of what's available.


#[no_mangle]

This tells Rust to export our function name as-is.


pub extern "C" fn OnLoad(_: *const GOBJ) {

This declares a public function, that is externally exposed to a "C" interface. The name of the function is OnLoad (named after where we are hooking), and it takes a parameter of *const GOBJ (a pointer to a GOBJ). The _: means the parameter is unused.


    unsafe {

This indicates that the following operation is unsafe (as Rust can't verify the C bindings won't crash the game).


        OSReport("Hello World\0".as_ptr() as _);

And lastly we have our line of code that logs "Hello World". OSReport is the system logger, which logs where Dolphin can show us. This is useful for debugging/testing our code. "Hello World\0".as_ptr() as _ Is our string. In C, strings are expected to all have a trailing null-terminator (that is, a 0 byte indicating the end of the string). In Rust, however, strings aren't null-terminated, so we need to add that before passing a string to C code (like OSReport), this is just a temporary hacky manner of doing that.