Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Data files: tune without restarting

Keep the numbers you tweak (speeds, damage, costs, wave sizes) in a JSON file in assets/ instead of in code. With hot reload on (the default in debug builds), saving the file changes them in the running game, within a quarter of a second, so you can tune a fight while watching it.

#![allow(unused)]
fn main() {
#[derive(serde::Deserialize)]
struct Tuning {
    speed: f32,
    damage: f32,
}

fn load_tuning(ctx: &mut Ctx, path: &str) {
    ctx.load_resource::<Tuning>(path); // e.g. "tuning.json": {"speed": 30, "damage": 2}
}

fn step_size(ctx: &Ctx) -> f32 {
    // The file's current values, every tick.
    ctx.world.resource::<Tuning>().speed * ctx.dt()
}
}
struct Tuning { float speed; float damage; };

[[maybe_unused]] static void load_tuning(crabby::ctx& ctx) {
    ctx.world().reflect_resource<Tuning>({crabby::field("speed", &Tuning::speed), crabby::field("damage", &Tuning::damage)});
    ctx.load_json<Tuning>("tuning.json");   // {"speed": 30, "damage": 2}
    // Systems read ctx.world().resource<Tuning>(): the file's current values.
}

In Rust the file becomes a resource: any type that implements serde::Deserialize, replaced whole on each reload (use #[serde(default)] for optional fields). In C and C++ the resource is a plain struct described with reflect_resource, and the file’s fields merge into it, so the file may list only some of them (C: crabby_ctx_load_resource_json). C++ can also load a file into a component of one entity: ctx.load_json<T>(path, e).

  • Loading fails with a clear message: a missing file lists the folders searched, and bad JSON says the line and column.
  • A file that doesn’t parse while the game runs (often one caught halfway through saving) keeps the old values and prints why; the next good save applies.
  • ctx.reloaded_files() names the files reloaded this frame, textures included, for work that depends on them (rebuilding a map, say). In C++, ctx.was_reloaded("map.json") (C: crabby_ctx_was_reloaded).
  • Headless runs reload too, so an agent or a test can change a file between ticks.