Walkthrough: hello-unit
examples/hello-unit in the SDK repository is a complete unit for FINAL
FANTASY XIII (Steam). It:
- verifies one call site in the game executable (another mod’s entry detour there is accepted);
- keeps a storage record counting the sessions it ran in, in the mod’s host storage (never in the game’s saves);
- adds a settings page with a section and a checkbox to the shared Mod Settings menu;
- logs a greeting at start and a line at shutdown.
1. Get the code
Section titled “1. Get the code”git clone https://github.com/hectormiguel1/workshop-extension-sdkcd workshop-extension-sdk2. Read the unit
Section titled “2. Read the unit”Open examples/hello-unit/src/lib.rs. From top to bottom:
-
IDis the stable unit, storage region and settings provider ID,example.hello. -
NEEDSrequires FINAL FANTASY XIII, the log service and a mapped image. -
sites!declaresSITES: one function entry with its first 16 retail bytes, kindcall. -
Savedis the stored record:#[derive(Clone, Debug, PartialEq, workshop_ext_sdk::PackedRecord)]#[packed(version = 1, schema = 1)]pub struct Saved {#[packed(max = 65535)]pub sessions: u16,#[packed(default = 1)]pub greet: bool,} -
settings!declaresmenu: a General section with a Greet at field idle checkbox bound to theGREETatomic. -
start(init, read, memory)is the unit’s logic. It takes the image reader and the memory policy as parameters, so tests can run it:host.require(&NEEDS), or returnUNUSABLE_CONTEXT;sites::verify(SITES, ...), logging every problem and accepted detour; returnREFUSEDunless every site passed;init.storage(ID): read the record (Saved::load), add one session, write it back against the revision it read;init.settings(): registermenu::queryundermenu::ID;HOST.set(host), soshutdowncan log later;- log
hello: session Nwhen the checkbox is on.
-
live_startpasses the real image reader andwin::LiveMemoryon Windows (and stand-ins elsewhere, so the code builds everywhere). -
ff13_unit! { init: live_start, shutdown: stop }emits the two exports.
3. Run its tests
Section titled “3. Run its tests”cargo test -p hello-unitThe tests run start against FakeHost with a reader that serves the
expected bytes:
- the first run returns 0, logs
hello: session 1, registers a two-row menu and stores{ sessions: 1, greet: true }; - seeding that record back, the next run counts session 2;
- XIII-2 is refused with code 1, an unreadable site with code 2, and a null context with code 1.
4. Build the DLL
Section titled “4. Build the DLL”cargo build -p hello-unit --target i686-pc-windows-gnu --profile host-dllcargo run -p workshop-ext-sdk --example export_check -- \ target/i686-pc-windows-gnu/host-dll/hello_unit.dllhost-dll is the workspace’s shipping profile (release, fat LTO, one
codegen unit, symbols stripped, panics unwind). export_check prints
exports exactly init, shutdown.
5. Package and run it
Section titled “5. Package and run it”- In CrystalWorkshop, open FINAL FANTASY XIII, then the Project page.
- Add the DLL under the unit id
example.helloand tick Late (first field idle), to match the example’s “Greet at field idle” setting. - Export… › Shard (.cws), name it “Hello unit”, version
0.1.0. - Install the shard with PulseDepot (and the XIII Mod Settings mod for the menu), apply, start the game.
Crux.jsonl then shows hello: session 1, and hello: session 2 the next
time you start the game. The example ships no translated texts, so in the
XIII Mod Settings menu its labels read “Unavailable” until you add them
(see In-game settings).
The full step-by-step is in Package a shard.
Make it yours
Section titled “Make it yours”- Change
ID(and the package name) before you change anything else. - Replace
SITESwith the addresses your unit needs, copied with their bytes from the executable you verified. - Add hooks with
init.install_hooks(see Sites and hooks) and settings that follow the save slot withPerSave(see Storage and per-save state).
