Skip to content

Non Stream Files (API)

Ali Hussain edited this page Sep 28, 2023 · 1 revision

Non-Stream Files

Files in Smash Ultimate take two forms: stream files (in the stream:/ directory of the arc) which are uncompressed and non-stream files, which are usually compressed. Internally the game views the two completely separately. Most users will be interested in non-stream files, however due to how the game handles them, they are the most restricted.

First to use the API to modify non-stream files on-the-fly you need to create a callback. This is a function called whenever files registered to the callback are loaded by the game.

The structure for a non-stream callback is as follows:

use arcropolis_api::arc_callback;

#[arc_callback]
fn my_callback(hash: u64, data: &mut [u8]) -> Option<usize> {
    None
}

The inputs:

  • hash - the hash40 of the absolute file path of the file being loaded
  • data - the buffer to load the file into. more on this in a second.

The return value options:

  • Some(N) - The callback has loaded the file into the buffer. The file is N bytes long.
  • None - the callback did not load a file. When None is returned, Arcropolis will load the file from the SD card (if available) or from the vanilla data.arc

However, just creating a callback doesn't do anything! You need to register files to use the callback:

const MAX_FILE_SIZE: usize = 0x1234;

fn main() {
    my_callback::install("fighter/fox/model/body/c00/body_fox_001_col.nutexb", MAX_FILE_SIZE);
}

When installing your callback you need to provide two things:

  1. A path/hash for the file. This can either be a string to be hashed or a u64 of the raw hash.
  2. A maximum file size for the given file. The game pre-allocates a buffer to load the file into that we must use. In order to patch the file size we need to know on boot the largest size the file will be. (NOTE: this amount of space WILL be allocated, so your estimate must be at least as large as the file being loaded, but must be reasonable for memory constraints)

One more feature of Arcropolis callbacks is loading the original file within the callback to allow for modifying vanilla files at runtime.

load_original_file:

Arguments:

  • hash - hash to load from
  • buffer - buffer to load into

Return: Option<usize> - the size of the file loaded, or None if no file exists.